xref: /dflybsd-src/sys/dev/netif/msk/if_msk.c (revision 030b0c8c4cf27c560ccec70410c8e21934ae677d)
12d586421SSepherosa Ziehau /******************************************************************************
22d586421SSepherosa Ziehau  *
32d586421SSepherosa Ziehau  * Name   : sky2.c
42d586421SSepherosa Ziehau  * Project: Gigabit Ethernet Driver for FreeBSD 5.x/6.x
52d586421SSepherosa Ziehau  * Version: $Revision: 1.23 $
62d586421SSepherosa Ziehau  * Date   : $Date: 2005/12/22 09:04:11 $
72d586421SSepherosa Ziehau  * Purpose: Main driver source file
82d586421SSepherosa Ziehau  *
92d586421SSepherosa Ziehau  *****************************************************************************/
102d586421SSepherosa Ziehau 
112d586421SSepherosa Ziehau /******************************************************************************
122d586421SSepherosa Ziehau  *
132d586421SSepherosa Ziehau  *	LICENSE:
142d586421SSepherosa Ziehau  *	Copyright (C) Marvell International Ltd. and/or its affiliates
152d586421SSepherosa Ziehau  *
162d586421SSepherosa Ziehau  *	The computer program files contained in this folder ("Files")
172d586421SSepherosa Ziehau  *	are provided to you under the BSD-type license terms provided
182d586421SSepherosa Ziehau  *	below, and any use of such Files and any derivative works
192d586421SSepherosa Ziehau  *	thereof created by you shall be governed by the following terms
202d586421SSepherosa Ziehau  *	and conditions:
212d586421SSepherosa Ziehau  *
222d586421SSepherosa Ziehau  *	- Redistributions of source code must retain the above copyright
232d586421SSepherosa Ziehau  *	  notice, this list of conditions and the following disclaimer.
242d586421SSepherosa Ziehau  *	- Redistributions in binary form must reproduce the above
252d586421SSepherosa Ziehau  *	  copyright notice, this list of conditions and the following
262d586421SSepherosa Ziehau  *	  disclaimer in the documentation and/or other materials provided
272d586421SSepherosa Ziehau  *	  with the distribution.
282d586421SSepherosa Ziehau  *	- Neither the name of Marvell nor the names of its contributors
292d586421SSepherosa Ziehau  *	  may be used to endorse or promote products derived from this
302d586421SSepherosa Ziehau  *	  software without specific prior written permission.
312d586421SSepherosa Ziehau  *
322d586421SSepherosa Ziehau  *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
332d586421SSepherosa Ziehau  *	"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
342d586421SSepherosa Ziehau  *	LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
352d586421SSepherosa Ziehau  *	FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
362d586421SSepherosa Ziehau  *	COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
372d586421SSepherosa Ziehau  *	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
382d586421SSepherosa Ziehau  *	BUT NOT LIMITED TO, PROCUREMENT OF  SUBSTITUTE GOODS OR SERVICES;
392d586421SSepherosa Ziehau  *	LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
402d586421SSepherosa Ziehau  *	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
412d586421SSepherosa Ziehau  *	STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
422d586421SSepherosa Ziehau  *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
432d586421SSepherosa Ziehau  *	OF THE POSSIBILITY OF SUCH DAMAGE.
442d586421SSepherosa Ziehau  *	/LICENSE
452d586421SSepherosa Ziehau  *
462d586421SSepherosa Ziehau  *****************************************************************************/
472d586421SSepherosa Ziehau 
482d586421SSepherosa Ziehau /*-
492d586421SSepherosa Ziehau  * Copyright (c) 1997, 1998, 1999, 2000
502d586421SSepherosa Ziehau  *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
512d586421SSepherosa Ziehau  *
522d586421SSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
532d586421SSepherosa Ziehau  * modification, are permitted provided that the following conditions
542d586421SSepherosa Ziehau  * are met:
552d586421SSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
562d586421SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer.
572d586421SSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
582d586421SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
592d586421SSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
602d586421SSepherosa Ziehau  * 3. All advertising materials mentioning features or use of this software
612d586421SSepherosa Ziehau  *    must display the following acknowledgement:
622d586421SSepherosa Ziehau  *	This product includes software developed by Bill Paul.
632d586421SSepherosa Ziehau  * 4. Neither the name of the author nor the names of any co-contributors
642d586421SSepherosa Ziehau  *    may be used to endorse or promote products derived from this software
652d586421SSepherosa Ziehau  *    without specific prior written permission.
662d586421SSepherosa Ziehau  *
672d586421SSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
682d586421SSepherosa Ziehau  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
692d586421SSepherosa Ziehau  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
702d586421SSepherosa Ziehau  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
712d586421SSepherosa Ziehau  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
722d586421SSepherosa Ziehau  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
732d586421SSepherosa Ziehau  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
742d586421SSepherosa Ziehau  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
752d586421SSepherosa Ziehau  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
762d586421SSepherosa Ziehau  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
772d586421SSepherosa Ziehau  * THE POSSIBILITY OF SUCH DAMAGE.
782d586421SSepherosa Ziehau  */
792d586421SSepherosa Ziehau /*-
802d586421SSepherosa Ziehau  * Copyright (c) 2003 Nathan L. Binkert <binkertn@umich.edu>
812d586421SSepherosa Ziehau  *
822d586421SSepherosa Ziehau  * Permission to use, copy, modify, and distribute this software for any
832d586421SSepherosa Ziehau  * purpose with or without fee is hereby granted, provided that the above
842d586421SSepherosa Ziehau  * copyright notice and this permission notice appear in all copies.
852d586421SSepherosa Ziehau  *
862d586421SSepherosa Ziehau  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
872d586421SSepherosa Ziehau  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
882d586421SSepherosa Ziehau  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
892d586421SSepherosa Ziehau  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
902d586421SSepherosa Ziehau  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
912d586421SSepherosa Ziehau  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
922d586421SSepherosa Ziehau  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
932d586421SSepherosa Ziehau  */
942d586421SSepherosa Ziehau 
952d586421SSepherosa Ziehau /* $FreeBSD: src/sys/dev/msk/if_msk.c,v 1.26 2007/12/05 09:41:58 remko Exp $ */
962d586421SSepherosa Ziehau 
972d586421SSepherosa Ziehau /*
982d586421SSepherosa Ziehau  * Device driver for the Marvell Yukon II Ethernet controller.
992d586421SSepherosa Ziehau  * Due to lack of documentation, this driver is based on the code from
1002d586421SSepherosa Ziehau  * sk(4) and Marvell's myk(4) driver for FreeBSD 5.x.
1012d586421SSepherosa Ziehau  */
1022d586421SSepherosa Ziehau 
1032d586421SSepherosa Ziehau #include <sys/param.h>
1042d586421SSepherosa Ziehau #include <sys/endian.h>
1052d586421SSepherosa Ziehau #include <sys/kernel.h>
1062d586421SSepherosa Ziehau #include <sys/bus.h>
1072d586421SSepherosa Ziehau #include <sys/in_cksum.h>
1089db4b353SSepherosa Ziehau #include <sys/interrupt.h>
1092d586421SSepherosa Ziehau #include <sys/malloc.h>
1102d586421SSepherosa Ziehau #include <sys/proc.h>
1112d586421SSepherosa Ziehau #include <sys/rman.h>
1122d586421SSepherosa Ziehau #include <sys/serialize.h>
1132d586421SSepherosa Ziehau #include <sys/socket.h>
1142d586421SSepherosa Ziehau #include <sys/sockio.h>
1152d586421SSepherosa Ziehau #include <sys/sysctl.h>
1162d586421SSepherosa Ziehau 
1172d586421SSepherosa Ziehau #include <net/ethernet.h>
1182d586421SSepherosa Ziehau #include <net/if.h>
1192d586421SSepherosa Ziehau #include <net/bpf.h>
1202d586421SSepherosa Ziehau #include <net/if_arp.h>
1212d586421SSepherosa Ziehau #include <net/if_dl.h>
1222d586421SSepherosa Ziehau #include <net/if_media.h>
1232d586421SSepherosa Ziehau #include <net/ifq_var.h>
1242d586421SSepherosa Ziehau #include <net/vlan/if_vlan_var.h>
1252d586421SSepherosa Ziehau 
1262d586421SSepherosa Ziehau #include <netinet/ip.h>
1272d586421SSepherosa Ziehau #include <netinet/ip_var.h>
1282d586421SSepherosa Ziehau 
1292d586421SSepherosa Ziehau #include <dev/netif/mii_layer/miivar.h>
1302d586421SSepherosa Ziehau 
1312d586421SSepherosa Ziehau #include <bus/pci/pcireg.h>
1322d586421SSepherosa Ziehau #include <bus/pci/pcivar.h>
1332d586421SSepherosa Ziehau 
1342d586421SSepherosa Ziehau #include "if_mskreg.h"
1352d586421SSepherosa Ziehau 
1362d586421SSepherosa Ziehau /* "device miibus" required.  See GENERIC if you get errors here. */
1372d586421SSepherosa Ziehau #include "miibus_if.h"
1382d586421SSepherosa Ziehau 
1392d586421SSepherosa Ziehau #define MSK_CSUM_FEATURES	(CSUM_TCP | CSUM_UDP)
1402d586421SSepherosa Ziehau 
1412d586421SSepherosa Ziehau /*
1422d586421SSepherosa Ziehau  * Devices supported by this driver.
1432d586421SSepherosa Ziehau  */
1442d586421SSepherosa Ziehau static const struct msk_product {
1452d586421SSepherosa Ziehau 	uint16_t	msk_vendorid;
1462d586421SSepherosa Ziehau 	uint16_t	msk_deviceid;
1472d586421SSepherosa Ziehau 	const char	*msk_name;
1482d586421SSepherosa Ziehau } msk_products[] = {
1492d586421SSepherosa Ziehau 	{ VENDORID_SK, DEVICEID_SK_YUKON2,
1502d586421SSepherosa Ziehau 	    "SK-9Sxx Gigabit Ethernet" },
1512d586421SSepherosa Ziehau 	{ VENDORID_SK, DEVICEID_SK_YUKON2_EXPR,
1522d586421SSepherosa Ziehau 	    "SK-9Exx Gigabit Ethernet"},
1532d586421SSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_8021CU,
1542d586421SSepherosa Ziehau 	    "Marvell Yukon 88E8021CU Gigabit Ethernet" },
1552d586421SSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_8021X,
1562d586421SSepherosa Ziehau 	    "Marvell Yukon 88E8021 SX/LX Gigabit Ethernet" },
1572d586421SSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_8022CU,
1582d586421SSepherosa Ziehau 	    "Marvell Yukon 88E8022CU Gigabit Ethernet" },
1592d586421SSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_8022X,
1602d586421SSepherosa Ziehau 	    "Marvell Yukon 88E8022 SX/LX Gigabit Ethernet" },
1612d586421SSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_8061CU,
1622d586421SSepherosa Ziehau 	    "Marvell Yukon 88E8061CU Gigabit Ethernet" },
1632d586421SSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_8061X,
1642d586421SSepherosa Ziehau 	    "Marvell Yukon 88E8061 SX/LX Gigabit Ethernet" },
1652d586421SSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_8062CU,
1662d586421SSepherosa Ziehau 	    "Marvell Yukon 88E8062CU Gigabit Ethernet" },
1672d586421SSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_8062X,
1682d586421SSepherosa Ziehau 	    "Marvell Yukon 88E8062 SX/LX Gigabit Ethernet" },
1692d586421SSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_8035,
170b0968976SSepherosa Ziehau 	    "Marvell Yukon 88E8035 Fast Ethernet" },
1712d586421SSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_8036,
172b0968976SSepherosa Ziehau 	    "Marvell Yukon 88E8036 Fast Ethernet" },
1732d586421SSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_8038,
174b0968976SSepherosa Ziehau 	    "Marvell Yukon 88E8038 Fast Ethernet" },
1752d586421SSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_8039,
176b0968976SSepherosa Ziehau 	    "Marvell Yukon 88E8039 Fast Ethernet" },
177080bd27eSSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_8040,
178080bd27eSSepherosa Ziehau 	    "Marvell Yukon 88E8040 Fast Ethernet" },
179080bd27eSSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_8040T,
180080bd27eSSepherosa Ziehau 	    "Marvell Yukon 88E8040T Fast Ethernet" },
181cb658b16SSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_8042,
182cb658b16SSepherosa Ziehau 	    "Marvell Yukon 88E8042 Fast Ethernet" },
183080bd27eSSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_8048,
184080bd27eSSepherosa Ziehau 	    "Marvell Yukon 88E8048 Fast Ethernet" },
1852d586421SSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_4361,
1862d586421SSepherosa Ziehau 	    "Marvell Yukon 88E8050 Gigabit Ethernet" },
1872d586421SSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_4360,
1882d586421SSepherosa Ziehau 	    "Marvell Yukon 88E8052 Gigabit Ethernet" },
1892d586421SSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_4362,
1902d586421SSepherosa Ziehau 	    "Marvell Yukon 88E8053 Gigabit Ethernet" },
1912d586421SSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_4363,
1922d586421SSepherosa Ziehau 	    "Marvell Yukon 88E8055 Gigabit Ethernet" },
1932d586421SSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_4364,
1942d586421SSepherosa Ziehau 	    "Marvell Yukon 88E8056 Gigabit Ethernet" },
195d9e919c4SSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_4365,
196d9e919c4SSepherosa Ziehau 	    "Marvell Yukon 88E8070 Gigabit Ethernet" },
1972d586421SSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_436A,
1982d586421SSepherosa Ziehau 	    "Marvell Yukon 88E8058 Gigabit Ethernet" },
199d9e919c4SSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_436B,
200d9e919c4SSepherosa Ziehau 	    "Marvell Yukon 88E8071 Gigabit Ethernet" },
201d9e919c4SSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_436C,
202d9e919c4SSepherosa Ziehau 	    "Marvell Yukon 88E8072 Gigabit Ethernet" },
2030d557164SSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_436D,
2040d557164SSepherosa Ziehau 	    "Marvell Yukon 88E8055 Gigabit Ethernet" },
2050d557164SSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_4370,
2060d557164SSepherosa Ziehau 	    "Marvell Yukon 88E8075 Gigabit Ethernet" },
2073b7c5d2cSSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_4380,
2083b7c5d2cSSepherosa Ziehau 	    "Marvell Yukon 88E8057 Gigabit Ethernet" },
2098e916b42SSepherosa Ziehau 	{ VENDORID_MARVELL, DEVICEID_MRVL_4381,
2108e916b42SSepherosa Ziehau 	    "Marvell Yukon 88E8059 Gigabit Ethernet" },
2112d586421SSepherosa Ziehau 	{ VENDORID_DLINK, DEVICEID_DLINK_DGE550SX,
2122d586421SSepherosa Ziehau 	    "D-Link 550SX Gigabit Ethernet" },
2132d586421SSepherosa Ziehau 	{ VENDORID_DLINK, DEVICEID_DLINK_DGE560T,
2142d586421SSepherosa Ziehau 	    "D-Link 560T Gigabit Ethernet" },
2152d586421SSepherosa Ziehau 	{ 0, 0, NULL }
2162d586421SSepherosa Ziehau };
2172d586421SSepherosa Ziehau 
2182d586421SSepherosa Ziehau static const char *model_name[] = {
2192d586421SSepherosa Ziehau 	"Yukon XL",
2202d586421SSepherosa Ziehau 	"Yukon EC Ultra",
221d9e919c4SSepherosa Ziehau 	"Yukon EX",
2222d586421SSepherosa Ziehau 	"Yukon EC",
223080bd27eSSepherosa Ziehau 	"Yukon FE",
2243b7c5d2cSSepherosa Ziehau 	"Yukon FE+",
2253b7c5d2cSSepherosa Ziehau 	"Yukon Supreme",
2268e916b42SSepherosa Ziehau 	"Yukon Ultra 2",
2278e916b42SSepherosa Ziehau 	"Yukon Unknown",
2288e916b42SSepherosa Ziehau 	"Yukon Optima"
2292d586421SSepherosa Ziehau };
2302d586421SSepherosa Ziehau 
2312d586421SSepherosa Ziehau static int	mskc_probe(device_t);
2322d586421SSepherosa Ziehau static int	mskc_attach(device_t);
2332d586421SSepherosa Ziehau static int	mskc_detach(device_t);
2342d586421SSepherosa Ziehau static int	mskc_shutdown(device_t);
2352d586421SSepherosa Ziehau static int	mskc_suspend(device_t);
2362d586421SSepherosa Ziehau static int	mskc_resume(device_t);
2372d586421SSepherosa Ziehau static void	mskc_intr(void *);
2382d586421SSepherosa Ziehau 
2392d586421SSepherosa Ziehau static void	mskc_reset(struct msk_softc *);
240f59f1081SSepherosa Ziehau static void	mskc_set_imtimer(struct msk_softc *);
2412d586421SSepherosa Ziehau static void	mskc_intr_hwerr(struct msk_softc *);
2422d586421SSepherosa Ziehau static int	mskc_handle_events(struct msk_softc *);
2432d586421SSepherosa Ziehau static void	mskc_phy_power(struct msk_softc *, int);
2442d586421SSepherosa Ziehau static int	mskc_setup_rambuffer(struct msk_softc *);
2452d586421SSepherosa Ziehau static int	mskc_status_dma_alloc(struct msk_softc *);
2462d586421SSepherosa Ziehau static void	mskc_status_dma_free(struct msk_softc *);
247f59f1081SSepherosa Ziehau static int	mskc_sysctl_proc_limit(SYSCTL_HANDLER_ARGS);
248f59f1081SSepherosa Ziehau static int	mskc_sysctl_intr_rate(SYSCTL_HANDLER_ARGS);
249f59f1081SSepherosa Ziehau 
2502d586421SSepherosa Ziehau static int	msk_probe(device_t);
2512d586421SSepherosa Ziehau static int	msk_attach(device_t);
2522d586421SSepherosa Ziehau static int	msk_detach(device_t);
2532d586421SSepherosa Ziehau static int	msk_miibus_readreg(device_t, int, int);
2542d586421SSepherosa Ziehau static int	msk_miibus_writereg(device_t, int, int, int);
2552d586421SSepherosa Ziehau static void	msk_miibus_statchg(device_t);
2562d586421SSepherosa Ziehau 
2572d586421SSepherosa Ziehau static void	msk_init(void *);
2582d586421SSepherosa Ziehau static int	msk_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
259f0a26983SSepherosa Ziehau static void	msk_start(struct ifnet *, struct ifaltq_subque *);
2602d586421SSepherosa Ziehau static void	msk_watchdog(struct ifnet *);
2612d586421SSepherosa Ziehau static int	msk_mediachange(struct ifnet *);
2622d586421SSepherosa Ziehau static void	msk_mediastatus(struct ifnet *, struct ifmediareq *);
2632d586421SSepherosa Ziehau 
2642d586421SSepherosa Ziehau static void	msk_tick(void *);
2652d586421SSepherosa Ziehau static void	msk_intr_phy(struct msk_if_softc *);
2662d586421SSepherosa Ziehau static void	msk_intr_gmac(struct msk_if_softc *);
2672d586421SSepherosa Ziehau static __inline void
2682d586421SSepherosa Ziehau 		msk_rxput(struct msk_if_softc *);
2692d586421SSepherosa Ziehau static void	msk_handle_hwerr(struct msk_if_softc *, uint32_t);
270eda7db08SSepherosa Ziehau static void	msk_rxeof(struct msk_if_softc *, uint32_t, int);
2712d586421SSepherosa Ziehau static void	msk_txeof(struct msk_if_softc *, int);
2722d586421SSepherosa Ziehau static void	msk_set_prefetch(struct msk_softc *, int, bus_addr_t, uint32_t);
2732d586421SSepherosa Ziehau static void	msk_set_rambuffer(struct msk_if_softc *);
2742d586421SSepherosa Ziehau static void	msk_stop(struct msk_if_softc *);
2752d586421SSepherosa Ziehau 
2762d586421SSepherosa Ziehau static int	msk_txrx_dma_alloc(struct msk_if_softc *);
2772d586421SSepherosa Ziehau static void	msk_txrx_dma_free(struct msk_if_softc *);
2782d586421SSepherosa Ziehau static int	msk_init_rx_ring(struct msk_if_softc *);
2792d586421SSepherosa Ziehau static void	msk_init_tx_ring(struct msk_if_softc *);
2802d586421SSepherosa Ziehau static __inline void
2812d586421SSepherosa Ziehau 		msk_discard_rxbuf(struct msk_if_softc *, int);
2822499c577SSepherosa Ziehau static int	msk_newbuf(struct msk_if_softc *, int, int);
2832d586421SSepherosa Ziehau static int	msk_encap(struct msk_if_softc *, struct mbuf **);
2842d586421SSepherosa Ziehau 
2852d586421SSepherosa Ziehau #ifdef MSK_JUMBO
2862d586421SSepherosa Ziehau static int msk_init_jumbo_rx_ring(struct msk_if_softc *);
2872d586421SSepherosa Ziehau static __inline void msk_discard_jumbo_rxbuf(struct msk_if_softc *, int);
2882d586421SSepherosa Ziehau static int msk_jumbo_newbuf(struct msk_if_softc *, int);
2892d586421SSepherosa Ziehau static void msk_jumbo_rxeof(struct msk_if_softc *, uint32_t, int);
2902d586421SSepherosa Ziehau static void *msk_jalloc(struct msk_if_softc *);
2912d586421SSepherosa Ziehau static void msk_jfree(void *, void *);
2922d586421SSepherosa Ziehau #endif
2932d586421SSepherosa Ziehau 
2942d586421SSepherosa Ziehau static int	msk_phy_readreg(struct msk_if_softc *, int, int);
2952d586421SSepherosa Ziehau static int	msk_phy_writereg(struct msk_if_softc *, int, int, int);
2962d586421SSepherosa Ziehau 
297dc7303ffSSepherosa Ziehau static void	msk_rxfilter(struct msk_if_softc *);
2982d586421SSepherosa Ziehau static void	msk_setvlan(struct msk_if_softc *, struct ifnet *);
299d9e919c4SSepherosa Ziehau static void	msk_set_tx_stfwd(struct msk_if_softc *);
3002d586421SSepherosa Ziehau 
3012d586421SSepherosa Ziehau static int	msk_dmamem_create(device_t, bus_size_t, bus_dma_tag_t *,
3022d586421SSepherosa Ziehau 				  void **, bus_addr_t *, bus_dmamap_t *);
3032d586421SSepherosa Ziehau static void	msk_dmamem_destroy(bus_dma_tag_t, void *, bus_dmamap_t);
3042d586421SSepherosa Ziehau 
3052d586421SSepherosa Ziehau static device_method_t mskc_methods[] = {
3062d586421SSepherosa Ziehau 	/* Device interface */
3072d586421SSepherosa Ziehau 	DEVMETHOD(device_probe,		mskc_probe),
3082d586421SSepherosa Ziehau 	DEVMETHOD(device_attach,	mskc_attach),
3092d586421SSepherosa Ziehau 	DEVMETHOD(device_detach,	mskc_detach),
3102d586421SSepherosa Ziehau 	DEVMETHOD(device_suspend,	mskc_suspend),
3112d586421SSepherosa Ziehau 	DEVMETHOD(device_resume,	mskc_resume),
3122d586421SSepherosa Ziehau 	DEVMETHOD(device_shutdown,	mskc_shutdown),
3132d586421SSepherosa Ziehau 
3142d586421SSepherosa Ziehau 	/* bus interface */
3152d586421SSepherosa Ziehau 	DEVMETHOD(bus_print_child,	bus_generic_print_child),
3162d586421SSepherosa Ziehau 	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
3172d586421SSepherosa Ziehau 
3182d586421SSepherosa Ziehau 	{ NULL, NULL }
3192d586421SSepherosa Ziehau };
3202d586421SSepherosa Ziehau 
3212d586421SSepherosa Ziehau static DEFINE_CLASS_0(mskc, mskc_driver, mskc_methods, sizeof(struct msk_softc));
3222d586421SSepherosa Ziehau static devclass_t mskc_devclass;
3232d586421SSepherosa Ziehau 
3242d586421SSepherosa Ziehau static device_method_t msk_methods[] = {
3252d586421SSepherosa Ziehau 	/* Device interface */
3262d586421SSepherosa Ziehau 	DEVMETHOD(device_probe,		msk_probe),
3272d586421SSepherosa Ziehau 	DEVMETHOD(device_attach,	msk_attach),
3282d586421SSepherosa Ziehau 	DEVMETHOD(device_detach,	msk_detach),
3292d586421SSepherosa Ziehau 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
3302d586421SSepherosa Ziehau 
3312d586421SSepherosa Ziehau 	/* bus interface */
3322d586421SSepherosa Ziehau 	DEVMETHOD(bus_print_child,	bus_generic_print_child),
3332d586421SSepherosa Ziehau 	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
3342d586421SSepherosa Ziehau 
3352d586421SSepherosa Ziehau 	/* MII interface */
3362d586421SSepherosa Ziehau 	DEVMETHOD(miibus_readreg,	msk_miibus_readreg),
3372d586421SSepherosa Ziehau 	DEVMETHOD(miibus_writereg,	msk_miibus_writereg),
3382d586421SSepherosa Ziehau 	DEVMETHOD(miibus_statchg,	msk_miibus_statchg),
3392d586421SSepherosa Ziehau 
3402d586421SSepherosa Ziehau 	{ NULL, NULL }
3412d586421SSepherosa Ziehau };
3422d586421SSepherosa Ziehau 
3432d586421SSepherosa Ziehau static DEFINE_CLASS_0(msk, msk_driver, msk_methods, sizeof(struct msk_if_softc));
3442d586421SSepherosa Ziehau static devclass_t msk_devclass;
3452d586421SSepherosa Ziehau 
3462d586421SSepherosa Ziehau DECLARE_DUMMY_MODULE(if_msk);
347aa2b9d05SSascha Wildner DRIVER_MODULE(if_msk, pci, mskc_driver, mskc_devclass, NULL, NULL);
348aa2b9d05SSascha Wildner DRIVER_MODULE(if_msk, mskc, msk_driver, msk_devclass, NULL, NULL);
349aa2b9d05SSascha Wildner DRIVER_MODULE(miibus, msk, miibus_driver, miibus_devclass, NULL, NULL);
3502d586421SSepherosa Ziehau 
351496e336aSSepherosa Ziehau static int	mskc_msi_enable = 0;
352f59f1081SSepherosa Ziehau static int	mskc_intr_rate = 0;
353f59f1081SSepherosa Ziehau static int	mskc_process_limit = MSK_PROC_DEFAULT;
354f59f1081SSepherosa Ziehau 
355f59f1081SSepherosa Ziehau TUNABLE_INT("hw.mskc.intr_rate", &mskc_intr_rate);
356f59f1081SSepherosa Ziehau TUNABLE_INT("hw.mskc.process_limit", &mskc_process_limit);
357d24322f3SSepherosa Ziehau TUNABLE_INT("hw.mskc.msi.enable", &mskc_msi_enable);
358f59f1081SSepherosa Ziehau 
3592d586421SSepherosa Ziehau static int
msk_miibus_readreg(device_t dev,int phy,int reg)3602d586421SSepherosa Ziehau msk_miibus_readreg(device_t dev, int phy, int reg)
3612d586421SSepherosa Ziehau {
3622d586421SSepherosa Ziehau 	struct msk_if_softc *sc_if;
3632d586421SSepherosa Ziehau 
3642d586421SSepherosa Ziehau 	if (phy != PHY_ADDR_MARV)
3652d586421SSepherosa Ziehau 		return (0);
3662d586421SSepherosa Ziehau 
3672d586421SSepherosa Ziehau 	sc_if = device_get_softc(dev);
3682d586421SSepherosa Ziehau 
3692d586421SSepherosa Ziehau 	return (msk_phy_readreg(sc_if, phy, reg));
3702d586421SSepherosa Ziehau }
3712d586421SSepherosa Ziehau 
3722d586421SSepherosa Ziehau static int
msk_phy_readreg(struct msk_if_softc * sc_if,int phy,int reg)3732d586421SSepherosa Ziehau msk_phy_readreg(struct msk_if_softc *sc_if, int phy, int reg)
3742d586421SSepherosa Ziehau {
3752d586421SSepherosa Ziehau 	struct msk_softc *sc;
3762d586421SSepherosa Ziehau 	int i, val;
3772d586421SSepherosa Ziehau 
3782d586421SSepherosa Ziehau 	sc = sc_if->msk_softc;
3792d586421SSepherosa Ziehau 
3802d586421SSepherosa Ziehau         GMAC_WRITE_2(sc, sc_if->msk_port, GM_SMI_CTRL,
3812d586421SSepherosa Ziehau 	    GM_SMI_CT_PHY_AD(phy) | GM_SMI_CT_REG_AD(reg) | GM_SMI_CT_OP_RD);
3822d586421SSepherosa Ziehau 
3832d586421SSepherosa Ziehau 	for (i = 0; i < MSK_TIMEOUT; i++) {
3842d586421SSepherosa Ziehau 		DELAY(1);
3852d586421SSepherosa Ziehau 		val = GMAC_READ_2(sc, sc_if->msk_port, GM_SMI_CTRL);
3862d586421SSepherosa Ziehau 		if ((val & GM_SMI_CT_RD_VAL) != 0) {
3872d586421SSepherosa Ziehau 			val = GMAC_READ_2(sc, sc_if->msk_port, GM_SMI_DATA);
3882d586421SSepherosa Ziehau 			break;
3892d586421SSepherosa Ziehau 		}
3902d586421SSepherosa Ziehau 	}
3912d586421SSepherosa Ziehau 
3922d586421SSepherosa Ziehau 	if (i == MSK_TIMEOUT) {
3932d586421SSepherosa Ziehau 		if_printf(sc_if->msk_ifp, "phy failed to come ready\n");
3942d586421SSepherosa Ziehau 		val = 0;
3952d586421SSepherosa Ziehau 	}
3962d586421SSepherosa Ziehau 
3972d586421SSepherosa Ziehau 	return (val);
3982d586421SSepherosa Ziehau }
3992d586421SSepherosa Ziehau 
4002d586421SSepherosa Ziehau static int
msk_miibus_writereg(device_t dev,int phy,int reg,int val)4012d586421SSepherosa Ziehau msk_miibus_writereg(device_t dev, int phy, int reg, int val)
4022d586421SSepherosa Ziehau {
4032d586421SSepherosa Ziehau 	struct msk_if_softc *sc_if;
4042d586421SSepherosa Ziehau 
4052d586421SSepherosa Ziehau 	if (phy != PHY_ADDR_MARV)
4062d586421SSepherosa Ziehau 		return (0);
4072d586421SSepherosa Ziehau 
4082d586421SSepherosa Ziehau 	sc_if = device_get_softc(dev);
4092d586421SSepherosa Ziehau 
4102d586421SSepherosa Ziehau 	return (msk_phy_writereg(sc_if, phy, reg, val));
4112d586421SSepherosa Ziehau }
4122d586421SSepherosa Ziehau 
4132d586421SSepherosa Ziehau static int
msk_phy_writereg(struct msk_if_softc * sc_if,int phy,int reg,int val)4142d586421SSepherosa Ziehau msk_phy_writereg(struct msk_if_softc *sc_if, int phy, int reg, int val)
4152d586421SSepherosa Ziehau {
4162d586421SSepherosa Ziehau 	struct msk_softc *sc;
4172d586421SSepherosa Ziehau 	int i;
4182d586421SSepherosa Ziehau 
4192d586421SSepherosa Ziehau 	sc = sc_if->msk_softc;
4202d586421SSepherosa Ziehau 
4212d586421SSepherosa Ziehau 	GMAC_WRITE_2(sc, sc_if->msk_port, GM_SMI_DATA, val);
4222d586421SSepherosa Ziehau         GMAC_WRITE_2(sc, sc_if->msk_port, GM_SMI_CTRL,
4232d586421SSepherosa Ziehau 	    GM_SMI_CT_PHY_AD(phy) | GM_SMI_CT_REG_AD(reg));
4242d586421SSepherosa Ziehau 	for (i = 0; i < MSK_TIMEOUT; i++) {
4252d586421SSepherosa Ziehau 		DELAY(1);
4262d586421SSepherosa Ziehau 		if ((GMAC_READ_2(sc, sc_if->msk_port, GM_SMI_CTRL) &
4272d586421SSepherosa Ziehau 		    GM_SMI_CT_BUSY) == 0)
4282d586421SSepherosa Ziehau 			break;
4292d586421SSepherosa Ziehau 	}
4302d586421SSepherosa Ziehau 	if (i == MSK_TIMEOUT)
4312d586421SSepherosa Ziehau 		if_printf(sc_if->msk_ifp, "phy write timeout\n");
4322d586421SSepherosa Ziehau 
4332d586421SSepherosa Ziehau 	return (0);
4342d586421SSepherosa Ziehau }
4352d586421SSepherosa Ziehau 
4362d586421SSepherosa Ziehau static void
msk_miibus_statchg(device_t dev)4372d586421SSepherosa Ziehau msk_miibus_statchg(device_t dev)
4382d586421SSepherosa Ziehau {
4392d586421SSepherosa Ziehau 	struct msk_if_softc *sc_if;
4402d586421SSepherosa Ziehau 	struct msk_softc *sc;
4412d586421SSepherosa Ziehau 	struct mii_data *mii;
4422d586421SSepherosa Ziehau 	uint32_t gmac;
4432d586421SSepherosa Ziehau 
4442d586421SSepherosa Ziehau 	sc_if = device_get_softc(dev);
4452d586421SSepherosa Ziehau 	sc = sc_if->msk_softc;
4462d586421SSepherosa Ziehau 
4472d586421SSepherosa Ziehau 	mii = device_get_softc(sc_if->msk_miibus);
4482d586421SSepherosa Ziehau 
4492d586421SSepherosa Ziehau 	sc_if->msk_link = 0;
4504992f870SSepherosa Ziehau 	if ((mii->mii_media_status & (IFM_AVALID | IFM_ACTIVE)) ==
4514992f870SSepherosa Ziehau 	    (IFM_AVALID | IFM_ACTIVE)) {
4524992f870SSepherosa Ziehau 		switch (IFM_SUBTYPE(mii->mii_media_active)) {
4534992f870SSepherosa Ziehau 		case IFM_10_T:
4544992f870SSepherosa Ziehau 		case IFM_100_TX:
4554992f870SSepherosa Ziehau 			sc_if->msk_link = 1;
4564992f870SSepherosa Ziehau 			break;
4574992f870SSepherosa Ziehau 		case IFM_1000_T:
4584992f870SSepherosa Ziehau 		case IFM_1000_SX:
4594992f870SSepherosa Ziehau 		case IFM_1000_LX:
4604992f870SSepherosa Ziehau 		case IFM_1000_CX:
4614992f870SSepherosa Ziehau 			if ((sc_if->msk_flags & MSK_FLAG_FASTETHER) == 0)
4624992f870SSepherosa Ziehau 				sc_if->msk_link = 1;
4634992f870SSepherosa Ziehau 			break;
4644992f870SSepherosa Ziehau 		}
4654992f870SSepherosa Ziehau 	}
4662d586421SSepherosa Ziehau 
4672d586421SSepherosa Ziehau 	if (sc_if->msk_link != 0) {
4682d586421SSepherosa Ziehau 		/* Enable Tx FIFO Underrun. */
4692d586421SSepherosa Ziehau 		CSR_WRITE_1(sc, MR_ADDR(sc_if->msk_port, GMAC_IRQ_MSK),
4702d586421SSepherosa Ziehau 		    GM_IS_TX_FF_UR | GM_IS_RX_FF_OR);
4712d586421SSepherosa Ziehau 		/*
4722d586421SSepherosa Ziehau 		 * Because mii(4) notify msk(4) that it detected link status
4732d586421SSepherosa Ziehau 		 * change, there is no need to enable automatic
4742d586421SSepherosa Ziehau 		 * speed/flow-control/duplex updates.
4752d586421SSepherosa Ziehau 		 */
4762d586421SSepherosa Ziehau 		gmac = GM_GPCR_AU_ALL_DIS;
4772d586421SSepherosa Ziehau 		switch (IFM_SUBTYPE(mii->mii_media_active)) {
4782d586421SSepherosa Ziehau 		case IFM_1000_SX:
4792d586421SSepherosa Ziehau 		case IFM_1000_T:
4802d586421SSepherosa Ziehau 			gmac |= GM_GPCR_SPEED_1000;
4812d586421SSepherosa Ziehau 			break;
4822d586421SSepherosa Ziehau 		case IFM_100_TX:
4832d586421SSepherosa Ziehau 			gmac |= GM_GPCR_SPEED_100;
4842d586421SSepherosa Ziehau 			break;
4852d586421SSepherosa Ziehau 		case IFM_10_T:
4862d586421SSepherosa Ziehau 			break;
4872d586421SSepherosa Ziehau 		}
4882d586421SSepherosa Ziehau 
4898f5842deSSepherosa Ziehau 		if ((mii->mii_media_active & IFM_GMASK) & IFM_FDX)
4902d586421SSepherosa Ziehau 			gmac |= GM_GPCR_DUP_FULL;
4918f5842deSSepherosa Ziehau 		else
4928f5842deSSepherosa Ziehau 			gmac |= GM_GPCR_FC_RX_DIS | GM_GPCR_FC_TX_DIS;
4932d586421SSepherosa Ziehau 		/* Disable Rx flow control. */
4942d586421SSepherosa Ziehau 		if (((mii->mii_media_active & IFM_GMASK) & IFM_FLAG0) == 0)
4952d586421SSepherosa Ziehau 			gmac |= GM_GPCR_FC_RX_DIS;
4962d586421SSepherosa Ziehau 		/* Disable Tx flow control. */
4972d586421SSepherosa Ziehau 		if (((mii->mii_media_active & IFM_GMASK) & IFM_FLAG1) == 0)
4982d586421SSepherosa Ziehau 			gmac |= GM_GPCR_FC_TX_DIS;
4992d586421SSepherosa Ziehau 		gmac |= GM_GPCR_RX_ENA | GM_GPCR_TX_ENA;
5002d586421SSepherosa Ziehau 		GMAC_WRITE_2(sc, sc_if->msk_port, GM_GP_CTRL, gmac);
5012d586421SSepherosa Ziehau 		/* Read again to ensure writing. */
5022d586421SSepherosa Ziehau 		GMAC_READ_2(sc, sc_if->msk_port, GM_GP_CTRL);
5032d586421SSepherosa Ziehau 
5048f5842deSSepherosa Ziehau 		gmac = GMC_PAUSE_OFF;
5058f5842deSSepherosa Ziehau 		if (((mii->mii_media_active & IFM_GMASK) & IFM_FLAG0) &&
5068f5842deSSepherosa Ziehau 		    ((mii->mii_media_active & IFM_GMASK) & IFM_FDX))
5072d586421SSepherosa Ziehau 			gmac = GMC_PAUSE_ON;
5082d586421SSepherosa Ziehau 		CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, GMAC_CTRL), gmac);
5092d586421SSepherosa Ziehau 
5102d586421SSepherosa Ziehau 		/* Enable PHY interrupt for FIFO underrun/overflow. */
5112d586421SSepherosa Ziehau 		msk_phy_writereg(sc_if, PHY_ADDR_MARV,
5122d586421SSepherosa Ziehau 		    PHY_MARV_INT_MASK, PHY_M_IS_FIFO_ERROR);
5132d586421SSepherosa Ziehau 	} else {
5142d586421SSepherosa Ziehau 		/*
5152d586421SSepherosa Ziehau 		 * Link state changed to down.
5162d586421SSepherosa Ziehau 		 * Disable PHY interrupts.
5172d586421SSepherosa Ziehau 		 */
5182d586421SSepherosa Ziehau 		msk_phy_writereg(sc_if, PHY_ADDR_MARV, PHY_MARV_INT_MASK, 0);
5192d586421SSepherosa Ziehau 		/* Disable Rx/Tx MAC. */
5202d586421SSepherosa Ziehau 		gmac = GMAC_READ_2(sc, sc_if->msk_port, GM_GP_CTRL);
52153f9b600SSepherosa Ziehau 		if (gmac & (GM_GPCR_RX_ENA | GM_GPCR_TX_ENA)) {
5222d586421SSepherosa Ziehau 			gmac &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA);
5232d586421SSepherosa Ziehau 			GMAC_WRITE_2(sc, sc_if->msk_port, GM_GP_CTRL, gmac);
5242d586421SSepherosa Ziehau 			/* Read again to ensure writing. */
5252d586421SSepherosa Ziehau 			GMAC_READ_2(sc, sc_if->msk_port, GM_GP_CTRL);
5262d586421SSepherosa Ziehau 		}
5272d586421SSepherosa Ziehau 	}
52853f9b600SSepherosa Ziehau }
5292d586421SSepherosa Ziehau 
5302d586421SSepherosa Ziehau static void
msk_rxfilter(struct msk_if_softc * sc_if)531dc7303ffSSepherosa Ziehau msk_rxfilter(struct msk_if_softc *sc_if)
5322d586421SSepherosa Ziehau {
5332d586421SSepherosa Ziehau 	struct msk_softc *sc;
5342d586421SSepherosa Ziehau 	struct ifnet *ifp;
5352d586421SSepherosa Ziehau 	struct ifmultiaddr *ifma;
5362d586421SSepherosa Ziehau 	uint32_t mchash[2];
5372d586421SSepherosa Ziehau 	uint32_t crc;
5382d586421SSepherosa Ziehau 	uint16_t mode;
5392d586421SSepherosa Ziehau 
5402d586421SSepherosa Ziehau 	sc = sc_if->msk_softc;
5412d586421SSepherosa Ziehau 	ifp = sc_if->msk_ifp;
5422d586421SSepherosa Ziehau 
5432d586421SSepherosa Ziehau 	bzero(mchash, sizeof(mchash));
5442d586421SSepherosa Ziehau 	mode = GMAC_READ_2(sc, sc_if->msk_port, GM_RX_CTRL);
545dc7303ffSSepherosa Ziehau 	if ((ifp->if_flags & IFF_PROMISC) != 0) {
5462d586421SSepherosa Ziehau 		mode &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
547dc7303ffSSepherosa Ziehau 	} else if ((ifp->if_flags & IFF_ALLMULTI) != 0) {
548dc7303ffSSepherosa Ziehau 		mode |= (GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
5492d586421SSepherosa Ziehau 		mchash[0] = 0xffff;
5502d586421SSepherosa Ziehau 		mchash[1] = 0xffff;
5512d586421SSepherosa Ziehau 	} else {
552dc7303ffSSepherosa Ziehau 		mode |= GM_RXCR_UCF_ENA;
553441d34b2SSascha Wildner 		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
5542d586421SSepherosa Ziehau 			if (ifma->ifma_addr->sa_family != AF_LINK)
5552d586421SSepherosa Ziehau 				continue;
5562d586421SSepherosa Ziehau 			crc = ether_crc32_be(LLADDR((struct sockaddr_dl *)
5572d586421SSepherosa Ziehau 			    ifma->ifma_addr), ETHER_ADDR_LEN);
5582d586421SSepherosa Ziehau 			/* Just want the 6 least significant bits. */
5592d586421SSepherosa Ziehau 			crc &= 0x3f;
5602d586421SSepherosa Ziehau 			/* Set the corresponding bit in the hash table. */
5612d586421SSepherosa Ziehau 			mchash[crc >> 5] |= 1 << (crc & 0x1f);
5622d586421SSepherosa Ziehau 		}
563dc7303ffSSepherosa Ziehau 		if (mchash[0] != 0 || mchash[1] != 0)
5642d586421SSepherosa Ziehau 			mode |= GM_RXCR_MCF_ENA;
5652d586421SSepherosa Ziehau 	}
5662d586421SSepherosa Ziehau 
5672d586421SSepherosa Ziehau 	GMAC_WRITE_2(sc, sc_if->msk_port, GM_MC_ADDR_H1,
5682d586421SSepherosa Ziehau 	    mchash[0] & 0xffff);
5692d586421SSepherosa Ziehau 	GMAC_WRITE_2(sc, sc_if->msk_port, GM_MC_ADDR_H2,
5702d586421SSepherosa Ziehau 	    (mchash[0] >> 16) & 0xffff);
5712d586421SSepherosa Ziehau 	GMAC_WRITE_2(sc, sc_if->msk_port, GM_MC_ADDR_H3,
5722d586421SSepherosa Ziehau 	    mchash[1] & 0xffff);
5732d586421SSepherosa Ziehau 	GMAC_WRITE_2(sc, sc_if->msk_port, GM_MC_ADDR_H4,
5742d586421SSepherosa Ziehau 	    (mchash[1] >> 16) & 0xffff);
5752d586421SSepherosa Ziehau 	GMAC_WRITE_2(sc, sc_if->msk_port, GM_RX_CTRL, mode);
5762d586421SSepherosa Ziehau }
5772d586421SSepherosa Ziehau 
5782d586421SSepherosa Ziehau static void
msk_setvlan(struct msk_if_softc * sc_if,struct ifnet * ifp)5792d586421SSepherosa Ziehau msk_setvlan(struct msk_if_softc *sc_if, struct ifnet *ifp)
5802d586421SSepherosa Ziehau {
5812d586421SSepherosa Ziehau 	struct msk_softc *sc;
5822d586421SSepherosa Ziehau 
5832d586421SSepherosa Ziehau 	sc = sc_if->msk_softc;
5842d586421SSepherosa Ziehau 	if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) {
5852d586421SSepherosa Ziehau 		CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, RX_GMF_CTRL_T),
5862d586421SSepherosa Ziehau 		    RX_VLAN_STRIP_ON);
5872d586421SSepherosa Ziehau 		CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, TX_GMF_CTRL_T),
5882d586421SSepherosa Ziehau 		    TX_VLAN_TAG_ON);
5892d586421SSepherosa Ziehau 	} else {
5902d586421SSepherosa Ziehau 		CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, RX_GMF_CTRL_T),
5912d586421SSepherosa Ziehau 		    RX_VLAN_STRIP_OFF);
5922d586421SSepherosa Ziehau 		CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, TX_GMF_CTRL_T),
5932d586421SSepherosa Ziehau 		    TX_VLAN_TAG_OFF);
5942d586421SSepherosa Ziehau 	}
5952d586421SSepherosa Ziehau }
5962d586421SSepherosa Ziehau 
5972d586421SSepherosa Ziehau static int
msk_init_rx_ring(struct msk_if_softc * sc_if)5982d586421SSepherosa Ziehau msk_init_rx_ring(struct msk_if_softc *sc_if)
5992d586421SSepherosa Ziehau {
6002d586421SSepherosa Ziehau 	struct msk_ring_data *rd;
6012d586421SSepherosa Ziehau 	struct msk_rxdesc *rxd;
6022d586421SSepherosa Ziehau 	int i, prod;
6032d586421SSepherosa Ziehau 
6042d586421SSepherosa Ziehau 	sc_if->msk_cdata.msk_rx_cons = 0;
6052d586421SSepherosa Ziehau 	sc_if->msk_cdata.msk_rx_prod = 0;
6062d586421SSepherosa Ziehau 	sc_if->msk_cdata.msk_rx_putwm = MSK_PUT_WM;
6072d586421SSepherosa Ziehau 
6082d586421SSepherosa Ziehau 	rd = &sc_if->msk_rdata;
6092d586421SSepherosa Ziehau 	bzero(rd->msk_rx_ring, sizeof(struct msk_rx_desc) * MSK_RX_RING_CNT);
6102d586421SSepherosa Ziehau 	prod = sc_if->msk_cdata.msk_rx_prod;
6112d586421SSepherosa Ziehau 	for (i = 0; i < MSK_RX_RING_CNT; i++) {
6122d586421SSepherosa Ziehau 		rxd = &sc_if->msk_cdata.msk_rxdesc[prod];
6132d586421SSepherosa Ziehau 		rxd->rx_m = NULL;
6142d586421SSepherosa Ziehau 		rxd->rx_le = &rd->msk_rx_ring[prod];
6152499c577SSepherosa Ziehau 		if (msk_newbuf(sc_if, prod, 1) != 0)
6162d586421SSepherosa Ziehau 			return (ENOBUFS);
6172d586421SSepherosa Ziehau 		MSK_INC(prod, MSK_RX_RING_CNT);
6182d586421SSepherosa Ziehau 	}
6192d586421SSepherosa Ziehau 
6202d586421SSepherosa Ziehau 	/* Update prefetch unit. */
6212d586421SSepherosa Ziehau 	sc_if->msk_cdata.msk_rx_prod = MSK_RX_RING_CNT - 1;
6222d586421SSepherosa Ziehau 	CSR_WRITE_2(sc_if->msk_softc,
6232d586421SSepherosa Ziehau 	    Y2_PREF_Q_ADDR(sc_if->msk_rxq, PREF_UNIT_PUT_IDX_REG),
6242d586421SSepherosa Ziehau 	    sc_if->msk_cdata.msk_rx_prod);
6252d586421SSepherosa Ziehau 
6262d586421SSepherosa Ziehau 	return (0);
6272d586421SSepherosa Ziehau }
6282d586421SSepherosa Ziehau 
6292d586421SSepherosa Ziehau #ifdef MSK_JUMBO
6302d586421SSepherosa Ziehau static int
msk_init_jumbo_rx_ring(struct msk_if_softc * sc_if)6312d586421SSepherosa Ziehau msk_init_jumbo_rx_ring(struct msk_if_softc *sc_if)
6322d586421SSepherosa Ziehau {
6332d586421SSepherosa Ziehau 	struct msk_ring_data *rd;
6342d586421SSepherosa Ziehau 	struct msk_rxdesc *rxd;
6352d586421SSepherosa Ziehau 	int i, prod;
6362d586421SSepherosa Ziehau 
6372d586421SSepherosa Ziehau 	MSK_IF_LOCK_ASSERT(sc_if);
6382d586421SSepherosa Ziehau 
6392d586421SSepherosa Ziehau 	sc_if->msk_cdata.msk_rx_cons = 0;
6402d586421SSepherosa Ziehau 	sc_if->msk_cdata.msk_rx_prod = 0;
6412d586421SSepherosa Ziehau 	sc_if->msk_cdata.msk_rx_putwm = MSK_PUT_WM;
6422d586421SSepherosa Ziehau 
6432d586421SSepherosa Ziehau 	rd = &sc_if->msk_rdata;
6442d586421SSepherosa Ziehau 	bzero(rd->msk_jumbo_rx_ring,
6452d586421SSepherosa Ziehau 	    sizeof(struct msk_rx_desc) * MSK_JUMBO_RX_RING_CNT);
6462d586421SSepherosa Ziehau 	prod = sc_if->msk_cdata.msk_rx_prod;
6472d586421SSepherosa Ziehau 	for (i = 0; i < MSK_JUMBO_RX_RING_CNT; i++) {
6482d586421SSepherosa Ziehau 		rxd = &sc_if->msk_cdata.msk_jumbo_rxdesc[prod];
6492d586421SSepherosa Ziehau 		rxd->rx_m = NULL;
6502d586421SSepherosa Ziehau 		rxd->rx_le = &rd->msk_jumbo_rx_ring[prod];
6512d586421SSepherosa Ziehau 		if (msk_jumbo_newbuf(sc_if, prod) != 0)
6522d586421SSepherosa Ziehau 			return (ENOBUFS);
6532d586421SSepherosa Ziehau 		MSK_INC(prod, MSK_JUMBO_RX_RING_CNT);
6542d586421SSepherosa Ziehau 	}
6552d586421SSepherosa Ziehau 
6562d586421SSepherosa Ziehau 	bus_dmamap_sync(sc_if->msk_cdata.msk_jumbo_rx_ring_tag,
6572d586421SSepherosa Ziehau 	    sc_if->msk_cdata.msk_jumbo_rx_ring_map,
6582d586421SSepherosa Ziehau 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
6592d586421SSepherosa Ziehau 
6602d586421SSepherosa Ziehau 	sc_if->msk_cdata.msk_rx_prod = MSK_JUMBO_RX_RING_CNT - 1;
6612d586421SSepherosa Ziehau 	CSR_WRITE_2(sc_if->msk_softc,
6622d586421SSepherosa Ziehau 	    Y2_PREF_Q_ADDR(sc_if->msk_rxq, PREF_UNIT_PUT_IDX_REG),
6632d586421SSepherosa Ziehau 	    sc_if->msk_cdata.msk_rx_prod);
6642d586421SSepherosa Ziehau 
6652d586421SSepherosa Ziehau 	return (0);
6662d586421SSepherosa Ziehau }
6672d586421SSepherosa Ziehau #endif
6682d586421SSepherosa Ziehau 
6692d586421SSepherosa Ziehau static void
msk_init_tx_ring(struct msk_if_softc * sc_if)6702d586421SSepherosa Ziehau msk_init_tx_ring(struct msk_if_softc *sc_if)
6712d586421SSepherosa Ziehau {
6722d586421SSepherosa Ziehau 	struct msk_ring_data *rd;
6732d586421SSepherosa Ziehau 	struct msk_txdesc *txd;
6742d586421SSepherosa Ziehau 	int i;
6752d586421SSepherosa Ziehau 
6762d586421SSepherosa Ziehau 	sc_if->msk_cdata.msk_tx_prod = 0;
6772d586421SSepherosa Ziehau 	sc_if->msk_cdata.msk_tx_cons = 0;
6782d586421SSepherosa Ziehau 	sc_if->msk_cdata.msk_tx_cnt = 0;
6792d586421SSepherosa Ziehau 
6802d586421SSepherosa Ziehau 	rd = &sc_if->msk_rdata;
6812d586421SSepherosa Ziehau 	bzero(rd->msk_tx_ring, sizeof(struct msk_tx_desc) * MSK_TX_RING_CNT);
6822d586421SSepherosa Ziehau 	for (i = 0; i < MSK_TX_RING_CNT; i++) {
6832d586421SSepherosa Ziehau 		txd = &sc_if->msk_cdata.msk_txdesc[i];
6842d586421SSepherosa Ziehau 		txd->tx_m = NULL;
6852d586421SSepherosa Ziehau 		txd->tx_le = &rd->msk_tx_ring[i];
6862d586421SSepherosa Ziehau 	}
6872d586421SSepherosa Ziehau }
6882d586421SSepherosa Ziehau 
6892d586421SSepherosa Ziehau static __inline void
msk_discard_rxbuf(struct msk_if_softc * sc_if,int idx)6902d586421SSepherosa Ziehau msk_discard_rxbuf(struct msk_if_softc *sc_if, int idx)
6912d586421SSepherosa Ziehau {
6922d586421SSepherosa Ziehau 	struct msk_rx_desc *rx_le;
6932d586421SSepherosa Ziehau 	struct msk_rxdesc *rxd;
6942d586421SSepherosa Ziehau 	struct mbuf *m;
6952d586421SSepherosa Ziehau 
6962d586421SSepherosa Ziehau 	rxd = &sc_if->msk_cdata.msk_rxdesc[idx];
6972d586421SSepherosa Ziehau 	m = rxd->rx_m;
6982d586421SSepherosa Ziehau 	rx_le = rxd->rx_le;
6992d586421SSepherosa Ziehau 	rx_le->msk_control = htole32(m->m_len | OP_PACKET | HW_OWNER);
7002d586421SSepherosa Ziehau }
7012d586421SSepherosa Ziehau 
7022d586421SSepherosa Ziehau #ifdef MSK_JUMBO
7032d586421SSepherosa Ziehau static __inline void
msk_discard_jumbo_rxbuf(struct msk_if_softc * sc_if,int idx)7042d586421SSepherosa Ziehau msk_discard_jumbo_rxbuf(struct msk_if_softc *sc_if, int	idx)
7052d586421SSepherosa Ziehau {
7062d586421SSepherosa Ziehau 	struct msk_rx_desc *rx_le;
7072d586421SSepherosa Ziehau 	struct msk_rxdesc *rxd;
7082d586421SSepherosa Ziehau 	struct mbuf *m;
7092d586421SSepherosa Ziehau 
7102d586421SSepherosa Ziehau 	rxd = &sc_if->msk_cdata.msk_jumbo_rxdesc[idx];
7112d586421SSepherosa Ziehau 	m = rxd->rx_m;
7122d586421SSepherosa Ziehau 	rx_le = rxd->rx_le;
7132d586421SSepherosa Ziehau 	rx_le->msk_control = htole32(m->m_len | OP_PACKET | HW_OWNER);
7142d586421SSepherosa Ziehau }
7152d586421SSepherosa Ziehau #endif
7162d586421SSepherosa Ziehau 
7172d586421SSepherosa Ziehau static int
msk_newbuf(struct msk_if_softc * sc_if,int idx,int init)7182499c577SSepherosa Ziehau msk_newbuf(struct msk_if_softc *sc_if, int idx, int init)
7192d586421SSepherosa Ziehau {
7202d586421SSepherosa Ziehau 	struct msk_rx_desc *rx_le;
7212d586421SSepherosa Ziehau 	struct msk_rxdesc *rxd;
7222d586421SSepherosa Ziehau 	struct mbuf *m;
7232d586421SSepherosa Ziehau 	bus_dma_segment_t seg;
7242d586421SSepherosa Ziehau 	bus_dmamap_t map;
7252499c577SSepherosa Ziehau 	int error, nseg;
7262d586421SSepherosa Ziehau 
727*b5523eacSSascha Wildner 	m = m_getcl(init ? M_WAITOK : M_NOWAIT, MT_DATA, M_PKTHDR);
7282d586421SSepherosa Ziehau 	if (m == NULL)
7292d586421SSepherosa Ziehau 		return (ENOBUFS);
7302d586421SSepherosa Ziehau 
7312d586421SSepherosa Ziehau 	m->m_len = m->m_pkthdr.len = MCLBYTES;
7322a9b20a4SSepherosa Ziehau 	if ((sc_if->msk_flags & MSK_FLAG_RAMBUF) == 0)
7332d586421SSepherosa Ziehau 		m_adj(m, ETHER_ALIGN);
7342d586421SSepherosa Ziehau 
7352499c577SSepherosa Ziehau 	error = bus_dmamap_load_mbuf_segment(sc_if->msk_cdata.msk_rx_tag,
7362499c577SSepherosa Ziehau 			sc_if->msk_cdata.msk_rx_sparemap,
7372499c577SSepherosa Ziehau 			m, &seg, 1, &nseg, BUS_DMA_NOWAIT);
7382499c577SSepherosa Ziehau 	if (error) {
7392d586421SSepherosa Ziehau 		m_freem(m);
7402499c577SSepherosa Ziehau 		if (init)
7412499c577SSepherosa Ziehau 			if_printf(&sc_if->arpcom.ac_if, "can't load RX mbuf\n");
7422499c577SSepherosa Ziehau 		return (error);
7432d586421SSepherosa Ziehau 	}
7442d586421SSepherosa Ziehau 
7452d586421SSepherosa Ziehau 	rxd = &sc_if->msk_cdata.msk_rxdesc[idx];
7462d586421SSepherosa Ziehau 	if (rxd->rx_m != NULL) {
7472d586421SSepherosa Ziehau 		bus_dmamap_sync(sc_if->msk_cdata.msk_rx_tag, rxd->rx_dmamap,
7482d586421SSepherosa Ziehau 		    BUS_DMASYNC_POSTREAD);
7492d586421SSepherosa Ziehau 		bus_dmamap_unload(sc_if->msk_cdata.msk_rx_tag, rxd->rx_dmamap);
7502d586421SSepherosa Ziehau 	}
7512499c577SSepherosa Ziehau 
7522d586421SSepherosa Ziehau 	map = rxd->rx_dmamap;
7532d586421SSepherosa Ziehau 	rxd->rx_dmamap = sc_if->msk_cdata.msk_rx_sparemap;
7542d586421SSepherosa Ziehau 	sc_if->msk_cdata.msk_rx_sparemap = map;
7552499c577SSepherosa Ziehau 
7562d586421SSepherosa Ziehau 	rxd->rx_m = m;
7572d586421SSepherosa Ziehau 	rx_le = rxd->rx_le;
7582d586421SSepherosa Ziehau 	rx_le->msk_addr = htole32(MSK_ADDR_LO(seg.ds_addr));
7592499c577SSepherosa Ziehau 	rx_le->msk_control = htole32(seg.ds_len | OP_PACKET | HW_OWNER);
7602d586421SSepherosa Ziehau 
7612d586421SSepherosa Ziehau 	return (0);
7622d586421SSepherosa Ziehau }
7632d586421SSepherosa Ziehau 
7642d586421SSepherosa Ziehau #ifdef MSK_JUMBO
7652d586421SSepherosa Ziehau static int
msk_jumbo_newbuf(struct msk_if_softc * sc_if,int idx)7662d586421SSepherosa Ziehau msk_jumbo_newbuf(struct msk_if_softc *sc_if, int idx)
7672d586421SSepherosa Ziehau {
7682d586421SSepherosa Ziehau 	struct msk_rx_desc *rx_le;
7692d586421SSepherosa Ziehau 	struct msk_rxdesc *rxd;
7702d586421SSepherosa Ziehau 	struct mbuf *m;
7712d586421SSepherosa Ziehau 	bus_dma_segment_t segs[1];
7722d586421SSepherosa Ziehau 	bus_dmamap_t map;
7732d586421SSepherosa Ziehau 	int nsegs;
7742d586421SSepherosa Ziehau 	void *buf;
7752d586421SSepherosa Ziehau 
776*b5523eacSSascha Wildner 	MGETHDR(m, M_NOWAIT, MT_DATA);
7772d586421SSepherosa Ziehau 	if (m == NULL)
7782d586421SSepherosa Ziehau 		return (ENOBUFS);
7792d586421SSepherosa Ziehau 	buf = msk_jalloc(sc_if);
7802d586421SSepherosa Ziehau 	if (buf == NULL) {
7812d586421SSepherosa Ziehau 		m_freem(m);
7822d586421SSepherosa Ziehau 		return (ENOBUFS);
7832d586421SSepherosa Ziehau 	}
7842d586421SSepherosa Ziehau 	/* Attach the buffer to the mbuf. */
78534b49ab5SSascha Wildner 	MEXTADD(m, buf, MSK_JLEN, msk_jfree, sc_if, 0, EXT_NET_DRV);
7862d586421SSepherosa Ziehau 	if ((m->m_flags & M_EXT) == 0) {
7872d586421SSepherosa Ziehau 		m_freem(m);
7882d586421SSepherosa Ziehau 		return (ENOBUFS);
7892d586421SSepherosa Ziehau 	}
7902d586421SSepherosa Ziehau 	m->m_pkthdr.len = m->m_len = MSK_JLEN;
7912d586421SSepherosa Ziehau 	m_adj(m, ETHER_ALIGN);
7922d586421SSepherosa Ziehau 
7932d586421SSepherosa Ziehau 	if (bus_dmamap_load_mbuf_sg(sc_if->msk_cdata.msk_jumbo_rx_tag,
7942d586421SSepherosa Ziehau 	    sc_if->msk_cdata.msk_jumbo_rx_sparemap, m, segs, &nsegs,
7952d586421SSepherosa Ziehau 	    BUS_DMA_NOWAIT) != 0) {
7962d586421SSepherosa Ziehau 		m_freem(m);
7972d586421SSepherosa Ziehau 		return (ENOBUFS);
7982d586421SSepherosa Ziehau 	}
7992d586421SSepherosa Ziehau 	KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
8002d586421SSepherosa Ziehau 
8012d586421SSepherosa Ziehau 	rxd = &sc_if->msk_cdata.msk_jumbo_rxdesc[idx];
8022d586421SSepherosa Ziehau 	if (rxd->rx_m != NULL) {
8032d586421SSepherosa Ziehau 		bus_dmamap_sync(sc_if->msk_cdata.msk_jumbo_rx_tag,
8042d586421SSepherosa Ziehau 		    rxd->rx_dmamap, BUS_DMASYNC_POSTREAD);
8052d586421SSepherosa Ziehau 		bus_dmamap_unload(sc_if->msk_cdata.msk_jumbo_rx_tag,
8062d586421SSepherosa Ziehau 		    rxd->rx_dmamap);
8072d586421SSepherosa Ziehau 	}
8082d586421SSepherosa Ziehau 	map = rxd->rx_dmamap;
8092d586421SSepherosa Ziehau 	rxd->rx_dmamap = sc_if->msk_cdata.msk_jumbo_rx_sparemap;
8102d586421SSepherosa Ziehau 	sc_if->msk_cdata.msk_jumbo_rx_sparemap = map;
8112d586421SSepherosa Ziehau 	bus_dmamap_sync(sc_if->msk_cdata.msk_jumbo_rx_tag, rxd->rx_dmamap,
8122d586421SSepherosa Ziehau 	    BUS_DMASYNC_PREREAD);
8132d586421SSepherosa Ziehau 	rxd->rx_m = m;
8142d586421SSepherosa Ziehau 	rx_le = rxd->rx_le;
8152d586421SSepherosa Ziehau 	rx_le->msk_addr = htole32(MSK_ADDR_LO(segs[0].ds_addr));
8162d586421SSepherosa Ziehau 	rx_le->msk_control =
8172d586421SSepherosa Ziehau 	    htole32(segs[0].ds_len | OP_PACKET | HW_OWNER);
8182d586421SSepherosa Ziehau 
8192d586421SSepherosa Ziehau 	return (0);
8202d586421SSepherosa Ziehau }
8212d586421SSepherosa Ziehau #endif
8222d586421SSepherosa Ziehau 
8232d586421SSepherosa Ziehau /*
8242d586421SSepherosa Ziehau  * Set media options.
8252d586421SSepherosa Ziehau  */
8262d586421SSepherosa Ziehau static int
msk_mediachange(struct ifnet * ifp)8272d586421SSepherosa Ziehau msk_mediachange(struct ifnet *ifp)
8282d586421SSepherosa Ziehau {
8292d586421SSepherosa Ziehau 	struct msk_if_softc *sc_if = ifp->if_softc;
8302d586421SSepherosa Ziehau 	struct mii_data	*mii;
83118804a77SSepherosa Ziehau 	int error;
8322d586421SSepherosa Ziehau 
8332d586421SSepherosa Ziehau 	mii = device_get_softc(sc_if->msk_miibus);
83418804a77SSepherosa Ziehau 	error = mii_mediachg(mii);
8352d586421SSepherosa Ziehau 
83618804a77SSepherosa Ziehau 	return (error);
8372d586421SSepherosa Ziehau }
8382d586421SSepherosa Ziehau 
8392d586421SSepherosa Ziehau /*
8402d586421SSepherosa Ziehau  * Report current media status.
8412d586421SSepherosa Ziehau  */
8422d586421SSepherosa Ziehau static void
msk_mediastatus(struct ifnet * ifp,struct ifmediareq * ifmr)8432d586421SSepherosa Ziehau msk_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
8442d586421SSepherosa Ziehau {
8452d586421SSepherosa Ziehau 	struct msk_if_softc *sc_if = ifp->if_softc;
8462d586421SSepherosa Ziehau 	struct mii_data	*mii;
8472d586421SSepherosa Ziehau 
8482d586421SSepherosa Ziehau 	mii = device_get_softc(sc_if->msk_miibus);
8492d586421SSepherosa Ziehau 	mii_pollstat(mii);
8502d586421SSepherosa Ziehau 
8512d586421SSepherosa Ziehau 	ifmr->ifm_active = mii->mii_media_active;
8522d586421SSepherosa Ziehau 	ifmr->ifm_status = mii->mii_media_status;
8532d586421SSepherosa Ziehau }
8542d586421SSepherosa Ziehau 
8552d586421SSepherosa Ziehau static int
msk_ioctl(struct ifnet * ifp,u_long command,caddr_t data,struct ucred * cr)8562d586421SSepherosa Ziehau msk_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr)
8572d586421SSepherosa Ziehau {
8582d586421SSepherosa Ziehau 	struct msk_if_softc *sc_if;
8592d586421SSepherosa Ziehau 	struct ifreq *ifr;
8602d586421SSepherosa Ziehau 	struct mii_data	*mii;
8612d586421SSepherosa Ziehau 	int error, mask;
8622d586421SSepherosa Ziehau 
8632d586421SSepherosa Ziehau 	sc_if = ifp->if_softc;
8642d586421SSepherosa Ziehau 	ifr = (struct ifreq *)data;
8652d586421SSepherosa Ziehau 	error = 0;
8662d586421SSepherosa Ziehau 
8672d586421SSepherosa Ziehau 	switch(command) {
8682d586421SSepherosa Ziehau 	case SIOCSIFMTU:
8692d586421SSepherosa Ziehau #ifdef MSK_JUMBO
8702d586421SSepherosa Ziehau 		if (ifr->ifr_mtu > MSK_JUMBO_MTU || ifr->ifr_mtu < ETHERMIN) {
8712d586421SSepherosa Ziehau 			error = EINVAL;
8722d586421SSepherosa Ziehau 			break;
8732d586421SSepherosa Ziehau 		}
8742d586421SSepherosa Ziehau 		if (sc_if->msk_softc->msk_hw_id == CHIP_ID_YUKON_FE &&
8752d586421SSepherosa Ziehau 		    ifr->ifr_mtu > MSK_MAX_FRAMELEN) {
8762d586421SSepherosa Ziehau 			error = EINVAL;
8772d586421SSepherosa Ziehau 			break;
8782d586421SSepherosa Ziehau 		}
8792d586421SSepherosa Ziehau 		ifp->if_mtu = ifr->ifr_mtu;
8802d586421SSepherosa Ziehau 		if ((ifp->if_flags & IFF_RUNNING) != 0)
8812d586421SSepherosa Ziehau 			msk_init(sc_if);
8822d586421SSepherosa Ziehau #else
8832d586421SSepherosa Ziehau 		error = EOPNOTSUPP;
8842d586421SSepherosa Ziehau #endif
8852d586421SSepherosa Ziehau 		break;
8862d586421SSepherosa Ziehau 
8872d586421SSepherosa Ziehau 	case SIOCSIFFLAGS:
8882d586421SSepherosa Ziehau 		if (ifp->if_flags & IFF_UP) {
8892d586421SSepherosa Ziehau 			if (ifp->if_flags & IFF_RUNNING) {
8902d586421SSepherosa Ziehau 				if (((ifp->if_flags ^ sc_if->msk_if_flags)
891dc7303ffSSepherosa Ziehau 				    & (IFF_PROMISC | IFF_ALLMULTI)) != 0)
892dc7303ffSSepherosa Ziehau 					msk_rxfilter(sc_if);
8932d586421SSepherosa Ziehau 			} else {
8942d586421SSepherosa Ziehau 				if (sc_if->msk_detach == 0)
8952d586421SSepherosa Ziehau 					msk_init(sc_if);
8962d586421SSepherosa Ziehau 			}
8972d586421SSepherosa Ziehau 		} else {
8982d586421SSepherosa Ziehau 			if (ifp->if_flags & IFF_RUNNING)
8992d586421SSepherosa Ziehau 				msk_stop(sc_if);
9002d586421SSepherosa Ziehau 		}
9012d586421SSepherosa Ziehau 		sc_if->msk_if_flags = ifp->if_flags;
9022d586421SSepherosa Ziehau 		break;
9032d586421SSepherosa Ziehau 
9042d586421SSepherosa Ziehau 	case SIOCADDMULTI:
9052d586421SSepherosa Ziehau 	case SIOCDELMULTI:
9062d586421SSepherosa Ziehau 		if (ifp->if_flags & IFF_RUNNING)
907dc7303ffSSepherosa Ziehau 			msk_rxfilter(sc_if);
9082d586421SSepherosa Ziehau 		break;
9092d586421SSepherosa Ziehau 
9102d586421SSepherosa Ziehau 	case SIOCGIFMEDIA:
9112d586421SSepherosa Ziehau 	case SIOCSIFMEDIA:
9122d586421SSepherosa Ziehau 		mii = device_get_softc(sc_if->msk_miibus);
9132d586421SSepherosa Ziehau 		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
9142d586421SSepherosa Ziehau 		break;
9152d586421SSepherosa Ziehau 
9162d586421SSepherosa Ziehau 	case SIOCSIFCAP:
9172d586421SSepherosa Ziehau 		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
9182d586421SSepherosa Ziehau 		if ((mask & IFCAP_TXCSUM) != 0) {
9192d586421SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_TXCSUM;
9202d586421SSepherosa Ziehau 			if ((IFCAP_TXCSUM & ifp->if_capenable) != 0 &&
9212d586421SSepherosa Ziehau 			    (IFCAP_TXCSUM & ifp->if_capabilities) != 0)
9222d586421SSepherosa Ziehau 				ifp->if_hwassist |= MSK_CSUM_FEATURES;
9232d586421SSepherosa Ziehau 			else
9242d586421SSepherosa Ziehau 				ifp->if_hwassist &= ~MSK_CSUM_FEATURES;
9252d586421SSepherosa Ziehau 		}
9262d586421SSepherosa Ziehau #ifdef notyet
9272d586421SSepherosa Ziehau 		if ((mask & IFCAP_VLAN_HWTAGGING) != 0) {
9282d586421SSepherosa Ziehau 			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
9292d586421SSepherosa Ziehau 			msk_setvlan(sc_if, ifp);
9302d586421SSepherosa Ziehau 		}
9312d586421SSepherosa Ziehau #endif
9322d586421SSepherosa Ziehau 
9332d586421SSepherosa Ziehau 		if (sc_if->msk_framesize > MSK_MAX_FRAMELEN &&
9342d586421SSepherosa Ziehau 		    sc_if->msk_softc->msk_hw_id == CHIP_ID_YUKON_EC_U) {
9352d586421SSepherosa Ziehau 			/*
9362d586421SSepherosa Ziehau 			 * In Yukon EC Ultra, TSO & checksum offload is not
9372d586421SSepherosa Ziehau 			 * supported for jumbo frame.
9382d586421SSepherosa Ziehau 			 */
9392d586421SSepherosa Ziehau 			ifp->if_hwassist &= ~MSK_CSUM_FEATURES;
9402d586421SSepherosa Ziehau 			ifp->if_capenable &= ~IFCAP_TXCSUM;
9412d586421SSepherosa Ziehau 		}
9422d586421SSepherosa Ziehau 		break;
9432d586421SSepherosa Ziehau 
9442d586421SSepherosa Ziehau 	default:
9452d586421SSepherosa Ziehau 		error = ether_ioctl(ifp, command, data);
9462d586421SSepherosa Ziehau 		break;
9472d586421SSepherosa Ziehau 	}
9482d586421SSepherosa Ziehau 
9492d586421SSepherosa Ziehau 	return (error);
9502d586421SSepherosa Ziehau }
9512d586421SSepherosa Ziehau 
9522d586421SSepherosa Ziehau static int
mskc_probe(device_t dev)9532d586421SSepherosa Ziehau mskc_probe(device_t dev)
9542d586421SSepherosa Ziehau {
9552d586421SSepherosa Ziehau 	const struct msk_product *mp;
9562d586421SSepherosa Ziehau 	uint16_t vendor, devid;
9572d586421SSepherosa Ziehau 
9582d586421SSepherosa Ziehau 	vendor = pci_get_vendor(dev);
9592d586421SSepherosa Ziehau 	devid = pci_get_device(dev);
9602d586421SSepherosa Ziehau 	for (mp = msk_products; mp->msk_name != NULL; ++mp) {
9612d586421SSepherosa Ziehau 		if (vendor == mp->msk_vendorid && devid == mp->msk_deviceid) {
9622d586421SSepherosa Ziehau 			device_set_desc(dev, mp->msk_name);
9632d586421SSepherosa Ziehau 			return (0);
9642d586421SSepherosa Ziehau 		}
9652d586421SSepherosa Ziehau 	}
9662d586421SSepherosa Ziehau 	return (ENXIO);
9672d586421SSepherosa Ziehau }
9682d586421SSepherosa Ziehau 
9692d586421SSepherosa Ziehau static int
mskc_setup_rambuffer(struct msk_softc * sc)9702d586421SSepherosa Ziehau mskc_setup_rambuffer(struct msk_softc *sc)
9712d586421SSepherosa Ziehau {
9722d586421SSepherosa Ziehau 	int next;
9732d586421SSepherosa Ziehau 	int i;
9742d586421SSepherosa Ziehau 
9752d586421SSepherosa Ziehau 	/* Get adapter SRAM size. */
9762a9b20a4SSepherosa Ziehau 	sc->msk_ramsize = CSR_READ_1(sc, B2_E_0) * 4;
9772d586421SSepherosa Ziehau 	if (bootverbose) {
9782d586421SSepherosa Ziehau 		device_printf(sc->msk_dev,
9792d586421SSepherosa Ziehau 		    "RAM buffer size : %dKB\n", sc->msk_ramsize);
9802d586421SSepherosa Ziehau 	}
9812a9b20a4SSepherosa Ziehau 	if (sc->msk_ramsize == 0)
9822a9b20a4SSepherosa Ziehau 		return (0);
9832a9b20a4SSepherosa Ziehau 	sc->msk_pflags |= MSK_FLAG_RAMBUF;
9842a9b20a4SSepherosa Ziehau 
9852d586421SSepherosa Ziehau 	/*
9862d586421SSepherosa Ziehau 	 * Give receiver 2/3 of memory and round down to the multiple
9872d586421SSepherosa Ziehau 	 * of 1024. Tx/Rx RAM buffer size of Yukon II shoud be multiple
9882d586421SSepherosa Ziehau 	 * of 1024.
9892d586421SSepherosa Ziehau 	 */
9902d586421SSepherosa Ziehau 	sc->msk_rxqsize = rounddown((sc->msk_ramsize * 1024 * 2) / 3, 1024);
9912d586421SSepherosa Ziehau 	sc->msk_txqsize = (sc->msk_ramsize * 1024) - sc->msk_rxqsize;
9922d586421SSepherosa Ziehau 	for (i = 0, next = 0; i < sc->msk_num_port; i++) {
9932d586421SSepherosa Ziehau 		sc->msk_rxqstart[i] = next;
9942d586421SSepherosa Ziehau 		sc->msk_rxqend[i] = next + sc->msk_rxqsize - 1;
9952d586421SSepherosa Ziehau 		next = sc->msk_rxqend[i] + 1;
9962d586421SSepherosa Ziehau 		sc->msk_txqstart[i] = next;
9972d586421SSepherosa Ziehau 		sc->msk_txqend[i] = next + sc->msk_txqsize - 1;
9982d586421SSepherosa Ziehau 		next = sc->msk_txqend[i] + 1;
9992d586421SSepherosa Ziehau 		if (bootverbose) {
10002d586421SSepherosa Ziehau 			device_printf(sc->msk_dev,
10012d586421SSepherosa Ziehau 			    "Port %d : Rx Queue %dKB(0x%08x:0x%08x)\n", i,
10022d586421SSepherosa Ziehau 			    sc->msk_rxqsize / 1024, sc->msk_rxqstart[i],
10032d586421SSepherosa Ziehau 			    sc->msk_rxqend[i]);
10042d586421SSepherosa Ziehau 			device_printf(sc->msk_dev,
10052d586421SSepherosa Ziehau 			    "Port %d : Tx Queue %dKB(0x%08x:0x%08x)\n", i,
10062d586421SSepherosa Ziehau 			    sc->msk_txqsize / 1024, sc->msk_txqstart[i],
10072d586421SSepherosa Ziehau 			    sc->msk_txqend[i]);
10082d586421SSepherosa Ziehau 		}
10092d586421SSepherosa Ziehau 	}
10102d586421SSepherosa Ziehau 
10112d586421SSepherosa Ziehau 	return (0);
10122d586421SSepherosa Ziehau }
10132d586421SSepherosa Ziehau 
10142d586421SSepherosa Ziehau static void
mskc_phy_power(struct msk_softc * sc,int mode)10152d586421SSepherosa Ziehau mskc_phy_power(struct msk_softc *sc, int mode)
10162d586421SSepherosa Ziehau {
101760ad6a1fSSepherosa Ziehau 	uint32_t our, val;
10182d586421SSepherosa Ziehau 	int i;
10192d586421SSepherosa Ziehau 
10202d586421SSepherosa Ziehau 	switch (mode) {
10212d586421SSepherosa Ziehau 	case MSK_PHY_POWERUP:
10222d586421SSepherosa Ziehau 		/* Switch power to VCC (WA for VAUX problem). */
10232d586421SSepherosa Ziehau 		CSR_WRITE_1(sc, B0_POWER_CTRL,
10242d586421SSepherosa Ziehau 		    PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON);
10252d586421SSepherosa Ziehau 		/* Disable Core Clock Division, set Clock Select to 0. */
10262d586421SSepherosa Ziehau 		CSR_WRITE_4(sc, B2_Y2_CLK_CTRL, Y2_CLK_DIV_DIS);
10272d586421SSepherosa Ziehau 
10282d586421SSepherosa Ziehau 		val = 0;
10292d586421SSepherosa Ziehau 		if (sc->msk_hw_id == CHIP_ID_YUKON_XL &&
10302d586421SSepherosa Ziehau 		    sc->msk_hw_rev > CHIP_REV_YU_XL_A1) {
10312d586421SSepherosa Ziehau 			/* Enable bits are inverted. */
10322d586421SSepherosa Ziehau 			val = Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
10332d586421SSepherosa Ziehau 			      Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
10342d586421SSepherosa Ziehau 			      Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS;
10352d586421SSepherosa Ziehau 		}
10362d586421SSepherosa Ziehau 		/*
10372d586421SSepherosa Ziehau 		 * Enable PCI & Core Clock, enable clock gating for both Links.
10382d586421SSepherosa Ziehau 		 */
10392d586421SSepherosa Ziehau 		CSR_WRITE_1(sc, B2_Y2_CLK_GATE, val);
10402d586421SSepherosa Ziehau 
104160ad6a1fSSepherosa Ziehau 		our = CSR_PCI_READ_4(sc, PCI_OUR_REG_1);
104260ad6a1fSSepherosa Ziehau 		our &= ~(PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD);
1043d9e919c4SSepherosa Ziehau 		if (sc->msk_hw_id == CHIP_ID_YUKON_XL) {
1044e7e20ceeSSepherosa Ziehau 			if (sc->msk_hw_rev > CHIP_REV_YU_XL_A1) {
10452d586421SSepherosa Ziehau 				/* Deassert Low Power for 1st PHY. */
104660ad6a1fSSepherosa Ziehau 				our |= PCI_Y2_PHY1_COMA;
10472d586421SSepherosa Ziehau 				if (sc->msk_num_port > 1)
104860ad6a1fSSepherosa Ziehau 					our |= PCI_Y2_PHY2_COMA;
1049e7e20ceeSSepherosa Ziehau 			}
1050d9e919c4SSepherosa Ziehau 		}
105160ad6a1fSSepherosa Ziehau 		if (sc->msk_hw_id == CHIP_ID_YUKON_EC_U ||
105260ad6a1fSSepherosa Ziehau 		    sc->msk_hw_id == CHIP_ID_YUKON_EX ||
105360ad6a1fSSepherosa Ziehau 		    sc->msk_hw_id >= CHIP_ID_YUKON_FE_P) {
105460ad6a1fSSepherosa Ziehau 			val = CSR_PCI_READ_4(sc, PCI_OUR_REG_4);
105560ad6a1fSSepherosa Ziehau 			val &= (PCI_FORCE_ASPM_REQUEST |
105660ad6a1fSSepherosa Ziehau 			    PCI_ASPM_GPHY_LINK_DOWN | PCI_ASPM_INT_FIFO_EMPTY |
105760ad6a1fSSepherosa Ziehau 			    PCI_ASPM_CLKRUN_REQUEST);
10582d586421SSepherosa Ziehau 			/* Set all bits to 0 except bits 15..12. */
105960ad6a1fSSepherosa Ziehau 			CSR_PCI_WRITE_4(sc, PCI_OUR_REG_4, val);
106060ad6a1fSSepherosa Ziehau 			val = CSR_PCI_READ_4(sc, PCI_OUR_REG_5);
106160ad6a1fSSepherosa Ziehau 			val &= PCI_CTL_TIM_VMAIN_AV_MSK;
106260ad6a1fSSepherosa Ziehau 			CSR_PCI_WRITE_4(sc, PCI_OUR_REG_5, val);
106321437caeSSepherosa Ziehau 			CSR_PCI_WRITE_4(sc, PCI_CFG_REG_1, 0);
106460ad6a1fSSepherosa Ziehau 			CSR_WRITE_2(sc, B0_CTST, Y2_HW_WOL_ON);
1065d9e919c4SSepherosa Ziehau 			/*
1066d9e919c4SSepherosa Ziehau 			 * Disable status race, workaround for
1067d9e919c4SSepherosa Ziehau 			 * Yukon EC Ultra & Yukon EX.
1068d9e919c4SSepherosa Ziehau 			 */
1069d9e919c4SSepherosa Ziehau 			val = CSR_READ_4(sc, B2_GP_IO);
1070d9e919c4SSepherosa Ziehau 			val |= GLB_GPIO_STAT_RACE_DIS;
1071d9e919c4SSepherosa Ziehau 			CSR_WRITE_4(sc, B2_GP_IO, val);
1072d9e919c4SSepherosa Ziehau 			CSR_READ_4(sc, B2_GP_IO);
10732d586421SSepherosa Ziehau 		}
107460ad6a1fSSepherosa Ziehau 		/* Release PHY from PowerDown/COMA mode. */
107560ad6a1fSSepherosa Ziehau 		CSR_PCI_WRITE_4(sc, PCI_OUR_REG_1, our);
107660ad6a1fSSepherosa Ziehau 
10772d586421SSepherosa Ziehau 		for (i = 0; i < sc->msk_num_port; i++) {
10782d586421SSepherosa Ziehau 			CSR_WRITE_2(sc, MR_ADDR(i, GMAC_LINK_CTRL),
10792d586421SSepherosa Ziehau 			    GMLC_RST_SET);
10802d586421SSepherosa Ziehau 			CSR_WRITE_2(sc, MR_ADDR(i, GMAC_LINK_CTRL),
10812d586421SSepherosa Ziehau 			    GMLC_RST_CLR);
10822d586421SSepherosa Ziehau 		}
10832d586421SSepherosa Ziehau 		break;
10842d586421SSepherosa Ziehau 	case MSK_PHY_POWERDOWN:
108521437caeSSepherosa Ziehau 		val = CSR_PCI_READ_4(sc, PCI_OUR_REG_1);
10862d586421SSepherosa Ziehau 		val |= PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD;
10872d586421SSepherosa Ziehau 		if (sc->msk_hw_id == CHIP_ID_YUKON_XL &&
10882d586421SSepherosa Ziehau 		    sc->msk_hw_rev > CHIP_REV_YU_XL_A1) {
10892d586421SSepherosa Ziehau 			val &= ~PCI_Y2_PHY1_COMA;
10902d586421SSepherosa Ziehau 			if (sc->msk_num_port > 1)
10912d586421SSepherosa Ziehau 				val &= ~PCI_Y2_PHY2_COMA;
10922d586421SSepherosa Ziehau 		}
109321437caeSSepherosa Ziehau 		CSR_PCI_WRITE_4(sc, PCI_OUR_REG_1, val);
10942d586421SSepherosa Ziehau 
10952d586421SSepherosa Ziehau 		val = Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
10962d586421SSepherosa Ziehau 		      Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
10972d586421SSepherosa Ziehau 		      Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS;
10982d586421SSepherosa Ziehau 		if (sc->msk_hw_id == CHIP_ID_YUKON_XL &&
10992d586421SSepherosa Ziehau 		    sc->msk_hw_rev > CHIP_REV_YU_XL_A1) {
11002d586421SSepherosa Ziehau 			/* Enable bits are inverted. */
11012d586421SSepherosa Ziehau 			val = 0;
11022d586421SSepherosa Ziehau 		}
11032d586421SSepherosa Ziehau 		/*
11042d586421SSepherosa Ziehau 		 * Disable PCI & Core Clock, disable clock gating for
11052d586421SSepherosa Ziehau 		 * both Links.
11062d586421SSepherosa Ziehau 		 */
11072d586421SSepherosa Ziehau 		CSR_WRITE_1(sc, B2_Y2_CLK_GATE, val);
11082d586421SSepherosa Ziehau 		CSR_WRITE_1(sc, B0_POWER_CTRL,
11092d586421SSepherosa Ziehau 		    PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_ON | PC_VCC_OFF);
11102d586421SSepherosa Ziehau 		break;
11112d586421SSepherosa Ziehau 	default:
11122d586421SSepherosa Ziehau 		break;
11132d586421SSepherosa Ziehau 	}
11142d586421SSepherosa Ziehau }
11152d586421SSepherosa Ziehau 
11162d586421SSepherosa Ziehau static void
mskc_reset(struct msk_softc * sc)11172d586421SSepherosa Ziehau mskc_reset(struct msk_softc *sc)
11182d586421SSepherosa Ziehau {
11192d586421SSepherosa Ziehau 	bus_addr_t addr;
11202d586421SSepherosa Ziehau 	uint16_t status;
11212d586421SSepherosa Ziehau 	uint32_t val;
11222d586421SSepherosa Ziehau 	int i;
11232d586421SSepherosa Ziehau 
11242d586421SSepherosa Ziehau 	/* Disable ASF. */
112539f451b4SSepherosa Ziehau 	if (sc->msk_hw_id >= CHIP_ID_YUKON_XL &&
112639f451b4SSepherosa Ziehau 	    sc->msk_hw_id <= CHIP_ID_YUKON_SUPR) {
112739f451b4SSepherosa Ziehau 		if (sc->msk_hw_id == CHIP_ID_YUKON_EX ||
112839f451b4SSepherosa Ziehau 		    sc->msk_hw_id == CHIP_ID_YUKON_SUPR) {
112939f451b4SSepherosa Ziehau 			CSR_WRITE_4(sc, B28_Y2_CPU_WDOG, 0);
1130d9e919c4SSepherosa Ziehau 			status = CSR_READ_2(sc, B28_Y2_ASF_HCU_CCSR);
1131d9e919c4SSepherosa Ziehau 			/* Clear AHB bridge & microcontroller reset. */
1132d9e919c4SSepherosa Ziehau 			status &= ~(Y2_ASF_HCU_CCSR_AHB_RST |
1133d9e919c4SSepherosa Ziehau 			    Y2_ASF_HCU_CCSR_CPU_RST_MODE);
1134d9e919c4SSepherosa Ziehau 			/* Clear ASF microcontroller state. */
1135d9e919c4SSepherosa Ziehau 			status &= ~Y2_ASF_HCU_CCSR_UC_STATE_MSK;
113639f451b4SSepherosa Ziehau 			status &= ~Y2_ASF_HCU_CCSR_CPU_CLK_DIVIDE_MSK;
1137d9e919c4SSepherosa Ziehau 			CSR_WRITE_2(sc, B28_Y2_ASF_HCU_CCSR, status);
113839f451b4SSepherosa Ziehau 			CSR_WRITE_4(sc, B28_Y2_CPU_WDOG, 0);
1139d9e919c4SSepherosa Ziehau 		} else {
1140d9e919c4SSepherosa Ziehau 			CSR_WRITE_1(sc, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET);
11412d586421SSepherosa Ziehau 		}
1142d9e919c4SSepherosa Ziehau 		CSR_WRITE_2(sc, B0_CTST, Y2_ASF_DISABLE);
11432d586421SSepherosa Ziehau 		/*
114439f451b4SSepherosa Ziehau 		 * Since we disabled ASF, S/W reset is required for
114539f451b4SSepherosa Ziehau 		 * Power Management.
11462d586421SSepherosa Ziehau 		 */
11472d586421SSepherosa Ziehau 		CSR_WRITE_2(sc, B0_CTST, CS_RST_SET);
11482d586421SSepherosa Ziehau 		CSR_WRITE_2(sc, B0_CTST, CS_RST_CLR);
114939f451b4SSepherosa Ziehau 	}
11502d586421SSepherosa Ziehau 
11512d586421SSepherosa Ziehau 	/* Clear all error bits in the PCI status register. */
11522d586421SSepherosa Ziehau 	status = pci_read_config(sc->msk_dev, PCIR_STATUS, 2);
11532d586421SSepherosa Ziehau 	CSR_WRITE_1(sc, B2_TST_CTRL1, TST_CFG_WRITE_ON);
11542d586421SSepherosa Ziehau 
11552d586421SSepherosa Ziehau 	pci_write_config(sc->msk_dev, PCIR_STATUS, status |
11562d586421SSepherosa Ziehau 	    PCIM_STATUS_PERR | PCIM_STATUS_SERR | PCIM_STATUS_RMABORT |
11572d586421SSepherosa Ziehau 	    PCIM_STATUS_RTABORT | PCIM_STATUS_PERRREPORT, 2);
11582d586421SSepherosa Ziehau 	CSR_WRITE_2(sc, B0_CTST, CS_MRST_CLR);
11592d586421SSepherosa Ziehau 
11602d586421SSepherosa Ziehau 	switch (sc->msk_bustype) {
11612d586421SSepherosa Ziehau 	case MSK_PEX_BUS:
11622d586421SSepherosa Ziehau 		/* Clear all PEX errors. */
11632d586421SSepherosa Ziehau 		CSR_PCI_WRITE_4(sc, PEX_UNC_ERR_STAT, 0xffffffff);
11642d586421SSepherosa Ziehau 		val = CSR_PCI_READ_4(sc, PEX_UNC_ERR_STAT);
11652d586421SSepherosa Ziehau 		if ((val & PEX_RX_OV) != 0) {
11662d586421SSepherosa Ziehau 			sc->msk_intrmask &= ~Y2_IS_HW_ERR;
11672d586421SSepherosa Ziehau 			sc->msk_intrhwemask &= ~Y2_IS_PCI_EXP;
11682d586421SSepherosa Ziehau 		}
11692d586421SSepherosa Ziehau 		break;
11702d586421SSepherosa Ziehau 	case MSK_PCI_BUS:
11712d586421SSepherosa Ziehau 	case MSK_PCIX_BUS:
11722d586421SSepherosa Ziehau 		/* Set Cache Line Size to 2(8bytes) if configured to 0. */
11732d586421SSepherosa Ziehau 		val = pci_read_config(sc->msk_dev, PCIR_CACHELNSZ, 1);
11742d586421SSepherosa Ziehau 		if (val == 0)
11752d586421SSepherosa Ziehau 			pci_write_config(sc->msk_dev, PCIR_CACHELNSZ, 2, 1);
11762d586421SSepherosa Ziehau 		if (sc->msk_bustype == MSK_PCIX_BUS) {
11772d586421SSepherosa Ziehau 			/* Set Cache Line Size opt. */
117821437caeSSepherosa Ziehau 			val = CSR_PCI_READ_4(sc, PCI_OUR_REG_1);
11792d586421SSepherosa Ziehau 			val |= PCI_CLS_OPT;
118021437caeSSepherosa Ziehau 			CSR_PCI_WRITE_4(sc, PCI_OUR_REG_1, val);
11812d586421SSepherosa Ziehau 		}
11822d586421SSepherosa Ziehau 		break;
11832d586421SSepherosa Ziehau 	}
11842d586421SSepherosa Ziehau 	/* Set PHY power state. */
11852d586421SSepherosa Ziehau 	mskc_phy_power(sc, MSK_PHY_POWERUP);
11862d586421SSepherosa Ziehau 
11872d586421SSepherosa Ziehau 	/* Reset GPHY/GMAC Control */
11882d586421SSepherosa Ziehau 	for (i = 0; i < sc->msk_num_port; i++) {
11892d586421SSepherosa Ziehau 		/* GPHY Control reset. */
119086d08fa7SSepherosa Ziehau 		CSR_WRITE_1(sc, MR_ADDR(i, GPHY_CTRL), GPC_RST_SET);
119186d08fa7SSepherosa Ziehau 		CSR_WRITE_1(sc, MR_ADDR(i, GPHY_CTRL), GPC_RST_CLR);
11922d586421SSepherosa Ziehau 		/* GMAC Control reset. */
11932d586421SSepherosa Ziehau 		CSR_WRITE_4(sc, MR_ADDR(i, GMAC_CTRL), GMC_RST_SET);
11942d586421SSepherosa Ziehau 		CSR_WRITE_4(sc, MR_ADDR(i, GMAC_CTRL), GMC_RST_CLR);
11952d586421SSepherosa Ziehau 		CSR_WRITE_4(sc, MR_ADDR(i, GMAC_CTRL), GMC_F_LOOPB_OFF);
11960d557164SSepherosa Ziehau 		if (sc->msk_hw_id == CHIP_ID_YUKON_EX ||
11970d557164SSepherosa Ziehau 		    sc->msk_hw_id == CHIP_ID_YUKON_SUPR) {
1198d9e919c4SSepherosa Ziehau 			CSR_WRITE_4(sc, MR_ADDR(i, GMAC_CTRL),
1199d9e919c4SSepherosa Ziehau 			    GMC_BYP_MACSECRX_ON | GMC_BYP_MACSECTX_ON |
1200d9e919c4SSepherosa Ziehau 			    GMC_BYP_RETR_ON);
1201d9e919c4SSepherosa Ziehau 		}
12022d586421SSepherosa Ziehau 	}
12030d557164SSepherosa Ziehau 
12040d557164SSepherosa Ziehau 	if (sc->msk_hw_id == CHIP_ID_YUKON_SUPR &&
12050d557164SSepherosa Ziehau 	    sc->msk_hw_rev > CHIP_REV_YU_SU_B0)
12060d557164SSepherosa Ziehau 		CSR_PCI_WRITE_4(sc, PCI_OUR_REG_3, PCI_CLK_MACSEC_DIS);
12078e916b42SSepherosa Ziehau 	if (sc->msk_hw_id == CHIP_ID_YUKON_OPT && sc->msk_hw_rev == 0) {
12088e916b42SSepherosa Ziehau 		/* Disable PCIe PHY powerdown(reg 0x80, bit7). */
12098e916b42SSepherosa Ziehau 		CSR_WRITE_4(sc, Y2_PEX_PHY_DATA, (0x0080 << 16) | 0x0080);
12108e916b42SSepherosa Ziehau 	}
12112d586421SSepherosa Ziehau 	CSR_WRITE_1(sc, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
12122d586421SSepherosa Ziehau 
12132d586421SSepherosa Ziehau 	/* LED On. */
12142d586421SSepherosa Ziehau 	CSR_WRITE_2(sc, B0_CTST, Y2_LED_STAT_ON);
12152d586421SSepherosa Ziehau 
12162d586421SSepherosa Ziehau 	/* Clear TWSI IRQ. */
12172d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, B2_I2C_IRQ, I2C_CLR_IRQ);
12182d586421SSepherosa Ziehau 
12192d586421SSepherosa Ziehau 	/* Turn off hardware timer. */
12202d586421SSepherosa Ziehau 	CSR_WRITE_1(sc, B2_TI_CTRL, TIM_STOP);
12212d586421SSepherosa Ziehau 	CSR_WRITE_1(sc, B2_TI_CTRL, TIM_CLR_IRQ);
12222d586421SSepherosa Ziehau 
12232d586421SSepherosa Ziehau 	/* Turn off descriptor polling. */
12242d586421SSepherosa Ziehau 	CSR_WRITE_1(sc, B28_DPT_CTRL, DPT_STOP);
12252d586421SSepherosa Ziehau 
12262d586421SSepherosa Ziehau 	/* Turn off time stamps. */
12272d586421SSepherosa Ziehau 	CSR_WRITE_1(sc, GMAC_TI_ST_CTRL, GMT_ST_STOP);
12282d586421SSepherosa Ziehau 	CSR_WRITE_1(sc, GMAC_TI_ST_CTRL, GMT_ST_CLR_IRQ);
12292d586421SSepherosa Ziehau 
123002eb431eSSepherosa Ziehau 	if (sc->msk_hw_id == CHIP_ID_YUKON_XL ||
123102eb431eSSepherosa Ziehau 	    sc->msk_hw_id == CHIP_ID_YUKON_EC ||
123202eb431eSSepherosa Ziehau 	    sc->msk_hw_id == CHIP_ID_YUKON_FE) {
12332d586421SSepherosa Ziehau 		/* Configure timeout values. */
12342d586421SSepherosa Ziehau 		for (i = 0; i < sc->msk_num_port; i++) {
123502eb431eSSepherosa Ziehau 			CSR_WRITE_2(sc, SELECT_RAM_BUFFER(i, B3_RI_CTRL),
123602eb431eSSepherosa Ziehau 			    RI_RST_SET);
123702eb431eSSepherosa Ziehau 			CSR_WRITE_2(sc, SELECT_RAM_BUFFER(i, B3_RI_CTRL),
123802eb431eSSepherosa Ziehau 			    RI_RST_CLR);
12392d586421SSepherosa Ziehau 			CSR_WRITE_1(sc, SELECT_RAM_BUFFER(i, B3_RI_WTO_R1),
12402d586421SSepherosa Ziehau 			    MSK_RI_TO_53);
12412d586421SSepherosa Ziehau 			CSR_WRITE_1(sc, SELECT_RAM_BUFFER(i, B3_RI_WTO_XA1),
12422d586421SSepherosa Ziehau 			    MSK_RI_TO_53);
12432d586421SSepherosa Ziehau 			CSR_WRITE_1(sc, SELECT_RAM_BUFFER(i, B3_RI_WTO_XS1),
12442d586421SSepherosa Ziehau 			    MSK_RI_TO_53);
12452d586421SSepherosa Ziehau 			CSR_WRITE_1(sc, SELECT_RAM_BUFFER(i, B3_RI_RTO_R1),
12462d586421SSepherosa Ziehau 			    MSK_RI_TO_53);
12472d586421SSepherosa Ziehau 			CSR_WRITE_1(sc, SELECT_RAM_BUFFER(i, B3_RI_RTO_XA1),
12482d586421SSepherosa Ziehau 			    MSK_RI_TO_53);
12492d586421SSepherosa Ziehau 			CSR_WRITE_1(sc, SELECT_RAM_BUFFER(i, B3_RI_RTO_XS1),
12502d586421SSepherosa Ziehau 			    MSK_RI_TO_53);
12512d586421SSepherosa Ziehau 			CSR_WRITE_1(sc, SELECT_RAM_BUFFER(i, B3_RI_WTO_R2),
12522d586421SSepherosa Ziehau 			    MSK_RI_TO_53);
12532d586421SSepherosa Ziehau 			CSR_WRITE_1(sc, SELECT_RAM_BUFFER(i, B3_RI_WTO_XA2),
12542d586421SSepherosa Ziehau 			    MSK_RI_TO_53);
12552d586421SSepherosa Ziehau 			CSR_WRITE_1(sc, SELECT_RAM_BUFFER(i, B3_RI_WTO_XS2),
12562d586421SSepherosa Ziehau 			    MSK_RI_TO_53);
12572d586421SSepherosa Ziehau 			CSR_WRITE_1(sc, SELECT_RAM_BUFFER(i, B3_RI_RTO_R2),
12582d586421SSepherosa Ziehau 			    MSK_RI_TO_53);
12592d586421SSepherosa Ziehau 			CSR_WRITE_1(sc, SELECT_RAM_BUFFER(i, B3_RI_RTO_XA2),
12602d586421SSepherosa Ziehau 			    MSK_RI_TO_53);
12612d586421SSepherosa Ziehau 			CSR_WRITE_1(sc, SELECT_RAM_BUFFER(i, B3_RI_RTO_XS2),
12622d586421SSepherosa Ziehau 			    MSK_RI_TO_53);
12632d586421SSepherosa Ziehau 		}
126402eb431eSSepherosa Ziehau 	}
12652d586421SSepherosa Ziehau 
12662d586421SSepherosa Ziehau 	/* Disable all interrupts. */
12672d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, B0_HWE_IMSK, 0);
12682d586421SSepherosa Ziehau 	CSR_READ_4(sc, B0_HWE_IMSK);
12692d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, B0_IMSK, 0);
12702d586421SSepherosa Ziehau 	CSR_READ_4(sc, B0_IMSK);
12712d586421SSepherosa Ziehau 
12722d586421SSepherosa Ziehau         /*
12732d586421SSepherosa Ziehau          * On dual port PCI-X card, there is an problem where status
12742d586421SSepherosa Ziehau          * can be received out of order due to split transactions.
12752d586421SSepherosa Ziehau          */
127678c8aca9SSepherosa Ziehau 	if (sc->msk_pcixcap != 0 && sc->msk_num_port > 1) {
12772d586421SSepherosa Ziehau 		uint16_t pcix_cmd;
12782d586421SSepherosa Ziehau 
127978c8aca9SSepherosa Ziehau 		pcix_cmd = pci_read_config(sc->msk_dev,
128078c8aca9SSepherosa Ziehau 		    sc->msk_pcixcap + PCIXR_COMMAND, 2);
12812d586421SSepherosa Ziehau 		/* Clear Max Outstanding Split Transactions. */
128278c8aca9SSepherosa Ziehau 		pcix_cmd &= ~PCIXM_COMMAND_MAX_SPLITS;
12832d586421SSepherosa Ziehau 		CSR_WRITE_1(sc, B2_TST_CTRL1, TST_CFG_WRITE_ON);
128478c8aca9SSepherosa Ziehau 		pci_write_config(sc->msk_dev,
128578c8aca9SSepherosa Ziehau 		    sc->msk_pcixcap + PCIXR_COMMAND, pcix_cmd, 2);
12862d586421SSepherosa Ziehau 		CSR_WRITE_1(sc, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
12872d586421SSepherosa Ziehau 	}
128878c8aca9SSepherosa Ziehau 	if (sc->msk_pciecap != 0) {
128978c8aca9SSepherosa Ziehau 		/* Change Max. Read Request Size to 2048 bytes. */
129078c8aca9SSepherosa Ziehau 		if (pcie_get_max_readrq(sc->msk_dev) ==
129178c8aca9SSepherosa Ziehau 		    PCIEM_DEVCTL_MAX_READRQ_512) {
129278c8aca9SSepherosa Ziehau 			pcie_set_max_readrq(sc->msk_dev,
129378c8aca9SSepherosa Ziehau 			    PCIEM_DEVCTL_MAX_READRQ_2048);
12942d586421SSepherosa Ziehau 		}
12952d586421SSepherosa Ziehau 	}
12962d586421SSepherosa Ziehau 
12972d586421SSepherosa Ziehau 	/* Clear status list. */
12982d586421SSepherosa Ziehau 	bzero(sc->msk_stat_ring,
12992d586421SSepherosa Ziehau 	    sizeof(struct msk_stat_desc) * MSK_STAT_RING_CNT);
13002d586421SSepherosa Ziehau 	sc->msk_stat_cons = 0;
13012d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, STAT_CTRL, SC_STAT_RST_SET);
13022d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, STAT_CTRL, SC_STAT_RST_CLR);
13032d586421SSepherosa Ziehau 	/* Set the status list base address. */
13042d586421SSepherosa Ziehau 	addr = sc->msk_stat_ring_paddr;
13052d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, STAT_LIST_ADDR_LO, MSK_ADDR_LO(addr));
13062d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, STAT_LIST_ADDR_HI, MSK_ADDR_HI(addr));
13072d586421SSepherosa Ziehau 	/* Set the status list last index. */
13082d586421SSepherosa Ziehau 	CSR_WRITE_2(sc, STAT_LAST_IDX, MSK_STAT_RING_CNT - 1);
13092d586421SSepherosa Ziehau 	if (sc->msk_hw_id == CHIP_ID_YUKON_EC &&
13102d586421SSepherosa Ziehau 	    sc->msk_hw_rev == CHIP_REV_YU_EC_A1) {
13112d586421SSepherosa Ziehau 		/* WA for dev. #4.3 */
13122d586421SSepherosa Ziehau 		CSR_WRITE_2(sc, STAT_TX_IDX_TH, ST_TXTH_IDX_MASK);
13132d586421SSepherosa Ziehau 		/* WA for dev. #4.18 */
13142d586421SSepherosa Ziehau 		CSR_WRITE_1(sc, STAT_FIFO_WM, 0x21);
13152d586421SSepherosa Ziehau 		CSR_WRITE_1(sc, STAT_FIFO_ISR_WM, 0x07);
13162d586421SSepherosa Ziehau 	} else {
13172d586421SSepherosa Ziehau 		CSR_WRITE_2(sc, STAT_TX_IDX_TH, 0x0a);
13182d586421SSepherosa Ziehau 		CSR_WRITE_1(sc, STAT_FIFO_WM, 0x10);
13192d586421SSepherosa Ziehau 		if (sc->msk_hw_id == CHIP_ID_YUKON_XL &&
13202d586421SSepherosa Ziehau 		    sc->msk_hw_rev == CHIP_REV_YU_XL_A0)
13212d586421SSepherosa Ziehau 			CSR_WRITE_1(sc, STAT_FIFO_ISR_WM, 0x04);
13222d586421SSepherosa Ziehau 		else
13232d586421SSepherosa Ziehau 			CSR_WRITE_1(sc, STAT_FIFO_ISR_WM, 0x10);
13242d586421SSepherosa Ziehau 		CSR_WRITE_4(sc, STAT_ISR_TIMER_INI, 0x0190);
13252d586421SSepherosa Ziehau 	}
13262d586421SSepherosa Ziehau 	/*
13272d586421SSepherosa Ziehau 	 * Use default value for STAT_ISR_TIMER_INI, STAT_LEV_TIMER_INI.
13282d586421SSepherosa Ziehau 	 */
13292d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, STAT_TX_TIMER_INI, MSK_USECS(sc, 1000));
13302d586421SSepherosa Ziehau 
13312d586421SSepherosa Ziehau 	/* Enable status unit. */
13322d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, STAT_CTRL, SC_STAT_OP_ON);
13332d586421SSepherosa Ziehau 
13342d586421SSepherosa Ziehau 	CSR_WRITE_1(sc, STAT_TX_TIMER_CTRL, TIM_START);
13352d586421SSepherosa Ziehau 	CSR_WRITE_1(sc, STAT_LEV_TIMER_CTRL, TIM_START);
13362d586421SSepherosa Ziehau 	CSR_WRITE_1(sc, STAT_ISR_TIMER_CTRL, TIM_START);
13372d586421SSepherosa Ziehau }
13382d586421SSepherosa Ziehau 
13392d586421SSepherosa Ziehau static int
msk_probe(device_t dev)13402d586421SSepherosa Ziehau msk_probe(device_t dev)
13412d586421SSepherosa Ziehau {
13422d586421SSepherosa Ziehau 	struct msk_softc *sc = device_get_softc(device_get_parent(dev));
13432d586421SSepherosa Ziehau 	char desc[100];
13442d586421SSepherosa Ziehau 
13452d586421SSepherosa Ziehau 	/*
13462d586421SSepherosa Ziehau 	 * Not much to do here. We always know there will be
13472d586421SSepherosa Ziehau 	 * at least one GMAC present, and if there are two,
13482d586421SSepherosa Ziehau 	 * mskc_attach() will create a second device instance
13492d586421SSepherosa Ziehau 	 * for us.
13502d586421SSepherosa Ziehau 	 */
13512d586421SSepherosa Ziehau 	ksnprintf(desc, sizeof(desc),
13522d586421SSepherosa Ziehau 	    "Marvell Technology Group Ltd. %s Id 0x%02x Rev 0x%02x",
13532d586421SSepherosa Ziehau 	    model_name[sc->msk_hw_id - CHIP_ID_YUKON_XL], sc->msk_hw_id,
13542d586421SSepherosa Ziehau 	    sc->msk_hw_rev);
13552d586421SSepherosa Ziehau 	device_set_desc_copy(dev, desc);
13562d586421SSepherosa Ziehau 
13572d586421SSepherosa Ziehau 	return (0);
13582d586421SSepherosa Ziehau }
13592d586421SSepherosa Ziehau 
13602d586421SSepherosa Ziehau static int
msk_attach(device_t dev)13612d586421SSepherosa Ziehau msk_attach(device_t dev)
13622d586421SSepherosa Ziehau {
13632d586421SSepherosa Ziehau 	struct msk_softc *sc = device_get_softc(device_get_parent(dev));
13642d586421SSepherosa Ziehau 	struct msk_if_softc *sc_if = device_get_softc(dev);
13652d586421SSepherosa Ziehau 	struct ifnet *ifp = &sc_if->arpcom.ac_if;
13662d586421SSepherosa Ziehau 	int i, port, error;
13672d586421SSepherosa Ziehau 	uint8_t eaddr[ETHER_ADDR_LEN];
13682d586421SSepherosa Ziehau 
13692d586421SSepherosa Ziehau 	port = *(int *)device_get_ivars(dev);
13702d586421SSepherosa Ziehau 	KKASSERT(port == MSK_PORT_A || port == MSK_PORT_B);
13712d586421SSepherosa Ziehau 
13722d586421SSepherosa Ziehau 	kfree(device_get_ivars(dev), M_DEVBUF);
13732d586421SSepherosa Ziehau 	device_set_ivars(dev, NULL);
13742d586421SSepherosa Ziehau 
13752d586421SSepherosa Ziehau 	callout_init(&sc_if->msk_tick_ch);
13762d586421SSepherosa Ziehau 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
13772d586421SSepherosa Ziehau 
13782d586421SSepherosa Ziehau 	sc_if->msk_if_dev = dev;
13792d586421SSepherosa Ziehau 	sc_if->msk_port = port;
13802d586421SSepherosa Ziehau 	sc_if->msk_softc = sc;
13812d586421SSepherosa Ziehau 	sc_if->msk_ifp = ifp;
13822a9b20a4SSepherosa Ziehau 	sc_if->msk_flags = sc->msk_pflags;
13832d586421SSepherosa Ziehau 	sc->msk_if[port] = sc_if;
13842d586421SSepherosa Ziehau 
13852d586421SSepherosa Ziehau 	/* Setup Tx/Rx queue register offsets. */
13862d586421SSepherosa Ziehau 	if (port == MSK_PORT_A) {
13872d586421SSepherosa Ziehau 		sc_if->msk_txq = Q_XA1;
13882d586421SSepherosa Ziehau 		sc_if->msk_txsq = Q_XS1;
13892d586421SSepherosa Ziehau 		sc_if->msk_rxq = Q_R1;
13902d586421SSepherosa Ziehau 	} else {
13912d586421SSepherosa Ziehau 		sc_if->msk_txq = Q_XA2;
13922d586421SSepherosa Ziehau 		sc_if->msk_txsq = Q_XS2;
13932d586421SSepherosa Ziehau 		sc_if->msk_rxq = Q_R2;
13942d586421SSepherosa Ziehau 	}
13952d586421SSepherosa Ziehau 
13962d586421SSepherosa Ziehau 	error = msk_txrx_dma_alloc(sc_if);
13972d586421SSepherosa Ziehau 	if (error)
13982d586421SSepherosa Ziehau 		goto fail;
13992d586421SSepherosa Ziehau 
14002d586421SSepherosa Ziehau 	ifp->if_softc = sc_if;
14012d586421SSepherosa Ziehau 	ifp->if_mtu = ETHERMTU;
14022d586421SSepherosa Ziehau 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
14032d586421SSepherosa Ziehau 	ifp->if_init = msk_init;
14042d586421SSepherosa Ziehau 	ifp->if_ioctl = msk_ioctl;
14052d586421SSepherosa Ziehau 	ifp->if_start = msk_start;
14062d586421SSepherosa Ziehau 	ifp->if_watchdog = msk_watchdog;
14072d586421SSepherosa Ziehau 	ifq_set_maxlen(&ifp->if_snd, MSK_TX_RING_CNT - 1);
14082d586421SSepherosa Ziehau 	ifq_set_ready(&ifp->if_snd);
14092d586421SSepherosa Ziehau 
14102d586421SSepherosa Ziehau #ifdef notyet
14112d586421SSepherosa Ziehau 	/*
14122d586421SSepherosa Ziehau 	 * IFCAP_RXCSUM capability is intentionally disabled as the hardware
14132d586421SSepherosa Ziehau 	 * has serious bug in Rx checksum offload for all Yukon II family
14142d586421SSepherosa Ziehau 	 * hardware. It seems there is a workaround to make it work somtimes.
14152d586421SSepherosa Ziehau 	 * However, the workaround also have to check OP code sequences to
14162d586421SSepherosa Ziehau 	 * verify whether the OP code is correct. Sometimes it should compute
14172d586421SSepherosa Ziehau 	 * IP/TCP/UDP checksum in driver in order to verify correctness of
14182d586421SSepherosa Ziehau 	 * checksum computed by hardware. If you have to compute checksum
14192d586421SSepherosa Ziehau 	 * with software to verify the hardware's checksum why have hardware
14202d586421SSepherosa Ziehau 	 * compute the checksum? I think there is no reason to spend time to
14212d586421SSepherosa Ziehau 	 * make Rx checksum offload work on Yukon II hardware.
14222d586421SSepherosa Ziehau 	 */
14232d586421SSepherosa Ziehau 	ifp->if_capabilities = IFCAP_TXCSUM | IFCAP_VLAN_MTU |
14242d586421SSepherosa Ziehau 			       IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_HWCSUM;
14252d586421SSepherosa Ziehau 	ifp->if_hwassist = MSK_CSUM_FEATURES;
14262d586421SSepherosa Ziehau 	ifp->if_capenable = ifp->if_capabilities;
14272d586421SSepherosa Ziehau #endif
14282d586421SSepherosa Ziehau 
14292d586421SSepherosa Ziehau 	/*
14302d586421SSepherosa Ziehau 	 * Get station address for this interface. Note that
14312d586421SSepherosa Ziehau 	 * dual port cards actually come with three station
14322d586421SSepherosa Ziehau 	 * addresses: one for each port, plus an extra. The
14332d586421SSepherosa Ziehau 	 * extra one is used by the SysKonnect driver software
14342d586421SSepherosa Ziehau 	 * as a 'virtual' station address for when both ports
14352d586421SSepherosa Ziehau 	 * are operating in failover mode. Currently we don't
14362d586421SSepherosa Ziehau 	 * use this extra address.
14372d586421SSepherosa Ziehau 	 */
14382d586421SSepherosa Ziehau 	for (i = 0; i < ETHER_ADDR_LEN; i++)
14392d586421SSepherosa Ziehau 		eaddr[i] = CSR_READ_1(sc, B2_MAC_1 + (port * 8) + i);
14402d586421SSepherosa Ziehau 
14412d586421SSepherosa Ziehau 	sc_if->msk_framesize = ifp->if_mtu + ETHER_HDR_LEN + EVL_ENCAPLEN;
14422d586421SSepherosa Ziehau 
14432d586421SSepherosa Ziehau 	/*
14442d586421SSepherosa Ziehau 	 * Do miibus setup.
14452d586421SSepherosa Ziehau 	 */
14462d586421SSepherosa Ziehau 	error = mii_phy_probe(dev, &sc_if->msk_miibus,
14472d586421SSepherosa Ziehau 			      msk_mediachange, msk_mediastatus);
14482d586421SSepherosa Ziehau 	if (error) {
14492d586421SSepherosa Ziehau 		device_printf(sc_if->msk_if_dev, "no PHY found!\n");
14502d586421SSepherosa Ziehau 		goto fail;
14512d586421SSepherosa Ziehau 	}
14522d586421SSepherosa Ziehau 
14532d586421SSepherosa Ziehau 	/*
14542d586421SSepherosa Ziehau 	 * Call MI attach routine.  Can't hold locks when calling into ether_*.
14552d586421SSepherosa Ziehau 	 */
14562d586421SSepherosa Ziehau 	ether_ifattach(ifp, eaddr, &sc->msk_serializer);
14572d586421SSepherosa Ziehau #if 0
14582d586421SSepherosa Ziehau 	/*
14592d586421SSepherosa Ziehau 	 * Tell the upper layer(s) we support long frames.
14602d586421SSepherosa Ziehau 	 * Must appear after the call to ether_ifattach() because
14612d586421SSepherosa Ziehau 	 * ether_ifattach() sets ifi_hdrlen to the default value.
14622d586421SSepherosa Ziehau 	 */
14632d586421SSepherosa Ziehau         ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
14642d586421SSepherosa Ziehau #endif
14652d586421SSepherosa Ziehau 
14662d586421SSepherosa Ziehau 	return 0;
14672d586421SSepherosa Ziehau fail:
14682d586421SSepherosa Ziehau 	msk_detach(dev);
14692d586421SSepherosa Ziehau 	sc->msk_if[port] = NULL;
14702d586421SSepherosa Ziehau 	return (error);
14712d586421SSepherosa Ziehau }
14722d586421SSepherosa Ziehau 
14732d586421SSepherosa Ziehau /*
14742d586421SSepherosa Ziehau  * Attach the interface. Allocate softc structures, do ifmedia
14752d586421SSepherosa Ziehau  * setup and ethernet/BPF attach.
14762d586421SSepherosa Ziehau  */
14772d586421SSepherosa Ziehau static int
mskc_attach(device_t dev)14782d586421SSepherosa Ziehau mskc_attach(device_t dev)
14792d586421SSepherosa Ziehau {
14802d586421SSepherosa Ziehau 	struct msk_softc *sc;
148126595b18SSascha Wildner 	struct sysctl_ctx_list *ctx;
148226595b18SSascha Wildner 	struct sysctl_oid *tree;
14839db4b353SSepherosa Ziehau 	int error, *port, cpuid;
1484d24322f3SSepherosa Ziehau 	u_int irq_flags;
14852d586421SSepherosa Ziehau 
14862d586421SSepherosa Ziehau 	sc = device_get_softc(dev);
14872d586421SSepherosa Ziehau 	sc->msk_dev = dev;
14882d586421SSepherosa Ziehau 	lwkt_serialize_init(&sc->msk_serializer);
14892d586421SSepherosa Ziehau 
1490f59f1081SSepherosa Ziehau 	/*
1491f59f1081SSepherosa Ziehau 	 * Initailize sysctl variables
1492f59f1081SSepherosa Ziehau 	 */
1493f59f1081SSepherosa Ziehau 	sc->msk_process_limit = mskc_process_limit;
1494f59f1081SSepherosa Ziehau 	sc->msk_intr_rate = mskc_intr_rate;
1495f59f1081SSepherosa Ziehau 
14962d586421SSepherosa Ziehau #ifndef BURN_BRIDGES
14972d586421SSepherosa Ziehau 	/*
14982d586421SSepherosa Ziehau 	 * Handle power management nonsense.
14992d586421SSepherosa Ziehau 	 */
15002d586421SSepherosa Ziehau 	if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
15012d586421SSepherosa Ziehau 		uint32_t irq, bar0, bar1;
15022d586421SSepherosa Ziehau 
15032d586421SSepherosa Ziehau 		/* Save important PCI config data. */
15042d586421SSepherosa Ziehau 		bar0 = pci_read_config(dev, PCIR_BAR(0), 4);
15052d586421SSepherosa Ziehau 		bar1 = pci_read_config(dev, PCIR_BAR(1), 4);
15062d586421SSepherosa Ziehau 		irq = pci_read_config(dev, PCIR_INTLINE, 4);
15072d586421SSepherosa Ziehau 
15082d586421SSepherosa Ziehau 		/* Reset the power state. */
15092d586421SSepherosa Ziehau 		device_printf(dev, "chip is in D%d power mode "
15102d586421SSepherosa Ziehau 			      "-- setting to D0\n", pci_get_powerstate(dev));
15112d586421SSepherosa Ziehau 
15122d586421SSepherosa Ziehau 		pci_set_powerstate(dev, PCI_POWERSTATE_D0);
15132d586421SSepherosa Ziehau 
15142d586421SSepherosa Ziehau 		/* Restore PCI config data. */
15152d586421SSepherosa Ziehau 		pci_write_config(dev, PCIR_BAR(0), bar0, 4);
15162d586421SSepherosa Ziehau 		pci_write_config(dev, PCIR_BAR(1), bar1, 4);
15172d586421SSepherosa Ziehau 		pci_write_config(dev, PCIR_INTLINE, irq, 4);
15182d586421SSepherosa Ziehau 	}
15192d586421SSepherosa Ziehau #endif	/* BURN_BRIDGES */
15202d586421SSepherosa Ziehau 
15212d586421SSepherosa Ziehau 	/*
15222d586421SSepherosa Ziehau 	 * Map control/status registers.
15232d586421SSepherosa Ziehau 	 */
15242d586421SSepherosa Ziehau 	pci_enable_busmaster(dev);
15252d586421SSepherosa Ziehau 
15262d586421SSepherosa Ziehau 	/*
15272d586421SSepherosa Ziehau 	 * Allocate I/O resource
15282d586421SSepherosa Ziehau 	 */
15292d586421SSepherosa Ziehau #ifdef MSK_USEIOSPACE
15302d586421SSepherosa Ziehau 	sc->msk_res_type = SYS_RES_IOPORT;
15312d586421SSepherosa Ziehau 	sc->msk_res_rid = PCIR_BAR(1);
15322d586421SSepherosa Ziehau #else
15332d586421SSepherosa Ziehau 	sc->msk_res_type = SYS_RES_MEMORY;
15342d586421SSepherosa Ziehau 	sc->msk_res_rid = PCIR_BAR(0);
15352d586421SSepherosa Ziehau #endif
15362d586421SSepherosa Ziehau 	sc->msk_res = bus_alloc_resource_any(dev, sc->msk_res_type,
15372d586421SSepherosa Ziehau 					     &sc->msk_res_rid, RF_ACTIVE);
15382d586421SSepherosa Ziehau 	if (sc->msk_res == NULL) {
15392d586421SSepherosa Ziehau 		if (sc->msk_res_type == SYS_RES_MEMORY) {
15402d586421SSepherosa Ziehau 			sc->msk_res_type = SYS_RES_IOPORT;
15412d586421SSepherosa Ziehau 			sc->msk_res_rid = PCIR_BAR(1);
15422d586421SSepherosa Ziehau 		} else {
15432d586421SSepherosa Ziehau 			sc->msk_res_type = SYS_RES_MEMORY;
15442d586421SSepherosa Ziehau 			sc->msk_res_rid = PCIR_BAR(0);
15452d586421SSepherosa Ziehau 		}
15462d586421SSepherosa Ziehau 		sc->msk_res = bus_alloc_resource_any(dev, sc->msk_res_type,
15472d586421SSepherosa Ziehau 						     &sc->msk_res_rid,
15482d586421SSepherosa Ziehau 						     RF_ACTIVE);
15492d586421SSepherosa Ziehau 		if (sc->msk_res == NULL) {
15502d586421SSepherosa Ziehau 			device_printf(dev, "couldn't allocate %s resources\n",
15512d586421SSepherosa Ziehau 			sc->msk_res_type == SYS_RES_MEMORY ? "memory" : "I/O");
15522d586421SSepherosa Ziehau 			return (ENXIO);
15532d586421SSepherosa Ziehau 		}
15542d586421SSepherosa Ziehau 	}
15552d586421SSepherosa Ziehau 	sc->msk_res_bt = rman_get_bustag(sc->msk_res);
15562d586421SSepherosa Ziehau 	sc->msk_res_bh = rman_get_bushandle(sc->msk_res);
15572d586421SSepherosa Ziehau 
15582d586421SSepherosa Ziehau 	/*
15592d586421SSepherosa Ziehau 	 * Allocate IRQ
15602d586421SSepherosa Ziehau 	 */
1561d24322f3SSepherosa Ziehau 	sc->msk_irq_type = pci_alloc_1intr(dev, mskc_msi_enable,
1562d24322f3SSepherosa Ziehau 	    &sc->msk_irq_rid, &irq_flags);
1563d24322f3SSepherosa Ziehau 
1564d24322f3SSepherosa Ziehau 	sc->msk_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->msk_irq_rid,
1565d24322f3SSepherosa Ziehau 	    irq_flags);
15662d586421SSepherosa Ziehau 	if (sc->msk_irq == NULL) {
15672d586421SSepherosa Ziehau 		device_printf(dev, "couldn't allocate IRQ resources\n");
15682d586421SSepherosa Ziehau 		error = ENXIO;
15692d586421SSepherosa Ziehau 		goto fail;
15702d586421SSepherosa Ziehau 	}
15712d586421SSepherosa Ziehau 
157260ad6a1fSSepherosa Ziehau 	/* Enable all clocks before accessing any registers. */
157360ad6a1fSSepherosa Ziehau 	CSR_PCI_WRITE_4(sc, PCI_OUR_REG_3, 0);
157460ad6a1fSSepherosa Ziehau 
15752d586421SSepherosa Ziehau 	CSR_WRITE_2(sc, B0_CTST, CS_RST_CLR);
15762d586421SSepherosa Ziehau 	sc->msk_hw_id = CSR_READ_1(sc, B2_CHIP_ID);
15772d586421SSepherosa Ziehau 	sc->msk_hw_rev = (CSR_READ_1(sc, B2_MAC_CFG) >> 4) & 0x0f;
15782d586421SSepherosa Ziehau 	/* Bail out if chip is not recognized. */
15792d586421SSepherosa Ziehau 	if (sc->msk_hw_id < CHIP_ID_YUKON_XL ||
15808e916b42SSepherosa Ziehau 	    sc->msk_hw_id > CHIP_ID_YUKON_OPT ||
15818e916b42SSepherosa Ziehau 	    sc->msk_hw_id == CHIP_ID_YUKON_UNKNOWN) {
15822d586421SSepherosa Ziehau 		device_printf(dev, "unknown device: id=0x%02x, rev=0x%02x\n",
15832d586421SSepherosa Ziehau 		    sc->msk_hw_id, sc->msk_hw_rev);
15842d586421SSepherosa Ziehau 		error = ENXIO;
15852d586421SSepherosa Ziehau 		goto fail;
15862d586421SSepherosa Ziehau 	}
15872d586421SSepherosa Ziehau 
1588f59f1081SSepherosa Ziehau 	/*
1589f59f1081SSepherosa Ziehau 	 * Create sysctl tree
1590f59f1081SSepherosa Ziehau 	 */
159126595b18SSascha Wildner 	ctx = device_get_sysctl_ctx(dev);
159226595b18SSascha Wildner 	tree = device_get_sysctl_tree(dev);
159326595b18SSascha Wildner 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree),
15942d586421SSepherosa Ziehau 			OID_AUTO, "process_limit", CTLTYPE_INT | CTLFLAG_RW,
1595f59f1081SSepherosa Ziehau 			&sc->msk_process_limit, 0, mskc_sysctl_proc_limit,
1596f59f1081SSepherosa Ziehau 			"I", "max number of Rx events to process");
159726595b18SSascha Wildner 	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree),
1598f59f1081SSepherosa Ziehau 			OID_AUTO, "intr_rate", CTLTYPE_INT | CTLFLAG_RW,
1599f59f1081SSepherosa Ziehau 			sc, 0, mskc_sysctl_intr_rate,
1600f59f1081SSepherosa Ziehau 			"I", "max number of interrupt per second");
160126595b18SSascha Wildner 	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
16025bda51d4SSepherosa Ziehau 		       "defrag_avoided", CTLFLAG_RW, &sc->msk_defrag_avoided,
16035bda51d4SSepherosa Ziehau 		       0, "# of avoided m_defrag on TX path");
160426595b18SSascha Wildner 	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
16055bda51d4SSepherosa Ziehau 		       "leading_copied", CTLFLAG_RW, &sc->msk_leading_copied,
16065bda51d4SSepherosa Ziehau 		       0, "# of leading copies on TX path");
160726595b18SSascha Wildner 	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
16085bda51d4SSepherosa Ziehau 		       "trailing_copied", CTLFLAG_RW, &sc->msk_trailing_copied,
16095bda51d4SSepherosa Ziehau 		       0, "# of trailing copies on TX path");
16102d586421SSepherosa Ziehau 
16112d586421SSepherosa Ziehau 	sc->msk_pmd = CSR_READ_1(sc, B2_PMD_TYP);
16122d586421SSepherosa Ziehau 	if (sc->msk_pmd == 'L' || sc->msk_pmd == 'S')
16132d586421SSepherosa Ziehau 		sc->msk_coppertype = 0;
16142d586421SSepherosa Ziehau 	else
16152d586421SSepherosa Ziehau 		sc->msk_coppertype = 1;
16162d586421SSepherosa Ziehau 	/* Check number of MACs. */
16172d586421SSepherosa Ziehau 	sc->msk_num_port = 1;
16182d586421SSepherosa Ziehau 	if ((CSR_READ_1(sc, B2_Y2_HW_RES) & CFG_DUAL_MAC_MSK) ==
16192d586421SSepherosa Ziehau 	    CFG_DUAL_MAC_MSK) {
16202d586421SSepherosa Ziehau 		if (!(CSR_READ_1(sc, B2_Y2_CLK_GATE) & Y2_STATUS_LNK2_INAC))
16212d586421SSepherosa Ziehau 			sc->msk_num_port++;
16222d586421SSepherosa Ziehau 	}
16232d586421SSepherosa Ziehau 
16242d586421SSepherosa Ziehau 	/* Check bus type. */
162578c8aca9SSepherosa Ziehau 	if (pci_is_pcie(sc->msk_dev) == 0) {
16262d586421SSepherosa Ziehau 		sc->msk_bustype = MSK_PEX_BUS;
162778c8aca9SSepherosa Ziehau 		sc->msk_pciecap = pci_get_pciecap_ptr(sc->msk_dev);
162878c8aca9SSepherosa Ziehau 	} else if (pci_is_pcix(sc->msk_dev) == 0) {
16292d586421SSepherosa Ziehau 		sc->msk_bustype = MSK_PCIX_BUS;
163078c8aca9SSepherosa Ziehau 		sc->msk_pcixcap = pci_get_pcixcap_ptr(sc->msk_dev);
163178c8aca9SSepherosa Ziehau 	} else {
16322d586421SSepherosa Ziehau 		sc->msk_bustype = MSK_PCI_BUS;
163378c8aca9SSepherosa Ziehau 	}
16342d586421SSepherosa Ziehau 
16352d586421SSepherosa Ziehau 	switch (sc->msk_hw_id) {
16362d586421SSepherosa Ziehau 	case CHIP_ID_YUKON_EC:
16372d586421SSepherosa Ziehau 	case CHIP_ID_YUKON_EC_U:
16382d586421SSepherosa Ziehau 		sc->msk_clock = 125;	/* 125 Mhz */
16392d586421SSepherosa Ziehau 		break;
1640d9e919c4SSepherosa Ziehau 	case CHIP_ID_YUKON_EX:
1641d9e919c4SSepherosa Ziehau 		sc->msk_clock = 125;	/* 125 Mhz */
1642d9e919c4SSepherosa Ziehau 		break;
16432d586421SSepherosa Ziehau 	case CHIP_ID_YUKON_FE:
16442d586421SSepherosa Ziehau 		sc->msk_clock = 100;	/* 100 Mhz */
1645793a2c89SSepherosa Ziehau 		sc->msk_pflags |= MSK_FLAG_FASTETHER;
16462d586421SSepherosa Ziehau 		break;
1647080bd27eSSepherosa Ziehau 	case CHIP_ID_YUKON_FE_P:
1648080bd27eSSepherosa Ziehau 		sc->msk_clock = 50;	/* 50 Mhz */
1649080bd27eSSepherosa Ziehau 		/* DESCV2 */
1650080bd27eSSepherosa Ziehau 		sc->msk_pflags |= MSK_FLAG_FASTETHER;
1651080bd27eSSepherosa Ziehau 		if (sc->msk_hw_rev == CHIP_REV_YU_FE_P_A0) {
1652080bd27eSSepherosa Ziehau 			/*
1653080bd27eSSepherosa Ziehau 			 * XXX
1654080bd27eSSepherosa Ziehau 			 * FE+ A0 has status LE writeback bug so msk(4)
1655080bd27eSSepherosa Ziehau 			 * does not rely on status word of received frame
1656080bd27eSSepherosa Ziehau 			 * in msk_rxeof() which in turn disables all
1657080bd27eSSepherosa Ziehau 			 * hardware assistance bits reported by the status
1658080bd27eSSepherosa Ziehau 			 * word as well as validity of the recevied frame.
1659080bd27eSSepherosa Ziehau 			 * Just pass received frames to upper stack with
1660080bd27eSSepherosa Ziehau 			 * minimal test and let upper stack handle them.
1661080bd27eSSepherosa Ziehau 			 */
1662080bd27eSSepherosa Ziehau 			sc->msk_pflags |= MSK_FLAG_NORXCHK;
1663080bd27eSSepherosa Ziehau 		}
1664080bd27eSSepherosa Ziehau 		break;
16652d586421SSepherosa Ziehau 	case CHIP_ID_YUKON_XL:
16662d586421SSepherosa Ziehau 		sc->msk_clock = 156;	/* 156 Mhz */
16672d586421SSepherosa Ziehau 		break;
16680d557164SSepherosa Ziehau 	case CHIP_ID_YUKON_SUPR:
16690d557164SSepherosa Ziehau 		sc->msk_clock = 125;	/* 125 MHz */
16700d557164SSepherosa Ziehau 		break;
16713b7c5d2cSSepherosa Ziehau 	case CHIP_ID_YUKON_UL_2:
16723b7c5d2cSSepherosa Ziehau 		sc->msk_clock = 125;	/* 125 Mhz */
16733b7c5d2cSSepherosa Ziehau 		break;
16748e916b42SSepherosa Ziehau 	case CHIP_ID_YUKON_OPT:
16758e916b42SSepherosa Ziehau 		sc->msk_clock = 125;	/* 125 MHz */
16768e916b42SSepherosa Ziehau 		break;
16772d586421SSepherosa Ziehau 	default:
16782d586421SSepherosa Ziehau 		sc->msk_clock = 156;	/* 156 Mhz */
16792d586421SSepherosa Ziehau 		break;
16802d586421SSepherosa Ziehau 	}
16812d586421SSepherosa Ziehau 
16822d586421SSepherosa Ziehau 	error = mskc_status_dma_alloc(sc);
16832d586421SSepherosa Ziehau 	if (error)
16842d586421SSepherosa Ziehau 		goto fail;
16852d586421SSepherosa Ziehau 
16862d586421SSepherosa Ziehau 	/* Set base interrupt mask. */
16872d586421SSepherosa Ziehau 	sc->msk_intrmask = Y2_IS_HW_ERR | Y2_IS_STAT_BMU;
16882d586421SSepherosa Ziehau 	sc->msk_intrhwemask = Y2_IS_TIST_OV | Y2_IS_MST_ERR |
16892d586421SSepherosa Ziehau 	    Y2_IS_IRQ_STAT | Y2_IS_PCI_EXP | Y2_IS_PCI_NEXP;
16902d586421SSepherosa Ziehau 
16912d586421SSepherosa Ziehau 	/* Reset the adapter. */
16922d586421SSepherosa Ziehau 	mskc_reset(sc);
16932d586421SSepherosa Ziehau 
16942d586421SSepherosa Ziehau 	error = mskc_setup_rambuffer(sc);
16952d586421SSepherosa Ziehau 	if (error)
16962d586421SSepherosa Ziehau 		goto fail;
16972d586421SSepherosa Ziehau 
16982d586421SSepherosa Ziehau 	sc->msk_devs[MSK_PORT_A] = device_add_child(dev, "msk", -1);
16992d586421SSepherosa Ziehau 	if (sc->msk_devs[MSK_PORT_A] == NULL) {
17002d586421SSepherosa Ziehau 		device_printf(dev, "failed to add child for PORT_A\n");
17012d586421SSepherosa Ziehau 		error = ENXIO;
17022d586421SSepherosa Ziehau 		goto fail;
17032d586421SSepherosa Ziehau 	}
17042d586421SSepherosa Ziehau 	port = kmalloc(sizeof(*port), M_DEVBUF, M_WAITOK);
17052d586421SSepherosa Ziehau 	*port = MSK_PORT_A;
17062d586421SSepherosa Ziehau 	device_set_ivars(sc->msk_devs[MSK_PORT_A], port);
17072d586421SSepherosa Ziehau 
17082d586421SSepherosa Ziehau 	if (sc->msk_num_port > 1) {
17092d586421SSepherosa Ziehau 		sc->msk_devs[MSK_PORT_B] = device_add_child(dev, "msk", -1);
17102d586421SSepherosa Ziehau 		if (sc->msk_devs[MSK_PORT_B] == NULL) {
17112d586421SSepherosa Ziehau 			device_printf(dev, "failed to add child for PORT_B\n");
17122d586421SSepherosa Ziehau 			error = ENXIO;
17132d586421SSepherosa Ziehau 			goto fail;
17142d586421SSepherosa Ziehau 		}
17152d586421SSepherosa Ziehau 		port = kmalloc(sizeof(*port), M_DEVBUF, M_WAITOK);
17162d586421SSepherosa Ziehau 		*port = MSK_PORT_B;
17172d586421SSepherosa Ziehau 		device_set_ivars(sc->msk_devs[MSK_PORT_B], port);
17182d586421SSepherosa Ziehau 	}
17192d586421SSepherosa Ziehau 
17202d586421SSepherosa Ziehau 	bus_generic_attach(dev);
17212d586421SSepherosa Ziehau 
17224c77af2dSSepherosa Ziehau 	cpuid = rman_get_cpuid(sc->msk_irq);
17234c77af2dSSepherosa Ziehau 	if (sc->msk_if[0] != NULL)
17244c77af2dSSepherosa Ziehau 		ifq_set_cpuid(&sc->msk_if[0]->msk_ifp->if_snd, cpuid);
17254c77af2dSSepherosa Ziehau 	if (sc->msk_if[1] != NULL)
17264c77af2dSSepherosa Ziehau 		ifq_set_cpuid(&sc->msk_if[1]->msk_ifp->if_snd, cpuid);
17274c77af2dSSepherosa Ziehau 
17282d586421SSepherosa Ziehau 	error = bus_setup_intr(dev, sc->msk_irq, INTR_MPSAFE,
17292d586421SSepherosa Ziehau 			       mskc_intr, sc, &sc->msk_intrhand,
17302d586421SSepherosa Ziehau 			       &sc->msk_serializer);
17312d586421SSepherosa Ziehau 	if (error) {
17322d586421SSepherosa Ziehau 		device_printf(dev, "couldn't set up interrupt handler\n");
17332d586421SSepherosa Ziehau 		goto fail;
17342d586421SSepherosa Ziehau 	}
17352d586421SSepherosa Ziehau 	return 0;
17362d586421SSepherosa Ziehau fail:
17372d586421SSepherosa Ziehau 	mskc_detach(dev);
17382d586421SSepherosa Ziehau 	return (error);
17392d586421SSepherosa Ziehau }
17402d586421SSepherosa Ziehau 
17412d586421SSepherosa Ziehau /*
17422d586421SSepherosa Ziehau  * Shutdown hardware and free up resources. This can be called any
17432d586421SSepherosa Ziehau  * time after the mutex has been initialized. It is called in both
17442d586421SSepherosa Ziehau  * the error case in attach and the normal detach case so it needs
17452d586421SSepherosa Ziehau  * to be careful about only freeing resources that have actually been
17462d586421SSepherosa Ziehau  * allocated.
17472d586421SSepherosa Ziehau  */
17482d586421SSepherosa Ziehau static int
msk_detach(device_t dev)17492d586421SSepherosa Ziehau msk_detach(device_t dev)
17502d586421SSepherosa Ziehau {
17512d586421SSepherosa Ziehau 	struct msk_if_softc *sc_if = device_get_softc(dev);
17522d586421SSepherosa Ziehau 
17532d586421SSepherosa Ziehau 	if (device_is_attached(dev)) {
17542d586421SSepherosa Ziehau 		struct msk_softc *sc = sc_if->msk_softc;
17552d586421SSepherosa Ziehau 		struct ifnet *ifp = &sc_if->arpcom.ac_if;
17562d586421SSepherosa Ziehau 
17572d586421SSepherosa Ziehau 		lwkt_serialize_enter(ifp->if_serializer);
17582d586421SSepherosa Ziehau 
17592d586421SSepherosa Ziehau 		if (sc->msk_intrhand != NULL) {
17602d586421SSepherosa Ziehau 			if (sc->msk_if[MSK_PORT_A] != NULL)
17612d586421SSepherosa Ziehau 				msk_stop(sc->msk_if[MSK_PORT_A]);
17622d586421SSepherosa Ziehau 			if (sc->msk_if[MSK_PORT_B] != NULL)
17632d586421SSepherosa Ziehau 				msk_stop(sc->msk_if[MSK_PORT_B]);
17642d586421SSepherosa Ziehau 
17652d586421SSepherosa Ziehau 			bus_teardown_intr(sc->msk_dev, sc->msk_irq,
17662d586421SSepherosa Ziehau 					  sc->msk_intrhand);
17672d586421SSepherosa Ziehau 			sc->msk_intrhand = NULL;
17682d586421SSepherosa Ziehau 		}
17692d586421SSepherosa Ziehau 
17702d586421SSepherosa Ziehau 		lwkt_serialize_exit(ifp->if_serializer);
17712d586421SSepherosa Ziehau 
17722d586421SSepherosa Ziehau 		ether_ifdetach(ifp);
17732d586421SSepherosa Ziehau 	}
17742d586421SSepherosa Ziehau 
17752d586421SSepherosa Ziehau 	if (sc_if->msk_miibus != NULL)
17762d586421SSepherosa Ziehau 		device_delete_child(dev, sc_if->msk_miibus);
17772d586421SSepherosa Ziehau 
17782d586421SSepherosa Ziehau 	msk_txrx_dma_free(sc_if);
17792d586421SSepherosa Ziehau 	return (0);
17802d586421SSepherosa Ziehau }
17812d586421SSepherosa Ziehau 
17822d586421SSepherosa Ziehau static int
mskc_detach(device_t dev)17832d586421SSepherosa Ziehau mskc_detach(device_t dev)
17842d586421SSepherosa Ziehau {
17852d586421SSepherosa Ziehau 	struct msk_softc *sc = device_get_softc(dev);
17862d586421SSepherosa Ziehau 	int *port, i;
17872d586421SSepherosa Ziehau 
17882d586421SSepherosa Ziehau #ifdef INVARIANTS
17892d586421SSepherosa Ziehau 	if (device_is_attached(dev)) {
17902d586421SSepherosa Ziehau 		KASSERT(sc->msk_intrhand == NULL,
1791ed20d0e3SSascha Wildner 			("intr is not torn down yet"));
17922d586421SSepherosa Ziehau 	}
17932d586421SSepherosa Ziehau #endif
17942d586421SSepherosa Ziehau 
17952d586421SSepherosa Ziehau 	for (i = 0; i < sc->msk_num_port; ++i) {
17962d586421SSepherosa Ziehau 		if (sc->msk_devs[i] != NULL) {
17972d586421SSepherosa Ziehau 			port = device_get_ivars(sc->msk_devs[i]);
17982d586421SSepherosa Ziehau 			if (port != NULL) {
17992d586421SSepherosa Ziehau 				kfree(port, M_DEVBUF);
18002d586421SSepherosa Ziehau 				device_set_ivars(sc->msk_devs[i], NULL);
18012d586421SSepherosa Ziehau 			}
18022d586421SSepherosa Ziehau 			device_delete_child(dev, sc->msk_devs[i]);
18032d586421SSepherosa Ziehau 		}
18042d586421SSepherosa Ziehau 	}
18052d586421SSepherosa Ziehau 
18062d586421SSepherosa Ziehau 	/* Disable all interrupts. */
18072d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, B0_IMSK, 0);
18082d586421SSepherosa Ziehau 	CSR_READ_4(sc, B0_IMSK);
18092d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, B0_HWE_IMSK, 0);
18102d586421SSepherosa Ziehau 	CSR_READ_4(sc, B0_HWE_IMSK);
18112d586421SSepherosa Ziehau 
18122d586421SSepherosa Ziehau 	/* LED Off. */
18132d586421SSepherosa Ziehau 	CSR_WRITE_2(sc, B0_CTST, Y2_LED_STAT_OFF);
18142d586421SSepherosa Ziehau 
18152d586421SSepherosa Ziehau 	/* Put hardware reset. */
18162d586421SSepherosa Ziehau 	CSR_WRITE_2(sc, B0_CTST, CS_RST_SET);
18172d586421SSepherosa Ziehau 
18182d586421SSepherosa Ziehau 	mskc_status_dma_free(sc);
18192d586421SSepherosa Ziehau 
18202d586421SSepherosa Ziehau 	if (sc->msk_irq != NULL) {
18212d586421SSepherosa Ziehau 		bus_release_resource(dev, SYS_RES_IRQ, sc->msk_irq_rid,
18222d586421SSepherosa Ziehau 				     sc->msk_irq);
18232d586421SSepherosa Ziehau 	}
1824d24322f3SSepherosa Ziehau 	if (sc->msk_irq_type == PCI_INTR_TYPE_MSI)
1825d24322f3SSepherosa Ziehau 		pci_release_msi(dev);
1826d24322f3SSepherosa Ziehau 
18272d586421SSepherosa Ziehau 	if (sc->msk_res != NULL) {
18282d586421SSepherosa Ziehau 		bus_release_resource(dev, sc->msk_res_type, sc->msk_res_rid,
18292d586421SSepherosa Ziehau 				     sc->msk_res);
18302d586421SSepherosa Ziehau 	}
18312d586421SSepherosa Ziehau 
18322d586421SSepherosa Ziehau 	return (0);
18332d586421SSepherosa Ziehau }
18342d586421SSepherosa Ziehau 
18352d586421SSepherosa Ziehau /* Create status DMA region. */
18362d586421SSepherosa Ziehau static int
mskc_status_dma_alloc(struct msk_softc * sc)18372d586421SSepherosa Ziehau mskc_status_dma_alloc(struct msk_softc *sc)
18382d586421SSepherosa Ziehau {
1839c78f83cbSSepherosa Ziehau 	bus_dmamem_t dmem;
18402d586421SSepherosa Ziehau 	int error;
18412d586421SSepherosa Ziehau 
1842c78f83cbSSepherosa Ziehau 	error = bus_dmamem_coherent(NULL/* XXX parent */, MSK_STAT_ALIGN, 0,
1843c78f83cbSSepherosa Ziehau 			BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
1844c78f83cbSSepherosa Ziehau 			MSK_STAT_RING_SZ, BUS_DMA_WAITOK | BUS_DMA_ZERO, &dmem);
18452d586421SSepherosa Ziehau 	if (error) {
18462d586421SSepherosa Ziehau 		device_printf(sc->msk_dev,
1847c78f83cbSSepherosa Ziehau 		    "failed to create status coherent DMA memory\n");
1848c78f83cbSSepherosa Ziehau 		return error;
18492d586421SSepherosa Ziehau 	}
1850c78f83cbSSepherosa Ziehau 	sc->msk_stat_tag = dmem.dmem_tag;
1851c78f83cbSSepherosa Ziehau 	sc->msk_stat_map = dmem.dmem_map;
1852c78f83cbSSepherosa Ziehau 	sc->msk_stat_ring = dmem.dmem_addr;
1853c78f83cbSSepherosa Ziehau 	sc->msk_stat_ring_paddr = dmem.dmem_busaddr;
18542d586421SSepherosa Ziehau 
18552d586421SSepherosa Ziehau 	return (0);
18562d586421SSepherosa Ziehau }
18572d586421SSepherosa Ziehau 
18582d586421SSepherosa Ziehau static void
mskc_status_dma_free(struct msk_softc * sc)18592d586421SSepherosa Ziehau mskc_status_dma_free(struct msk_softc *sc)
18602d586421SSepherosa Ziehau {
18612d586421SSepherosa Ziehau 	/* Destroy status block. */
18622d586421SSepherosa Ziehau 	if (sc->msk_stat_tag) {
18632d586421SSepherosa Ziehau 		bus_dmamap_unload(sc->msk_stat_tag, sc->msk_stat_map);
18642d586421SSepherosa Ziehau 		bus_dmamem_free(sc->msk_stat_tag, sc->msk_stat_ring,
18652d586421SSepherosa Ziehau 				sc->msk_stat_map);
18662d586421SSepherosa Ziehau 		bus_dma_tag_destroy(sc->msk_stat_tag);
18672d586421SSepherosa Ziehau 		sc->msk_stat_tag = NULL;
18682d586421SSepherosa Ziehau 	}
18692d586421SSepherosa Ziehau }
18702d586421SSepherosa Ziehau 
18712d586421SSepherosa Ziehau static int
msk_txrx_dma_alloc(struct msk_if_softc * sc_if)18722d586421SSepherosa Ziehau msk_txrx_dma_alloc(struct msk_if_softc *sc_if)
18732d586421SSepherosa Ziehau {
18742d586421SSepherosa Ziehau 	int error, i, j;
18752d586421SSepherosa Ziehau #ifdef MSK_JUMBO
18762d586421SSepherosa Ziehau 	struct msk_rxdesc *jrxd;
18772d586421SSepherosa Ziehau 	struct msk_jpool_entry *entry;
18782d586421SSepherosa Ziehau 	uint8_t *ptr;
18792d586421SSepherosa Ziehau #endif
18802a9b20a4SSepherosa Ziehau 	bus_size_t rxalign;
18812d586421SSepherosa Ziehau 
18822d586421SSepherosa Ziehau 	/* Create parent DMA tag. */
18832d586421SSepherosa Ziehau 	/*
18842d586421SSepherosa Ziehau 	 * XXX
18852d586421SSepherosa Ziehau 	 * It seems that Yukon II supports full 64bits DMA operations. But
18862d586421SSepherosa Ziehau 	 * it needs two descriptors(list elements) for 64bits DMA operations.
18872d586421SSepherosa Ziehau 	 * Since we don't know what DMA address mappings(32bits or 64bits)
18882d586421SSepherosa Ziehau 	 * would be used in advance for each mbufs, we limits its DMA space
18892d586421SSepherosa Ziehau 	 * to be in range of 32bits address space. Otherwise, we should check
18902d586421SSepherosa Ziehau 	 * what DMA address is used and chain another descriptor for the
18912d586421SSepherosa Ziehau 	 * 64bits DMA operation. This also means descriptor ring size is
18922d586421SSepherosa Ziehau 	 * variable. Limiting DMA address to be in 32bit address space greatly
18932d586421SSepherosa Ziehau 	 * simplyfies descriptor handling and possibly would increase
18942d586421SSepherosa Ziehau 	 * performance a bit due to efficient handling of descriptors.
18952d586421SSepherosa Ziehau 	 * Apart from harassing checksum offloading mechanisms, it seems
18962d586421SSepherosa Ziehau 	 * it's really bad idea to use a seperate descriptor for 64bit
18972d586421SSepherosa Ziehau 	 * DMA operation to save small descriptor memory. Anyway, I've
18982d586421SSepherosa Ziehau 	 * never seen these exotic scheme on ethernet interface hardware.
18992d586421SSepherosa Ziehau 	 */
19002d586421SSepherosa Ziehau 	error = bus_dma_tag_create(
19012d586421SSepherosa Ziehau 		    NULL,			/* parent */
19022d586421SSepherosa Ziehau 		    1, 0,			/* alignment, boundary */
19032d586421SSepherosa Ziehau 		    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
19042d586421SSepherosa Ziehau 		    BUS_SPACE_MAXADDR,		/* highaddr */
19052d586421SSepherosa Ziehau 		    BUS_SPACE_MAXSIZE_32BIT,	/* maxsize */
19062d586421SSepherosa Ziehau 		    0,				/* nsegments */
19072d586421SSepherosa Ziehau 		    BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
19082d586421SSepherosa Ziehau 		    0,				/* flags */
19092d586421SSepherosa Ziehau 		    &sc_if->msk_cdata.msk_parent_tag);
19102d586421SSepherosa Ziehau 	if (error) {
19112d586421SSepherosa Ziehau 		device_printf(sc_if->msk_if_dev,
19122d586421SSepherosa Ziehau 			      "failed to create parent DMA tag\n");
19132d586421SSepherosa Ziehau 		return error;
19142d586421SSepherosa Ziehau 	}
19152d586421SSepherosa Ziehau 
19162d586421SSepherosa Ziehau 	/* Create DMA stuffs for Tx ring. */
19172d586421SSepherosa Ziehau 	error = msk_dmamem_create(sc_if->msk_if_dev, MSK_TX_RING_SZ,
19182d586421SSepherosa Ziehau 				  &sc_if->msk_cdata.msk_tx_ring_tag,
1919da44240fSMatthew Dillon 				  (void *)&sc_if->msk_rdata.msk_tx_ring,
19202d586421SSepherosa Ziehau 				  &sc_if->msk_rdata.msk_tx_ring_paddr,
19212d586421SSepherosa Ziehau 				  &sc_if->msk_cdata.msk_tx_ring_map);
19222d586421SSepherosa Ziehau 	if (error) {
19232d586421SSepherosa Ziehau 		device_printf(sc_if->msk_if_dev,
19242d586421SSepherosa Ziehau 			      "failed to create TX ring DMA stuffs\n");
19252d586421SSepherosa Ziehau 		return error;
19262d586421SSepherosa Ziehau 	}
19272d586421SSepherosa Ziehau 
19282d586421SSepherosa Ziehau 	/* Create DMA stuffs for Rx ring. */
19292d586421SSepherosa Ziehau 	error = msk_dmamem_create(sc_if->msk_if_dev, MSK_RX_RING_SZ,
19302d586421SSepherosa Ziehau 				  &sc_if->msk_cdata.msk_rx_ring_tag,
1931da44240fSMatthew Dillon 				  (void *)&sc_if->msk_rdata.msk_rx_ring,
19322d586421SSepherosa Ziehau 				  &sc_if->msk_rdata.msk_rx_ring_paddr,
19332d586421SSepherosa Ziehau 				  &sc_if->msk_cdata.msk_rx_ring_map);
19342d586421SSepherosa Ziehau 	if (error) {
19352d586421SSepherosa Ziehau 		device_printf(sc_if->msk_if_dev,
19362d586421SSepherosa Ziehau 			      "failed to create RX ring DMA stuffs\n");
19372d586421SSepherosa Ziehau 		return error;
19382d586421SSepherosa Ziehau 	}
19392d586421SSepherosa Ziehau 
19402d586421SSepherosa Ziehau 	/* Create tag for Tx buffers. */
19412d586421SSepherosa Ziehau 	error = bus_dma_tag_create(sc_if->msk_cdata.msk_parent_tag,/* parent */
19422d586421SSepherosa Ziehau 		    1, 0,			/* alignment, boundary */
19432d586421SSepherosa Ziehau 		    BUS_SPACE_MAXADDR,		/* lowaddr */
19442d586421SSepherosa Ziehau 		    BUS_SPACE_MAXADDR,		/* highaddr */
1945ad3a1ee4SSepherosa Ziehau 		    MSK_JUMBO_FRAMELEN,		/* maxsize */
19462d586421SSepherosa Ziehau 		    MSK_MAXTXSEGS,		/* nsegments */
1947ad3a1ee4SSepherosa Ziehau 		    MSK_MAXSGSIZE,		/* maxsegsize */
1948ad3a1ee4SSepherosa Ziehau 		    BUS_DMA_ALLOCNOW | BUS_DMA_WAITOK |
1949ad3a1ee4SSepherosa Ziehau 		    BUS_DMA_ONEBPAGE,		/* flags */
19502d586421SSepherosa Ziehau 		    &sc_if->msk_cdata.msk_tx_tag);
19512d586421SSepherosa Ziehau 	if (error) {
19522d586421SSepherosa Ziehau 		device_printf(sc_if->msk_if_dev,
19532d586421SSepherosa Ziehau 			      "failed to create Tx DMA tag\n");
19542d586421SSepherosa Ziehau 		return error;
19552d586421SSepherosa Ziehau 	}
19562d586421SSepherosa Ziehau 
19572d586421SSepherosa Ziehau 	/* Create DMA maps for Tx buffers. */
19582d586421SSepherosa Ziehau 	for (i = 0; i < MSK_TX_RING_CNT; i++) {
19592d586421SSepherosa Ziehau 		struct msk_txdesc *txd = &sc_if->msk_cdata.msk_txdesc[i];
19602d586421SSepherosa Ziehau 
1961ad3a1ee4SSepherosa Ziehau 		error = bus_dmamap_create(sc_if->msk_cdata.msk_tx_tag,
1962ad3a1ee4SSepherosa Ziehau 				BUS_DMA_WAITOK | BUS_DMA_ONEBPAGE,
19632d586421SSepherosa Ziehau 				&txd->tx_dmamap);
19642d586421SSepherosa Ziehau 		if (error) {
19652d586421SSepherosa Ziehau 			device_printf(sc_if->msk_if_dev,
19662d586421SSepherosa Ziehau 				      "failed to create %dth Tx dmamap\n", i);
19672d586421SSepherosa Ziehau 
19682d586421SSepherosa Ziehau 			for (j = 0; j < i; ++j) {
19692d586421SSepherosa Ziehau 				txd = &sc_if->msk_cdata.msk_txdesc[j];
19702d586421SSepherosa Ziehau 				bus_dmamap_destroy(sc_if->msk_cdata.msk_tx_tag,
19712d586421SSepherosa Ziehau 						   txd->tx_dmamap);
19722d586421SSepherosa Ziehau 			}
19732d586421SSepherosa Ziehau 			bus_dma_tag_destroy(sc_if->msk_cdata.msk_tx_tag);
19742d586421SSepherosa Ziehau 			sc_if->msk_cdata.msk_tx_tag = NULL;
19752d586421SSepherosa Ziehau 
19762d586421SSepherosa Ziehau 			return error;
19772d586421SSepherosa Ziehau 		}
19782d586421SSepherosa Ziehau 	}
19792d586421SSepherosa Ziehau 
19802a9b20a4SSepherosa Ziehau 	/*
19812a9b20a4SSepherosa Ziehau 	 * Workaround hardware hang which seems to happen when Rx buffer
19822a9b20a4SSepherosa Ziehau 	 * is not aligned on multiple of FIFO word(8 bytes).
19832a9b20a4SSepherosa Ziehau 	 */
19842a9b20a4SSepherosa Ziehau 	if (sc_if->msk_flags & MSK_FLAG_RAMBUF)
19852a9b20a4SSepherosa Ziehau 		rxalign = MSK_RX_BUF_ALIGN;
19862a9b20a4SSepherosa Ziehau 	else
19872a9b20a4SSepherosa Ziehau 		rxalign = 1;
19882a9b20a4SSepherosa Ziehau 
19892d586421SSepherosa Ziehau 	/* Create tag for Rx buffers. */
19902d586421SSepherosa Ziehau 	error = bus_dma_tag_create(sc_if->msk_cdata.msk_parent_tag,/* parent */
19912a9b20a4SSepherosa Ziehau 		    rxalign, 0,			/* alignment, boundary */
19922d586421SSepherosa Ziehau 		    BUS_SPACE_MAXADDR,		/* lowaddr */
19932d586421SSepherosa Ziehau 		    BUS_SPACE_MAXADDR,		/* highaddr */
19942d586421SSepherosa Ziehau 		    MCLBYTES,			/* maxsize */
19952d586421SSepherosa Ziehau 		    1,				/* nsegments */
19962d586421SSepherosa Ziehau 		    MCLBYTES,			/* maxsegsize */
19972a9b20a4SSepherosa Ziehau 		    BUS_DMA_ALLOCNOW | BUS_DMA_ALIGNED |
19982a9b20a4SSepherosa Ziehau 		    BUS_DMA_WAITOK,		/* flags */
19992d586421SSepherosa Ziehau 		    &sc_if->msk_cdata.msk_rx_tag);
20002d586421SSepherosa Ziehau 	if (error) {
20012d586421SSepherosa Ziehau 		device_printf(sc_if->msk_if_dev,
20022d586421SSepherosa Ziehau 			      "failed to create Rx DMA tag\n");
20032d586421SSepherosa Ziehau 		return error;
20042d586421SSepherosa Ziehau 	}
20052d586421SSepherosa Ziehau 
20062d586421SSepherosa Ziehau 	/* Create DMA maps for Rx buffers. */
2007ad3a1ee4SSepherosa Ziehau 	error = bus_dmamap_create(sc_if->msk_cdata.msk_rx_tag, BUS_DMA_WAITOK,
20082d586421SSepherosa Ziehau 				  &sc_if->msk_cdata.msk_rx_sparemap);
20092d586421SSepherosa Ziehau 	if (error) {
20102d586421SSepherosa Ziehau 		device_printf(sc_if->msk_if_dev,
20112d586421SSepherosa Ziehau 			      "failed to create spare Rx dmamap\n");
20122d586421SSepherosa Ziehau 		bus_dma_tag_destroy(sc_if->msk_cdata.msk_rx_tag);
20132d586421SSepherosa Ziehau 		sc_if->msk_cdata.msk_rx_tag = NULL;
20142d586421SSepherosa Ziehau 		return error;
20152d586421SSepherosa Ziehau 	}
20162d586421SSepherosa Ziehau 	for (i = 0; i < MSK_RX_RING_CNT; i++) {
20172d586421SSepherosa Ziehau 		struct msk_rxdesc *rxd = &sc_if->msk_cdata.msk_rxdesc[i];
20182d586421SSepherosa Ziehau 
2019ad3a1ee4SSepherosa Ziehau 		error = bus_dmamap_create(sc_if->msk_cdata.msk_rx_tag,
2020ad3a1ee4SSepherosa Ziehau 					  BUS_DMA_WAITOK, &rxd->rx_dmamap);
20212d586421SSepherosa Ziehau 		if (error) {
20222d586421SSepherosa Ziehau 			device_printf(sc_if->msk_if_dev,
20232d586421SSepherosa Ziehau 				      "failed to create %dth Rx dmamap\n", i);
20242d586421SSepherosa Ziehau 
20252d586421SSepherosa Ziehau 			for (j = 0; j < i; ++j) {
20262d586421SSepherosa Ziehau 				rxd = &sc_if->msk_cdata.msk_rxdesc[j];
20272d586421SSepherosa Ziehau 				bus_dmamap_destroy(sc_if->msk_cdata.msk_rx_tag,
20282d586421SSepherosa Ziehau 						   rxd->rx_dmamap);
20292d586421SSepherosa Ziehau 			}
20307f582564SSepherosa Ziehau 			bus_dmamap_destroy(sc_if->msk_cdata.msk_rx_tag,
20317f582564SSepherosa Ziehau 					   sc_if->msk_cdata.msk_rx_sparemap);
20322d586421SSepherosa Ziehau 			bus_dma_tag_destroy(sc_if->msk_cdata.msk_rx_tag);
20332d586421SSepherosa Ziehau 			sc_if->msk_cdata.msk_rx_tag = NULL;
20342d586421SSepherosa Ziehau 
20352d586421SSepherosa Ziehau 			return error;
20362d586421SSepherosa Ziehau 		}
20372d586421SSepherosa Ziehau 	}
20382d586421SSepherosa Ziehau 
20392d586421SSepherosa Ziehau #ifdef MSK_JUMBO
20402d586421SSepherosa Ziehau 	SLIST_INIT(&sc_if->msk_jfree_listhead);
20412d586421SSepherosa Ziehau 	SLIST_INIT(&sc_if->msk_jinuse_listhead);
20422d586421SSepherosa Ziehau 
20432d586421SSepherosa Ziehau 	/* Create tag for jumbo Rx ring. */
20442d586421SSepherosa Ziehau 	error = bus_dma_tag_create(sc_if->msk_cdata.msk_parent_tag,/* parent */
20452d586421SSepherosa Ziehau 		    MSK_RING_ALIGN, 0,		/* alignment, boundary */
20462d586421SSepherosa Ziehau 		    BUS_SPACE_MAXADDR,		/* lowaddr */
20472d586421SSepherosa Ziehau 		    BUS_SPACE_MAXADDR,		/* highaddr */
20482d586421SSepherosa Ziehau 		    MSK_JUMBO_RX_RING_SZ,	/* maxsize */
20492d586421SSepherosa Ziehau 		    1,				/* nsegments */
20502d586421SSepherosa Ziehau 		    MSK_JUMBO_RX_RING_SZ,	/* maxsegsize */
20512d586421SSepherosa Ziehau 		    0,				/* flags */
20522d586421SSepherosa Ziehau 		    NULL, NULL,			/* lockfunc, lockarg */
20532d586421SSepherosa Ziehau 		    &sc_if->msk_cdata.msk_jumbo_rx_ring_tag);
20542d586421SSepherosa Ziehau 	if (error != 0) {
20552d586421SSepherosa Ziehau 		device_printf(sc_if->msk_if_dev,
20562d586421SSepherosa Ziehau 		    "failed to create jumbo Rx ring DMA tag\n");
20572d586421SSepherosa Ziehau 		goto fail;
20582d586421SSepherosa Ziehau 	}
20592d586421SSepherosa Ziehau 
20602d586421SSepherosa Ziehau 	/* Allocate DMA'able memory and load the DMA map for jumbo Rx ring. */
20612d586421SSepherosa Ziehau 	error = bus_dmamem_alloc(sc_if->msk_cdata.msk_jumbo_rx_ring_tag,
20622d586421SSepherosa Ziehau 	    (void **)&sc_if->msk_rdata.msk_jumbo_rx_ring,
20632d586421SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
20642d586421SSepherosa Ziehau 	    &sc_if->msk_cdata.msk_jumbo_rx_ring_map);
20652d586421SSepherosa Ziehau 	if (error != 0) {
20662d586421SSepherosa Ziehau 		device_printf(sc_if->msk_if_dev,
20672d586421SSepherosa Ziehau 		    "failed to allocate DMA'able memory for jumbo Rx ring\n");
20682d586421SSepherosa Ziehau 		goto fail;
20692d586421SSepherosa Ziehau 	}
20702d586421SSepherosa Ziehau 
20712d586421SSepherosa Ziehau 	ctx.msk_busaddr = 0;
20722d586421SSepherosa Ziehau 	error = bus_dmamap_load(sc_if->msk_cdata.msk_jumbo_rx_ring_tag,
20732d586421SSepherosa Ziehau 	    sc_if->msk_cdata.msk_jumbo_rx_ring_map,
20742d586421SSepherosa Ziehau 	    sc_if->msk_rdata.msk_jumbo_rx_ring, MSK_JUMBO_RX_RING_SZ,
20752d586421SSepherosa Ziehau 	    msk_dmamap_cb, &ctx, 0);
20762d586421SSepherosa Ziehau 	if (error != 0) {
20772d586421SSepherosa Ziehau 		device_printf(sc_if->msk_if_dev,
20782d586421SSepherosa Ziehau 		    "failed to load DMA'able memory for jumbo Rx ring\n");
20792d586421SSepherosa Ziehau 		goto fail;
20802d586421SSepherosa Ziehau 	}
20812d586421SSepherosa Ziehau 	sc_if->msk_rdata.msk_jumbo_rx_ring_paddr = ctx.msk_busaddr;
20822d586421SSepherosa Ziehau 
20832d586421SSepherosa Ziehau 	/* Create tag for jumbo buffer blocks. */
20842d586421SSepherosa Ziehau 	error = bus_dma_tag_create(sc_if->msk_cdata.msk_parent_tag,/* parent */
20852d586421SSepherosa Ziehau 		    PAGE_SIZE, 0,		/* alignment, boundary */
20862d586421SSepherosa Ziehau 		    BUS_SPACE_MAXADDR,		/* lowaddr */
20872d586421SSepherosa Ziehau 		    BUS_SPACE_MAXADDR,		/* highaddr */
20882d586421SSepherosa Ziehau 		    MSK_JMEM,			/* maxsize */
20892d586421SSepherosa Ziehau 		    1,				/* nsegments */
20902d586421SSepherosa Ziehau 		    MSK_JMEM,			/* maxsegsize */
20912d586421SSepherosa Ziehau 		    0,				/* flags */
20922d586421SSepherosa Ziehau 		    NULL, NULL,			/* lockfunc, lockarg */
20932d586421SSepherosa Ziehau 		    &sc_if->msk_cdata.msk_jumbo_tag);
20942d586421SSepherosa Ziehau 	if (error != 0) {
20952d586421SSepherosa Ziehau 		device_printf(sc_if->msk_if_dev,
20962d586421SSepherosa Ziehau 		    "failed to create jumbo Rx buffer block DMA tag\n");
20972d586421SSepherosa Ziehau 		goto fail;
20982d586421SSepherosa Ziehau 	}
20992d586421SSepherosa Ziehau 
21002d586421SSepherosa Ziehau 	/* Create tag for jumbo Rx buffers. */
21012d586421SSepherosa Ziehau 	error = bus_dma_tag_create(sc_if->msk_cdata.msk_parent_tag,/* parent */
21022d586421SSepherosa Ziehau 		    PAGE_SIZE, 0,		/* alignment, boundary */
21032d586421SSepherosa Ziehau 		    BUS_SPACE_MAXADDR,		/* lowaddr */
21042d586421SSepherosa Ziehau 		    BUS_SPACE_MAXADDR,		/* highaddr */
21052d586421SSepherosa Ziehau 		    MCLBYTES * MSK_MAXRXSEGS,	/* maxsize */
21062d586421SSepherosa Ziehau 		    MSK_MAXRXSEGS,		/* nsegments */
21072d586421SSepherosa Ziehau 		    MSK_JLEN,			/* maxsegsize */
21082d586421SSepherosa Ziehau 		    0,				/* flags */
21092d586421SSepherosa Ziehau 		    NULL, NULL,			/* lockfunc, lockarg */
21102d586421SSepherosa Ziehau 		    &sc_if->msk_cdata.msk_jumbo_rx_tag);
21112d586421SSepherosa Ziehau 	if (error != 0) {
21122d586421SSepherosa Ziehau 		device_printf(sc_if->msk_if_dev,
21132d586421SSepherosa Ziehau 		    "failed to create jumbo Rx DMA tag\n");
21142d586421SSepherosa Ziehau 		goto fail;
21152d586421SSepherosa Ziehau 	}
21162d586421SSepherosa Ziehau 
21172d586421SSepherosa Ziehau 	/* Create DMA maps for jumbo Rx buffers. */
21182d586421SSepherosa Ziehau 	if ((error = bus_dmamap_create(sc_if->msk_cdata.msk_jumbo_rx_tag, 0,
21192d586421SSepherosa Ziehau 	    &sc_if->msk_cdata.msk_jumbo_rx_sparemap)) != 0) {
21202d586421SSepherosa Ziehau 		device_printf(sc_if->msk_if_dev,
21212d586421SSepherosa Ziehau 		    "failed to create spare jumbo Rx dmamap\n");
21222d586421SSepherosa Ziehau 		goto fail;
21232d586421SSepherosa Ziehau 	}
21242d586421SSepherosa Ziehau 	for (i = 0; i < MSK_JUMBO_RX_RING_CNT; i++) {
21252d586421SSepherosa Ziehau 		jrxd = &sc_if->msk_cdata.msk_jumbo_rxdesc[i];
21262d586421SSepherosa Ziehau 		jrxd->rx_m = NULL;
21272d586421SSepherosa Ziehau 		jrxd->rx_dmamap = NULL;
21282d586421SSepherosa Ziehau 		error = bus_dmamap_create(sc_if->msk_cdata.msk_jumbo_rx_tag, 0,
21292d586421SSepherosa Ziehau 		    &jrxd->rx_dmamap);
21302d586421SSepherosa Ziehau 		if (error != 0) {
21312d586421SSepherosa Ziehau 			device_printf(sc_if->msk_if_dev,
21322d586421SSepherosa Ziehau 			    "failed to create jumbo Rx dmamap\n");
21332d586421SSepherosa Ziehau 			goto fail;
21342d586421SSepherosa Ziehau 		}
21352d586421SSepherosa Ziehau 	}
21362d586421SSepherosa Ziehau 
21372d586421SSepherosa Ziehau 	/* Allocate DMA'able memory and load the DMA map for jumbo buf. */
21382d586421SSepherosa Ziehau 	error = bus_dmamem_alloc(sc_if->msk_cdata.msk_jumbo_tag,
21392d586421SSepherosa Ziehau 	    (void **)&sc_if->msk_rdata.msk_jumbo_buf,
21402d586421SSepherosa Ziehau 	    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
21412d586421SSepherosa Ziehau 	    &sc_if->msk_cdata.msk_jumbo_map);
21422d586421SSepherosa Ziehau 	if (error != 0) {
21432d586421SSepherosa Ziehau 		device_printf(sc_if->msk_if_dev,
21442d586421SSepherosa Ziehau 		    "failed to allocate DMA'able memory for jumbo buf\n");
21452d586421SSepherosa Ziehau 		goto fail;
21462d586421SSepherosa Ziehau 	}
21472d586421SSepherosa Ziehau 
21482d586421SSepherosa Ziehau 	ctx.msk_busaddr = 0;
21492d586421SSepherosa Ziehau 	error = bus_dmamap_load(sc_if->msk_cdata.msk_jumbo_tag,
21502d586421SSepherosa Ziehau 	    sc_if->msk_cdata.msk_jumbo_map, sc_if->msk_rdata.msk_jumbo_buf,
21512d586421SSepherosa Ziehau 	    MSK_JMEM, msk_dmamap_cb, &ctx, 0);
21522d586421SSepherosa Ziehau 	if (error != 0) {
21532d586421SSepherosa Ziehau 		device_printf(sc_if->msk_if_dev,
21542d586421SSepherosa Ziehau 		    "failed to load DMA'able memory for jumbobuf\n");
21552d586421SSepherosa Ziehau 		goto fail;
21562d586421SSepherosa Ziehau 	}
21572d586421SSepherosa Ziehau 	sc_if->msk_rdata.msk_jumbo_buf_paddr = ctx.msk_busaddr;
21582d586421SSepherosa Ziehau 
21592d586421SSepherosa Ziehau 	/*
21602d586421SSepherosa Ziehau 	 * Now divide it up into 9K pieces and save the addresses
21612d586421SSepherosa Ziehau 	 * in an array.
21622d586421SSepherosa Ziehau 	 */
21632d586421SSepherosa Ziehau 	ptr = sc_if->msk_rdata.msk_jumbo_buf;
21642d586421SSepherosa Ziehau 	for (i = 0; i < MSK_JSLOTS; i++) {
21652d586421SSepherosa Ziehau 		sc_if->msk_cdata.msk_jslots[i] = ptr;
21662d586421SSepherosa Ziehau 		ptr += MSK_JLEN;
21672d586421SSepherosa Ziehau 		entry = malloc(sizeof(struct msk_jpool_entry),
21682d586421SSepherosa Ziehau 		    M_DEVBUF, M_WAITOK);
21692d586421SSepherosa Ziehau 		if (entry == NULL) {
21702d586421SSepherosa Ziehau 			device_printf(sc_if->msk_if_dev,
21712d586421SSepherosa Ziehau 			    "no memory for jumbo buffers!\n");
21722d586421SSepherosa Ziehau 			error = ENOMEM;
21732d586421SSepherosa Ziehau 			goto fail;
21742d586421SSepherosa Ziehau 		}
21752d586421SSepherosa Ziehau 		entry->slot = i;
21762d586421SSepherosa Ziehau 		SLIST_INSERT_HEAD(&sc_if->msk_jfree_listhead, entry,
21772d586421SSepherosa Ziehau 		    jpool_entries);
21782d586421SSepherosa Ziehau 	}
21792d586421SSepherosa Ziehau #endif
21802d586421SSepherosa Ziehau 	return 0;
21812d586421SSepherosa Ziehau }
21822d586421SSepherosa Ziehau 
21832d586421SSepherosa Ziehau static void
msk_txrx_dma_free(struct msk_if_softc * sc_if)21842d586421SSepherosa Ziehau msk_txrx_dma_free(struct msk_if_softc *sc_if)
21852d586421SSepherosa Ziehau {
21862d586421SSepherosa Ziehau 	struct msk_txdesc *txd;
21872d586421SSepherosa Ziehau 	struct msk_rxdesc *rxd;
21882d586421SSepherosa Ziehau #ifdef MSK_JUMBO
21892d586421SSepherosa Ziehau 	struct msk_rxdesc *jrxd;
21902d586421SSepherosa Ziehau 	struct msk_jpool_entry *entry;
21912d586421SSepherosa Ziehau #endif
21922d586421SSepherosa Ziehau 	int i;
21932d586421SSepherosa Ziehau 
21942d586421SSepherosa Ziehau #ifdef MSK_JUMBO
21952d586421SSepherosa Ziehau 	MSK_JLIST_LOCK(sc_if);
21962d586421SSepherosa Ziehau 	while ((entry = SLIST_FIRST(&sc_if->msk_jinuse_listhead))) {
21972d586421SSepherosa Ziehau 		device_printf(sc_if->msk_if_dev,
21982d586421SSepherosa Ziehau 		    "asked to free buffer that is in use!\n");
21992d586421SSepherosa Ziehau 		SLIST_REMOVE_HEAD(&sc_if->msk_jinuse_listhead, jpool_entries);
22002d586421SSepherosa Ziehau 		SLIST_INSERT_HEAD(&sc_if->msk_jfree_listhead, entry,
22012d586421SSepherosa Ziehau 		    jpool_entries);
22022d586421SSepherosa Ziehau 	}
22032d586421SSepherosa Ziehau 
22042d586421SSepherosa Ziehau 	while (!SLIST_EMPTY(&sc_if->msk_jfree_listhead)) {
22052d586421SSepherosa Ziehau 		entry = SLIST_FIRST(&sc_if->msk_jfree_listhead);
22062d586421SSepherosa Ziehau 		SLIST_REMOVE_HEAD(&sc_if->msk_jfree_listhead, jpool_entries);
22072d586421SSepherosa Ziehau 		free(entry, M_DEVBUF);
22082d586421SSepherosa Ziehau 	}
22092d586421SSepherosa Ziehau 	MSK_JLIST_UNLOCK(sc_if);
22102d586421SSepherosa Ziehau 
22112d586421SSepherosa Ziehau 	/* Destroy jumbo buffer block. */
22122d586421SSepherosa Ziehau 	if (sc_if->msk_cdata.msk_jumbo_map)
22132d586421SSepherosa Ziehau 		bus_dmamap_unload(sc_if->msk_cdata.msk_jumbo_tag,
22142d586421SSepherosa Ziehau 		    sc_if->msk_cdata.msk_jumbo_map);
22152d586421SSepherosa Ziehau 
22162d586421SSepherosa Ziehau 	if (sc_if->msk_rdata.msk_jumbo_buf) {
22172d586421SSepherosa Ziehau 		bus_dmamem_free(sc_if->msk_cdata.msk_jumbo_tag,
22182d586421SSepherosa Ziehau 		    sc_if->msk_rdata.msk_jumbo_buf,
22192d586421SSepherosa Ziehau 		    sc_if->msk_cdata.msk_jumbo_map);
22202d586421SSepherosa Ziehau 		sc_if->msk_rdata.msk_jumbo_buf = NULL;
22212d586421SSepherosa Ziehau 		sc_if->msk_cdata.msk_jumbo_map = NULL;
22222d586421SSepherosa Ziehau 	}
22232d586421SSepherosa Ziehau 
22242d586421SSepherosa Ziehau 	/* Jumbo Rx ring. */
22252d586421SSepherosa Ziehau 	if (sc_if->msk_cdata.msk_jumbo_rx_ring_tag) {
22262d586421SSepherosa Ziehau 		if (sc_if->msk_cdata.msk_jumbo_rx_ring_map)
22272d586421SSepherosa Ziehau 			bus_dmamap_unload(sc_if->msk_cdata.msk_jumbo_rx_ring_tag,
22282d586421SSepherosa Ziehau 			    sc_if->msk_cdata.msk_jumbo_rx_ring_map);
22292d586421SSepherosa Ziehau 		if (sc_if->msk_cdata.msk_jumbo_rx_ring_map &&
22302d586421SSepherosa Ziehau 		    sc_if->msk_rdata.msk_jumbo_rx_ring)
22312d586421SSepherosa Ziehau 			bus_dmamem_free(sc_if->msk_cdata.msk_jumbo_rx_ring_tag,
22322d586421SSepherosa Ziehau 			    sc_if->msk_rdata.msk_jumbo_rx_ring,
22332d586421SSepherosa Ziehau 			    sc_if->msk_cdata.msk_jumbo_rx_ring_map);
22342d586421SSepherosa Ziehau 		sc_if->msk_rdata.msk_jumbo_rx_ring = NULL;
22352d586421SSepherosa Ziehau 		sc_if->msk_cdata.msk_jumbo_rx_ring_map = NULL;
22362d586421SSepherosa Ziehau 		bus_dma_tag_destroy(sc_if->msk_cdata.msk_jumbo_rx_ring_tag);
22372d586421SSepherosa Ziehau 		sc_if->msk_cdata.msk_jumbo_rx_ring_tag = NULL;
22382d586421SSepherosa Ziehau 	}
22392d586421SSepherosa Ziehau 
22402d586421SSepherosa Ziehau 	/* Jumbo Rx buffers. */
22412d586421SSepherosa Ziehau 	if (sc_if->msk_cdata.msk_jumbo_rx_tag) {
22422d586421SSepherosa Ziehau 		for (i = 0; i < MSK_JUMBO_RX_RING_CNT; i++) {
22432d586421SSepherosa Ziehau 			jrxd = &sc_if->msk_cdata.msk_jumbo_rxdesc[i];
22442d586421SSepherosa Ziehau 			if (jrxd->rx_dmamap) {
22452d586421SSepherosa Ziehau 				bus_dmamap_destroy(
22462d586421SSepherosa Ziehau 				    sc_if->msk_cdata.msk_jumbo_rx_tag,
22472d586421SSepherosa Ziehau 				    jrxd->rx_dmamap);
22482d586421SSepherosa Ziehau 				jrxd->rx_dmamap = NULL;
22492d586421SSepherosa Ziehau 			}
22502d586421SSepherosa Ziehau 		}
22512d586421SSepherosa Ziehau 		if (sc_if->msk_cdata.msk_jumbo_rx_sparemap) {
22522d586421SSepherosa Ziehau 			bus_dmamap_destroy(sc_if->msk_cdata.msk_jumbo_rx_tag,
22532d586421SSepherosa Ziehau 			    sc_if->msk_cdata.msk_jumbo_rx_sparemap);
22542d586421SSepherosa Ziehau 			sc_if->msk_cdata.msk_jumbo_rx_sparemap = 0;
22552d586421SSepherosa Ziehau 		}
22562d586421SSepherosa Ziehau 		bus_dma_tag_destroy(sc_if->msk_cdata.msk_jumbo_rx_tag);
22572d586421SSepherosa Ziehau 		sc_if->msk_cdata.msk_jumbo_rx_tag = NULL;
22582d586421SSepherosa Ziehau 	}
22592d586421SSepherosa Ziehau #endif
22602d586421SSepherosa Ziehau 
22612d586421SSepherosa Ziehau 	/* Tx ring. */
22622d586421SSepherosa Ziehau 	msk_dmamem_destroy(sc_if->msk_cdata.msk_tx_ring_tag,
22632d586421SSepherosa Ziehau 			   sc_if->msk_rdata.msk_tx_ring,
22642d586421SSepherosa Ziehau 			   sc_if->msk_cdata.msk_tx_ring_map);
22652d586421SSepherosa Ziehau 
22662d586421SSepherosa Ziehau 	/* Rx ring. */
22672d586421SSepherosa Ziehau 	msk_dmamem_destroy(sc_if->msk_cdata.msk_rx_ring_tag,
22682d586421SSepherosa Ziehau 			   sc_if->msk_rdata.msk_rx_ring,
22692d586421SSepherosa Ziehau 			   sc_if->msk_cdata.msk_rx_ring_map);
22702d586421SSepherosa Ziehau 
22712d586421SSepherosa Ziehau 	/* Tx buffers. */
22722d586421SSepherosa Ziehau 	if (sc_if->msk_cdata.msk_tx_tag) {
22732d586421SSepherosa Ziehau 		for (i = 0; i < MSK_TX_RING_CNT; i++) {
22742d586421SSepherosa Ziehau 			txd = &sc_if->msk_cdata.msk_txdesc[i];
22752d586421SSepherosa Ziehau 			bus_dmamap_destroy(sc_if->msk_cdata.msk_tx_tag,
22762d586421SSepherosa Ziehau 					   txd->tx_dmamap);
22772d586421SSepherosa Ziehau 		}
22782d586421SSepherosa Ziehau 		bus_dma_tag_destroy(sc_if->msk_cdata.msk_tx_tag);
22792d586421SSepherosa Ziehau 		sc_if->msk_cdata.msk_tx_tag = NULL;
22802d586421SSepherosa Ziehau 	}
22812d586421SSepherosa Ziehau 
22822d586421SSepherosa Ziehau 	/* Rx buffers. */
22832d586421SSepherosa Ziehau 	if (sc_if->msk_cdata.msk_rx_tag) {
22842d586421SSepherosa Ziehau 		for (i = 0; i < MSK_RX_RING_CNT; i++) {
22852d586421SSepherosa Ziehau 			rxd = &sc_if->msk_cdata.msk_rxdesc[i];
22862d586421SSepherosa Ziehau 			bus_dmamap_destroy(sc_if->msk_cdata.msk_rx_tag,
22872d586421SSepherosa Ziehau 					   rxd->rx_dmamap);
22882d586421SSepherosa Ziehau 		}
22892d586421SSepherosa Ziehau 		bus_dmamap_destroy(sc_if->msk_cdata.msk_rx_tag,
22902d586421SSepherosa Ziehau 				   sc_if->msk_cdata.msk_rx_sparemap);
22912d586421SSepherosa Ziehau 		bus_dma_tag_destroy(sc_if->msk_cdata.msk_rx_tag);
22922d586421SSepherosa Ziehau 		sc_if->msk_cdata.msk_rx_tag = NULL;
22932d586421SSepherosa Ziehau 	}
22942d586421SSepherosa Ziehau 
22952d586421SSepherosa Ziehau 	if (sc_if->msk_cdata.msk_parent_tag) {
22962d586421SSepherosa Ziehau 		bus_dma_tag_destroy(sc_if->msk_cdata.msk_parent_tag);
22972d586421SSepherosa Ziehau 		sc_if->msk_cdata.msk_parent_tag = NULL;
22982d586421SSepherosa Ziehau 	}
22992d586421SSepherosa Ziehau }
23002d586421SSepherosa Ziehau 
23012d586421SSepherosa Ziehau #ifdef MSK_JUMBO
23022d586421SSepherosa Ziehau /*
23032d586421SSepherosa Ziehau  * Allocate a jumbo buffer.
23042d586421SSepherosa Ziehau  */
23052d586421SSepherosa Ziehau static void *
msk_jalloc(struct msk_if_softc * sc_if)23062d586421SSepherosa Ziehau msk_jalloc(struct msk_if_softc *sc_if)
23072d586421SSepherosa Ziehau {
23082d586421SSepherosa Ziehau 	struct msk_jpool_entry *entry;
23092d586421SSepherosa Ziehau 
23102d586421SSepherosa Ziehau 	MSK_JLIST_LOCK(sc_if);
23112d586421SSepherosa Ziehau 
23122d586421SSepherosa Ziehau 	entry = SLIST_FIRST(&sc_if->msk_jfree_listhead);
23132d586421SSepherosa Ziehau 
23142d586421SSepherosa Ziehau 	if (entry == NULL) {
23152d586421SSepherosa Ziehau 		MSK_JLIST_UNLOCK(sc_if);
23162d586421SSepherosa Ziehau 		return (NULL);
23172d586421SSepherosa Ziehau 	}
23182d586421SSepherosa Ziehau 
23192d586421SSepherosa Ziehau 	SLIST_REMOVE_HEAD(&sc_if->msk_jfree_listhead, jpool_entries);
23202d586421SSepherosa Ziehau 	SLIST_INSERT_HEAD(&sc_if->msk_jinuse_listhead, entry, jpool_entries);
23212d586421SSepherosa Ziehau 
23222d586421SSepherosa Ziehau 	MSK_JLIST_UNLOCK(sc_if);
23232d586421SSepherosa Ziehau 
23242d586421SSepherosa Ziehau 	return (sc_if->msk_cdata.msk_jslots[entry->slot]);
23252d586421SSepherosa Ziehau }
23262d586421SSepherosa Ziehau 
23272d586421SSepherosa Ziehau /*
23282d586421SSepherosa Ziehau  * Release a jumbo buffer.
23292d586421SSepherosa Ziehau  */
23302d586421SSepherosa Ziehau static void
msk_jfree(void * buf,void * args)23312d586421SSepherosa Ziehau msk_jfree(void *buf, void *args)
23322d586421SSepherosa Ziehau {
23332d586421SSepherosa Ziehau 	struct msk_if_softc *sc_if;
23342d586421SSepherosa Ziehau 	struct msk_jpool_entry *entry;
23352d586421SSepherosa Ziehau 	int i;
23362d586421SSepherosa Ziehau 
23372d586421SSepherosa Ziehau 	/* Extract the softc struct pointer. */
23382d586421SSepherosa Ziehau 	sc_if = (struct msk_if_softc *)args;
23392d586421SSepherosa Ziehau 	KASSERT(sc_if != NULL, ("%s: can't find softc pointer!", __func__));
23402d586421SSepherosa Ziehau 
23412d586421SSepherosa Ziehau 	MSK_JLIST_LOCK(sc_if);
23422d586421SSepherosa Ziehau 	/* Calculate the slot this buffer belongs to. */
23432d586421SSepherosa Ziehau 	i = ((vm_offset_t)buf
23442d586421SSepherosa Ziehau 	     - (vm_offset_t)sc_if->msk_rdata.msk_jumbo_buf) / MSK_JLEN;
23452d586421SSepherosa Ziehau 	KASSERT(i >= 0 && i < MSK_JSLOTS,
23462d586421SSepherosa Ziehau 	    ("%s: asked to free buffer that we don't manage!", __func__));
23472d586421SSepherosa Ziehau 
23482d586421SSepherosa Ziehau 	entry = SLIST_FIRST(&sc_if->msk_jinuse_listhead);
23492d586421SSepherosa Ziehau 	KASSERT(entry != NULL, ("%s: buffer not in use!", __func__));
23502d586421SSepherosa Ziehau 	entry->slot = i;
23512d586421SSepherosa Ziehau 	SLIST_REMOVE_HEAD(&sc_if->msk_jinuse_listhead, jpool_entries);
23522d586421SSepherosa Ziehau 	SLIST_INSERT_HEAD(&sc_if->msk_jfree_listhead, entry, jpool_entries);
23532d586421SSepherosa Ziehau 	if (SLIST_EMPTY(&sc_if->msk_jinuse_listhead))
23542d586421SSepherosa Ziehau 		wakeup(sc_if);
23552d586421SSepherosa Ziehau 
23562d586421SSepherosa Ziehau 	MSK_JLIST_UNLOCK(sc_if);
23572d586421SSepherosa Ziehau }
23582d586421SSepherosa Ziehau #endif
23592d586421SSepherosa Ziehau 
23602d586421SSepherosa Ziehau static int
msk_encap(struct msk_if_softc * sc_if,struct mbuf ** m_head)23612d586421SSepherosa Ziehau msk_encap(struct msk_if_softc *sc_if, struct mbuf **m_head)
23622d586421SSepherosa Ziehau {
23632d586421SSepherosa Ziehau 	struct msk_txdesc *txd, *txd_last;
23642d586421SSepherosa Ziehau 	struct msk_tx_desc *tx_le;
23652d586421SSepherosa Ziehau 	struct mbuf *m;
23662d586421SSepherosa Ziehau 	bus_dmamap_t map;
23672d586421SSepherosa Ziehau 	bus_dma_segment_t txsegs[MSK_MAXTXSEGS];
23682d586421SSepherosa Ziehau 	uint32_t control, prod, si;
23692d586421SSepherosa Ziehau 	uint16_t offset, tcp_offset;
23705bda51d4SSepherosa Ziehau 	int error, i, nsegs, maxsegs, defrag;
2371def0e148SSepherosa Ziehau 
2372def0e148SSepherosa Ziehau 	maxsegs = MSK_TX_RING_CNT - sc_if->msk_cdata.msk_tx_cnt -
2373def0e148SSepherosa Ziehau 		  MSK_RESERVED_TX_DESC_CNT;
2374def0e148SSepherosa Ziehau 	KASSERT(maxsegs >= MSK_SPARE_TX_DESC_CNT,
2375ed20d0e3SSascha Wildner 		("not enough spare TX desc"));
2376def0e148SSepherosa Ziehau 	if (maxsegs > MSK_MAXTXSEGS)
2377def0e148SSepherosa Ziehau 		maxsegs = MSK_MAXTXSEGS;
23782d586421SSepherosa Ziehau 
23795bda51d4SSepherosa Ziehau 	/*
2380e71dee4bSSepherosa Ziehau 	 * Align TX buffer to 64bytes boundary.  This greately improves
23815bda51d4SSepherosa Ziehau 	 * bulk data TX performance on my 88E8053 (+100Mbps) at least.
23825bda51d4SSepherosa Ziehau 	 * Try avoiding m_defrag(), if the mbufs are not chained together
23835bda51d4SSepherosa Ziehau 	 * by m_next (i.e. m->m_len == m->m_pkthdr.len).
23845bda51d4SSepherosa Ziehau 	 */
23855bda51d4SSepherosa Ziehau 
2386e71dee4bSSepherosa Ziehau #define MSK_TXBUF_ALIGN	64
23875bda51d4SSepherosa Ziehau #define MSK_TXBUF_MASK	(MSK_TXBUF_ALIGN - 1)
23885bda51d4SSepherosa Ziehau 
23895bda51d4SSepherosa Ziehau 	defrag = 1;
23902d586421SSepherosa Ziehau 	m = *m_head;
23915bda51d4SSepherosa Ziehau 	if (m->m_len == m->m_pkthdr.len) {
23925bda51d4SSepherosa Ziehau 		int space;
23935bda51d4SSepherosa Ziehau 
23945bda51d4SSepherosa Ziehau 		space = ((uintptr_t)m->m_data & MSK_TXBUF_MASK);
23955bda51d4SSepherosa Ziehau 		if (space) {
23965bda51d4SSepherosa Ziehau 			if (M_WRITABLE(m)) {
23975bda51d4SSepherosa Ziehau 				if (M_TRAILINGSPACE(m) >= space) {
23985bda51d4SSepherosa Ziehau 					/* e.g. TCP ACKs */
23995bda51d4SSepherosa Ziehau 					bcopy(m->m_data, m->m_data + space,
24005bda51d4SSepherosa Ziehau 					      m->m_len);
24015bda51d4SSepherosa Ziehau 					m->m_data += space;
24025bda51d4SSepherosa Ziehau 					defrag = 0;
24035bda51d4SSepherosa Ziehau 					sc_if->msk_softc->msk_trailing_copied++;
24045bda51d4SSepherosa Ziehau 				} else {
24055bda51d4SSepherosa Ziehau 					space = MSK_TXBUF_ALIGN - space;
24065bda51d4SSepherosa Ziehau 					if (M_LEADINGSPACE(m) >= space) {
24075bda51d4SSepherosa Ziehau 						/* e.g. Small UDP datagrams */
24085bda51d4SSepherosa Ziehau 						bcopy(m->m_data,
24095bda51d4SSepherosa Ziehau 						      m->m_data - space,
24105bda51d4SSepherosa Ziehau 						      m->m_len);
24115bda51d4SSepherosa Ziehau 						m->m_data -= space;
24125bda51d4SSepherosa Ziehau 						defrag = 0;
24135bda51d4SSepherosa Ziehau 						sc_if->msk_softc->
24145bda51d4SSepherosa Ziehau 						msk_leading_copied++;
24155bda51d4SSepherosa Ziehau 					}
24165bda51d4SSepherosa Ziehau 				}
24175bda51d4SSepherosa Ziehau 			}
24185bda51d4SSepherosa Ziehau 		} else {
24195bda51d4SSepherosa Ziehau 			/* e.g. on forwarding path */
24205bda51d4SSepherosa Ziehau 			defrag = 0;
24215bda51d4SSepherosa Ziehau 		}
24225bda51d4SSepherosa Ziehau 	}
24235bda51d4SSepherosa Ziehau 	if (defrag) {
2424*b5523eacSSascha Wildner 		m = m_defrag(*m_head, M_NOWAIT);
24255bda51d4SSepherosa Ziehau 		if (m == NULL) {
24265bda51d4SSepherosa Ziehau 			m_freem(*m_head);
24275bda51d4SSepherosa Ziehau 			*m_head = NULL;
24285bda51d4SSepherosa Ziehau 			return ENOBUFS;
24295bda51d4SSepherosa Ziehau 		}
24305bda51d4SSepherosa Ziehau 		*m_head = m;
24315bda51d4SSepherosa Ziehau 	} else {
24325bda51d4SSepherosa Ziehau 		sc_if->msk_softc->msk_defrag_avoided++;
24335bda51d4SSepherosa Ziehau 	}
24345bda51d4SSepherosa Ziehau 
24355bda51d4SSepherosa Ziehau #undef MSK_TXBUF_MASK
24365bda51d4SSepherosa Ziehau #undef MSK_TXBUF_ALIGN
24375bda51d4SSepherosa Ziehau 
24385bda51d4SSepherosa Ziehau 	tcp_offset = offset = 0;
24392d586421SSepherosa Ziehau 	if (m->m_pkthdr.csum_flags & MSK_CSUM_FEATURES) {
24402d586421SSepherosa Ziehau 		/*
24412d586421SSepherosa Ziehau 		 * Since mbuf has no protocol specific structure information
24422d586421SSepherosa Ziehau 		 * in it we have to inspect protocol information here to
24432d586421SSepherosa Ziehau 		 * setup TSO and checksum offload. I don't know why Marvell
24442d586421SSepherosa Ziehau 		 * made a such decision in chip design because other GigE
24452d586421SSepherosa Ziehau 		 * hardwares normally takes care of all these chores in
24462d586421SSepherosa Ziehau 		 * hardware. However, TSO performance of Yukon II is very
24472d586421SSepherosa Ziehau 		 * good such that it's worth to implement it.
24482d586421SSepherosa Ziehau 		 */
24492d586421SSepherosa Ziehau 		struct ether_header *eh;
24502d586421SSepherosa Ziehau 		struct ip *ip;
24512d586421SSepherosa Ziehau 
24522d586421SSepherosa Ziehau 		/* TODO check for M_WRITABLE(m) */
24532d586421SSepherosa Ziehau 
24542d586421SSepherosa Ziehau 		offset = sizeof(struct ether_header);
24552d586421SSepherosa Ziehau 		m = m_pullup(m, offset);
24562d586421SSepherosa Ziehau 		if (m == NULL) {
24572d586421SSepherosa Ziehau 			*m_head = NULL;
24582d586421SSepherosa Ziehau 			return (ENOBUFS);
24592d586421SSepherosa Ziehau 		}
24602d586421SSepherosa Ziehau 		eh = mtod(m, struct ether_header *);
24612d586421SSepherosa Ziehau 		/* Check if hardware VLAN insertion is off. */
24622d586421SSepherosa Ziehau 		if (eh->ether_type == htons(ETHERTYPE_VLAN)) {
24632d586421SSepherosa Ziehau 			offset = sizeof(struct ether_vlan_header);
24642d586421SSepherosa Ziehau 			m = m_pullup(m, offset);
24652d586421SSepherosa Ziehau 			if (m == NULL) {
24662d586421SSepherosa Ziehau 				*m_head = NULL;
24672d586421SSepherosa Ziehau 				return (ENOBUFS);
24682d586421SSepherosa Ziehau 			}
24692d586421SSepherosa Ziehau 		}
24702d586421SSepherosa Ziehau 		m = m_pullup(m, offset + sizeof(struct ip));
24712d586421SSepherosa Ziehau 		if (m == NULL) {
24722d586421SSepherosa Ziehau 			*m_head = NULL;
24732d586421SSepherosa Ziehau 			return (ENOBUFS);
24742d586421SSepherosa Ziehau 		}
24752d586421SSepherosa Ziehau 		ip = (struct ip *)(mtod(m, char *) + offset);
24762d586421SSepherosa Ziehau 		offset += (ip->ip_hl << 2);
24772d586421SSepherosa Ziehau 		tcp_offset = offset;
24782d586421SSepherosa Ziehau 		/*
24792d586421SSepherosa Ziehau 		 * It seems that Yukon II has Tx checksum offload bug for
24802d586421SSepherosa Ziehau 		 * small TCP packets that's less than 60 bytes in size
24812d586421SSepherosa Ziehau 		 * (e.g. TCP window probe packet, pure ACK packet).
24822d586421SSepherosa Ziehau 		 * Common work around like padding with zeros to make the
24832d586421SSepherosa Ziehau 		 * frame minimum ethernet frame size didn't work at all.
24842d586421SSepherosa Ziehau 		 * Instead of disabling checksum offload completely we
24852d586421SSepherosa Ziehau 		 * resort to S/W checksum routine when we encounter short
24862d586421SSepherosa Ziehau 		 * TCP frames.
24872d586421SSepherosa Ziehau 		 * Short UDP packets appear to be handled correctly by
24882d586421SSepherosa Ziehau 		 * Yukon II.
24892d586421SSepherosa Ziehau 		 */
24902d586421SSepherosa Ziehau 		if (m->m_pkthdr.len < MSK_MIN_FRAMELEN &&
24912d586421SSepherosa Ziehau 		    (m->m_pkthdr.csum_flags & CSUM_TCP) != 0) {
24922d586421SSepherosa Ziehau 			uint16_t csum;
24932d586421SSepherosa Ziehau 
24942d586421SSepherosa Ziehau 			csum = in_cksum_skip(m, ntohs(ip->ip_len) + offset -
24952d586421SSepherosa Ziehau 			    (ip->ip_hl << 2), offset);
24962d586421SSepherosa Ziehau 			*(uint16_t *)(m->m_data + offset +
24972d586421SSepherosa Ziehau 			    m->m_pkthdr.csum_data) = csum;
24982d586421SSepherosa Ziehau 			m->m_pkthdr.csum_flags &= ~CSUM_TCP;
24992d586421SSepherosa Ziehau 		}
25002d586421SSepherosa Ziehau 		*m_head = m;
25012d586421SSepherosa Ziehau 	}
25022d586421SSepherosa Ziehau 
25032d586421SSepherosa Ziehau 	prod = sc_if->msk_cdata.msk_tx_prod;
25042d586421SSepherosa Ziehau 	txd = &sc_if->msk_cdata.msk_txdesc[prod];
25052d586421SSepherosa Ziehau 	txd_last = txd;
25062d586421SSepherosa Ziehau 	map = txd->tx_dmamap;
2507def0e148SSepherosa Ziehau 
2508def0e148SSepherosa Ziehau 	error = bus_dmamap_load_mbuf_defrag(sc_if->msk_cdata.msk_tx_tag, map,
2509def0e148SSepherosa Ziehau 			m_head, txsegs, maxsegs, &nsegs, BUS_DMA_NOWAIT);
2510def0e148SSepherosa Ziehau 	if (error) {
25112d586421SSepherosa Ziehau 		m_freem(*m_head);
25122d586421SSepherosa Ziehau 		*m_head = NULL;
2513def0e148SSepherosa Ziehau 		return error;
25142d586421SSepherosa Ziehau 	}
2515def0e148SSepherosa Ziehau 	bus_dmamap_sync(sc_if->msk_cdata.msk_tx_tag, map, BUS_DMASYNC_PREWRITE);
25162d586421SSepherosa Ziehau 
2517def0e148SSepherosa Ziehau 	m = *m_head;
25182d586421SSepherosa Ziehau 	control = 0;
25192d586421SSepherosa Ziehau 	tx_le = NULL;
25202d586421SSepherosa Ziehau 
25212d586421SSepherosa Ziehau #ifdef notyet
25222d586421SSepherosa Ziehau 	/* Check if we have a VLAN tag to insert. */
25232d586421SSepherosa Ziehau 	if ((m->m_flags & M_VLANTAG) != 0) {
25242d586421SSepherosa Ziehau 		tx_le = &sc_if->msk_rdata.msk_tx_ring[prod];
25252d586421SSepherosa Ziehau 		tx_le->msk_addr = htole32(0);
25262d586421SSepherosa Ziehau 		tx_le->msk_control = htole32(OP_VLAN | HW_OWNER |
25272d586421SSepherosa Ziehau 		    htons(m->m_pkthdr.ether_vtag));
25282d586421SSepherosa Ziehau 		sc_if->msk_cdata.msk_tx_cnt++;
25292d586421SSepherosa Ziehau 		MSK_INC(prod, MSK_TX_RING_CNT);
25302d586421SSepherosa Ziehau 		control |= INS_VLAN;
25312d586421SSepherosa Ziehau 	}
25322d586421SSepherosa Ziehau #endif
25332d586421SSepherosa Ziehau 	/* Check if we have to handle checksum offload. */
25342d586421SSepherosa Ziehau 	if (m->m_pkthdr.csum_flags & MSK_CSUM_FEATURES) {
25352d586421SSepherosa Ziehau 		tx_le = &sc_if->msk_rdata.msk_tx_ring[prod];
25362d586421SSepherosa Ziehau 		tx_le->msk_addr = htole32(((tcp_offset + m->m_pkthdr.csum_data)
25372d586421SSepherosa Ziehau 		    & 0xffff) | ((uint32_t)tcp_offset << 16));
25382d586421SSepherosa Ziehau 		tx_le->msk_control = htole32(1 << 16 | (OP_TCPLISW | HW_OWNER));
25392d586421SSepherosa Ziehau 		control = CALSUM | WR_SUM | INIT_SUM | LOCK_SUM;
25402d586421SSepherosa Ziehau 		if ((m->m_pkthdr.csum_flags & CSUM_UDP) != 0)
25412d586421SSepherosa Ziehau 			control |= UDPTCP;
25422d586421SSepherosa Ziehau 		sc_if->msk_cdata.msk_tx_cnt++;
25432d586421SSepherosa Ziehau 		MSK_INC(prod, MSK_TX_RING_CNT);
25442d586421SSepherosa Ziehau 	}
25452d586421SSepherosa Ziehau 
25462d586421SSepherosa Ziehau 	si = prod;
25472d586421SSepherosa Ziehau 	tx_le = &sc_if->msk_rdata.msk_tx_ring[prod];
25482d586421SSepherosa Ziehau 	tx_le->msk_addr = htole32(MSK_ADDR_LO(txsegs[0].ds_addr));
25492d586421SSepherosa Ziehau 	tx_le->msk_control = htole32(txsegs[0].ds_len | control |
25502d586421SSepherosa Ziehau 	    OP_PACKET);
25512d586421SSepherosa Ziehau 	sc_if->msk_cdata.msk_tx_cnt++;
25522d586421SSepherosa Ziehau 	MSK_INC(prod, MSK_TX_RING_CNT);
25532d586421SSepherosa Ziehau 
2554def0e148SSepherosa Ziehau 	for (i = 1; i < nsegs; i++) {
25552d586421SSepherosa Ziehau 		tx_le = &sc_if->msk_rdata.msk_tx_ring[prod];
25562d586421SSepherosa Ziehau 		tx_le->msk_addr = htole32(MSK_ADDR_LO(txsegs[i].ds_addr));
25572d586421SSepherosa Ziehau 		tx_le->msk_control = htole32(txsegs[i].ds_len | control |
25582d586421SSepherosa Ziehau 		    OP_BUFFER | HW_OWNER);
25592d586421SSepherosa Ziehau 		sc_if->msk_cdata.msk_tx_cnt++;
25602d586421SSepherosa Ziehau 		MSK_INC(prod, MSK_TX_RING_CNT);
25612d586421SSepherosa Ziehau 	}
25622d586421SSepherosa Ziehau 	/* Update producer index. */
25632d586421SSepherosa Ziehau 	sc_if->msk_cdata.msk_tx_prod = prod;
25642d586421SSepherosa Ziehau 
25652d586421SSepherosa Ziehau 	/* Set EOP on the last desciptor. */
25662d586421SSepherosa Ziehau 	prod = (prod + MSK_TX_RING_CNT - 1) % MSK_TX_RING_CNT;
25672d586421SSepherosa Ziehau 	tx_le = &sc_if->msk_rdata.msk_tx_ring[prod];
25682d586421SSepherosa Ziehau 	tx_le->msk_control |= htole32(EOP);
25692d586421SSepherosa Ziehau 
25702d586421SSepherosa Ziehau 	/* Turn the first descriptor ownership to hardware. */
25712d586421SSepherosa Ziehau 	tx_le = &sc_if->msk_rdata.msk_tx_ring[si];
25722d586421SSepherosa Ziehau 	tx_le->msk_control |= htole32(HW_OWNER);
25732d586421SSepherosa Ziehau 
25742d586421SSepherosa Ziehau 	txd = &sc_if->msk_cdata.msk_txdesc[prod];
25752d586421SSepherosa Ziehau 	map = txd_last->tx_dmamap;
25762d586421SSepherosa Ziehau 	txd_last->tx_dmamap = txd->tx_dmamap;
25772d586421SSepherosa Ziehau 	txd->tx_dmamap = map;
25782d586421SSepherosa Ziehau 	txd->tx_m = m;
25792d586421SSepherosa Ziehau 
25802d586421SSepherosa Ziehau 	return (0);
25812d586421SSepherosa Ziehau }
25822d586421SSepherosa Ziehau 
25832d586421SSepherosa Ziehau static void
msk_start(struct ifnet * ifp,struct ifaltq_subque * ifsq)2584f0a26983SSepherosa Ziehau msk_start(struct ifnet *ifp, struct ifaltq_subque *ifsq)
25852d586421SSepherosa Ziehau {
25862d586421SSepherosa Ziehau         struct msk_if_softc *sc_if;
25872d586421SSepherosa Ziehau         struct mbuf *m_head;
25882d586421SSepherosa Ziehau 	int enq;
25892d586421SSepherosa Ziehau 
25902d586421SSepherosa Ziehau 	sc_if = ifp->if_softc;
25912d586421SSepherosa Ziehau 
2592f0a26983SSepherosa Ziehau 	ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq);
25932d586421SSepherosa Ziehau 	ASSERT_SERIALIZED(ifp->if_serializer);
25942d586421SSepherosa Ziehau 
25959db4b353SSepherosa Ziehau 	if (!sc_if->msk_link) {
25969db4b353SSepherosa Ziehau 		ifq_purge(&ifp->if_snd);
25979db4b353SSepherosa Ziehau 		return;
25989db4b353SSepherosa Ziehau 	}
25999db4b353SSepherosa Ziehau 
26009ed293e0SSepherosa Ziehau 	if ((ifp->if_flags & IFF_RUNNING) == 0 || ifq_is_oactive(&ifp->if_snd))
26012d586421SSepherosa Ziehau 		return;
26022d586421SSepherosa Ziehau 
2603def0e148SSepherosa Ziehau 	enq = 0;
2604def0e148SSepherosa Ziehau 	while (!ifq_is_empty(&ifp->if_snd)) {
2605def0e148SSepherosa Ziehau 		if (MSK_IS_OACTIVE(sc_if)) {
26069ed293e0SSepherosa Ziehau 			ifq_set_oactive(&ifp->if_snd);
2607def0e148SSepherosa Ziehau 			break;
2608def0e148SSepherosa Ziehau 		}
2609def0e148SSepherosa Ziehau 
2610ac9843a1SSepherosa Ziehau 		m_head = ifq_dequeue(&ifp->if_snd);
26112d586421SSepherosa Ziehau 		if (m_head == NULL)
26122d586421SSepherosa Ziehau 			break;
26132d586421SSepherosa Ziehau 
26142d586421SSepherosa Ziehau 		/*
26152d586421SSepherosa Ziehau 		 * Pack the data into the transmit ring. If we
26162d586421SSepherosa Ziehau 		 * don't have room, set the OACTIVE flag and wait
26172d586421SSepherosa Ziehau 		 * for the NIC to drain the ring.
26182d586421SSepherosa Ziehau 		 */
26192d586421SSepherosa Ziehau 		if (msk_encap(sc_if, &m_head) != 0) {
2620d40991efSSepherosa Ziehau 			IFNET_STAT_INC(ifp, oerrors, 1);
2621def0e148SSepherosa Ziehau 			if (sc_if->msk_cdata.msk_tx_cnt == 0) {
2622def0e148SSepherosa Ziehau 				continue;
2623def0e148SSepherosa Ziehau 			} else {
26249ed293e0SSepherosa Ziehau 				ifq_set_oactive(&ifp->if_snd);
26252d586421SSepherosa Ziehau 				break;
26262d586421SSepherosa Ziehau 			}
2627def0e148SSepherosa Ziehau 		}
2628def0e148SSepherosa Ziehau 		enq = 1;
26292d586421SSepherosa Ziehau 
26302d586421SSepherosa Ziehau 		/*
26312d586421SSepherosa Ziehau 		 * If there's a BPF listener, bounce a copy of this frame
26322d586421SSepherosa Ziehau 		 * to him.
26332d586421SSepherosa Ziehau 		 */
26342d586421SSepherosa Ziehau 		BPF_MTAP(ifp, m_head);
26352d586421SSepherosa Ziehau 	}
26362d586421SSepherosa Ziehau 
2637def0e148SSepherosa Ziehau 	if (enq) {
26382d586421SSepherosa Ziehau 		/* Transmit */
26392d586421SSepherosa Ziehau 		CSR_WRITE_2(sc_if->msk_softc,
26402d586421SSepherosa Ziehau 		    Y2_PREF_Q_ADDR(sc_if->msk_txq, PREF_UNIT_PUT_IDX_REG),
26412d586421SSepherosa Ziehau 		    sc_if->msk_cdata.msk_tx_prod);
26422d586421SSepherosa Ziehau 
26432d586421SSepherosa Ziehau 		/* Set a timeout in case the chip goes out to lunch. */
26442d586421SSepherosa Ziehau 		ifp->if_timer = MSK_TX_TIMEOUT;
26452d586421SSepherosa Ziehau 	}
26462d586421SSepherosa Ziehau }
26472d586421SSepherosa Ziehau 
26482d586421SSepherosa Ziehau static void
msk_watchdog(struct ifnet * ifp)26492d586421SSepherosa Ziehau msk_watchdog(struct ifnet *ifp)
26502d586421SSepherosa Ziehau {
26512d586421SSepherosa Ziehau 	struct msk_if_softc *sc_if = ifp->if_softc;
26522d586421SSepherosa Ziehau 	uint32_t ridx;
26532d586421SSepherosa Ziehau 	int idx;
26542d586421SSepherosa Ziehau 
26552d586421SSepherosa Ziehau 	ASSERT_SERIALIZED(ifp->if_serializer);
26562d586421SSepherosa Ziehau 
26572d586421SSepherosa Ziehau 	if (sc_if->msk_link == 0) {
26582d586421SSepherosa Ziehau 		if (bootverbose)
26592d586421SSepherosa Ziehau 			if_printf(sc_if->msk_ifp, "watchdog timeout "
26602d586421SSepherosa Ziehau 			   "(missed link)\n");
2661d40991efSSepherosa Ziehau 		IFNET_STAT_INC(ifp, oerrors, 1);
26622d586421SSepherosa Ziehau 		msk_init(sc_if);
26632d586421SSepherosa Ziehau 		return;
26642d586421SSepherosa Ziehau 	}
26652d586421SSepherosa Ziehau 
26662d586421SSepherosa Ziehau 	/*
26672d586421SSepherosa Ziehau 	 * Reclaim first as there is a possibility of losing Tx completion
26682d586421SSepherosa Ziehau 	 * interrupts.
26692d586421SSepherosa Ziehau 	 */
26702d586421SSepherosa Ziehau 	ridx = sc_if->msk_port == MSK_PORT_A ? STAT_TXA1_RIDX : STAT_TXA2_RIDX;
26712d586421SSepherosa Ziehau 	idx = CSR_READ_2(sc_if->msk_softc, ridx);
26722d586421SSepherosa Ziehau 	if (sc_if->msk_cdata.msk_tx_cons != idx) {
26732d586421SSepherosa Ziehau 		msk_txeof(sc_if, idx);
26742d586421SSepherosa Ziehau 		if (sc_if->msk_cdata.msk_tx_cnt == 0) {
26752d586421SSepherosa Ziehau 			if_printf(ifp, "watchdog timeout (missed Tx interrupts) "
26762d586421SSepherosa Ziehau 			    "-- recovering\n");
26772d586421SSepherosa Ziehau 			if (!ifq_is_empty(&ifp->if_snd))
26789db4b353SSepherosa Ziehau 				if_devstart(ifp);
26792d586421SSepherosa Ziehau 			return;
26802d586421SSepherosa Ziehau 		}
26812d586421SSepherosa Ziehau 	}
26822d586421SSepherosa Ziehau 
26832d586421SSepherosa Ziehau 	if_printf(ifp, "watchdog timeout\n");
2684d40991efSSepherosa Ziehau 	IFNET_STAT_INC(ifp, oerrors, 1);
26852d586421SSepherosa Ziehau 	msk_init(sc_if);
26862d586421SSepherosa Ziehau 	if (!ifq_is_empty(&ifp->if_snd))
26879db4b353SSepherosa Ziehau 		if_devstart(ifp);
26882d586421SSepherosa Ziehau }
26892d586421SSepherosa Ziehau 
26902d586421SSepherosa Ziehau static int
mskc_shutdown(device_t dev)26912d586421SSepherosa Ziehau mskc_shutdown(device_t dev)
26922d586421SSepherosa Ziehau {
26932d586421SSepherosa Ziehau 	struct msk_softc *sc = device_get_softc(dev);
26942d586421SSepherosa Ziehau 	int i;
26952d586421SSepherosa Ziehau 
26962d586421SSepherosa Ziehau 	lwkt_serialize_enter(&sc->msk_serializer);
26972d586421SSepherosa Ziehau 
26982d586421SSepherosa Ziehau 	for (i = 0; i < sc->msk_num_port; i++) {
26992d586421SSepherosa Ziehau 		if (sc->msk_if[i] != NULL)
27002d586421SSepherosa Ziehau 			msk_stop(sc->msk_if[i]);
27012d586421SSepherosa Ziehau 	}
27022d586421SSepherosa Ziehau 
27032d586421SSepherosa Ziehau 	/* Put hardware reset. */
27042d586421SSepherosa Ziehau 	CSR_WRITE_2(sc, B0_CTST, CS_RST_SET);
27052d586421SSepherosa Ziehau 
27062d586421SSepherosa Ziehau 	lwkt_serialize_exit(&sc->msk_serializer);
27072d586421SSepherosa Ziehau 	return (0);
27082d586421SSepherosa Ziehau }
27092d586421SSepherosa Ziehau 
27102d586421SSepherosa Ziehau static int
mskc_suspend(device_t dev)27112d586421SSepherosa Ziehau mskc_suspend(device_t dev)
27122d586421SSepherosa Ziehau {
27132d586421SSepherosa Ziehau 	struct msk_softc *sc = device_get_softc(dev);
27142d586421SSepherosa Ziehau 	int i;
27152d586421SSepherosa Ziehau 
27162d586421SSepherosa Ziehau 	lwkt_serialize_enter(&sc->msk_serializer);
27172d586421SSepherosa Ziehau 
27182d586421SSepherosa Ziehau 	for (i = 0; i < sc->msk_num_port; i++) {
27192d586421SSepherosa Ziehau 		if (sc->msk_if[i] != NULL && sc->msk_if[i]->msk_ifp != NULL &&
27202d586421SSepherosa Ziehau 		    ((sc->msk_if[i]->msk_ifp->if_flags & IFF_RUNNING) != 0))
27212d586421SSepherosa Ziehau 			msk_stop(sc->msk_if[i]);
27222d586421SSepherosa Ziehau 	}
27232d586421SSepherosa Ziehau 
27242d586421SSepherosa Ziehau 	/* Disable all interrupts. */
27252d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, B0_IMSK, 0);
27262d586421SSepherosa Ziehau 	CSR_READ_4(sc, B0_IMSK);
27272d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, B0_HWE_IMSK, 0);
27282d586421SSepherosa Ziehau 	CSR_READ_4(sc, B0_HWE_IMSK);
27292d586421SSepherosa Ziehau 
27302d586421SSepherosa Ziehau 	mskc_phy_power(sc, MSK_PHY_POWERDOWN);
27312d586421SSepherosa Ziehau 
27322d586421SSepherosa Ziehau 	/* Put hardware reset. */
27332d586421SSepherosa Ziehau 	CSR_WRITE_2(sc, B0_CTST, CS_RST_SET);
27342d586421SSepherosa Ziehau 	sc->msk_suspended = 1;
27352d586421SSepherosa Ziehau 
27362d586421SSepherosa Ziehau 	lwkt_serialize_exit(&sc->msk_serializer);
27372d586421SSepherosa Ziehau 
27382d586421SSepherosa Ziehau 	return (0);
27392d586421SSepherosa Ziehau }
27402d586421SSepherosa Ziehau 
27412d586421SSepherosa Ziehau static int
mskc_resume(device_t dev)27422d586421SSepherosa Ziehau mskc_resume(device_t dev)
27432d586421SSepherosa Ziehau {
27442d586421SSepherosa Ziehau 	struct msk_softc *sc = device_get_softc(dev);
27452d586421SSepherosa Ziehau 	int i;
27462d586421SSepherosa Ziehau 
27472d586421SSepherosa Ziehau 	lwkt_serialize_enter(&sc->msk_serializer);
27482d586421SSepherosa Ziehau 
274960ad6a1fSSepherosa Ziehau 	/* Enable all clocks before accessing any registers. */
275060ad6a1fSSepherosa Ziehau 	CSR_PCI_WRITE_4(sc, PCI_OUR_REG_3, 0);
27512d586421SSepherosa Ziehau 	mskc_reset(sc);
27522d586421SSepherosa Ziehau 	for (i = 0; i < sc->msk_num_port; i++) {
27532d586421SSepherosa Ziehau 		if (sc->msk_if[i] != NULL && sc->msk_if[i]->msk_ifp != NULL &&
27542d586421SSepherosa Ziehau 		    ((sc->msk_if[i]->msk_ifp->if_flags & IFF_UP) != 0))
27552d586421SSepherosa Ziehau 			msk_init(sc->msk_if[i]);
27562d586421SSepherosa Ziehau 	}
27572d586421SSepherosa Ziehau 	sc->msk_suspended = 0;
27582d586421SSepherosa Ziehau 
27592d586421SSepherosa Ziehau 	lwkt_serialize_exit(&sc->msk_serializer);
27602d586421SSepherosa Ziehau 
27612d586421SSepherosa Ziehau 	return (0);
27622d586421SSepherosa Ziehau }
27632d586421SSepherosa Ziehau 
27642d586421SSepherosa Ziehau static void
msk_rxeof(struct msk_if_softc * sc_if,uint32_t status,int len)2765eda7db08SSepherosa Ziehau msk_rxeof(struct msk_if_softc *sc_if, uint32_t status, int len)
27662d586421SSepherosa Ziehau {
27672d586421SSepherosa Ziehau 	struct mbuf *m;
27682d586421SSepherosa Ziehau 	struct ifnet *ifp;
27692d586421SSepherosa Ziehau 	struct msk_rxdesc *rxd;
27702d586421SSepherosa Ziehau 	int cons, rxlen;
27712d586421SSepherosa Ziehau 
27722d586421SSepherosa Ziehau 	ifp = sc_if->msk_ifp;
27732d586421SSepherosa Ziehau 
27742d586421SSepherosa Ziehau 	cons = sc_if->msk_cdata.msk_rx_cons;
27752d586421SSepherosa Ziehau 	do {
27762d586421SSepherosa Ziehau 		rxlen = status >> 16;
27772d586421SSepherosa Ziehau 		if ((status & GMR_FS_VLAN) != 0 &&
27782d586421SSepherosa Ziehau 		    (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0)
27792d586421SSepherosa Ziehau 			rxlen -= EVL_ENCAPLEN;
2780080bd27eSSepherosa Ziehau 		if (sc_if->msk_flags & MSK_FLAG_NORXCHK) {
2781080bd27eSSepherosa Ziehau 			/*
2782080bd27eSSepherosa Ziehau 			 * For controllers that returns bogus status code
2783080bd27eSSepherosa Ziehau 			 * just do minimal check and let upper stack
2784080bd27eSSepherosa Ziehau 			 * handle this frame.
2785080bd27eSSepherosa Ziehau 			 */
2786080bd27eSSepherosa Ziehau 			if (len > MSK_MAX_FRAMELEN || len < ETHER_HDR_LEN) {
2787d40991efSSepherosa Ziehau 				IFNET_STAT_INC(ifp, ierrors, 1);
2788080bd27eSSepherosa Ziehau 				msk_discard_rxbuf(sc_if, cons);
2789080bd27eSSepherosa Ziehau 				break;
2790080bd27eSSepherosa Ziehau 			}
2791080bd27eSSepherosa Ziehau 		} else if (len > sc_if->msk_framesize ||
27922d586421SSepherosa Ziehau 		    ((status & GMR_FS_ANY_ERR) != 0) ||
27932d586421SSepherosa Ziehau 		    ((status & GMR_FS_RX_OK) == 0) || (rxlen != len)) {
27942d586421SSepherosa Ziehau 			/* Don't count flow-control packet as errors. */
27952d586421SSepherosa Ziehau 			if ((status & GMR_FS_GOOD_FC) == 0)
2796d40991efSSepherosa Ziehau 				IFNET_STAT_INC(ifp, ierrors, 1);
27972d586421SSepherosa Ziehau 			msk_discard_rxbuf(sc_if, cons);
27982d586421SSepherosa Ziehau 			break;
27992d586421SSepherosa Ziehau 		}
28002d586421SSepherosa Ziehau 		rxd = &sc_if->msk_cdata.msk_rxdesc[cons];
28012d586421SSepherosa Ziehau 		m = rxd->rx_m;
28022499c577SSepherosa Ziehau 		if (msk_newbuf(sc_if, cons, 0) != 0) {
2803d40991efSSepherosa Ziehau 			IFNET_STAT_INC(ifp, iqdrops, 1);
28042d586421SSepherosa Ziehau 			/* Reuse old buffer. */
28052d586421SSepherosa Ziehau 			msk_discard_rxbuf(sc_if, cons);
28062d586421SSepherosa Ziehau 			break;
28072d586421SSepherosa Ziehau 		}
28082d586421SSepherosa Ziehau 		m->m_pkthdr.rcvif = ifp;
28092d586421SSepherosa Ziehau 		m->m_pkthdr.len = m->m_len = len;
2810d40991efSSepherosa Ziehau 		IFNET_STAT_INC(ifp, ipackets, 1);
28112d586421SSepherosa Ziehau #ifdef notyet
28122d586421SSepherosa Ziehau 		/* Check for VLAN tagged packets. */
28132d586421SSepherosa Ziehau 		if ((status & GMR_FS_VLAN) != 0 &&
28142d586421SSepherosa Ziehau 		    (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) {
28152d586421SSepherosa Ziehau 			m->m_pkthdr.ether_vtag = sc_if->msk_vtag;
28162d586421SSepherosa Ziehau 			m->m_flags |= M_VLANTAG;
28172d586421SSepherosa Ziehau 		}
28182d586421SSepherosa Ziehau #endif
28190ae155c2SSepherosa Ziehau 
282073029d08SFranco Fichtner 		ifp->if_input(ifp, m, NULL, -1);
28212d586421SSepherosa Ziehau 	} while (0);
28222d586421SSepherosa Ziehau 
28232d586421SSepherosa Ziehau 	MSK_INC(sc_if->msk_cdata.msk_rx_cons, MSK_RX_RING_CNT);
28242d586421SSepherosa Ziehau 	MSK_INC(sc_if->msk_cdata.msk_rx_prod, MSK_RX_RING_CNT);
28252d586421SSepherosa Ziehau }
28262d586421SSepherosa Ziehau 
28272d586421SSepherosa Ziehau #ifdef MSK_JUMBO
28282d586421SSepherosa Ziehau static void
msk_jumbo_rxeof(struct msk_if_softc * sc_if,uint32_t status,int len)28292d586421SSepherosa Ziehau msk_jumbo_rxeof(struct msk_if_softc *sc_if, uint32_t status, int len)
28302d586421SSepherosa Ziehau {
28312d586421SSepherosa Ziehau 	struct mbuf *m;
28322d586421SSepherosa Ziehau 	struct ifnet *ifp;
28332d586421SSepherosa Ziehau 	struct msk_rxdesc *jrxd;
28342d586421SSepherosa Ziehau 	int cons, rxlen;
28352d586421SSepherosa Ziehau 
28362d586421SSepherosa Ziehau 	ifp = sc_if->msk_ifp;
28372d586421SSepherosa Ziehau 
28382d586421SSepherosa Ziehau 	MSK_IF_LOCK_ASSERT(sc_if);
28392d586421SSepherosa Ziehau 
28402d586421SSepherosa Ziehau 	cons = sc_if->msk_cdata.msk_rx_cons;
28412d586421SSepherosa Ziehau 	do {
28422d586421SSepherosa Ziehau 		rxlen = status >> 16;
28432d586421SSepherosa Ziehau 		if ((status & GMR_FS_VLAN) != 0 &&
28442d586421SSepherosa Ziehau 		    (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0)
28452d586421SSepherosa Ziehau 			rxlen -= ETHER_VLAN_ENCAP_LEN;
28462d586421SSepherosa Ziehau 		if (len > sc_if->msk_framesize ||
28472d586421SSepherosa Ziehau 		    ((status & GMR_FS_ANY_ERR) != 0) ||
28482d586421SSepherosa Ziehau 		    ((status & GMR_FS_RX_OK) == 0) || (rxlen != len)) {
28492d586421SSepherosa Ziehau 			/* Don't count flow-control packet as errors. */
28502d586421SSepherosa Ziehau 			if ((status & GMR_FS_GOOD_FC) == 0)
28512d586421SSepherosa Ziehau 				ifp->if_ierrors++;
28522d586421SSepherosa Ziehau 			msk_discard_jumbo_rxbuf(sc_if, cons);
28532d586421SSepherosa Ziehau 			break;
28542d586421SSepherosa Ziehau 		}
28552d586421SSepherosa Ziehau 		jrxd = &sc_if->msk_cdata.msk_jumbo_rxdesc[cons];
28562d586421SSepherosa Ziehau 		m = jrxd->rx_m;
28572d586421SSepherosa Ziehau 		if (msk_jumbo_newbuf(sc_if, cons) != 0) {
28582d586421SSepherosa Ziehau 			ifp->if_iqdrops++;
28592d586421SSepherosa Ziehau 			/* Reuse old buffer. */
28602d586421SSepherosa Ziehau 			msk_discard_jumbo_rxbuf(sc_if, cons);
28612d586421SSepherosa Ziehau 			break;
28622d586421SSepherosa Ziehau 		}
28632d586421SSepherosa Ziehau 		m->m_pkthdr.rcvif = ifp;
28642d586421SSepherosa Ziehau 		m->m_pkthdr.len = m->m_len = len;
28652d586421SSepherosa Ziehau 		ifp->if_ipackets++;
28662d586421SSepherosa Ziehau 		/* Check for VLAN tagged packets. */
28672d586421SSepherosa Ziehau 		if ((status & GMR_FS_VLAN) != 0 &&
28682d586421SSepherosa Ziehau 		    (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) {
28692d586421SSepherosa Ziehau 			m->m_pkthdr.ether_vtag = sc_if->msk_vtag;
28702d586421SSepherosa Ziehau 			m->m_flags |= M_VLANTAG;
28712d586421SSepherosa Ziehau 		}
28722d586421SSepherosa Ziehau 		MSK_IF_UNLOCK(sc_if);
287373029d08SFranco Fichtner 		ifp->if_input(ifp, m, NULL, -1);
28742d586421SSepherosa Ziehau 		MSK_IF_LOCK(sc_if);
28752d586421SSepherosa Ziehau 	} while (0);
28762d586421SSepherosa Ziehau 
28772d586421SSepherosa Ziehau 	MSK_INC(sc_if->msk_cdata.msk_rx_cons, MSK_JUMBO_RX_RING_CNT);
28782d586421SSepherosa Ziehau 	MSK_INC(sc_if->msk_cdata.msk_rx_prod, MSK_JUMBO_RX_RING_CNT);
28792d586421SSepherosa Ziehau }
28802d586421SSepherosa Ziehau #endif
28812d586421SSepherosa Ziehau 
28822d586421SSepherosa Ziehau static void
msk_txeof(struct msk_if_softc * sc_if,int idx)28832d586421SSepherosa Ziehau msk_txeof(struct msk_if_softc *sc_if, int idx)
28842d586421SSepherosa Ziehau {
28852d586421SSepherosa Ziehau 	struct msk_txdesc *txd;
28862d586421SSepherosa Ziehau 	struct msk_tx_desc *cur_tx;
28872d586421SSepherosa Ziehau 	struct ifnet *ifp;
28882d586421SSepherosa Ziehau 	uint32_t control;
28892d586421SSepherosa Ziehau 	int cons, prog;
28902d586421SSepherosa Ziehau 
28912d586421SSepherosa Ziehau 	ifp = sc_if->msk_ifp;
28922d586421SSepherosa Ziehau 
28932d586421SSepherosa Ziehau 	/*
28942d586421SSepherosa Ziehau 	 * Go through our tx ring and free mbufs for those
28952d586421SSepherosa Ziehau 	 * frames that have been sent.
28962d586421SSepherosa Ziehau 	 */
28972d586421SSepherosa Ziehau 	cons = sc_if->msk_cdata.msk_tx_cons;
28982d586421SSepherosa Ziehau 	prog = 0;
28992d586421SSepherosa Ziehau 	for (; cons != idx; MSK_INC(cons, MSK_TX_RING_CNT)) {
29002d586421SSepherosa Ziehau 		if (sc_if->msk_cdata.msk_tx_cnt <= 0)
29012d586421SSepherosa Ziehau 			break;
29022d586421SSepherosa Ziehau 		prog++;
29032d586421SSepherosa Ziehau 		cur_tx = &sc_if->msk_rdata.msk_tx_ring[cons];
29042d586421SSepherosa Ziehau 		control = le32toh(cur_tx->msk_control);
29052d586421SSepherosa Ziehau 		sc_if->msk_cdata.msk_tx_cnt--;
29062d586421SSepherosa Ziehau 		if ((control & EOP) == 0)
29072d586421SSepherosa Ziehau 			continue;
29082d586421SSepherosa Ziehau 		txd = &sc_if->msk_cdata.msk_txdesc[cons];
29092d586421SSepherosa Ziehau 		bus_dmamap_unload(sc_if->msk_cdata.msk_tx_tag, txd->tx_dmamap);
29102d586421SSepherosa Ziehau 
2911d40991efSSepherosa Ziehau 		IFNET_STAT_INC(ifp, opackets, 1);
29122d586421SSepherosa Ziehau 		KASSERT(txd->tx_m != NULL, ("%s: freeing NULL mbuf!",
29132d586421SSepherosa Ziehau 		    __func__));
29142d586421SSepherosa Ziehau 		m_freem(txd->tx_m);
29152d586421SSepherosa Ziehau 		txd->tx_m = NULL;
29162d586421SSepherosa Ziehau 	}
29172d586421SSepherosa Ziehau 
29182d586421SSepherosa Ziehau 	if (prog > 0) {
29192d586421SSepherosa Ziehau 		sc_if->msk_cdata.msk_tx_cons = cons;
2920def0e148SSepherosa Ziehau 		if (!MSK_IS_OACTIVE(sc_if))
29219ed293e0SSepherosa Ziehau 			ifq_clr_oactive(&ifp->if_snd);
29222d586421SSepherosa Ziehau 		if (sc_if->msk_cdata.msk_tx_cnt == 0)
29232d586421SSepherosa Ziehau 			ifp->if_timer = 0;
29242d586421SSepherosa Ziehau 		/* No need to sync LEs as we didn't update LEs. */
29252d586421SSepherosa Ziehau 	}
29262d586421SSepherosa Ziehau }
29272d586421SSepherosa Ziehau 
29282d586421SSepherosa Ziehau static void
msk_tick(void * xsc_if)29292d586421SSepherosa Ziehau msk_tick(void *xsc_if)
29302d586421SSepherosa Ziehau {
29312d586421SSepherosa Ziehau 	struct msk_if_softc *sc_if = xsc_if;
29322d586421SSepherosa Ziehau 	struct ifnet *ifp = &sc_if->arpcom.ac_if;
29332d586421SSepherosa Ziehau 	struct mii_data *mii;
29342d586421SSepherosa Ziehau 
29352d586421SSepherosa Ziehau 	lwkt_serialize_enter(ifp->if_serializer);
29362d586421SSepherosa Ziehau 
29372d586421SSepherosa Ziehau 	mii = device_get_softc(sc_if->msk_miibus);
29382d586421SSepherosa Ziehau 
29392d586421SSepherosa Ziehau 	mii_tick(mii);
2940cd237572SSepherosa Ziehau 	if (!sc_if->msk_link)
2941cd237572SSepherosa Ziehau 		msk_miibus_statchg(sc_if->msk_if_dev);
29422d586421SSepherosa Ziehau 	callout_reset(&sc_if->msk_tick_ch, hz, msk_tick, sc_if);
29432d586421SSepherosa Ziehau 
29442d586421SSepherosa Ziehau 	lwkt_serialize_exit(ifp->if_serializer);
29452d586421SSepherosa Ziehau }
29462d586421SSepherosa Ziehau 
29472d586421SSepherosa Ziehau static void
msk_intr_phy(struct msk_if_softc * sc_if)29482d586421SSepherosa Ziehau msk_intr_phy(struct msk_if_softc *sc_if)
29492d586421SSepherosa Ziehau {
29502d586421SSepherosa Ziehau 	uint16_t status;
29512d586421SSepherosa Ziehau 
29522d586421SSepherosa Ziehau 	msk_phy_readreg(sc_if, PHY_ADDR_MARV, PHY_MARV_INT_STAT);
29532d586421SSepherosa Ziehau 	status = msk_phy_readreg(sc_if, PHY_ADDR_MARV, PHY_MARV_INT_STAT);
29542d586421SSepherosa Ziehau 	/* Handle FIFO Underrun/Overflow? */
29552d586421SSepherosa Ziehau 	if (status & PHY_M_IS_FIFO_ERROR) {
29562d586421SSepherosa Ziehau 		device_printf(sc_if->msk_if_dev,
29572d586421SSepherosa Ziehau 		    "PHY FIFO underrun/overflow.\n");
29582d586421SSepherosa Ziehau 	}
29592d586421SSepherosa Ziehau }
29602d586421SSepherosa Ziehau 
29612d586421SSepherosa Ziehau static void
msk_intr_gmac(struct msk_if_softc * sc_if)29622d586421SSepherosa Ziehau msk_intr_gmac(struct msk_if_softc *sc_if)
29632d586421SSepherosa Ziehau {
29642d586421SSepherosa Ziehau 	struct msk_softc *sc;
29652d586421SSepherosa Ziehau 	uint8_t status;
29662d586421SSepherosa Ziehau 
29672d586421SSepherosa Ziehau 	sc = sc_if->msk_softc;
29682d586421SSepherosa Ziehau 	status = CSR_READ_1(sc, MR_ADDR(sc_if->msk_port, GMAC_IRQ_SRC));
29692d586421SSepherosa Ziehau 
29702d586421SSepherosa Ziehau 	/* GMAC Rx FIFO overrun. */
29712d586421SSepherosa Ziehau 	if ((status & GM_IS_RX_FF_OR) != 0) {
29722d586421SSepherosa Ziehau 		CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, RX_GMF_CTRL_T),
29732d586421SSepherosa Ziehau 		    GMF_CLI_RX_FO);
29742d586421SSepherosa Ziehau 	}
29752d586421SSepherosa Ziehau 	/* GMAC Tx FIFO underrun. */
29762d586421SSepherosa Ziehau 	if ((status & GM_IS_TX_FF_UR) != 0) {
29772d586421SSepherosa Ziehau 		CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, TX_GMF_CTRL_T),
29782d586421SSepherosa Ziehau 		    GMF_CLI_TX_FU);
29792d586421SSepherosa Ziehau 		device_printf(sc_if->msk_if_dev, "Tx FIFO underrun!\n");
29802d586421SSepherosa Ziehau 		/*
29812d586421SSepherosa Ziehau 		 * XXX
29822d586421SSepherosa Ziehau 		 * In case of Tx underrun, we may need to flush/reset
29832d586421SSepherosa Ziehau 		 * Tx MAC but that would also require resynchronization
29842d586421SSepherosa Ziehau 		 * with status LEs. Reintializing status LEs would
29852d586421SSepherosa Ziehau 		 * affect other port in dual MAC configuration so it
29862d586421SSepherosa Ziehau 		 * should be avoided as possible as we can.
29872d586421SSepherosa Ziehau 		 * Due to lack of documentation it's all vague guess but
29882d586421SSepherosa Ziehau 		 * it needs more investigation.
29892d586421SSepherosa Ziehau 		 */
29902d586421SSepherosa Ziehau 	}
29912d586421SSepherosa Ziehau }
29922d586421SSepherosa Ziehau 
29932d586421SSepherosa Ziehau static void
msk_handle_hwerr(struct msk_if_softc * sc_if,uint32_t status)29942d586421SSepherosa Ziehau msk_handle_hwerr(struct msk_if_softc *sc_if, uint32_t status)
29952d586421SSepherosa Ziehau {
29962d586421SSepherosa Ziehau 	struct msk_softc *sc;
29972d586421SSepherosa Ziehau 
29982d586421SSepherosa Ziehau 	sc = sc_if->msk_softc;
29992d586421SSepherosa Ziehau 	if ((status & Y2_IS_PAR_RD1) != 0) {
30002d586421SSepherosa Ziehau 		device_printf(sc_if->msk_if_dev,
30012d586421SSepherosa Ziehau 		    "RAM buffer read parity error\n");
30022d586421SSepherosa Ziehau 		/* Clear IRQ. */
30032d586421SSepherosa Ziehau 		CSR_WRITE_2(sc, SELECT_RAM_BUFFER(sc_if->msk_port, B3_RI_CTRL),
30042d586421SSepherosa Ziehau 		    RI_CLR_RD_PERR);
30052d586421SSepherosa Ziehau 	}
30062d586421SSepherosa Ziehau 	if ((status & Y2_IS_PAR_WR1) != 0) {
30072d586421SSepherosa Ziehau 		device_printf(sc_if->msk_if_dev,
30082d586421SSepherosa Ziehau 		    "RAM buffer write parity error\n");
30092d586421SSepherosa Ziehau 		/* Clear IRQ. */
30102d586421SSepherosa Ziehau 		CSR_WRITE_2(sc, SELECT_RAM_BUFFER(sc_if->msk_port, B3_RI_CTRL),
30112d586421SSepherosa Ziehau 		    RI_CLR_WR_PERR);
30122d586421SSepherosa Ziehau 	}
30132d586421SSepherosa Ziehau 	if ((status & Y2_IS_PAR_MAC1) != 0) {
30142d586421SSepherosa Ziehau 		device_printf(sc_if->msk_if_dev, "Tx MAC parity error\n");
30152d586421SSepherosa Ziehau 		/* Clear IRQ. */
30162d586421SSepherosa Ziehau 		CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, TX_GMF_CTRL_T),
30172d586421SSepherosa Ziehau 		    GMF_CLI_TX_PE);
30182d586421SSepherosa Ziehau 	}
30192d586421SSepherosa Ziehau 	if ((status & Y2_IS_PAR_RX1) != 0) {
30202d586421SSepherosa Ziehau 		device_printf(sc_if->msk_if_dev, "Rx parity error\n");
30212d586421SSepherosa Ziehau 		/* Clear IRQ. */
30222d586421SSepherosa Ziehau 		CSR_WRITE_4(sc, Q_ADDR(sc_if->msk_rxq, Q_CSR), BMU_CLR_IRQ_PAR);
30232d586421SSepherosa Ziehau 	}
30242d586421SSepherosa Ziehau 	if ((status & (Y2_IS_TCP_TXS1 | Y2_IS_TCP_TXA1)) != 0) {
30252d586421SSepherosa Ziehau 		device_printf(sc_if->msk_if_dev, "TCP segmentation error\n");
30262d586421SSepherosa Ziehau 		/* Clear IRQ. */
30272d586421SSepherosa Ziehau 		CSR_WRITE_4(sc, Q_ADDR(sc_if->msk_txq, Q_CSR), BMU_CLR_IRQ_TCP);
30282d586421SSepherosa Ziehau 	}
30292d586421SSepherosa Ziehau }
30302d586421SSepherosa Ziehau 
30312d586421SSepherosa Ziehau static void
mskc_intr_hwerr(struct msk_softc * sc)30322d586421SSepherosa Ziehau mskc_intr_hwerr(struct msk_softc *sc)
30332d586421SSepherosa Ziehau {
30342d586421SSepherosa Ziehau 	uint32_t status;
30352d586421SSepherosa Ziehau 	uint32_t tlphead[4];
30362d586421SSepherosa Ziehau 
30372d586421SSepherosa Ziehau 	status = CSR_READ_4(sc, B0_HWE_ISRC);
30382d586421SSepherosa Ziehau 	/* Time Stamp timer overflow. */
30392d586421SSepherosa Ziehau 	if ((status & Y2_IS_TIST_OV) != 0)
30402d586421SSepherosa Ziehau 		CSR_WRITE_1(sc, GMAC_TI_ST_CTRL, GMT_ST_CLR_IRQ);
30412d586421SSepherosa Ziehau 	if ((status & Y2_IS_PCI_NEXP) != 0) {
30422d586421SSepherosa Ziehau 		/*
30432d586421SSepherosa Ziehau 		 * PCI Express Error occured which is not described in PEX
30442d586421SSepherosa Ziehau 		 * spec.
30452d586421SSepherosa Ziehau 		 * This error is also mapped either to Master Abort(
30462d586421SSepherosa Ziehau 		 * Y2_IS_MST_ERR) or Target Abort (Y2_IS_IRQ_STAT) bit and
30472d586421SSepherosa Ziehau 		 * can only be cleared there.
30482d586421SSepherosa Ziehau                  */
30492d586421SSepherosa Ziehau 		device_printf(sc->msk_dev,
30502d586421SSepherosa Ziehau 		    "PCI Express protocol violation error\n");
30512d586421SSepherosa Ziehau 	}
30522d586421SSepherosa Ziehau 
30532d586421SSepherosa Ziehau 	if ((status & (Y2_IS_MST_ERR | Y2_IS_IRQ_STAT)) != 0) {
30542d586421SSepherosa Ziehau 		uint16_t v16;
30552d586421SSepherosa Ziehau 
30562d586421SSepherosa Ziehau 		if ((status & Y2_IS_MST_ERR) != 0)
30572d586421SSepherosa Ziehau 			device_printf(sc->msk_dev,
30582d586421SSepherosa Ziehau 			    "unexpected IRQ Status error\n");
30592d586421SSepherosa Ziehau 		else
30602d586421SSepherosa Ziehau 			device_printf(sc->msk_dev,
30612d586421SSepherosa Ziehau 			    "unexpected IRQ Master error\n");
30622d586421SSepherosa Ziehau 		/* Reset all bits in the PCI status register. */
30632d586421SSepherosa Ziehau 		v16 = pci_read_config(sc->msk_dev, PCIR_STATUS, 2);
30642d586421SSepherosa Ziehau 		CSR_WRITE_1(sc, B2_TST_CTRL1, TST_CFG_WRITE_ON);
30652d586421SSepherosa Ziehau 		pci_write_config(sc->msk_dev, PCIR_STATUS, v16 |
30662d586421SSepherosa Ziehau 		    PCIM_STATUS_PERR | PCIM_STATUS_SERR | PCIM_STATUS_RMABORT |
30672d586421SSepherosa Ziehau 		    PCIM_STATUS_RTABORT | PCIM_STATUS_PERRREPORT, 2);
30682d586421SSepherosa Ziehau 		CSR_WRITE_1(sc, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
30692d586421SSepherosa Ziehau 	}
30702d586421SSepherosa Ziehau 
30712d586421SSepherosa Ziehau 	/* Check for PCI Express Uncorrectable Error. */
30722d586421SSepherosa Ziehau 	if ((status & Y2_IS_PCI_EXP) != 0) {
30732d586421SSepherosa Ziehau 		uint32_t v32;
30742d586421SSepherosa Ziehau 
30752d586421SSepherosa Ziehau 		/*
30762d586421SSepherosa Ziehau 		 * On PCI Express bus bridges are called root complexes (RC).
30772d586421SSepherosa Ziehau 		 * PCI Express errors are recognized by the root complex too,
30782d586421SSepherosa Ziehau 		 * which requests the system to handle the problem. After
30792d586421SSepherosa Ziehau 		 * error occurence it may be that no access to the adapter
30802d586421SSepherosa Ziehau 		 * may be performed any longer.
30812d586421SSepherosa Ziehau 		 */
30822d586421SSepherosa Ziehau 
30832d586421SSepherosa Ziehau 		v32 = CSR_PCI_READ_4(sc, PEX_UNC_ERR_STAT);
30842d586421SSepherosa Ziehau 		if ((v32 & PEX_UNSUP_REQ) != 0) {
30852d586421SSepherosa Ziehau 			/* Ignore unsupported request error. */
30862d586421SSepherosa Ziehau 			if (bootverbose) {
30872d586421SSepherosa Ziehau 				device_printf(sc->msk_dev,
30882d586421SSepherosa Ziehau 				    "Uncorrectable PCI Express error\n");
30892d586421SSepherosa Ziehau 			}
30902d586421SSepherosa Ziehau 		}
30912d586421SSepherosa Ziehau 		if ((v32 & (PEX_FATAL_ERRORS | PEX_POIS_TLP)) != 0) {
30922d586421SSepherosa Ziehau 			int i;
30932d586421SSepherosa Ziehau 
30942d586421SSepherosa Ziehau 			/* Get TLP header form Log Registers. */
30952d586421SSepherosa Ziehau 			for (i = 0; i < 4; i++)
30962d586421SSepherosa Ziehau 				tlphead[i] = CSR_PCI_READ_4(sc,
30972d586421SSepherosa Ziehau 				    PEX_HEADER_LOG + i * 4);
30982d586421SSepherosa Ziehau 			/* Check for vendor defined broadcast message. */
30992d586421SSepherosa Ziehau 			if (!(tlphead[0] == 0x73004001 && tlphead[1] == 0x7f)) {
31002d586421SSepherosa Ziehau 				sc->msk_intrhwemask &= ~Y2_IS_PCI_EXP;
31012d586421SSepherosa Ziehau 				CSR_WRITE_4(sc, B0_HWE_IMSK,
31022d586421SSepherosa Ziehau 				    sc->msk_intrhwemask);
31032d586421SSepherosa Ziehau 				CSR_READ_4(sc, B0_HWE_IMSK);
31042d586421SSepherosa Ziehau 			}
31052d586421SSepherosa Ziehau 		}
31062d586421SSepherosa Ziehau 		/* Clear the interrupt. */
31072d586421SSepherosa Ziehau 		CSR_WRITE_1(sc, B2_TST_CTRL1, TST_CFG_WRITE_ON);
31082d586421SSepherosa Ziehau 		CSR_PCI_WRITE_4(sc, PEX_UNC_ERR_STAT, 0xffffffff);
31092d586421SSepherosa Ziehau 		CSR_WRITE_1(sc, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
31102d586421SSepherosa Ziehau 	}
31112d586421SSepherosa Ziehau 
31122d586421SSepherosa Ziehau 	if ((status & Y2_HWE_L1_MASK) != 0 && sc->msk_if[MSK_PORT_A] != NULL)
31132d586421SSepherosa Ziehau 		msk_handle_hwerr(sc->msk_if[MSK_PORT_A], status);
31142d586421SSepherosa Ziehau 	if ((status & Y2_HWE_L2_MASK) != 0 && sc->msk_if[MSK_PORT_B] != NULL)
31152d586421SSepherosa Ziehau 		msk_handle_hwerr(sc->msk_if[MSK_PORT_B], status >> 8);
31162d586421SSepherosa Ziehau }
31172d586421SSepherosa Ziehau 
31182d586421SSepherosa Ziehau static __inline void
msk_rxput(struct msk_if_softc * sc_if)31192d586421SSepherosa Ziehau msk_rxput(struct msk_if_softc *sc_if)
31202d586421SSepherosa Ziehau {
31212d586421SSepherosa Ziehau 	struct msk_softc *sc;
31222d586421SSepherosa Ziehau 
31232d586421SSepherosa Ziehau 	sc = sc_if->msk_softc;
31242d586421SSepherosa Ziehau #ifdef MSK_JUMBO
31252d586421SSepherosa Ziehau 	if (sc_if->msk_framesize > (MCLBYTES - ETHER_HDR_LEN)) {
31262d586421SSepherosa Ziehau 		bus_dmamap_sync(
31272d586421SSepherosa Ziehau 		    sc_if->msk_cdata.msk_jumbo_rx_ring_tag,
31282d586421SSepherosa Ziehau 		    sc_if->msk_cdata.msk_jumbo_rx_ring_map,
31292d586421SSepherosa Ziehau 		    BUS_DMASYNC_PREWRITE);
31302d586421SSepherosa Ziehau 	}
3131c78f83cbSSepherosa Ziehau #endif
31322d586421SSepherosa Ziehau 	CSR_WRITE_2(sc, Y2_PREF_Q_ADDR(sc_if->msk_rxq,
31332d586421SSepherosa Ziehau 	    PREF_UNIT_PUT_IDX_REG), sc_if->msk_cdata.msk_rx_prod);
31342d586421SSepherosa Ziehau }
31352d586421SSepherosa Ziehau 
31362d586421SSepherosa Ziehau static int
mskc_handle_events(struct msk_softc * sc)31372d586421SSepherosa Ziehau mskc_handle_events(struct msk_softc *sc)
31382d586421SSepherosa Ziehau {
31392d586421SSepherosa Ziehau 	struct msk_if_softc *sc_if;
31402d586421SSepherosa Ziehau 	int rxput[2];
31412d586421SSepherosa Ziehau 	struct msk_stat_desc *sd;
31422d586421SSepherosa Ziehau 	uint32_t control, status;
31432d586421SSepherosa Ziehau 	int cons, idx, len, port, rxprog;
31442d586421SSepherosa Ziehau 
31452d586421SSepherosa Ziehau 	idx = CSR_READ_2(sc, STAT_PUT_IDX);
31462d586421SSepherosa Ziehau 	if (idx == sc->msk_stat_cons)
31472d586421SSepherosa Ziehau 		return (0);
31482d586421SSepherosa Ziehau 
31492d586421SSepherosa Ziehau 	rxput[MSK_PORT_A] = rxput[MSK_PORT_B] = 0;
31502d586421SSepherosa Ziehau 
31512d586421SSepherosa Ziehau 	rxprog = 0;
31522d586421SSepherosa Ziehau 	for (cons = sc->msk_stat_cons; cons != idx;) {
31532d586421SSepherosa Ziehau 		sd = &sc->msk_stat_ring[cons];
31542d586421SSepherosa Ziehau 		control = le32toh(sd->msk_control);
31552d586421SSepherosa Ziehau 		if ((control & HW_OWNER) == 0)
31562d586421SSepherosa Ziehau 			break;
31572d586421SSepherosa Ziehau 		/*
31582d586421SSepherosa Ziehau 		 * Marvell's FreeBSD driver updates status LE after clearing
31592d586421SSepherosa Ziehau 		 * HW_OWNER. However we don't have a way to sync single LE
31602d586421SSepherosa Ziehau 		 * with bus_dma(9) API. bus_dma(9) provides a way to sync
31612d586421SSepherosa Ziehau 		 * an entire DMA map. So don't sync LE until we have a better
31622d586421SSepherosa Ziehau 		 * way to sync LEs.
31632d586421SSepherosa Ziehau 		 */
31642d586421SSepherosa Ziehau 		control &= ~HW_OWNER;
31652d586421SSepherosa Ziehau 		sd->msk_control = htole32(control);
31662d586421SSepherosa Ziehau 		status = le32toh(sd->msk_status);
31672d586421SSepherosa Ziehau 		len = control & STLE_LEN_MASK;
31682d586421SSepherosa Ziehau 		port = (control >> 16) & 0x01;
31692d586421SSepherosa Ziehau 		sc_if = sc->msk_if[port];
31702d586421SSepherosa Ziehau 		if (sc_if == NULL) {
31712d586421SSepherosa Ziehau 			device_printf(sc->msk_dev, "invalid port opcode "
31722d586421SSepherosa Ziehau 			    "0x%08x\n", control & STLE_OP_MASK);
31732d586421SSepherosa Ziehau 			continue;
31742d586421SSepherosa Ziehau 		}
31752d586421SSepherosa Ziehau 
31762d586421SSepherosa Ziehau 		switch (control & STLE_OP_MASK) {
31772d586421SSepherosa Ziehau 		case OP_RXVLAN:
31782d586421SSepherosa Ziehau 			sc_if->msk_vtag = ntohs(len);
31792d586421SSepherosa Ziehau 			break;
31802d586421SSepherosa Ziehau 		case OP_RXCHKSVLAN:
31812d586421SSepherosa Ziehau 			sc_if->msk_vtag = ntohs(len);
31822d586421SSepherosa Ziehau 			break;
31832d586421SSepherosa Ziehau 		case OP_RXSTAT:
3184f308b0acSSepherosa Ziehau 			if ((sc_if->msk_ifp->if_flags & IFF_RUNNING) == 0)
3185f308b0acSSepherosa Ziehau 				break;
31862d586421SSepherosa Ziehau #ifdef MSK_JUMBO
31872d586421SSepherosa Ziehau 			if (sc_if->msk_framesize > (MCLBYTES - ETHER_HDR_LEN))
31882d586421SSepherosa Ziehau 				msk_jumbo_rxeof(sc_if, status, len);
31892d586421SSepherosa Ziehau 			else
31902d586421SSepherosa Ziehau #endif
3191eda7db08SSepherosa Ziehau 				msk_rxeof(sc_if, status, len);
31922d586421SSepherosa Ziehau 			rxprog++;
31932d586421SSepherosa Ziehau 			/*
31942d586421SSepherosa Ziehau 			 * Because there is no way to sync single Rx LE
31952d586421SSepherosa Ziehau 			 * put the DMA sync operation off until the end of
31962d586421SSepherosa Ziehau 			 * event processing.
31972d586421SSepherosa Ziehau 			 */
31982d586421SSepherosa Ziehau 			rxput[port]++;
31992d586421SSepherosa Ziehau 			/* Update prefetch unit if we've passed water mark. */
32002d586421SSepherosa Ziehau 			if (rxput[port] >= sc_if->msk_cdata.msk_rx_putwm) {
32012d586421SSepherosa Ziehau 				msk_rxput(sc_if);
32022d586421SSepherosa Ziehau 				rxput[port] = 0;
32032d586421SSepherosa Ziehau 			}
32042d586421SSepherosa Ziehau 			break;
32052d586421SSepherosa Ziehau 		case OP_TXINDEXLE:
32062d586421SSepherosa Ziehau 			if (sc->msk_if[MSK_PORT_A] != NULL) {
32072d586421SSepherosa Ziehau 				msk_txeof(sc->msk_if[MSK_PORT_A],
32082d586421SSepherosa Ziehau 				    status & STLE_TXA1_MSKL);
32092d586421SSepherosa Ziehau 			}
32102d586421SSepherosa Ziehau 			if (sc->msk_if[MSK_PORT_B] != NULL) {
32112d586421SSepherosa Ziehau 				msk_txeof(sc->msk_if[MSK_PORT_B],
32122d586421SSepherosa Ziehau 				    ((status & STLE_TXA2_MSKL) >>
32132d586421SSepherosa Ziehau 				    STLE_TXA2_SHIFTL) |
32142d586421SSepherosa Ziehau 				    ((len & STLE_TXA2_MSKH) <<
32152d586421SSepherosa Ziehau 				    STLE_TXA2_SHIFTH));
32162d586421SSepherosa Ziehau 			}
32172d586421SSepherosa Ziehau 			break;
32182d586421SSepherosa Ziehau 		default:
32192d586421SSepherosa Ziehau 			device_printf(sc->msk_dev, "unhandled opcode 0x%08x\n",
32202d586421SSepherosa Ziehau 			    control & STLE_OP_MASK);
32212d586421SSepherosa Ziehau 			break;
32222d586421SSepherosa Ziehau 		}
32232d586421SSepherosa Ziehau 		MSK_INC(cons, MSK_STAT_RING_CNT);
32242d586421SSepherosa Ziehau 		if (rxprog > sc->msk_process_limit)
32252d586421SSepherosa Ziehau 			break;
32262d586421SSepherosa Ziehau 	}
32272d586421SSepherosa Ziehau 
32282d586421SSepherosa Ziehau 	sc->msk_stat_cons = cons;
32292d586421SSepherosa Ziehau 	/* XXX We should sync status LEs here. See above notes. */
32302d586421SSepherosa Ziehau 
32312d586421SSepherosa Ziehau 	if (rxput[MSK_PORT_A] > 0)
32322d586421SSepherosa Ziehau 		msk_rxput(sc->msk_if[MSK_PORT_A]);
32332d586421SSepherosa Ziehau 	if (rxput[MSK_PORT_B] > 0)
32342d586421SSepherosa Ziehau 		msk_rxput(sc->msk_if[MSK_PORT_B]);
32352d586421SSepherosa Ziehau 
32362d586421SSepherosa Ziehau 	return (sc->msk_stat_cons != CSR_READ_2(sc, STAT_PUT_IDX));
32372d586421SSepherosa Ziehau }
32382d586421SSepherosa Ziehau 
32392d586421SSepherosa Ziehau /* Legacy interrupt handler for shared interrupt. */
32402d586421SSepherosa Ziehau static void
mskc_intr(void * xsc)32412d586421SSepherosa Ziehau mskc_intr(void *xsc)
32422d586421SSepherosa Ziehau {
32432d586421SSepherosa Ziehau 	struct msk_softc *sc;
32442d586421SSepherosa Ziehau 	struct msk_if_softc *sc_if0, *sc_if1;
32452d586421SSepherosa Ziehau 	struct ifnet *ifp0, *ifp1;
32462d586421SSepherosa Ziehau 	uint32_t status;
32472d586421SSepherosa Ziehau 
32482d586421SSepherosa Ziehau 	sc = xsc;
32492d586421SSepherosa Ziehau 	ASSERT_SERIALIZED(&sc->msk_serializer);
32502d586421SSepherosa Ziehau 
32512d586421SSepherosa Ziehau 	/* Reading B0_Y2_SP_ISRC2 masks further interrupts. */
32522d586421SSepherosa Ziehau 	status = CSR_READ_4(sc, B0_Y2_SP_ISRC2);
32532d586421SSepherosa Ziehau 	if (status == 0 || status == 0xffffffff || sc->msk_suspended != 0 ||
32542d586421SSepherosa Ziehau 	    (status & sc->msk_intrmask) == 0) {
32552d586421SSepherosa Ziehau 		CSR_WRITE_4(sc, B0_Y2_SP_ICR, 2);
32562d586421SSepherosa Ziehau 		return;
32572d586421SSepherosa Ziehau 	}
32582d586421SSepherosa Ziehau 
32592d586421SSepherosa Ziehau 	sc_if0 = sc->msk_if[MSK_PORT_A];
32602d586421SSepherosa Ziehau 	sc_if1 = sc->msk_if[MSK_PORT_B];
32612d586421SSepherosa Ziehau 	ifp0 = ifp1 = NULL;
32622d586421SSepherosa Ziehau 	if (sc_if0 != NULL)
32632d586421SSepherosa Ziehau 		ifp0 = sc_if0->msk_ifp;
32642d586421SSepherosa Ziehau 	if (sc_if1 != NULL)
32652d586421SSepherosa Ziehau 		ifp1 = sc_if1->msk_ifp;
32662d586421SSepherosa Ziehau 
32672d586421SSepherosa Ziehau 	if ((status & Y2_IS_IRQ_PHY1) != 0 && sc_if0 != NULL)
32682d586421SSepherosa Ziehau 		msk_intr_phy(sc_if0);
32692d586421SSepherosa Ziehau 	if ((status & Y2_IS_IRQ_PHY2) != 0 && sc_if1 != NULL)
32702d586421SSepherosa Ziehau 		msk_intr_phy(sc_if1);
32712d586421SSepherosa Ziehau 	if ((status & Y2_IS_IRQ_MAC1) != 0 && sc_if0 != NULL)
32722d586421SSepherosa Ziehau 		msk_intr_gmac(sc_if0);
32732d586421SSepherosa Ziehau 	if ((status & Y2_IS_IRQ_MAC2) != 0 && sc_if1 != NULL)
32742d586421SSepherosa Ziehau 		msk_intr_gmac(sc_if1);
32752d586421SSepherosa Ziehau 	if ((status & (Y2_IS_CHK_RX1 | Y2_IS_CHK_RX2)) != 0) {
32762d586421SSepherosa Ziehau 		device_printf(sc->msk_dev, "Rx descriptor error\n");
32772d586421SSepherosa Ziehau 		sc->msk_intrmask &= ~(Y2_IS_CHK_RX1 | Y2_IS_CHK_RX2);
32782d586421SSepherosa Ziehau 		CSR_WRITE_4(sc, B0_IMSK, sc->msk_intrmask);
32792d586421SSepherosa Ziehau 		CSR_READ_4(sc, B0_IMSK);
32802d586421SSepherosa Ziehau 	}
32812d586421SSepherosa Ziehau         if ((status & (Y2_IS_CHK_TXA1 | Y2_IS_CHK_TXA2)) != 0) {
32822d586421SSepherosa Ziehau 		device_printf(sc->msk_dev, "Tx descriptor error\n");
32832d586421SSepherosa Ziehau 		sc->msk_intrmask &= ~(Y2_IS_CHK_TXA1 | Y2_IS_CHK_TXA2);
32842d586421SSepherosa Ziehau 		CSR_WRITE_4(sc, B0_IMSK, sc->msk_intrmask);
32852d586421SSepherosa Ziehau 		CSR_READ_4(sc, B0_IMSK);
32862d586421SSepherosa Ziehau 	}
32872d586421SSepherosa Ziehau 	if ((status & Y2_IS_HW_ERR) != 0)
32882d586421SSepherosa Ziehau 		mskc_intr_hwerr(sc);
32892d586421SSepherosa Ziehau 
32902d586421SSepherosa Ziehau 	while (mskc_handle_events(sc) != 0)
32912d586421SSepherosa Ziehau 		;
32922d586421SSepherosa Ziehau 	if ((status & Y2_IS_STAT_BMU) != 0)
32932d586421SSepherosa Ziehau 		CSR_WRITE_4(sc, STAT_CTRL, SC_STAT_CLR_IRQ);
32942d586421SSepherosa Ziehau 
32952d586421SSepherosa Ziehau 	/* Reenable interrupts. */
32962d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, B0_Y2_SP_ICR, 2);
32972d586421SSepherosa Ziehau 
32982d586421SSepherosa Ziehau 	if (ifp0 != NULL && (ifp0->if_flags & IFF_RUNNING) != 0 &&
32992d586421SSepherosa Ziehau 	    !ifq_is_empty(&ifp0->if_snd))
33009db4b353SSepherosa Ziehau 		if_devstart(ifp0);
33012d586421SSepherosa Ziehau 	if (ifp1 != NULL && (ifp1->if_flags & IFF_RUNNING) != 0 &&
33022d586421SSepherosa Ziehau 	    !ifq_is_empty(&ifp1->if_snd))
33039db4b353SSepherosa Ziehau 		if_devstart(ifp1);
33042d586421SSepherosa Ziehau }
33052d586421SSepherosa Ziehau 
33062d586421SSepherosa Ziehau static void
msk_set_tx_stfwd(struct msk_if_softc * sc_if)3307d9e919c4SSepherosa Ziehau msk_set_tx_stfwd(struct msk_if_softc *sc_if)
3308d9e919c4SSepherosa Ziehau {
3309d9e919c4SSepherosa Ziehau 	struct msk_softc *sc = sc_if->msk_softc;
3310d9e919c4SSepherosa Ziehau 	struct ifnet *ifp = sc_if->msk_ifp;
3311d9e919c4SSepherosa Ziehau 
33127b7b65f4SSepherosa Ziehau 	if ((sc->msk_hw_id == CHIP_ID_YUKON_EX &&
33137b7b65f4SSepherosa Ziehau 	    sc->msk_hw_rev != CHIP_REV_YU_EX_A0) ||
33147b7b65f4SSepherosa Ziehau 	    sc->msk_hw_id >= CHIP_ID_YUKON_SUPR) {
33157b7b65f4SSepherosa Ziehau 		CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, TX_GMF_CTRL_T),
33167b7b65f4SSepherosa Ziehau 		    TX_STFW_ENA);
3317d9e919c4SSepherosa Ziehau 	} else {
3318d9e919c4SSepherosa Ziehau 		if (ifp->if_mtu > ETHERMTU) {
3319d9e919c4SSepherosa Ziehau 			/* Set Tx GMAC FIFO Almost Empty Threshold. */
3320d9e919c4SSepherosa Ziehau 			CSR_WRITE_4(sc,
3321d9e919c4SSepherosa Ziehau 			    MR_ADDR(sc_if->msk_port, TX_GMF_AE_THR),
3322d9e919c4SSepherosa Ziehau 			    MSK_ECU_JUMBO_WM << 16 | MSK_ECU_AE_THR);
3323d9e919c4SSepherosa Ziehau 			/* Disable Store & Forward mode for Tx. */
33247b7b65f4SSepherosa Ziehau 			CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, TX_GMF_CTRL_T),
33257b7b65f4SSepherosa Ziehau 			    TX_STFW_DIS);
3326d9e919c4SSepherosa Ziehau 		} else {
33277b7b65f4SSepherosa Ziehau 			CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, TX_GMF_CTRL_T),
33287b7b65f4SSepherosa Ziehau 			    TX_STFW_ENA);
3329d9e919c4SSepherosa Ziehau 		}
3330d9e919c4SSepherosa Ziehau 	}
3331d9e919c4SSepherosa Ziehau }
3332d9e919c4SSepherosa Ziehau 
3333d9e919c4SSepherosa Ziehau static void
msk_init(void * xsc)33342d586421SSepherosa Ziehau msk_init(void *xsc)
33352d586421SSepherosa Ziehau {
33362d586421SSepherosa Ziehau 	struct msk_if_softc *sc_if = xsc;
33372d586421SSepherosa Ziehau 	struct msk_softc *sc = sc_if->msk_softc;
33382d586421SSepherosa Ziehau 	struct ifnet *ifp = sc_if->msk_ifp;
33392d586421SSepherosa Ziehau 	struct mii_data	 *mii;
33402d586421SSepherosa Ziehau 	uint16_t eaddr[ETHER_ADDR_LEN / 2];
33412d586421SSepherosa Ziehau 	uint16_t gmac;
3342080bd27eSSepherosa Ziehau 	uint32_t reg;
33432d586421SSepherosa Ziehau 	int error, i;
33442d586421SSepherosa Ziehau 
33452d586421SSepherosa Ziehau 	ASSERT_SERIALIZED(ifp->if_serializer);
33462d586421SSepherosa Ziehau 
33472d586421SSepherosa Ziehau 	mii = device_get_softc(sc_if->msk_miibus);
33482d586421SSepherosa Ziehau 
33492d586421SSepherosa Ziehau 	error = 0;
33502d586421SSepherosa Ziehau 	/* Cancel pending I/O and free all Rx/Tx buffers. */
33512d586421SSepherosa Ziehau 	msk_stop(sc_if);
33522d586421SSepherosa Ziehau 
33532d586421SSepherosa Ziehau 	sc_if->msk_framesize = ifp->if_mtu + ETHER_HDR_LEN + EVL_ENCAPLEN;
33542d586421SSepherosa Ziehau 	if (sc_if->msk_framesize > MSK_MAX_FRAMELEN &&
33552d586421SSepherosa Ziehau 	    sc_if->msk_softc->msk_hw_id == CHIP_ID_YUKON_EC_U) {
33562d586421SSepherosa Ziehau 		/*
33572d586421SSepherosa Ziehau 		 * In Yukon EC Ultra, TSO & checksum offload is not
33582d586421SSepherosa Ziehau 		 * supported for jumbo frame.
33592d586421SSepherosa Ziehau 		 */
33602d586421SSepherosa Ziehau 		ifp->if_hwassist &= ~MSK_CSUM_FEATURES;
33612d586421SSepherosa Ziehau 		ifp->if_capenable &= ~IFCAP_TXCSUM;
33622d586421SSepherosa Ziehau 	}
33632d586421SSepherosa Ziehau 
336455223f24SSepherosa Ziehau 	/* GMAC Control reset. */
336555223f24SSepherosa Ziehau 	CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, GMAC_CTRL), GMC_RST_SET);
336655223f24SSepherosa Ziehau 	CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, GMAC_CTRL), GMC_RST_CLR);
336755223f24SSepherosa Ziehau 	CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, GMAC_CTRL), GMC_F_LOOPB_OFF);
33680d557164SSepherosa Ziehau 	if (sc->msk_hw_id == CHIP_ID_YUKON_EX ||
33690d557164SSepherosa Ziehau 	    sc->msk_hw_id == CHIP_ID_YUKON_SUPR) {
3370d9e919c4SSepherosa Ziehau 		CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, GMAC_CTRL),
3371d9e919c4SSepherosa Ziehau 		    GMC_BYP_MACSECRX_ON | GMC_BYP_MACSECTX_ON |
3372d9e919c4SSepherosa Ziehau 		    GMC_BYP_RETR_ON);
3373d9e919c4SSepherosa Ziehau 	}
337455223f24SSepherosa Ziehau 
33752d586421SSepherosa Ziehau 	/*
337655223f24SSepherosa Ziehau 	 * Initialize GMAC first such that speed/duplex/flow-control
337755223f24SSepherosa Ziehau 	 * parameters are renegotiated when interface is brought up.
33782d586421SSepherosa Ziehau 	 */
337955223f24SSepherosa Ziehau 	GMAC_WRITE_2(sc, sc_if->msk_port, GM_GP_CTRL, 0);
33802d586421SSepherosa Ziehau 
33812d586421SSepherosa Ziehau 	/* Dummy read the Interrupt Source Register. */
33822d586421SSepherosa Ziehau 	CSR_READ_1(sc, MR_ADDR(sc_if->msk_port, GMAC_IRQ_SRC));
33832d586421SSepherosa Ziehau 
33842d586421SSepherosa Ziehau 	/* Set MIB Clear Counter Mode. */
33852d586421SSepherosa Ziehau 	gmac = GMAC_READ_2(sc, sc_if->msk_port, GM_PHY_ADDR);
33862d586421SSepherosa Ziehau 	GMAC_WRITE_2(sc, sc_if->msk_port, GM_PHY_ADDR, gmac | GM_PAR_MIB_CLR);
33872d586421SSepherosa Ziehau 	/* Read all MIB Counters with Clear Mode set. */
33882d586421SSepherosa Ziehau 	for (i = 0; i < GM_MIB_CNT_SIZE; i++)
33892d586421SSepherosa Ziehau 		GMAC_READ_2(sc, sc_if->msk_port, GM_MIB_CNT_BASE + 8 * i);
33902d586421SSepherosa Ziehau 	/* Clear MIB Clear Counter Mode. */
33912d586421SSepherosa Ziehau 	gmac &= ~GM_PAR_MIB_CLR;
33922d586421SSepherosa Ziehau 	GMAC_WRITE_2(sc, sc_if->msk_port, GM_PHY_ADDR, gmac);
33932d586421SSepherosa Ziehau 
33942d586421SSepherosa Ziehau 	/* Disable FCS. */
33952d586421SSepherosa Ziehau 	GMAC_WRITE_2(sc, sc_if->msk_port, GM_RX_CTRL, GM_RXCR_CRC_DIS);
33962d586421SSepherosa Ziehau 
33972d586421SSepherosa Ziehau 	/* Setup Transmit Control Register. */
33982d586421SSepherosa Ziehau 	GMAC_WRITE_2(sc, sc_if->msk_port, GM_TX_CTRL, TX_COL_THR(TX_COL_DEF));
33992d586421SSepherosa Ziehau 
34002d586421SSepherosa Ziehau 	/* Setup Transmit Flow Control Register. */
34012d586421SSepherosa Ziehau 	GMAC_WRITE_2(sc, sc_if->msk_port, GM_TX_FLOW_CTRL, 0xffff);
34022d586421SSepherosa Ziehau 
34032d586421SSepherosa Ziehau 	/* Setup Transmit Parameter Register. */
34042d586421SSepherosa Ziehau 	GMAC_WRITE_2(sc, sc_if->msk_port, GM_TX_PARAM,
34052d586421SSepherosa Ziehau 	    TX_JAM_LEN_VAL(TX_JAM_LEN_DEF) | TX_JAM_IPG_VAL(TX_JAM_IPG_DEF) |
34062d586421SSepherosa Ziehau 	    TX_IPG_JAM_DATA(TX_IPG_JAM_DEF) | TX_BACK_OFF_LIM(TX_BOF_LIM_DEF));
34072d586421SSepherosa Ziehau 
34082d586421SSepherosa Ziehau 	gmac = DATA_BLIND_VAL(DATA_BLIND_DEF) |
34092d586421SSepherosa Ziehau 	    GM_SMOD_VLAN_ENA | IPG_DATA_VAL(IPG_DATA_DEF);
34102d586421SSepherosa Ziehau 
34112d586421SSepherosa Ziehau 	if (sc_if->msk_framesize > MSK_MAX_FRAMELEN)
34122d586421SSepherosa Ziehau 		gmac |= GM_SMOD_JUMBO_ENA;
34132d586421SSepherosa Ziehau 	GMAC_WRITE_2(sc, sc_if->msk_port, GM_SERIAL_MODE, gmac);
34142d586421SSepherosa Ziehau 
34152d586421SSepherosa Ziehau 	/* Set station address. */
34162d586421SSepherosa Ziehau         bcopy(IF_LLADDR(ifp), eaddr, ETHER_ADDR_LEN);
34172d586421SSepherosa Ziehau         for (i = 0; i < ETHER_ADDR_LEN /2; i++)
34182d586421SSepherosa Ziehau 		GMAC_WRITE_2(sc, sc_if->msk_port, GM_SRC_ADDR_1L + i * 4,
34192d586421SSepherosa Ziehau 		    eaddr[i]);
34202d586421SSepherosa Ziehau         for (i = 0; i < ETHER_ADDR_LEN /2; i++)
34212d586421SSepherosa Ziehau 		GMAC_WRITE_2(sc, sc_if->msk_port, GM_SRC_ADDR_2L + i * 4,
34222d586421SSepherosa Ziehau 		    eaddr[i]);
34232d586421SSepherosa Ziehau 
34242d586421SSepherosa Ziehau 	/* Disable interrupts for counter overflows. */
34252d586421SSepherosa Ziehau 	GMAC_WRITE_2(sc, sc_if->msk_port, GM_TX_IRQ_MSK, 0);
34262d586421SSepherosa Ziehau 	GMAC_WRITE_2(sc, sc_if->msk_port, GM_RX_IRQ_MSK, 0);
34272d586421SSepherosa Ziehau 	GMAC_WRITE_2(sc, sc_if->msk_port, GM_TR_IRQ_MSK, 0);
34282d586421SSepherosa Ziehau 
34292d586421SSepherosa Ziehau 	/* Configure Rx MAC FIFO. */
34302d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, RX_GMF_CTRL_T), GMF_RST_SET);
34312d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, RX_GMF_CTRL_T), GMF_RST_CLR);
3432080bd27eSSepherosa Ziehau 	reg = GMF_OPER_ON | GMF_RX_F_FL_ON;
3433d9e919c4SSepherosa Ziehau 	if (sc->msk_hw_id == CHIP_ID_YUKON_FE_P ||
3434d9e919c4SSepherosa Ziehau 	    sc->msk_hw_id == CHIP_ID_YUKON_EX)
3435080bd27eSSepherosa Ziehau 		reg |= GMF_RX_OVER_ON;
3436080bd27eSSepherosa Ziehau 	CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, RX_GMF_CTRL_T), reg);
34372d586421SSepherosa Ziehau 
3438dc7303ffSSepherosa Ziehau 	/* Set receive filter. */
3439dc7303ffSSepherosa Ziehau 	msk_rxfilter(sc_if);
34402d586421SSepherosa Ziehau 
344110cc281dSSepherosa Ziehau 	if (sc->msk_hw_id == CHIP_ID_YUKON_XL) {
344210cc281dSSepherosa Ziehau 		/* Clear flush mask - HW bug. */
344310cc281dSSepherosa Ziehau 		CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, RX_GMF_FL_MSK), 0);
344410cc281dSSepherosa Ziehau 	} else {
34452d586421SSepherosa Ziehau 		/* Flush Rx MAC FIFO on any flow control or error. */
34462d586421SSepherosa Ziehau 		CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, RX_GMF_FL_MSK),
34472d586421SSepherosa Ziehau 		    GMR_FS_ANY_ERR);
344810cc281dSSepherosa Ziehau 	}
34492d586421SSepherosa Ziehau 
34508510fba4SSepherosa Ziehau 	/*
34518510fba4SSepherosa Ziehau 	 * Set Rx FIFO flush threshold to 64 bytes 1 FIFO word
34528510fba4SSepherosa Ziehau 	 * due to hardware hang on receipt of pause frames.
34538510fba4SSepherosa Ziehau 	 */
3454080bd27eSSepherosa Ziehau 	reg = RX_GMF_FL_THR_DEF + 1;
3455080bd27eSSepherosa Ziehau 	/* Another magic for Yukon FE+ - From Linux. */
3456080bd27eSSepherosa Ziehau 	if (sc->msk_hw_id == CHIP_ID_YUKON_FE_P &&
3457080bd27eSSepherosa Ziehau 	    sc->msk_hw_rev == CHIP_REV_YU_FE_P_A0)
3458080bd27eSSepherosa Ziehau 		reg = 0x178;
3459080bd27eSSepherosa Ziehau 	CSR_WRITE_2(sc, MR_ADDR(sc_if->msk_port, RX_GMF_FL_THR), reg);
3460080bd27eSSepherosa Ziehau 
34612d586421SSepherosa Ziehau 
34622d586421SSepherosa Ziehau 	/* Configure Tx MAC FIFO. */
34632d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, TX_GMF_CTRL_T), GMF_RST_SET);
34642d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, TX_GMF_CTRL_T), GMF_RST_CLR);
34652d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, TX_GMF_CTRL_T), GMF_OPER_ON);
34662d586421SSepherosa Ziehau 
34672d586421SSepherosa Ziehau 	/* Configure hardware VLAN tag insertion/stripping. */
34682d586421SSepherosa Ziehau 	msk_setvlan(sc_if, ifp);
34692d586421SSepherosa Ziehau 
34702a9b20a4SSepherosa Ziehau 	if ((sc_if->msk_flags & MSK_FLAG_RAMBUF) == 0) {
34712d586421SSepherosa Ziehau 		/* Set Rx Pause threshould. */
3472ab5e50d3SSepherosa Ziehau 		CSR_WRITE_2(sc, MR_ADDR(sc_if->msk_port, RX_GMF_LP_THR),
34732d586421SSepherosa Ziehau 		    MSK_ECU_LLPP);
3474ab5e50d3SSepherosa Ziehau 		CSR_WRITE_2(sc, MR_ADDR(sc_if->msk_port, RX_GMF_UP_THR),
34752d586421SSepherosa Ziehau 		    MSK_ECU_ULPP);
3476d9e919c4SSepherosa Ziehau 		/* Configure store-and-forward for Tx. */
3477d9e919c4SSepherosa Ziehau 		msk_set_tx_stfwd(sc_if);
34782d586421SSepherosa Ziehau 	}
34792d586421SSepherosa Ziehau 
3480080bd27eSSepherosa Ziehau 	if (sc->msk_hw_id == CHIP_ID_YUKON_FE_P &&
3481080bd27eSSepherosa Ziehau 	    sc->msk_hw_rev == CHIP_REV_YU_FE_P_A0) {
3482080bd27eSSepherosa Ziehau 		/* Disable dynamic watermark - from Linux. */
3483080bd27eSSepherosa Ziehau 		reg = CSR_READ_4(sc, MR_ADDR(sc_if->msk_port, TX_GMF_EA));
3484080bd27eSSepherosa Ziehau 		reg &= ~0x03;
3485080bd27eSSepherosa Ziehau 		CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, TX_GMF_EA), reg);
3486080bd27eSSepherosa Ziehau 	}
3487080bd27eSSepherosa Ziehau 
34882d586421SSepherosa Ziehau 	/*
34892d586421SSepherosa Ziehau 	 * Disable Force Sync bit and Alloc bit in Tx RAM interface
34902d586421SSepherosa Ziehau 	 * arbiter as we don't use Sync Tx queue.
34912d586421SSepherosa Ziehau 	 */
34922d586421SSepherosa Ziehau 	CSR_WRITE_1(sc, MR_ADDR(sc_if->msk_port, TXA_CTRL),
34932d586421SSepherosa Ziehau 	    TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC);
34942d586421SSepherosa Ziehau 	/* Enable the RAM Interface Arbiter. */
34952d586421SSepherosa Ziehau 	CSR_WRITE_1(sc, MR_ADDR(sc_if->msk_port, TXA_CTRL), TXA_ENA_ARB);
34962d586421SSepherosa Ziehau 
34972d586421SSepherosa Ziehau 	/* Setup RAM buffer. */
34982d586421SSepherosa Ziehau 	msk_set_rambuffer(sc_if);
34992d586421SSepherosa Ziehau 
35002d586421SSepherosa Ziehau 	/* Disable Tx sync Queue. */
35012d586421SSepherosa Ziehau 	CSR_WRITE_1(sc, RB_ADDR(sc_if->msk_txsq, RB_CTRL), RB_RST_SET);
35022d586421SSepherosa Ziehau 
35032d586421SSepherosa Ziehau 	/* Setup Tx Queue Bus Memory Interface. */
35042d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, Q_ADDR(sc_if->msk_txq, Q_CSR), BMU_CLR_RESET);
35052d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, Q_ADDR(sc_if->msk_txq, Q_CSR), BMU_OPER_INIT);
35062d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, Q_ADDR(sc_if->msk_txq, Q_CSR), BMU_FIFO_OP_ON);
35072d586421SSepherosa Ziehau 	CSR_WRITE_2(sc, Q_ADDR(sc_if->msk_txq, Q_WM), MSK_BMU_TX_WM);
3508d9e919c4SSepherosa Ziehau 	switch (sc->msk_hw_id) {
3509d9e919c4SSepherosa Ziehau 	case CHIP_ID_YUKON_EC_U:
3510d9e919c4SSepherosa Ziehau 		if (sc->msk_hw_rev == CHIP_REV_YU_EC_U_A0) {
35112d586421SSepherosa Ziehau 			/* Fix for Yukon-EC Ultra: set BMU FIFO level */
3512d9e919c4SSepherosa Ziehau 			CSR_WRITE_2(sc, Q_ADDR(sc_if->msk_txq, Q_AL),
3513d9e919c4SSepherosa Ziehau 			    MSK_ECU_TXFF_LEV);
3514d9e919c4SSepherosa Ziehau 		}
3515d9e919c4SSepherosa Ziehau 		break;
3516d9e919c4SSepherosa Ziehau 	case CHIP_ID_YUKON_EX:
3517d9e919c4SSepherosa Ziehau 		/*
3518d9e919c4SSepherosa Ziehau 		 * Yukon Extreme seems to have silicon bug for
3519d9e919c4SSepherosa Ziehau 		 * automatic Tx checksum calculation capability.
3520d9e919c4SSepherosa Ziehau 		 */
3521d9e919c4SSepherosa Ziehau 		if (sc->msk_hw_rev == CHIP_REV_YU_EX_B0) {
3522d9e919c4SSepherosa Ziehau 			CSR_WRITE_4(sc, Q_ADDR(sc_if->msk_txq, Q_F),
3523d9e919c4SSepherosa Ziehau 			    F_TX_CHK_AUTO_OFF);
3524d9e919c4SSepherosa Ziehau 		}
3525d9e919c4SSepherosa Ziehau 		break;
35262d586421SSepherosa Ziehau  	}
35272d586421SSepherosa Ziehau 
35282d586421SSepherosa Ziehau 	/* Setup Rx Queue Bus Memory Interface. */
35292d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, Q_ADDR(sc_if->msk_rxq, Q_CSR), BMU_CLR_RESET);
35302d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, Q_ADDR(sc_if->msk_rxq, Q_CSR), BMU_OPER_INIT);
35312d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, Q_ADDR(sc_if->msk_rxq, Q_CSR), BMU_FIFO_OP_ON);
35322d586421SSepherosa Ziehau 	CSR_WRITE_2(sc, Q_ADDR(sc_if->msk_rxq, Q_WM), MSK_BMU_RX_WM);
35332d586421SSepherosa Ziehau         if (sc->msk_hw_id == CHIP_ID_YUKON_EC_U &&
35342d586421SSepherosa Ziehau 	    sc->msk_hw_rev >= CHIP_REV_YU_EC_U_A1) {
35352d586421SSepherosa Ziehau 		/* MAC Rx RAM Read is controlled by hardware. */
35362d586421SSepherosa Ziehau                 CSR_WRITE_4(sc, Q_ADDR(sc_if->msk_rxq, Q_F), F_M_RX_RAM_DIS);
35372d586421SSepherosa Ziehau 	}
35382d586421SSepherosa Ziehau 
35392d586421SSepherosa Ziehau 	msk_set_prefetch(sc, sc_if->msk_txq,
35402d586421SSepherosa Ziehau 	    sc_if->msk_rdata.msk_tx_ring_paddr, MSK_TX_RING_CNT - 1);
35412d586421SSepherosa Ziehau 	msk_init_tx_ring(sc_if);
35422d586421SSepherosa Ziehau 
35432d586421SSepherosa Ziehau 	/* Disable Rx checksum offload and RSS hash. */
35442d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, Q_ADDR(sc_if->msk_rxq, Q_CSR),
35452d586421SSepherosa Ziehau 	    BMU_DIS_RX_CHKSUM | BMU_DIS_RX_RSS_HASH);
35462d586421SSepherosa Ziehau #ifdef MSK_JUMBO
35472d586421SSepherosa Ziehau 	if (sc_if->msk_framesize > (MCLBYTES - ETHER_HDR_LEN)) {
35482d586421SSepherosa Ziehau 		msk_set_prefetch(sc, sc_if->msk_rxq,
35492d586421SSepherosa Ziehau 		    sc_if->msk_rdata.msk_jumbo_rx_ring_paddr,
35502d586421SSepherosa Ziehau 		    MSK_JUMBO_RX_RING_CNT - 1);
35512d586421SSepherosa Ziehau 		error = msk_init_jumbo_rx_ring(sc_if);
35522d586421SSepherosa Ziehau 	} else
35532d586421SSepherosa Ziehau #endif
35542d586421SSepherosa Ziehau 	{
35552d586421SSepherosa Ziehau 		msk_set_prefetch(sc, sc_if->msk_rxq,
35562d586421SSepherosa Ziehau 		    sc_if->msk_rdata.msk_rx_ring_paddr,
35572d586421SSepherosa Ziehau 		    MSK_RX_RING_CNT - 1);
35582d586421SSepherosa Ziehau 		error = msk_init_rx_ring(sc_if);
35592d586421SSepherosa Ziehau 	}
35602d586421SSepherosa Ziehau 	if (error != 0) {
35612d586421SSepherosa Ziehau 		device_printf(sc_if->msk_if_dev,
35622d586421SSepherosa Ziehau 		    "initialization failed: no memory for Rx buffers\n");
35632d586421SSepherosa Ziehau 		msk_stop(sc_if);
35642d586421SSepherosa Ziehau 		return;
35652d586421SSepherosa Ziehau 	}
35660d557164SSepherosa Ziehau 	if (sc->msk_hw_id == CHIP_ID_YUKON_EX ||
35670d557164SSepherosa Ziehau 	    sc->msk_hw_id == CHIP_ID_YUKON_SUPR) {
3568441c9e87SSepherosa Ziehau 		/* Disable flushing of non-ASF packets. */
3569441c9e87SSepherosa Ziehau 		CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, RX_GMF_CTRL_T),
3570441c9e87SSepherosa Ziehau 		    GMF_RX_MACSEC_FLUSH_OFF);
3571441c9e87SSepherosa Ziehau 	}
35722d586421SSepherosa Ziehau 
35732d586421SSepherosa Ziehau 	/* Configure interrupt handling. */
35742d586421SSepherosa Ziehau 	if (sc_if->msk_port == MSK_PORT_A) {
35752d586421SSepherosa Ziehau 		sc->msk_intrmask |= Y2_IS_PORT_A;
35762d586421SSepherosa Ziehau 		sc->msk_intrhwemask |= Y2_HWE_L1_MASK;
35772d586421SSepherosa Ziehau 	} else {
35782d586421SSepherosa Ziehau 		sc->msk_intrmask |= Y2_IS_PORT_B;
35792d586421SSepherosa Ziehau 		sc->msk_intrhwemask |= Y2_HWE_L2_MASK;
35802d586421SSepherosa Ziehau 	}
35812d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, B0_HWE_IMSK, sc->msk_intrhwemask);
35822d586421SSepherosa Ziehau 	CSR_READ_4(sc, B0_HWE_IMSK);
35832d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, B0_IMSK, sc->msk_intrmask);
35842d586421SSepherosa Ziehau 	CSR_READ_4(sc, B0_IMSK);
35852d586421SSepherosa Ziehau 
35862d586421SSepherosa Ziehau 	sc_if->msk_link = 0;
35872d586421SSepherosa Ziehau 	mii_mediachg(mii);
35882d586421SSepherosa Ziehau 
3589f59f1081SSepherosa Ziehau 	mskc_set_imtimer(sc);
3590f59f1081SSepherosa Ziehau 
35912d586421SSepherosa Ziehau 	ifp->if_flags |= IFF_RUNNING;
35929ed293e0SSepherosa Ziehau 	ifq_clr_oactive(&ifp->if_snd);
35932d586421SSepherosa Ziehau 
35942d586421SSepherosa Ziehau 	callout_reset(&sc_if->msk_tick_ch, hz, msk_tick, sc_if);
35952d586421SSepherosa Ziehau }
35962d586421SSepherosa Ziehau 
35972d586421SSepherosa Ziehau static void
msk_set_rambuffer(struct msk_if_softc * sc_if)35982d586421SSepherosa Ziehau msk_set_rambuffer(struct msk_if_softc *sc_if)
35992d586421SSepherosa Ziehau {
36002d586421SSepherosa Ziehau 	struct msk_softc *sc;
36012d586421SSepherosa Ziehau 	int ltpp, utpp;
36022d586421SSepherosa Ziehau 
36032a9b20a4SSepherosa Ziehau 	if ((sc_if->msk_flags & MSK_FLAG_RAMBUF) == 0)
36042a9b20a4SSepherosa Ziehau 		return;
36052a9b20a4SSepherosa Ziehau 
36062d586421SSepherosa Ziehau 	sc = sc_if->msk_softc;
36072d586421SSepherosa Ziehau 
36082d586421SSepherosa Ziehau 	/* Setup Rx Queue. */
36092d586421SSepherosa Ziehau 	CSR_WRITE_1(sc, RB_ADDR(sc_if->msk_rxq, RB_CTRL), RB_RST_CLR);
36102d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, RB_ADDR(sc_if->msk_rxq, RB_START),
36112d586421SSepherosa Ziehau 	    sc->msk_rxqstart[sc_if->msk_port] / 8);
36122d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, RB_ADDR(sc_if->msk_rxq, RB_END),
36132d586421SSepherosa Ziehau 	    sc->msk_rxqend[sc_if->msk_port] / 8);
36142d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, RB_ADDR(sc_if->msk_rxq, RB_WP),
36152d586421SSepherosa Ziehau 	    sc->msk_rxqstart[sc_if->msk_port] / 8);
36162d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, RB_ADDR(sc_if->msk_rxq, RB_RP),
36172d586421SSepherosa Ziehau 	    sc->msk_rxqstart[sc_if->msk_port] / 8);
36182d586421SSepherosa Ziehau 
36192d586421SSepherosa Ziehau 	utpp = (sc->msk_rxqend[sc_if->msk_port] + 1 -
36202d586421SSepherosa Ziehau 	    sc->msk_rxqstart[sc_if->msk_port] - MSK_RB_ULPP) / 8;
36212d586421SSepherosa Ziehau 	ltpp = (sc->msk_rxqend[sc_if->msk_port] + 1 -
36222d586421SSepherosa Ziehau 	    sc->msk_rxqstart[sc_if->msk_port] - MSK_RB_LLPP_B) / 8;
36232d586421SSepherosa Ziehau 	if (sc->msk_rxqsize < MSK_MIN_RXQ_SIZE)
36242d586421SSepherosa Ziehau 		ltpp += (MSK_RB_LLPP_B - MSK_RB_LLPP_S) / 8;
36252d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, RB_ADDR(sc_if->msk_rxq, RB_RX_UTPP), utpp);
36262d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, RB_ADDR(sc_if->msk_rxq, RB_RX_LTPP), ltpp);
36272d586421SSepherosa Ziehau 	/* Set Rx priority(RB_RX_UTHP/RB_RX_LTHP) thresholds? */
36282d586421SSepherosa Ziehau 
36292d586421SSepherosa Ziehau 	CSR_WRITE_1(sc, RB_ADDR(sc_if->msk_rxq, RB_CTRL), RB_ENA_OP_MD);
36302d586421SSepherosa Ziehau 	CSR_READ_1(sc, RB_ADDR(sc_if->msk_rxq, RB_CTRL));
36312d586421SSepherosa Ziehau 
36322d586421SSepherosa Ziehau 	/* Setup Tx Queue. */
36332d586421SSepherosa Ziehau 	CSR_WRITE_1(sc, RB_ADDR(sc_if->msk_txq, RB_CTRL), RB_RST_CLR);
36342d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, RB_ADDR(sc_if->msk_txq, RB_START),
36352d586421SSepherosa Ziehau 	    sc->msk_txqstart[sc_if->msk_port] / 8);
36362d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, RB_ADDR(sc_if->msk_txq, RB_END),
36372d586421SSepherosa Ziehau 	    sc->msk_txqend[sc_if->msk_port] / 8);
36382d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, RB_ADDR(sc_if->msk_txq, RB_WP),
36392d586421SSepherosa Ziehau 	    sc->msk_txqstart[sc_if->msk_port] / 8);
36402d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, RB_ADDR(sc_if->msk_txq, RB_RP),
36412d586421SSepherosa Ziehau 	    sc->msk_txqstart[sc_if->msk_port] / 8);
36422d586421SSepherosa Ziehau 	/* Enable Store & Forward for Tx side. */
36432d586421SSepherosa Ziehau 	CSR_WRITE_1(sc, RB_ADDR(sc_if->msk_txq, RB_CTRL), RB_ENA_STFWD);
36442d586421SSepherosa Ziehau 	CSR_WRITE_1(sc, RB_ADDR(sc_if->msk_txq, RB_CTRL), RB_ENA_OP_MD);
36452d586421SSepherosa Ziehau 	CSR_READ_1(sc, RB_ADDR(sc_if->msk_txq, RB_CTRL));
36462d586421SSepherosa Ziehau }
36472d586421SSepherosa Ziehau 
36482d586421SSepherosa Ziehau static void
msk_set_prefetch(struct msk_softc * sc,int qaddr,bus_addr_t addr,uint32_t count)36492d586421SSepherosa Ziehau msk_set_prefetch(struct msk_softc *sc, int qaddr, bus_addr_t addr,
36502d586421SSepherosa Ziehau     uint32_t count)
36512d586421SSepherosa Ziehau {
36522d586421SSepherosa Ziehau 
36532d586421SSepherosa Ziehau 	/* Reset the prefetch unit. */
36542d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, Y2_PREF_Q_ADDR(qaddr, PREF_UNIT_CTRL_REG),
36552d586421SSepherosa Ziehau 	    PREF_UNIT_RST_SET);
36562d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, Y2_PREF_Q_ADDR(qaddr, PREF_UNIT_CTRL_REG),
36572d586421SSepherosa Ziehau 	    PREF_UNIT_RST_CLR);
36582d586421SSepherosa Ziehau 	/* Set LE base address. */
36592d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, Y2_PREF_Q_ADDR(qaddr, PREF_UNIT_ADDR_LOW_REG),
36602d586421SSepherosa Ziehau 	    MSK_ADDR_LO(addr));
36612d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, Y2_PREF_Q_ADDR(qaddr, PREF_UNIT_ADDR_HI_REG),
36622d586421SSepherosa Ziehau 	    MSK_ADDR_HI(addr));
36632d586421SSepherosa Ziehau 	/* Set the list last index. */
36642d586421SSepherosa Ziehau 	CSR_WRITE_2(sc, Y2_PREF_Q_ADDR(qaddr, PREF_UNIT_LAST_IDX_REG),
36652d586421SSepherosa Ziehau 	    count);
36662d586421SSepherosa Ziehau 	/* Turn on prefetch unit. */
36672d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, Y2_PREF_Q_ADDR(qaddr, PREF_UNIT_CTRL_REG),
36682d586421SSepherosa Ziehau 	    PREF_UNIT_OP_ON);
36692d586421SSepherosa Ziehau 	/* Dummy read to ensure write. */
36702d586421SSepherosa Ziehau 	CSR_READ_4(sc, Y2_PREF_Q_ADDR(qaddr, PREF_UNIT_CTRL_REG));
36712d586421SSepherosa Ziehau }
36722d586421SSepherosa Ziehau 
36732d586421SSepherosa Ziehau static void
msk_stop(struct msk_if_softc * sc_if)36742d586421SSepherosa Ziehau msk_stop(struct msk_if_softc *sc_if)
36752d586421SSepherosa Ziehau {
36762d586421SSepherosa Ziehau 	struct msk_softc *sc = sc_if->msk_softc;
36772d586421SSepherosa Ziehau 	struct ifnet *ifp = sc_if->msk_ifp;
36782d586421SSepherosa Ziehau 	struct msk_txdesc *txd;
36792d586421SSepherosa Ziehau 	struct msk_rxdesc *rxd;
36802d586421SSepherosa Ziehau #ifdef MSK_JUMBO
36812d586421SSepherosa Ziehau 	struct msk_rxdesc *jrxd;
36822d586421SSepherosa Ziehau #endif
36832d586421SSepherosa Ziehau 	uint32_t val;
36842d586421SSepherosa Ziehau 	int i;
36852d586421SSepherosa Ziehau 
36862d586421SSepherosa Ziehau 	ASSERT_SERIALIZED(ifp->if_serializer);
36872d586421SSepherosa Ziehau 
36882d586421SSepherosa Ziehau 	callout_stop(&sc_if->msk_tick_ch);
36892d586421SSepherosa Ziehau 	ifp->if_timer = 0;
36902d586421SSepherosa Ziehau 
36912d586421SSepherosa Ziehau 	/* Disable interrupts. */
36922d586421SSepherosa Ziehau 	if (sc_if->msk_port == MSK_PORT_A) {
36932d586421SSepherosa Ziehau 		sc->msk_intrmask &= ~Y2_IS_PORT_A;
36942d586421SSepherosa Ziehau 		sc->msk_intrhwemask &= ~Y2_HWE_L1_MASK;
36952d586421SSepherosa Ziehau 	} else {
36962d586421SSepherosa Ziehau 		sc->msk_intrmask &= ~Y2_IS_PORT_B;
36972d586421SSepherosa Ziehau 		sc->msk_intrhwemask &= ~Y2_HWE_L2_MASK;
36982d586421SSepherosa Ziehau 	}
36992d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, B0_HWE_IMSK, sc->msk_intrhwemask);
37002d586421SSepherosa Ziehau 	CSR_READ_4(sc, B0_HWE_IMSK);
37012d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, B0_IMSK, sc->msk_intrmask);
37022d586421SSepherosa Ziehau 	CSR_READ_4(sc, B0_IMSK);
37032d586421SSepherosa Ziehau 
37042d586421SSepherosa Ziehau 	/* Disable Tx/Rx MAC. */
37052d586421SSepherosa Ziehau 	val = GMAC_READ_2(sc, sc_if->msk_port, GM_GP_CTRL);
37062d586421SSepherosa Ziehau 	val &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA);
37072d586421SSepherosa Ziehau 	GMAC_WRITE_2(sc, sc_if->msk_port, GM_GP_CTRL, val);
37082d586421SSepherosa Ziehau 	/* Read again to ensure writing. */
37092d586421SSepherosa Ziehau 	GMAC_READ_2(sc, sc_if->msk_port, GM_GP_CTRL);
37102d586421SSepherosa Ziehau 
37112d586421SSepherosa Ziehau 	/* Stop Tx BMU. */
37122d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, Q_ADDR(sc_if->msk_txq, Q_CSR), BMU_STOP);
37132d586421SSepherosa Ziehau 	val = CSR_READ_4(sc, Q_ADDR(sc_if->msk_txq, Q_CSR));
37142d586421SSepherosa Ziehau 	for (i = 0; i < MSK_TIMEOUT; i++) {
37152d586421SSepherosa Ziehau 		if ((val & (BMU_STOP | BMU_IDLE)) == 0) {
37162d586421SSepherosa Ziehau 			CSR_WRITE_4(sc, Q_ADDR(sc_if->msk_txq, Q_CSR),
37172d586421SSepherosa Ziehau 			    BMU_STOP);
371869853fa0SSepherosa Ziehau 			val = CSR_READ_4(sc, Q_ADDR(sc_if->msk_txq, Q_CSR));
37192d586421SSepherosa Ziehau 		} else
37202d586421SSepherosa Ziehau 			break;
37212d586421SSepherosa Ziehau 		DELAY(1);
37222d586421SSepherosa Ziehau 	}
37232d586421SSepherosa Ziehau 	if (i == MSK_TIMEOUT)
37242d586421SSepherosa Ziehau 		device_printf(sc_if->msk_if_dev, "Tx BMU stop failed\n");
37252d586421SSepherosa Ziehau 	CSR_WRITE_1(sc, RB_ADDR(sc_if->msk_txq, RB_CTRL),
37262d586421SSepherosa Ziehau 	    RB_RST_SET | RB_DIS_OP_MD);
37272d586421SSepherosa Ziehau 
37282d586421SSepherosa Ziehau 	/* Disable all GMAC interrupt. */
37292d586421SSepherosa Ziehau 	CSR_WRITE_1(sc, MR_ADDR(sc_if->msk_port, GMAC_IRQ_MSK), 0);
37302d586421SSepherosa Ziehau 	/* Disable PHY interrupt. */
37312d586421SSepherosa Ziehau 	msk_phy_writereg(sc_if, PHY_ADDR_MARV, PHY_MARV_INT_MASK, 0);
37322d586421SSepherosa Ziehau 
37332d586421SSepherosa Ziehau 	/* Disable the RAM Interface Arbiter. */
37342d586421SSepherosa Ziehau 	CSR_WRITE_1(sc, MR_ADDR(sc_if->msk_port, TXA_CTRL), TXA_DIS_ARB);
37352d586421SSepherosa Ziehau 
37362d586421SSepherosa Ziehau 	/* Reset the PCI FIFO of the async Tx queue */
37372d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, Q_ADDR(sc_if->msk_txq, Q_CSR),
37382d586421SSepherosa Ziehau 	    BMU_RST_SET | BMU_FIFO_RST);
37392d586421SSepherosa Ziehau 
37402d586421SSepherosa Ziehau 	/* Reset the Tx prefetch units. */
37412d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, Y2_PREF_Q_ADDR(sc_if->msk_txq, PREF_UNIT_CTRL_REG),
37422d586421SSepherosa Ziehau 	    PREF_UNIT_RST_SET);
37432d586421SSepherosa Ziehau 
37442d586421SSepherosa Ziehau 	/* Reset the RAM Buffer async Tx queue. */
37452d586421SSepherosa Ziehau 	CSR_WRITE_1(sc, RB_ADDR(sc_if->msk_txq, RB_CTRL), RB_RST_SET);
37462d586421SSepherosa Ziehau 
37472d586421SSepherosa Ziehau 	/* Reset Tx MAC FIFO. */
37482d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, TX_GMF_CTRL_T), GMF_RST_SET);
37492d586421SSepherosa Ziehau 	/* Set Pause Off. */
37502d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, GMAC_CTRL), GMC_PAUSE_OFF);
37512d586421SSepherosa Ziehau 
37522d586421SSepherosa Ziehau 	/*
37532d586421SSepherosa Ziehau 	 * The Rx Stop command will not work for Yukon-2 if the BMU does not
37542d586421SSepherosa Ziehau 	 * reach the end of packet and since we can't make sure that we have
37552d586421SSepherosa Ziehau 	 * incoming data, we must reset the BMU while it is not during a DMA
37562d586421SSepherosa Ziehau 	 * transfer. Since it is possible that the Rx path is still active,
37572d586421SSepherosa Ziehau 	 * the Rx RAM buffer will be stopped first, so any possible incoming
37582d586421SSepherosa Ziehau 	 * data will not trigger a DMA. After the RAM buffer is stopped, the
37592d586421SSepherosa Ziehau 	 * BMU is polled until any DMA in progress is ended and only then it
37602d586421SSepherosa Ziehau 	 * will be reset.
37612d586421SSepherosa Ziehau 	 */
37622d586421SSepherosa Ziehau 
37632d586421SSepherosa Ziehau 	/* Disable the RAM Buffer receive queue. */
37642d586421SSepherosa Ziehau 	CSR_WRITE_1(sc, RB_ADDR(sc_if->msk_rxq, RB_CTRL), RB_DIS_OP_MD);
37652d586421SSepherosa Ziehau 	for (i = 0; i < MSK_TIMEOUT; i++) {
37662d586421SSepherosa Ziehau 		if (CSR_READ_1(sc, RB_ADDR(sc_if->msk_rxq, Q_RSL)) ==
37672d586421SSepherosa Ziehau 		    CSR_READ_1(sc, RB_ADDR(sc_if->msk_rxq, Q_RL)))
37682d586421SSepherosa Ziehau 			break;
37692d586421SSepherosa Ziehau 		DELAY(1);
37702d586421SSepherosa Ziehau 	}
37712d586421SSepherosa Ziehau 	if (i == MSK_TIMEOUT)
37722d586421SSepherosa Ziehau 		device_printf(sc_if->msk_if_dev, "Rx BMU stop failed\n");
37732d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, Q_ADDR(sc_if->msk_rxq, Q_CSR),
37742d586421SSepherosa Ziehau 	    BMU_RST_SET | BMU_FIFO_RST);
37752d586421SSepherosa Ziehau 	/* Reset the Rx prefetch unit. */
37762d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, Y2_PREF_Q_ADDR(sc_if->msk_rxq, PREF_UNIT_CTRL_REG),
37772d586421SSepherosa Ziehau 	    PREF_UNIT_RST_SET);
37782d586421SSepherosa Ziehau 	/* Reset the RAM Buffer receive queue. */
37792d586421SSepherosa Ziehau 	CSR_WRITE_1(sc, RB_ADDR(sc_if->msk_rxq, RB_CTRL), RB_RST_SET);
37802d586421SSepherosa Ziehau 	/* Reset Rx MAC FIFO. */
37812d586421SSepherosa Ziehau 	CSR_WRITE_4(sc, MR_ADDR(sc_if->msk_port, RX_GMF_CTRL_T), GMF_RST_SET);
37822d586421SSepherosa Ziehau 
37832d586421SSepherosa Ziehau 	/* Free Rx and Tx mbufs still in the queues. */
37842d586421SSepherosa Ziehau 	for (i = 0; i < MSK_RX_RING_CNT; i++) {
37852d586421SSepherosa Ziehau 		rxd = &sc_if->msk_cdata.msk_rxdesc[i];
37862d586421SSepherosa Ziehau 		if (rxd->rx_m != NULL) {
37872d586421SSepherosa Ziehau 			bus_dmamap_unload(sc_if->msk_cdata.msk_rx_tag,
37882d586421SSepherosa Ziehau 			    rxd->rx_dmamap);
37892d586421SSepherosa Ziehau 			m_freem(rxd->rx_m);
37902d586421SSepherosa Ziehau 			rxd->rx_m = NULL;
37912d586421SSepherosa Ziehau 		}
37922d586421SSepherosa Ziehau 	}
37932d586421SSepherosa Ziehau #ifdef MSK_JUMBO
37942d586421SSepherosa Ziehau 	for (i = 0; i < MSK_JUMBO_RX_RING_CNT; i++) {
37952d586421SSepherosa Ziehau 		jrxd = &sc_if->msk_cdata.msk_jumbo_rxdesc[i];
37962d586421SSepherosa Ziehau 		if (jrxd->rx_m != NULL) {
37972d586421SSepherosa Ziehau 			bus_dmamap_sync(sc_if->msk_cdata.msk_jumbo_rx_tag,
37982d586421SSepherosa Ziehau 			    jrxd->rx_dmamap, BUS_DMASYNC_POSTREAD);
37992d586421SSepherosa Ziehau 			bus_dmamap_unload(sc_if->msk_cdata.msk_jumbo_rx_tag,
38002d586421SSepherosa Ziehau 			    jrxd->rx_dmamap);
38012d586421SSepherosa Ziehau 			m_freem(jrxd->rx_m);
38022d586421SSepherosa Ziehau 			jrxd->rx_m = NULL;
38032d586421SSepherosa Ziehau 		}
38042d586421SSepherosa Ziehau 	}
38052d586421SSepherosa Ziehau #endif
38062d586421SSepherosa Ziehau 	for (i = 0; i < MSK_TX_RING_CNT; i++) {
38072d586421SSepherosa Ziehau 		txd = &sc_if->msk_cdata.msk_txdesc[i];
38082d586421SSepherosa Ziehau 		if (txd->tx_m != NULL) {
38092d586421SSepherosa Ziehau 			bus_dmamap_unload(sc_if->msk_cdata.msk_tx_tag,
38102d586421SSepherosa Ziehau 			    txd->tx_dmamap);
38112d586421SSepherosa Ziehau 			m_freem(txd->tx_m);
38122d586421SSepherosa Ziehau 			txd->tx_m = NULL;
38132d586421SSepherosa Ziehau 		}
38142d586421SSepherosa Ziehau 	}
38152d586421SSepherosa Ziehau 
38162d586421SSepherosa Ziehau 	/*
38172d586421SSepherosa Ziehau 	 * Mark the interface down.
38182d586421SSepherosa Ziehau 	 */
38199ed293e0SSepherosa Ziehau 	ifp->if_flags &= ~IFF_RUNNING;
38209ed293e0SSepherosa Ziehau 	ifq_clr_oactive(&ifp->if_snd);
38212d586421SSepherosa Ziehau 	sc_if->msk_link = 0;
38222d586421SSepherosa Ziehau }
38232d586421SSepherosa Ziehau 
38242d586421SSepherosa Ziehau static int
mskc_sysctl_proc_limit(SYSCTL_HANDLER_ARGS)3825f59f1081SSepherosa Ziehau mskc_sysctl_proc_limit(SYSCTL_HANDLER_ARGS)
38262d586421SSepherosa Ziehau {
3827f59f1081SSepherosa Ziehau 	return sysctl_int_range(oidp, arg1, arg2, req,
3828f59f1081SSepherosa Ziehau 				MSK_PROC_MIN, MSK_PROC_MAX);
38292d586421SSepherosa Ziehau }
38302d586421SSepherosa Ziehau 
3831f59f1081SSepherosa Ziehau static int
mskc_sysctl_intr_rate(SYSCTL_HANDLER_ARGS)3832f59f1081SSepherosa Ziehau mskc_sysctl_intr_rate(SYSCTL_HANDLER_ARGS)
3833f59f1081SSepherosa Ziehau {
3834f59f1081SSepherosa Ziehau 	struct msk_softc *sc = arg1;
3835f59f1081SSepherosa Ziehau 	struct lwkt_serialize *serializer = &sc->msk_serializer;
3836f59f1081SSepherosa Ziehau 	int error = 0, v;
3837f59f1081SSepherosa Ziehau 
3838f59f1081SSepherosa Ziehau 	lwkt_serialize_enter(serializer);
3839f59f1081SSepherosa Ziehau 
3840f59f1081SSepherosa Ziehau 	v = sc->msk_intr_rate;
3841f59f1081SSepherosa Ziehau 	error = sysctl_handle_int(oidp, &v, 0, req);
3842f59f1081SSepherosa Ziehau 	if (error || req->newptr == NULL)
3843f59f1081SSepherosa Ziehau 		goto back;
3844f59f1081SSepherosa Ziehau 	if (v < 0) {
3845f59f1081SSepherosa Ziehau 		error = EINVAL;
3846f59f1081SSepherosa Ziehau 		goto back;
3847f59f1081SSepherosa Ziehau 	}
3848f59f1081SSepherosa Ziehau 
3849f59f1081SSepherosa Ziehau 	if (sc->msk_intr_rate != v) {
3850f59f1081SSepherosa Ziehau 		int flag = 0, i;
3851f59f1081SSepherosa Ziehau 
3852f59f1081SSepherosa Ziehau 		sc->msk_intr_rate = v;
3853f59f1081SSepherosa Ziehau 		for (i = 0; i < 2; ++i) {
3854f59f1081SSepherosa Ziehau 			if (sc->msk_if[i] != NULL) {
3855f59f1081SSepherosa Ziehau 				flag |= sc->msk_if[i]->
3856f59f1081SSepherosa Ziehau 					arpcom.ac_if.if_flags & IFF_RUNNING;
3857f59f1081SSepherosa Ziehau 			}
3858f59f1081SSepherosa Ziehau 		}
3859f59f1081SSepherosa Ziehau 		if (flag)
3860f59f1081SSepherosa Ziehau 			mskc_set_imtimer(sc);
3861f59f1081SSepherosa Ziehau 	}
3862f59f1081SSepherosa Ziehau back:
3863f59f1081SSepherosa Ziehau 	lwkt_serialize_exit(serializer);
3864f59f1081SSepherosa Ziehau 	return error;
3865f59f1081SSepherosa Ziehau }
38662d586421SSepherosa Ziehau 
38672d586421SSepherosa Ziehau static int
msk_dmamem_create(device_t dev,bus_size_t size,bus_dma_tag_t * dtag,void ** addr,bus_addr_t * paddr,bus_dmamap_t * dmap)38682d586421SSepherosa Ziehau msk_dmamem_create(device_t dev, bus_size_t size, bus_dma_tag_t *dtag,
38692d586421SSepherosa Ziehau 		  void **addr, bus_addr_t *paddr, bus_dmamap_t *dmap)
38702d586421SSepherosa Ziehau {
38712d586421SSepherosa Ziehau 	struct msk_if_softc *sc_if = device_get_softc(dev);
3872c78f83cbSSepherosa Ziehau 	bus_dmamem_t dmem;
38732d586421SSepherosa Ziehau 	int error;
38742d586421SSepherosa Ziehau 
3875c78f83cbSSepherosa Ziehau 	error = bus_dmamem_coherent(sc_if->msk_cdata.msk_parent_tag,
38762d586421SSepherosa Ziehau 			MSK_RING_ALIGN, 0,
38772d586421SSepherosa Ziehau 			BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
3878c78f83cbSSepherosa Ziehau 			size, BUS_DMA_WAITOK | BUS_DMA_ZERO, &dmem);
38792d586421SSepherosa Ziehau 	if (error) {
3880c78f83cbSSepherosa Ziehau 		device_printf(dev, "can't create coherent DMA memory\n");
38812d586421SSepherosa Ziehau 		return error;
38822d586421SSepherosa Ziehau 	}
38832d586421SSepherosa Ziehau 
3884c78f83cbSSepherosa Ziehau 	*dtag = dmem.dmem_tag;
3885c78f83cbSSepherosa Ziehau 	*dmap = dmem.dmem_map;
3886c78f83cbSSepherosa Ziehau 	*addr = dmem.dmem_addr;
3887c78f83cbSSepherosa Ziehau 	*paddr = dmem.dmem_busaddr;
38882d586421SSepherosa Ziehau 
38892d586421SSepherosa Ziehau 	return 0;
38902d586421SSepherosa Ziehau }
38912d586421SSepherosa Ziehau 
38922d586421SSepherosa Ziehau static void
msk_dmamem_destroy(bus_dma_tag_t dtag,void * addr,bus_dmamap_t dmap)38932d586421SSepherosa Ziehau msk_dmamem_destroy(bus_dma_tag_t dtag, void *addr, bus_dmamap_t dmap)
38942d586421SSepherosa Ziehau {
38952d586421SSepherosa Ziehau 	if (dtag != NULL) {
38962d586421SSepherosa Ziehau 		bus_dmamap_unload(dtag, dmap);
38972d586421SSepherosa Ziehau 		bus_dmamem_free(dtag, addr, dmap);
38982d586421SSepherosa Ziehau 		bus_dma_tag_destroy(dtag);
38992d586421SSepherosa Ziehau 	}
39002d586421SSepherosa Ziehau }
3901f59f1081SSepherosa Ziehau 
3902f59f1081SSepherosa Ziehau static void
mskc_set_imtimer(struct msk_softc * sc)3903f59f1081SSepherosa Ziehau mskc_set_imtimer(struct msk_softc *sc)
3904f59f1081SSepherosa Ziehau {
3905f59f1081SSepherosa Ziehau 	if (sc->msk_intr_rate > 0) {
3906f59f1081SSepherosa Ziehau 		/*
3907f59f1081SSepherosa Ziehau 		 * XXX myk(4) seems to use 125MHz for EC/FE/XL
3908f59f1081SSepherosa Ziehau 		 *     and 78.125MHz for rest of chip types
3909f59f1081SSepherosa Ziehau 		 */
3910f59f1081SSepherosa Ziehau 		CSR_WRITE_4(sc, B2_IRQM_INI,
3911f59f1081SSepherosa Ziehau 			    MSK_USECS(sc, 1000000 / sc->msk_intr_rate));
3912f59f1081SSepherosa Ziehau 		CSR_WRITE_4(sc, B2_IRQM_MSK, sc->msk_intrmask);
3913f59f1081SSepherosa Ziehau 		CSR_WRITE_4(sc, B2_IRQM_CTRL, TIM_START);
3914f59f1081SSepherosa Ziehau 	} else {
3915f59f1081SSepherosa Ziehau 		CSR_WRITE_4(sc, B2_IRQM_CTRL, TIM_STOP);
3916f59f1081SSepherosa Ziehau 	}
3917f59f1081SSepherosa Ziehau }
3918