changeset 13768:ed21ea5d20cf

212 Atheros AR8132 / L1c Gigabit Ethernet Adapter Reviewed by: Garrett D'Amore <garrett@damore.org> Reviewed by: Milan Jurik <milan.jurik@xylab.cz> Approved by: Dan McDonald <danmcd@nexenta.com>
author Gary Mills <gary_mills@fastmail.fm>
date Fri, 10 Aug 2012 10:52:49 -0400
parents 8c906b14afbd
children 2317a7492de4
files usr/src/man/man7d/atge.7d usr/src/pkg/manifests/driver-network-atge.mf usr/src/uts/common/Makefile.files usr/src/uts/common/io/atge/atge.h usr/src/uts/common/io/atge/atge_cmn_reg.h usr/src/uts/common/io/atge/atge_l1_reg.h usr/src/uts/common/io/atge/atge_l1c.c usr/src/uts/common/io/atge/atge_l1c_reg.h usr/src/uts/common/io/atge/atge_l1e.c usr/src/uts/common/io/atge/atge_l1e_reg.h usr/src/uts/common/io/atge/atge_main.c usr/src/uts/common/io/atge/atge_mii.c
diffstat 12 files changed, 2690 insertions(+), 250 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/man/man7d/atge.7d	Tue Aug 07 21:36:09 2012 -0500
+++ b/usr/src/man/man7d/atge.7d	Fri Aug 10 10:52:49 2012 -0400
@@ -1,4 +1,5 @@
 '\" te
+.\" Copyright (c) 2012 Gary Mills
 .\" Copyright (c) 2009, Sun Microsystems, Inc. All Rights Reserved
 .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.
 .\"  See the License for the specific language governing permissions and limitations under the License. When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the
@@ -9,12 +10,20 @@
 .SH DESCRIPTION
 .sp
 .LP
-The \fBatge\fR ethernet driver is GLD based supporting the Atheros/Attansic L1E
-Gigabit Ethernet 10/100/1000 Base (AR8121/AR8113) chipsets:
+The \fBatge\fR ethernet driver supports the
+Atheros/Attansic L1, L1E, and L1C Ethernet
+(AR8121/AR8113/8114, AR8131/AR8132, and AR8151/AR8152) chipsets:
 .sp
 .in +2
 .nf
-pciex1969,1026 Atheros/Attansic GigabitE 10/100/1000 Base (AR8121/AR8113)
+pciex1969,1026 Atheros AR8121/8113/8114
+pciex1969,1048 Attansic L1
+pciex1969,1062 Atheros AR8132 Fast Ethernet
+pciex1969,1063 Atheros AR8131 Gigabit Ethernet
+pciex1969,1073 Atheros AR8151 v1.0 Gigabit Ethernet
+pciex1969,1083 Atheros AR8151 v2.0 Gigabit Ethernet
+pciex1969,2060 Atheros AR8152 v1.1 Fast Ethernet
+pciex1969,2062 Atheros AR8152 v2.0 Fast Ethernet
 .fi
 .in -2
 .sp
--- a/usr/src/pkg/manifests/driver-network-atge.mf	Tue Aug 07 21:36:09 2012 -0500
+++ b/usr/src/pkg/manifests/driver-network-atge.mf	Fri Aug 10 10:52:49 2012 -0400
@@ -21,6 +21,7 @@
 
 #
 # Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2012 Gary Mills
 #
 
 #
@@ -43,7 +44,13 @@
 dir path=usr/share/man/man7d
 driver name=atge \
     alias=pciex1969,1026 \
-    alias=pciex1969,1048
+    alias=pciex1969,1048 \
+    alias=pciex1969,1062 \
+    alias=pciex1969,1063 \
+    alias=pciex1969,1073 \
+    alias=pciex1969,1083 \
+    alias=pciex1969,2060 \
+    alias=pciex1969,2062
 file path=kernel/drv/$(ARCH64)/atge group=sys
 file path=kernel/drv/atge group=sys
 file path=usr/share/man/man7d/atge.7d
--- a/usr/src/uts/common/Makefile.files	Tue Aug 07 21:36:09 2012 -0500
+++ b/usr/src/uts/common/Makefile.files	Fri Aug 10 10:52:49 2012 -0400
@@ -1846,7 +1846,7 @@
 
 VR_OBJS += vr.o
 
-ATGE_OBJS += atge_main.o atge_l1e.o atge_mii.o atge_l1.o
+ATGE_OBJS += atge_main.o atge_l1e.o atge_mii.o atge_l1.o atge_l1c.o
 
 YGE_OBJS = yge.o
 
--- a/usr/src/uts/common/io/atge/atge.h	Tue Aug 07 21:36:09 2012 -0500
+++ b/usr/src/uts/common/io/atge/atge.h	Fri Aug 10 10:52:49 2012 -0400
@@ -19,6 +19,8 @@
  * CDDL HEADER END
  */
 /*
+ * Copyright (c) 2012 Gary Mills
+ *
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
@@ -33,6 +35,7 @@
 #include <sys/ethernet.h>
 #include <sys/mac_provider.h>
 #include "atge_l1e_reg.h"
+#include "atge_l1c_reg.h"
 
 #define	ATGE_PCI_REG_NUMBER	1
 
@@ -48,10 +51,20 @@
 #define	ATGE_FLAG_FASTETHER	0x0010
 #define	ATGE_FLAG_JUMBO		0x0020
 #define	ATGE_MII_CHECK		0x0040
+#define	ATGE_FLAG_ASPM_MON	0x0080
+#define	ATGE_FLAG_CMB_BUG	0x0100
+#define	ATGE_FLAG_SMB_BUG	0x0200
+#define	ATGE_FLAG_APS		0x1000
 
 #define	ATGE_CHIP_L1_DEV_ID	0x1048
 #define	ATGE_CHIP_L2_DEV_ID	0x2048
 #define	ATGE_CHIP_L1E_DEV_ID	0x1026
+#define	ATGE_CHIP_L1CG_DEV_ID	0x1063
+#define	ATGE_CHIP_L1CF_DEV_ID	0x1062
+#define	ATGE_CHIP_AR8151V1_DEV_ID	0x1073
+#define	ATGE_CHIP_AR8151V2_DEV_ID	0x1083
+#define	ATGE_CHIP_AR8152V1_DEV_ID	0x2060
+#define	ATGE_CHIP_AR8152V2_DEV_ID	0x2062
 
 #define	ATGE_PROMISC		0x001
 #define	ATGE_ALL_MULTICST	0x002
@@ -142,6 +155,8 @@
  * General purpose macros.
  */
 #define	ATGE_MODEL(atgep)	atgep->atge_model
+#define	ATGE_VID(atgep)		atgep->atge_vid
+#define	ATGE_DID(atgep)		atgep->atge_did
 
 /*
  * Different type of chip models.
@@ -150,6 +165,7 @@
 	ATGE_CHIP_L1 = 1,
 	ATGE_CHIP_L2,
 	ATGE_CHIP_L1E,
+	ATGE_CHIP_L1C,
 } atge_model_t;
 
 typedef	struct	atge_cards {
@@ -221,6 +237,20 @@
 } atge_l1_data_t;
 
 /*
+ * L1C specific private data.
+ */
+typedef	struct	atge_l1c_data {
+	atge_ring_t		*atge_rx_ring;
+	atge_dma_t		*atge_l1c_cmb;
+	atge_dma_t		*atge_l1c_rr;
+	atge_dma_t		*atge_l1c_smb;
+	int			atge_l1c_rr_consumers;
+	uint32_t		atge_l1c_intr_status;
+	uint32_t		atge_l1c_rx_prod_cons;
+	uint32_t		atge_l1c_tx_prod_cons;
+} atge_l1c_data_t;
+
+/*
  * TX descriptor table is same with L1, L1E and L2E chips.
  */
 #pragma pack(1)
@@ -257,6 +287,8 @@
 	dev_info_t		*atge_dip;
 	char			atge_name[8];
 	atge_model_t		atge_model;
+	uint16_t		atge_vid;
+	uint16_t		atge_did;
 	int			atge_chip_rev;
 	uint8_t			atge_revid;
 
@@ -300,6 +332,8 @@
 	int			atge_tx_resched;
 	int			atge_mtu;
 	int			atge_int_mod;
+	int			atge_int_rx_mod; /* L1C */
+	int			atge_int_tx_mod; /* L1C */
 	int			atge_max_frame_size;
 
 
--- a/usr/src/uts/common/io/atge/atge_cmn_reg.h	Tue Aug 07 21:36:09 2012 -0500
+++ b/usr/src/uts/common/io/atge/atge_cmn_reg.h	Fri Aug 10 10:52:49 2012 -0400
@@ -19,9 +19,37 @@
  * CDDL HEADER END
  */
 /*
+ * Copyright (c) 2012 Gary Mills
+ *
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ * Copyright (c) 2009, Pyun YongHyeon <yongari@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
 
 #ifndef _ATGE_CMN_REG_H
 #define	_ATGE_CMN_REG_H
@@ -43,15 +71,23 @@
 
 #define	ATGE_MASTER_CFG		0x1400
 #define	MASTER_RESET		0x00000001
-#define	MASTER_MTIMER_ENB	0x00000002
 #define	MASTER_ITIMER_ENB	0x00000004	/* L1 */
-#define	MASTER_IM_TX_TIMER_ENB	0x00000004	/* L1E */
 #define	MASTER_MANUAL_INT_ENB	0x00000008
-#define	MASTER_IM_RX_TIMER_ENB	0x00000020
 #define	MASTER_INT_RDCLR	0x00000040
+#define	MASTER_SA_TIMER_ENB	0x00000080
+#define	MASTER_MTIMER_ENB	0x00000100
 #define	MASTER_LED_MODE		0x00000200
+#define	MASTER_MANUAL_INTR_ENB	0x00000200
+#define	MASTER_IM_TX_TIMER_ENB	0x00000400
+#define	MASTER_IM_RX_TIMER_ENB	0x00000800
+#define	MASTER_CLK_SEL_DIS	0x00001000
+#define	MASTER_CLK_SWH_MODE	0x00002000
+#define	MASTER_INTR_RD_CLR	0x00004000
 #define	MASTER_CHIP_REV_MASK	0x00FF0000
 #define	MASTER_CHIP_ID_MASK	0xFF000000
+#define	MASTER_CHIP_ID_MASKXXX	0x7F000000 /* XXX */
+#define	MASTER_OTP_SEL		0x80000000
+#define	MASTER_TEST_MODE_SHIFT	2
 #define	MASTER_CHIP_REV_SHIFT	16
 #define	MASTER_CHIP_ID_SHIFT	24
 
@@ -67,6 +103,12 @@
 #define	IDLE_STATUS_SMB		0x00000040
 #define	IDLE_STATUS_CMB		0x00000080
 
+#define	ATGE_SERDES_LOCK		0x1424
+#define	SERDES_LOCK_DET			0x00000001
+#define	SERDES_LOCK_DET_ENB		0x00000002
+#define	SERDES_MAC_CLK_SLOWDOWN		0x00020000
+#define	SERDES_PHY_CLK_SLOWDOWN		0x00040000
+
 #define	ATGE_MAC_CFG			0x1480
 #define	ATGE_CFG_TX_ENB			0x00000001
 #define	ATGE_CFG_RX_ENB			0x00000002
@@ -93,6 +135,9 @@
 #define	ATGE_CFG_ALLMULTI		0x02000000
 #define	ATGE_CFG_BCAST			0x04000000
 #define	ATGE_CFG_DBG			0x08000000
+#define	ATGE_CFG_SINGLE_PAUSE_ENB	0x10000000
+#define	ATGE_CFG_HASH_ALG_CRC32		0x20000000
+#define	ATGE_CFG_SPEED_MODE_SW		0x40000000
 #define	ATGE_CFG_PREAMBLE_SHIFT		10
 #define	ATGE_CFG_PREAMBLE_DEFAULT	7
 
@@ -116,7 +161,7 @@
 #define	INTR_GPHY			0x00001000
 #define	INTR_RX_PKT			0x00010000
 #define	INTR_TX_PKT			0x00020000
-#define	INTR_TX_DMA			0x00040000
+#define	INTR_TX_DMA			0x00040000	/* L1 intr status */
 #define	INTR_MAC_RX			0x00400000
 #define	INTR_MAC_TX			0x00800000
 #define	INTR_UNDERRUN			0x01000000
@@ -133,9 +178,6 @@
 #define	INTR_RX_PKT2			0x00100000
 #define	INTR_RX_PKT3			0x00200000
 
-/* L1 intr status */
-#define	INTR_TX_DMA			0x00040000
-
 /*
  * L1E specific errors. We keep it here since some errors are common for
  * both L1 and L1E chip.
@@ -158,11 +200,6 @@
 #define	TXQ_CFG_TX_FIFO_BURST_DEFAULT	256
 
 /*
- * RXQ CFG register.
- */
-#define	ATGE_RXQ_CFG			0x15A0
-
-/*
  * Common registers for DMA CFG.
  */
 #define	ATGE_DMA_CFG			0x15C0
@@ -237,6 +274,113 @@
 #define	ATGE_DMA_BLOCK			0x1534
 #define	DMA_BLOCK_LOAD			0x00000001
 
+/* From Freebsd if_alcreg.h */
+/* 0x0000 - 0x02FF : PCIe configuration space */
+
+#define	ATGE_PEX_UNC_ERR_SEV		0x10C
+#define	PEX_UNC_ERR_SEV_TRN		0x00000001
+#define	PEX_UNC_ERR_SEV_DLP		0x00000010
+#define	PEX_UNC_ERR_SEV_PSN_TLP		0x00001000
+#define	PEX_UNC_ERR_SEV_FCP		0x00002000
+#define	PEX_UNC_ERR_SEV_CPL_TO		0x00004000
+#define	PEX_UNC_ERR_SEV_CA		0x00008000
+#define	PEX_UNC_ERR_SEV_UC		0x00010000
+#define	PEX_UNC_ERR_SEV_ROV		0x00020000
+#define	PEX_UNC_ERR_SEV_MLFP		0x00040000
+#define	PEX_UNC_ERR_SEV_ECRC		0x00080000
+#define	PEX_UNC_ERR_SEV_UR		0x00100000
+
+#define	ATGE_PCIE_PHYMISC		0x1000
+#define	PCIE_PHYMISC_FORCE_RCV_DET	0x00000004
+
+#define	ATGE_PCIE_PHYMISC2		0x1004
+#define	PCIE_PHYMISC2_SERDES_CDR_MASK	0x00030000
+#define	PCIE_PHYMISC2_SERDES_TH_MASK	0x000C0000
+#define	PCIE_PHYMISC2_SERDES_CDR_SHIFT	16
+#define	PCIE_PHYMISC2_SERDES_TH_SHIFT	18
+
+#define	ATGE_LTSSM_ID_CFG		0x12FC
+#define	LTSSM_ID_WRO_ENB		0x00001000
+
+#define	ATGE_SMB_STAT_TIMER		0x15C4
+#define	SMB_STAT_TIMER_MASK		0x00FFFFFF
+#define	SMB_STAT_TIMER_SHIFT		0
+
+#define	ATGE_CMB_TD_THRESH		0x15C8
+#define	CMB_TD_THRESH_MASK		0x0000FFFF
+#define	CMB_TD_THRESH_SHIFT		0
+
+#define	ATGE_CMB_TX_TIMER		0x15CC
+#define	CMB_TX_TIMER_MASK		0x0000FFFF
+#define	CMB_TX_TIMER_SHIFT		0
+
+#define	ATGE_MBOX_RD0_PROD_IDX		0x15E0
+
+#define	ATGE_MBOX_RD1_PROD_IDX		0x15E4
+
+#define	ATGE_MBOX_RD2_PROD_IDX		0x15E8
+
+#define	ATGE_MBOX_RD3_PROD_IDX		0x15EC
+
+#define	ATGE_MBOX_RD_PROD_MASK		0x0000FFFF
+#define	MBOX_RD_PROD_SHIFT		0
+
+#define	ATGE_MBOX_TD_PROD_IDX		0x15F0
+#define	MBOX_TD_PROD_HI_IDX_MASK	0x0000FFFF
+#define	MBOX_TD_PROD_LO_IDX_MASK	0xFFFF0000
+#define	MBOX_TD_PROD_HI_IDX_SHIFT	0
+#define	MBOX_TD_PROD_LO_IDX_SHIFT	16
+
+#define	ATGE_MBOX_TD_CONS_IDX		0x15F4
+#define	MBOX_TD_CONS_HI_IDX_MASK	0x0000FFFF
+#define	MBOX_TD_CONS_LO_IDX_MASK	0xFFFF0000
+#define	MBOX_TD_CONS_HI_IDX_SHIFT	0
+#define	MBOX_TD_CONS_LO_IDX_SHIFT	16
+
+#define	ATGE_MBOX_RD01_CONS_IDX		0x15F8
+#define	MBOX_RD0_CONS_IDX_MASK		0x0000FFFF
+#define	MBOX_RD1_CONS_IDX_MASK		0xFFFF0000
+#define	MBOX_RD0_CONS_IDX_SHIFT		0
+#define	MBOX_RD1_CONS_IDX_SHIFT		16
+
+#define	ATGE_MBOX_RD23_CONS_IDX		0x15FC
+#define	MBOX_RD2_CONS_IDX_MASK		0x0000FFFF
+#define	MBOX_RD3_CONS_IDX_MASK		0xFFFF0000
+#define	MBOX_RD2_CONS_IDX_SHIFT		0
+#define	MBOX_RD3_CONS_IDX_SHIFT		16
+
+#define	ATGE_INTR_RETRIG_TIMER		0x1608
+#define	INTR_RETRIG_TIMER_MASK		0x0000FFFF
+#define	INTR_RETRIG_TIMER_SHIFT		0
+
+#define	ATGE_HDS_CFG			0x160C
+#define	HDS_CFG_ENB			0x00000001
+#define	HDS_CFG_BACKFILLSIZE_MASK	0x000FFF00
+#define	HDS_CFG_MAX_HDRSIZE_MASK	0xFFF00000
+#define	HDS_CFG_BACKFILLSIZE_SHIFT	8
+#define	HDS_CFG_MAX_HDRSIZE_SHIFT	20
+
+/* AR813x/AR815x registers for MAC statistics */
+#define	ATGE_RX_MIB_BASE		0x1700
+
+#define	ATGE_TX_MIB_BASE		0x1760
+
+#define	ATGE_CLK_GATING_CFG		0x1814
+#define	CLK_GATING_DMAW_ENB		0x0001
+#define	CLK_GATING_DMAR_ENB		0x0002
+#define	CLK_GATING_TXQ_ENB		0x0004
+#define	CLK_GATING_RXQ_ENB		0x0008
+#define	CLK_GATING_TXMAC_ENB		0x0010
+#define	CLK_GATING_RXMAC_ENB		0x0020
+
+#define	ATGE_DEBUG_DATA0		0x1900
+
+#define	ATGE_DEBUG_DATA1		0x1904
+
+#define	ATGE_MII_DBG_ADDR		0x1D
+#define	ATGE_MII_DBG_DATA		0x1E
+/* End Freebsd if_alcreg.h */
+
 #define	ATGE_MBOX			0x15F0
 #define	MBOX_RD_PROD_IDX_MASK		0x000007FF
 #define	MBOX_RRD_CONS_IDX_MASK		0x003FF800
@@ -349,8 +493,10 @@
 #define	RXQ_FIFO_PAUSE_THRESH_LO_SHIFT	0
 #define	RXQ_FIFO_PAUSE_THRESH_HI_SHIFT	16
 
+/*
+ * RXQ CFG register.
+ */
 #define	ATGE_RXQ_CFG			0x15A0
-#define	ATGE_TXQ_CFG			0x1580
 #define	RXQ_CFG_ALIGN_32		0x00000000
 #define	RXQ_CFG_ALIGN_64		0x00000001
 #define	RXQ_CFG_ALIGN_128		0x00000002
@@ -381,6 +527,81 @@
 #define	ATPHY_DBG_ADDR			0x1D
 #define	ATPHY_DBG_DATA			0x1E
 
+/* From Freebsd if_alcreg.h */
+#define	MII_ANA_CFG0			0x00
+#define	ANA_RESTART_CAL			0x0001
+#define	ANA_MANUL_SWICH_ON_MASK		0x001E
+#define	ANA_MAN_ENABLE			0x0020
+#define	ANA_SEL_HSP			0x0040
+#define	ANA_EN_HB			0x0080
+#define	ANA_EN_HBIAS			0x0100
+#define	ANA_OEN_125M			0x0200
+#define	ANA_EN_LCKDT			0x0400
+#define	ANA_LCKDT_PHY			0x0800
+#define	ANA_AFE_MODE			0x1000
+#define	ANA_VCO_SLOW			0x2000
+#define	ANA_VCO_FAST			0x4000
+#define	ANA_SEL_CLK125M_DSP		0x8000
+#define	ANA_MANUL_SWICH_ON_SHIFT	1
+
+#define	MII_ANA_CFG4			0x04
+#define	ANA_IECHO_ADJ_MASK		0x0F
+#define	ANA_IECHO_ADJ_3_MASK		0x000F
+#define	ANA_IECHO_ADJ_2_MASK		0x00F0
+#define	ANA_IECHO_ADJ_1_MASK		0x0F00
+#define	ANA_IECHO_ADJ_0_MASK		0xF000
+#define	ANA_IECHO_ADJ_3_SHIFT		0
+#define	ANA_IECHO_ADJ_2_SHIFT		4
+#define	ANA_IECHO_ADJ_1_SHIFT		8
+#define	ANA_IECHO_ADJ_0_SHIFT		12
+
+#define	MII_ANA_CFG5			0x05
+#define	ANA_SERDES_CDR_BW_MASK		0x0003
+#define	ANA_MS_PAD_DBG			0x0004
+#define	ANA_SPEEDUP_DBG			0x0008
+#define	ANA_SERDES_TH_LOS_MASK		0x0030
+#define	ANA_SERDES_EN_DEEM		0x0040
+#define	ANA_SERDES_TXELECIDLE		0x0080
+#define	ANA_SERDES_BEACON		0x0100
+#define	ANA_SERDES_HALFTXDR		0x0200
+#define	ANA_SERDES_SEL_HSP		0x0400
+#define	ANA_SERDES_EN_PLL		0x0800
+#define	ANA_SERDES_EN			0x1000
+#define	ANA_SERDES_EN_LCKDT		0x2000
+#define	ANA_SERDES_CDR_BW_SHIFT		0
+#define	ANA_SERDES_TH_LOS_SHIFT		4
+
+#define	MII_ANA_CFG11			0x0B
+#define	ANA_PS_HIB_EN			0x8000
+
+#define	MII_ANA_CFG18			0x12
+#define	ANA_TEST_MODE_10BT_01MASK	0x0003
+#define	ANA_LOOP_SEL_10BT		0x0004
+#define	ANA_RGMII_MODE_SW		0x0008
+#define	ANA_EN_LONGECABLE		0x0010
+#define	ANA_TEST_MODE_10BT_2		0x0020
+#define	ANA_EN_10BT_IDLE		0x0400
+#define	ANA_EN_MASK_TB			0x0800
+#define	ANA_TRIGGER_SEL_TIMER_MASK	0x3000
+#define	ANA_INTERVAL_SEL_TIMER_MASK	0xC000
+#define	ANA_TEST_MODE_10BT_01SHIFT	0
+#define	ANA_TRIGGER_SEL_TIMER_SHIFT	12
+#define	ANA_INTERVAL_SEL_TIMER_SHIFT	14
+
+#define	MII_ANA_CFG41			0x29
+#define	ANA_TOP_PS_EN			0x8000
+
+#define	MII_ANA_CFG54			0x36
+#define	ANA_LONG_CABLE_TH_100_MASK	0x003F
+#define	ANA_DESERVED			0x0040
+#define	ANA_EN_LIT_CH			0x0080
+#define	ANA_SHORT_CABLE_TH_100_MASK	0x3F00
+#define	ANA_BP_BAD_LINK_ACCUM		0x4000
+#define	ANA_BP_SMALL_BW			0x8000
+#define	ANA_LONG_CABLE_TH_100_SHIFT	0
+#define	ANA_SHORT_CABLE_TH_100_SHIFT	8
+/* End Freebsd if_alcreg.h */
+
 #define	ATGE_TD_EOP			0x00000001
 #define	ATGE_TD_BUFLEN_MASK		0x00003FFF
 #define	ATGE_TD_BUFLEN_SHIFT		0
--- a/usr/src/uts/common/io/atge/atge_l1_reg.h	Tue Aug 07 21:36:09 2012 -0500
+++ b/usr/src/uts/common/io/atge/atge_l1_reg.h	Fri Aug 10 10:52:49 2012 -0400
@@ -21,6 +21,7 @@
 /*
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright (c) 2012 Gary Mills
  */
 
 #ifndef _ATGE_L1_REG_H
@@ -181,7 +182,6 @@
 /*
  * PHY registers.
  */
-#define	L1_CSMB_CTRL		0x15D0
 #define	PHY_CDTS_STAT_OK	0x0000
 #define	PHY_CDTS_STAT_SHORT	0x0100
 #define	PHY_CDTS_STAT_OPEN	0x0200
@@ -198,8 +198,6 @@
 #define	DMA_CFG_WR_BURST_MASK	0x07
 #define	DMA_CFG_WR_BURST_SHIFT	7
 
-#define	RXQ_CFG_ENB		0x80000000
-
 #define	L1_RD_LEN_MASK		0x0000FFFF
 #define	L1_RD_LEN_SHIFT	0
 
@@ -219,8 +217,6 @@
 #define	RXQ_CFG_RD_BURST_MASK		0x000000FF
 #define	RXQ_CFG_RRD_BURST_THRESH_MASK	0x0000FF00
 #define	RXQ_CFG_RD_PREF_MIN_IPG_MASK	0x001F0000
-#define	RXQ_CFG_CUT_THROUGH_ENB		0x40000000
-#define	RXQ_CFG_ENB			0x80000000
 #define	RXQ_CFG_RD_BURST_SHIFT		0
 #define	RXQ_CFG_RD_BURST_DEFAULT	8
 #define	RXQ_CFG_RRD_BURST_THRESH_SHIFT	8
@@ -228,16 +224,9 @@
 #define	RXQ_CFG_RD_PREF_MIN_IPG_SHIFT	16
 #define	RXQ_CFG_RD_PREF_MIN_IPG_DEFAULT	1
 
-#define	TXQ_CFG_ENB			0x00000020
-#define	TXQ_CFG_ENHANCED_MODE		0x00000040
 #define	TXQ_CFG_TPD_FETCH_THRESH_MASK	0x00003F00
-#define	TXQ_CFG_TX_FIFO_BURST_MASK	0xFFFF0000
-#define	TXQ_CFG_TPD_BURST_SHIFT		0
-#define	TXQ_CFG_TPD_BURST_DEFAULT	4
 #define	TXQ_CFG_TPD_FETCH_THRESH_SHIFT	8
 #define	TXQ_CFG_TPD_FETCH_DEFAULT	16
-#define	TXQ_CFG_TX_FIFO_BURST_SHIFT	16
-#define	TXQ_CFG_TX_FIFO_BURST_DEFAULT	256
 
 #define	L1_TX_JUMBO_TPD_TH_IPG		0x1584
 #define	TX_JUMBO_TPD_TH_MASK		0x000007FF
@@ -264,22 +253,10 @@
 #define	CSMB_CTRL_CMB_ENB		0x00000004
 #define	CSMB_CTRL_SMB_ENB		0x00000008
 
-#define	INTR_TX_FIFO_UNDERRUN		0x00000040
-#define	INTR_RX_FIFO_OFLOW		0x00000008
-#define	INTR_TX_DMA			0x00040000
 #define	INTR_RX_DMA			0x00080000
 #define	INTR_CMB_RX			0x00100000
 #define	INTR_CMB_TX			0x00200000
-#define	INTR_MAC_RX			0x00400000
-#define	INTR_MAC_TX			0x00800000
-#define	INTR_UNDERRUN			0x01000000
-#define	INTR_FRAME_ERROR		0x02000000
-#define	INTR_FRAME_OK			0x04000000
-#define	INTR_CSUM_ERROR			0x08000000
-#define	INTR_PHY_LINK_DOWN		0x10000000
 #define	INTR_DIS_SMB			0x20000000
-#define	INTR_DIS_DMA			0x40000000
-#define	INTR_DIS_INT			0x80000000
 
 #define	L1_INTRS	\
 	(INTR_SMB | INTR_DMA_RD_TO_RST | INTR_DMA_WR_TO_RST |	\
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/atge/atge_l1c.c	Fri Aug 10 10:52:49 2012 -0400
@@ -0,0 +1,1034 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2012 Gary Mills
+ *
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2009, Pyun YongHyeon <yongari@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/stream.h>
+#include <sys/strsun.h>
+#include <sys/stat.h>
+#include <sys/modctl.h>
+#include <sys/ethernet.h>
+#include <sys/debug.h>
+#include <sys/conf.h>
+#include <sys/mii.h>
+#include <sys/miiregs.h>
+#include <sys/sysmacros.h>
+#include <sys/dditypes.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/byteorder.h>
+#include <sys/note.h>
+#include <sys/vlan.h>
+#include <sys/stream.h>
+
+#include "atge.h"
+#include "atge_l1c_reg.h"
+#include "atge_cmn_reg.h"
+
+static ddi_dma_attr_t atge_l1c_dma_attr_tx_desc = {
+	DMA_ATTR_V0,		/* dma_attr_version */
+	0,			/* dma_attr_addr_lo */
+	0x0000ffffffffull,	/* dma_attr_addr_hi */
+	0x0000ffffffffull,	/* dma_attr_count_max */
+	L1C_TX_RING_ALIGN,	/* dma_attr_align */
+	0x0000fffc,		/* dma_attr_burstsizes */
+	1,			/* dma_attr_minxfer */
+	0x0000ffffffffull,	/* dma_attr_maxxfer */
+	0x0000ffffffffull,	/* dma_attr_seg */
+	1,			/* dma_attr_sgllen */
+	1,			/* dma_attr_granular */
+	0			/* dma_attr_flags */
+};
+
+static ddi_dma_attr_t atge_l1c_dma_attr_rx_desc = {
+	DMA_ATTR_V0,		/* dma_attr_version */
+	0,			/* dma_attr_addr_lo */
+	0x0000ffffffffull,	/* dma_attr_addr_hi */
+	0x0000ffffffffull,	/* dma_attr_count_max */
+	L1C_RX_RING_ALIGN,	/* dma_attr_align */
+	0x0000fffc,		/* dma_attr_burstsizes */
+	1,			/* dma_attr_minxfer */
+	0x0000ffffffffull,	/* dma_attr_maxxfer */
+	0x0000ffffffffull,	/* dma_attr_seg */
+	1,			/* dma_attr_sgllen */
+	1,			/* dma_attr_granular */
+	0			/* dma_attr_flags */
+};
+
+static ddi_dma_attr_t atge_l1c_dma_attr_cmb = {
+	DMA_ATTR_V0,		/* dma_attr_version */
+	0,			/* dma_attr_addr_lo */
+	0x0000ffffffffull,	/* dma_attr_addr_hi */
+	0x0000ffffffffull,	/* dma_attr_count_max */
+	L1C_CMB_ALIGN,		/* dma_attr_align */
+	0x0000fffc,		/* dma_attr_burstsizes */
+	1,			/* dma_attr_minxfer */
+	0x0000ffffffffull,	/* dma_attr_maxxfer */
+	0x0000ffffffffull,	/* dma_attr_seg */
+	1,			/* dma_attr_sgllen */
+	1,			/* dma_attr_granular */
+	0			/* dma_attr_flags */
+};
+
+static ddi_dma_attr_t atge_l1c_dma_attr_smb = {
+	DMA_ATTR_V0,		/* dma_attr_version */
+	0,			/* dma_attr_addr_lo */
+	0x0000ffffffffull,	/* dma_attr_addr_hi */
+	0x0000ffffffffull,	/* dma_attr_count_max */
+	L1C_SMB_ALIGN,		/* dma_attr_align */
+	0x0000fffc,		/* dma_attr_burstsizes */
+	1,			/* dma_attr_minxfer */
+	0x0000ffffffffull,	/* dma_attr_maxxfer */
+	0x0000ffffffffull,	/* dma_attr_seg */
+	1,			/* dma_attr_sgllen */
+	1,			/* dma_attr_granular */
+	0			/* dma_attr_flags */
+};
+
+static ddi_dma_attr_t atge_l1c_dma_attr_rr = {
+	DMA_ATTR_V0,		/* dma_attr_version */
+	0,			/* dma_attr_addr_lo */
+	0x0000ffffffffull,	/* dma_attr_addr_hi */
+	0x0000ffffffffull,	/* dma_attr_count_max */
+	L1C_RR_RING_ALIGN,	/* dma_attr_align */
+	0x0000fffc,		/* dma_attr_burstsizes */
+	1,			/* dma_attr_minxfer */
+	0x0000ffffffffull,	/* dma_attr_maxxfer */
+	0x0000ffffffffull,	/* dma_attr_seg */
+	1,			/* dma_attr_sgllen */
+	1,			/* dma_attr_granular */
+	0			/* dma_attr_flags */
+};
+
+int
+atge_l1c_alloc_dma(atge_t *atgep)
+{
+	atge_l1c_data_t *l1c;
+	atge_dma_t *dma;
+	int err;
+
+	l1c = kmem_zalloc(sizeof (atge_l1c_data_t), KM_SLEEP);
+	atgep->atge_private_data = l1c;
+
+	/*
+	 * Allocate TX ring descriptor.
+	 */
+	atgep->atge_tx_buf_len = atgep->atge_mtu +
+	    sizeof (struct ether_header) + VLAN_TAGSZ + ETHERFCSL;
+	atgep->atge_tx_ring = kmem_alloc(sizeof (atge_ring_t), KM_SLEEP);
+	atgep->atge_tx_ring->r_atge = atgep;
+	atgep->atge_tx_ring->r_desc_ring = NULL;
+	dma = atge_alloc_a_dma_blk(atgep, &atge_l1c_dma_attr_tx_desc,
+	    ATGE_TX_RING_SZ, DDI_DMA_RDWR);
+	if (dma == NULL) {
+		atge_error(atgep->atge_dip, "DMA allocation failed for TX"
+		    " desc ring");
+		return (DDI_FAILURE);
+	}
+	atgep->atge_tx_ring->r_desc_ring = dma;
+
+	/*
+	 * Allocate DMA buffers for TX ring.
+	 */
+	err = atge_alloc_buffers(atgep->atge_tx_ring, ATGE_TX_RING_CNT,
+	    atgep->atge_tx_buf_len, DDI_DMA_WRITE);
+	if (err != DDI_SUCCESS) {
+		atge_error(atgep->atge_dip, "DMA allocation failed for"
+		    " TX Ring");
+		return (err);
+	}
+
+	/*
+	 * Allocate RX ring.
+	 */
+	atgep->atge_rx_buf_len = atgep->atge_mtu +
+	    sizeof (struct ether_header) + VLAN_TAGSZ + ETHERFCSL;
+	l1c->atge_rx_ring = kmem_alloc(sizeof (atge_ring_t), KM_SLEEP);
+	l1c->atge_rx_ring->r_atge = atgep;
+	l1c->atge_rx_ring->r_desc_ring = NULL;
+	dma = atge_alloc_a_dma_blk(atgep, &atge_l1c_dma_attr_rx_desc,
+	    L1C_RX_RING_SZ, DDI_DMA_RDWR);
+	if (dma == NULL) {
+		atge_error(atgep->atge_dip, "DMA allocation failed"
+		    " for RX Ring");
+		return (DDI_FAILURE);
+	}
+	l1c->atge_rx_ring->r_desc_ring = dma;
+
+	/*
+	 * Allocate DMA buffers for RX ring.
+	 */
+	err = atge_alloc_buffers(l1c->atge_rx_ring, L1C_RX_RING_CNT,
+	    atgep->atge_rx_buf_len, DDI_DMA_READ);
+	if (err != DDI_SUCCESS) {
+		atge_error(atgep->atge_dip, "DMA allocation failed for"
+		    " RX buffers");
+		return (err);
+	}
+
+	/*
+	 * Allocate CMB used for fetching interrupt status data.
+	 */
+	ATGE_DB(("%s: %s() L1C_CMB_BLOCK_SZ : 0x%x", atgep->atge_name,
+	    __func__, L1C_CMB_BLOCK_SZ));
+
+	dma = atge_alloc_a_dma_blk(atgep, &atge_l1c_dma_attr_cmb,
+	    L1C_CMB_BLOCK_SZ, DDI_DMA_RDWR);
+	l1c->atge_l1c_cmb = dma;
+	if (dma == NULL) {
+		atge_error(atgep->atge_dip, "DMA allocation failed for CMB");
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * RR ring (Return Ring for RX and TX).
+	 */
+	ATGE_DB(("%s: %s() L1C_RR_RING_SZ : 0x%x", atgep->atge_name,
+	    __func__, L1C_RR_RING_SZ));
+
+	dma = atge_alloc_a_dma_blk(atgep, &atge_l1c_dma_attr_rr,
+	    L1C_RR_RING_SZ, DDI_DMA_RDWR);
+	l1c->atge_l1c_rr = dma;
+	if (dma == NULL) {
+		atge_error(atgep->atge_dip, "DMA allocation failed"
+		    " for RX RR ring");
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * SMB for statistics.
+	 */
+	ATGE_DB(("%s: %s() L1C_SMB_BLOCK_SZ : 0x%x", atgep->atge_name,
+	    __func__, L1C_SMB_BLOCK_SZ));
+
+	dma = atge_alloc_a_dma_blk(atgep, &atge_l1c_dma_attr_smb,
+	    L1C_SMB_BLOCK_SZ, DDI_DMA_RDWR);
+	l1c->atge_l1c_smb = dma;
+	if (dma == NULL) {
+		atge_error(atgep->atge_dip, "DMA allocation failed for SMB");
+		return (DDI_FAILURE);
+	}
+
+	atgep->atge_hw_stats = kmem_zalloc(sizeof (atge_l1c_smb_t), KM_SLEEP);
+
+	return (DDI_SUCCESS);
+}
+
+void
+atge_l1c_free_dma(atge_t *atgep)
+{
+	atge_l1c_data_t *l1c;
+
+	l1c = atgep->atge_private_data;
+
+	/*
+	 * Free TX ring.
+	 */
+	if (atgep->atge_tx_ring != NULL) {
+		atge_free_buffers(atgep->atge_tx_ring,  ATGE_TX_RING_CNT);
+
+		if (atgep->atge_tx_ring->r_desc_ring != NULL) {
+			atge_free_a_dma_blk(atgep->atge_tx_ring->r_desc_ring);
+		}
+
+		kmem_free(atgep->atge_tx_ring, sizeof (atge_ring_t));
+		atgep->atge_tx_ring = NULL;
+	}
+
+	if (l1c && l1c->atge_l1c_cmb != NULL) {
+		atge_free_a_dma_blk(l1c->atge_l1c_cmb);
+		l1c->atge_l1c_cmb = NULL;
+	}
+
+	if (l1c && l1c->atge_l1c_rr != NULL) {
+		atge_free_a_dma_blk(l1c->atge_l1c_rr);
+		l1c->atge_l1c_rr = NULL;
+	}
+
+	if (l1c && l1c->atge_l1c_smb != NULL) {
+		atge_free_a_dma_blk(l1c->atge_l1c_smb);
+		l1c->atge_l1c_smb = NULL;
+	}
+
+	/*
+	 * Free RX ring.
+	 */
+	if (l1c && l1c->atge_rx_ring != NULL) {
+		atge_free_buffers(l1c->atge_rx_ring,  L1C_RX_RING_CNT);
+
+		if (l1c->atge_rx_ring->r_desc_ring != NULL) {
+			atge_free_a_dma_blk(l1c->atge_rx_ring->r_desc_ring);
+		}
+
+		kmem_free(l1c->atge_rx_ring, sizeof (atge_ring_t));
+		l1c->atge_rx_ring = NULL;
+	}
+
+	/*
+	 * Free the memory allocated for gathering hw stats.
+	 */
+	if (atgep->atge_hw_stats != NULL) {
+		kmem_free(atgep->atge_hw_stats, sizeof (atge_l1c_smb_t));
+		atgep->atge_hw_stats = NULL;
+	}
+
+	/*
+	 * Free the private area.
+	 */
+	if (l1c != NULL) {
+		kmem_free(l1c, sizeof (atge_l1c_data_t));
+		atgep->atge_private_data = NULL;
+	}
+}
+
+void
+atge_l1c_init_rx_ring(atge_t *atgep)
+{
+	atge_l1c_data_t *l1c;
+	atge_dma_t *dma;
+	l1c_rx_desc_t *rx;
+	int i;
+
+	l1c = atgep->atge_private_data;
+	l1c->atge_rx_ring->r_consumer = L1C_RX_RING_CNT - 1;
+	dma = l1c->atge_rx_ring->r_desc_ring;
+	bzero(dma->addr, L1C_RX_RING_SZ);
+
+	for (i = 0; i < L1C_RX_RING_CNT; i++) {
+		rx = (l1c_rx_desc_t *)(dma->addr +
+		    (i * sizeof (l1c_rx_desc_t)));
+
+		ATGE_PUT64(dma, &rx->addr,
+		    l1c->atge_rx_ring->r_buf_tbl[i]->cookie.dmac_laddress);
+		/* No length field. */
+	}
+
+	DMA_SYNC(dma, 0, 0, DDI_DMA_SYNC_FORDEV);
+	/* Let controller know availability of new Rx buffers. */
+	OUTL(atgep, ATGE_MBOX_RD0_PROD_IDX, l1c->atge_rx_ring->r_consumer);
+}
+
+void
+atge_l1c_init_tx_ring(atge_t *atgep)
+{
+	atgep->atge_tx_ring->r_producer = 0;
+	atgep->atge_tx_ring->r_consumer = 0;
+	atgep->atge_tx_ring->r_avail_desc = ATGE_TX_RING_CNT;
+
+	bzero(atgep->atge_tx_ring->r_desc_ring->addr, ATGE_TX_RING_SZ);
+	DMA_SYNC(atgep->atge_tx_ring->r_desc_ring, 0, 0, DDI_DMA_SYNC_FORDEV);
+}
+
+void
+atge_l1c_init_rr_ring(atge_t *atgep)
+{
+	atge_l1c_data_t *l1c;
+	atge_dma_t *dma;
+
+	l1c = atgep->atge_private_data;
+	l1c->atge_l1c_rr_consumers = 0;
+
+	dma = l1c->atge_l1c_rr;
+	bzero(dma->addr, L1C_RR_RING_SZ);
+	DMA_SYNC(dma, 0, 0, DDI_DMA_SYNC_FORDEV);
+}
+
+void
+atge_l1c_init_smb(atge_t *atgep)
+{
+	atge_l1c_data_t *l1c;
+	atge_dma_t *dma;
+
+	l1c = atgep->atge_private_data;
+	dma = l1c->atge_l1c_smb;
+	bzero(dma->addr, L1C_SMB_BLOCK_SZ);
+	DMA_SYNC(dma, 0, 0, DDI_DMA_SYNC_FORDEV);
+}
+
+void
+atge_l1c_init_cmb(atge_t *atgep)
+{
+	atge_l1c_data_t *l1c;
+	atge_dma_t *dma;
+
+	l1c = atgep->atge_private_data;
+	dma = l1c->atge_l1c_cmb;
+	bzero(dma->addr, L1C_CMB_BLOCK_SZ);
+	DMA_SYNC(dma, 0, 0, DDI_DMA_SYNC_FORDEV);
+}
+
+void
+atge_l1c_program_dma(atge_t *atgep)
+{
+	atge_l1c_data_t *l1c;
+	atge_ring_t *r;
+	uint32_t reg;
+
+	l1c = atgep->atge_private_data;
+
+	/*
+	 * Clear WOL status and disable all WOL feature as WOL
+	 * would interfere Rx operation under normal environments.
+	 */
+	(void) INL(atgep, ATGE_WOL_CFG);
+	OUTL(atgep, ATGE_WOL_CFG, 0);
+
+	/* TX */
+	r = atgep->atge_tx_ring;
+	OUTL(atgep, L1C_TX_BASE_ADDR_HI,
+	    ATGE_ADDR_HI(r->r_desc_ring->cookie.dmac_laddress));
+	OUTL(atgep, L1C_TDL_HEAD_ADDR_LO,
+	    ATGE_ADDR_LO(r->r_desc_ring->cookie.dmac_laddress));
+	/* We don't use high priority ring. */
+	OUTL(atgep, L1C_TDH_HEAD_ADDR_LO, 0);
+
+	/* RX */
+	r = l1c->atge_rx_ring;
+	OUTL(atgep, L1C_RX_BASE_ADDR_HI,
+	    ATGE_ADDR_HI(r->r_desc_ring->cookie.dmac_laddress));
+	OUTL(atgep, L1C_RD0_HEAD_ADDR_LO,
+	    ATGE_ADDR_LO(r->r_desc_ring->cookie.dmac_laddress));
+	/* We use one Rx ring. */
+	OUTL(atgep, L1C_RD1_HEAD_ADDR_LO, 0);
+	OUTL(atgep, L1C_RD2_HEAD_ADDR_LO, 0);
+	OUTL(atgep, L1C_RD3_HEAD_ADDR_LO, 0);
+
+	/* RR Ring */
+	/*
+	 * Let hardware split jumbo frames into alc_max_buf_sized chunks.
+	 * if it do not fit the buffer size. Rx return descriptor holds
+	 * a counter that indicates how many fragments were made by the
+	 * hardware. The buffer size should be multiple of 8 bytes.
+	 * Since hardware has limit on the size of buffer size, always
+	 * use the maximum value.
+	 * For strict-alignment architectures make sure to reduce buffer
+	 * size by 8 bytes to make room for alignment fixup.
+	 */
+	OUTL(atgep, L1C_RX_BUF_SIZE, RX_BUF_SIZE_MAX); /* XXX */
+
+	/* Set Rx return descriptor base addresses. */
+	OUTL(atgep, L1C_RRD0_HEAD_ADDR_LO,
+	    ATGE_ADDR_LO(l1c->atge_l1c_rr->cookie.dmac_laddress));
+	/* We use one Rx return ring. */
+	OUTL(atgep, L1C_RRD1_HEAD_ADDR_LO, 0);
+	OUTL(atgep, L1C_RRD2_HEAD_ADDR_LO, 0);
+	OUTL(atgep, L1C_RRD3_HEAD_ADDR_LO, 0);
+
+	/* CMB */
+	OUTL(atgep, L1C_CMB_BASE_ADDR_LO,
+	    ATGE_ADDR_LO(l1c->atge_l1c_cmb->cookie.dmac_laddress));
+
+	/* SMB */
+	OUTL(atgep, L1C_SMB_BASE_ADDR_HI,
+	    ATGE_ADDR_HI(l1c->atge_l1c_smb->cookie.dmac_laddress));
+	OUTL(atgep, L1C_SMB_BASE_ADDR_LO,
+	    ATGE_ADDR_LO(l1c->atge_l1c_smb->cookie.dmac_laddress));
+
+	/*
+	 * Set RX return ring (RR) counter.
+	 */
+	/* Set Rx descriptor counter. */
+	OUTL(atgep, L1C_RD_RING_CNT,
+	    (L1C_RX_RING_CNT << RD_RING_CNT_SHIFT) & RD_RING_CNT_MASK);
+	/* Set Rx return descriptor counter. */
+	OUTL(atgep, L1C_RRD_RING_CNT,
+	    (L1C_RR_RING_CNT << RRD_RING_CNT_SHIFT) & RRD_RING_CNT_MASK);
+
+	/*
+	 * Set TX descriptor counter.
+	 */
+	OUTL(atgep, L1C_TD_RING_CNT,
+	    (ATGE_TX_RING_CNT << TD_RING_CNT_SHIFT) & TD_RING_CNT_MASK);
+
+	switch (ATGE_DID(atgep)) {
+	case ATGE_CHIP_AR8152V1_DEV_ID:
+		/* Reconfigure SRAM - Vendor magic. */
+		OUTL(atgep, L1C_SRAM_RX_FIFO_LEN, 0x000002A0);
+		OUTL(atgep, L1C_SRAM_TX_FIFO_LEN, 0x00000100);
+		OUTL(atgep, L1C_SRAM_RX_FIFO_ADDR, 0x029F0000);
+		OUTL(atgep, L1C_SRAM_RD_ADDR, 0x02BF02A0);
+		OUTL(atgep, L1C_SRAM_TX_FIFO_ADDR, 0x03BF02C0);
+		OUTL(atgep, L1C_SRAM_TRD_ADDR, 0x03DF03C0);
+		OUTL(atgep, L1C_TXF_WATER_MARK, 0x00000000);
+		OUTL(atgep, L1C_RD_DMA_CFG, 0x00000000);
+		break;
+	}
+
+	/*
+	 * Inform hardware that we have loaded DMA registers.
+	 */
+	OUTL(atgep, ATGE_DMA_BLOCK, DMA_BLOCK_LOAD);
+
+	/* Configure interrupt moderation timer. */
+	reg = ATGE_USECS(atgep->atge_int_rx_mod) << IM_TIMER_RX_SHIFT;
+	reg |= ATGE_USECS(atgep->atge_int_tx_mod) << IM_TIMER_TX_SHIFT;
+	OUTL(atgep, ATGE_IM_TIMER, reg);
+	/*
+	 * We don't want to automatic interrupt clear as task queue
+	 * for the interrupt should know interrupt status.
+	 */
+	reg = 0;
+	if (ATGE_USECS(atgep->atge_int_rx_mod) != 0)
+		reg |= MASTER_IM_RX_TIMER_ENB;
+	if (ATGE_USECS(atgep->atge_int_tx_mod) != 0)
+		reg |= MASTER_IM_TX_TIMER_ENB;
+	OUTL(atgep, ATGE_MASTER_CFG, reg);
+}
+
+void
+atge_l1c_clear_stats(atge_t *atgep)
+{
+	atge_l1c_smb_t smb;
+	uint32_t *reg;
+	int i;
+
+	/*
+	 * Clear RX stats first.
+	 */
+	i = 0;
+	reg = &smb.rx_frames;
+	while (reg++ <= &smb.rx_pkts_filtered) {
+		(void) INL(atgep, ATGE_RX_MIB_BASE + i);
+		i += sizeof (uint32_t);
+	}
+
+	/*
+	 * Clear TX stats.
+	 */
+	i = 0;
+	reg = &smb.tx_frames;
+	while (reg++ <= &smb.tx_mcast_bytes) {
+		(void) INL(atgep, ATGE_TX_MIB_BASE + i);
+		i += sizeof (uint32_t);
+	}
+}
+
+void
+atge_l1c_gather_stats(atge_t *atgep)
+{
+	atge_l1c_data_t *l1c;
+	atge_dma_t *dma;
+	atge_l1c_smb_t *stat;
+	atge_l1c_smb_t *smb;
+
+	ASSERT(atgep != NULL);
+
+	l1c = atgep->atge_private_data;
+	dma = l1c->atge_l1c_smb;
+	DMA_SYNC(dma, 0, 0, DDI_DMA_SYNC_FORKERNEL);
+	stat = (atge_l1c_smb_t *)atgep->atge_hw_stats;
+	smb = (atge_l1c_smb_t *)dma->addr;
+
+	/* Rx stats. */
+	stat->rx_frames += smb->rx_frames;
+	stat->rx_bcast_frames += smb->rx_bcast_frames;
+	stat->rx_mcast_frames += smb->rx_mcast_frames;
+	stat->rx_pause_frames += smb->rx_pause_frames;
+	stat->rx_control_frames += smb->rx_control_frames;
+	stat->rx_crcerrs += smb->rx_crcerrs;
+	stat->rx_lenerrs += smb->rx_lenerrs;
+	stat->rx_bytes += smb->rx_bytes;
+	stat->rx_runts += smb->rx_runts;
+	stat->rx_fragments += smb->rx_fragments;
+	stat->rx_pkts_64 += smb->rx_pkts_64;
+	stat->rx_pkts_65_127 += smb->rx_pkts_65_127;
+	stat->rx_pkts_128_255 += smb->rx_pkts_128_255;
+	stat->rx_pkts_256_511 += smb->rx_pkts_256_511;
+	stat->rx_pkts_512_1023 += smb->rx_pkts_512_1023;
+	stat->rx_pkts_1024_1518 += smb->rx_pkts_1024_1518;
+	stat->rx_pkts_1519_max += smb->rx_pkts_1519_max;
+	stat->rx_pkts_truncated += smb->rx_pkts_truncated;
+	stat->rx_fifo_oflows += smb->rx_fifo_oflows;
+	stat->rx_alignerrs += smb->rx_alignerrs;
+	stat->rx_bcast_bytes += smb->rx_bcast_bytes;
+	stat->rx_mcast_bytes += smb->rx_mcast_bytes;
+	stat->rx_pkts_filtered += smb->rx_pkts_filtered;
+
+	/* Tx stats. */
+	stat->tx_frames += smb->tx_frames;
+	stat->tx_bcast_frames += smb->tx_bcast_frames;
+	stat->tx_mcast_frames += smb->tx_mcast_frames;
+	stat->tx_pause_frames += smb->tx_pause_frames;
+	stat->tx_excess_defer += smb->tx_excess_defer;
+	stat->tx_control_frames += smb->tx_control_frames;
+	stat->tx_deferred += smb->tx_deferred;
+	stat->tx_bytes += smb->tx_bytes;
+	stat->tx_pkts_64 += smb->tx_pkts_64;
+	stat->tx_pkts_65_127 += smb->tx_pkts_65_127;
+	stat->tx_pkts_128_255 += smb->tx_pkts_128_255;
+	stat->tx_pkts_256_511 += smb->tx_pkts_256_511;
+	stat->tx_pkts_512_1023 += smb->tx_pkts_512_1023;
+	stat->tx_pkts_1024_1518 += smb->tx_pkts_1024_1518;
+	stat->tx_pkts_1519_max += smb->tx_pkts_1519_max;
+	stat->tx_single_colls += smb->tx_single_colls;
+	stat->tx_multi_colls += smb->tx_multi_colls;
+	stat->tx_late_colls += smb->tx_late_colls;
+	stat->tx_excess_colls += smb->tx_excess_colls;
+	stat->tx_underrun += smb->tx_underrun;
+	stat->tx_desc_underrun += smb->tx_desc_underrun;
+	stat->tx_lenerrs += smb->tx_lenerrs;
+	stat->tx_pkts_truncated += smb->tx_pkts_truncated;
+	stat->tx_bcast_bytes += smb->tx_bcast_bytes;
+	stat->tx_mcast_bytes += smb->tx_mcast_bytes;
+
+	/*
+	 * Update global counters in atge_t.
+	 */
+	atgep->atge_brdcstrcv += smb->rx_bcast_frames;
+	atgep->atge_multircv += smb->rx_mcast_frames;
+	atgep->atge_multixmt += smb->tx_mcast_frames;
+	atgep->atge_brdcstxmt += smb->tx_bcast_frames;
+
+	atgep->atge_align_errors += smb->rx_alignerrs;
+	atgep->atge_fcs_errors += smb->rx_crcerrs;
+	atgep->atge_defer_xmts += smb->tx_deferred;
+	atgep->atge_first_collisions += smb->tx_single_colls;
+	atgep->atge_multi_collisions += smb->tx_multi_colls * 2;
+	atgep->atge_tx_late_collisions += smb->tx_late_colls;
+	atgep->atge_ex_collisions += smb->tx_excess_colls;
+	atgep->atge_toolong_errors += smb->rx_lenerrs;
+	atgep->atge_overflow += smb->rx_fifo_oflows;
+	atgep->atge_underflow += (smb->tx_underrun + smb->tx_desc_underrun);
+	atgep->atge_runt += smb->rx_runts;
+
+
+	atgep->atge_collisions += smb->tx_single_colls +
+	    smb->tx_multi_colls * 2 + smb->tx_late_colls;
+
+	/*
+	 * tx_pkts_truncated counter looks suspicious. It constantly
+	 * increments with no sign of Tx errors. Hence we don't factor it.
+	 */
+	atgep->atge_macxmt_errors += smb->tx_late_colls + smb->tx_underrun;
+
+	atgep->atge_macrcv_errors += smb->rx_crcerrs + smb->rx_lenerrs +
+	    smb->rx_runts + smb->rx_pkts_truncated +
+	    smb->rx_alignerrs;
+
+	smb->updated = 0;
+	DMA_SYNC(dma, 0, 0, DDI_DMA_SYNC_FORDEV);
+}
+
+void
+atge_l1c_stop_tx_mac(atge_t *atgep)
+{
+	uint32_t reg;
+	int t;
+
+	ATGE_DB(("%s: %s() called", atgep->atge_name, __func__));
+
+	reg = INL(atgep, ATGE_MAC_CFG);
+	if ((reg & ATGE_CFG_TX_ENB) != 0) {
+		reg &= ~ATGE_CFG_TX_ENB;
+		OUTL(atgep, ATGE_MAC_CFG, reg);
+	}
+
+	/* Stop TX DMA engine. */
+	reg = INL(atgep, ATGE_DMA_CFG);
+	if ((reg & DMA_CFG_RD_ENB) != 0) {
+		reg &= ~DMA_CFG_RD_ENB;
+		OUTL(atgep, ATGE_DMA_CFG, reg);
+	}
+
+	for (t = ATGE_RESET_TIMEOUT; t > 0; t--) {
+		if ((INL(atgep, ATGE_IDLE_STATUS) &
+		    (IDLE_STATUS_TXMAC | IDLE_STATUS_DMARD)) == 0)
+			break;
+
+		drv_usecwait(10);
+	}
+
+	if (t == 0) {
+		/* This should be an FMA event. */
+		atge_error(atgep->atge_dip, "stopping TX DMA Engine timeout");
+	}
+}
+
+void
+atge_l1c_stop_rx_mac(atge_t *atgep)
+{
+	uint32_t reg;
+	int t;
+
+	ATGE_DB(("%s: %s() called", atgep->atge_name, __func__));
+
+	reg = INL(atgep, ATGE_MAC_CFG);
+	if ((reg & ATGE_CFG_RX_ENB) != 0) {
+		reg &= ~ATGE_CFG_RX_ENB;
+		OUTL(atgep, ATGE_MAC_CFG, reg);
+	}
+
+	/* Stop RX DMA engine. */
+	reg = INL(atgep, ATGE_DMA_CFG);
+	if ((reg & DMA_CFG_WR_ENB) != 0) {
+		reg &= ~DMA_CFG_WR_ENB;
+		OUTL(atgep, ATGE_DMA_CFG, reg);
+	}
+
+	for (t = ATGE_RESET_TIMEOUT; t > 0; t--) {
+		if ((INL(atgep, ATGE_IDLE_STATUS) &
+		    (IDLE_STATUS_RXMAC | IDLE_STATUS_DMAWR)) == 0)
+			break;
+		drv_usecwait(10);
+	}
+
+	if (t == 0) {
+		/* This should be an FMA event. */
+		atge_error(atgep->atge_dip, " stopping RX DMA Engine timeout");
+	}
+}
+
+/*
+ * Receives (consumes) packets.
+ */
+static mblk_t *
+atge_l1c_rx(atge_t *atgep)
+{
+	atge_l1c_data_t *l1c;
+	mblk_t *mp = NULL, *rx_head = NULL, *rx_tail = NULL;
+	l1c_rx_rdesc_t *rx_rr;
+	uint32_t rdinfo, status, totlen, pktlen, slotlen;
+	int nsegs, rx_cons = 0, cnt;
+	atge_dma_t *buf;
+	uchar_t *bufp;
+	int sync = 0;
+
+	l1c = atgep->atge_private_data;
+	ASSERT(l1c != NULL);
+
+	DMA_SYNC(l1c->atge_l1c_rr, 0, 0, DDI_DMA_SYNC_FORKERNEL);
+	for (;;) {
+		rx_rr = (l1c_rx_rdesc_t *)(l1c->atge_l1c_rr->addr +
+		    (l1c->atge_l1c_rr_consumers * sizeof (l1c_rx_rdesc_t)));
+
+		rdinfo = ATGE_GET32(l1c->atge_l1c_rr, &rx_rr->rdinfo);
+		status = ATGE_GET32(l1c->atge_l1c_rr, &rx_rr->status);
+
+		rx_cons = L1C_RRD_RD_IDX(rdinfo);
+		nsegs = L1C_RRD_RD_CNT(rdinfo);
+		totlen = L1C_RRD_BYTES(status);
+
+		ATGE_DB(("%s: %s() PKT -- rdinfo : 0x%x,"
+		    "status : 0x%x, totlen : %d,"
+		    " rx_cons : %d, nsegs : %d", atgep->atge_name, __func__,
+		    rdinfo, status, totlen, rx_cons, nsegs));
+
+		if ((status & L1C_RRD_VALID) == 0) {
+			break;
+		}
+
+		if ((status & (L1C_RRD_ERR_CRC | L1C_RRD_ERR_ALIGN |
+		    L1C_RRD_ERR_TRUNC | L1C_RRD_ERR_RUNT |
+		    L1C_RRD_ERR_ICMP | L1C_RRD_ERR_LENGTH)) != 0) {
+			atge_error(atgep->atge_dip, "errored pkt");
+
+			l1c->atge_rx_ring->r_consumer += nsegs;
+			l1c->atge_rx_ring->r_consumer %= L1C_RX_RING_CNT;
+			break;
+		}
+
+		ASSERT(rx_cons >= 0 && rx_cons <= L1C_RX_RING_CNT);
+
+		mp = allocb(totlen + L1C_HEADROOM, BPRI_MED);
+		if (mp != NULL) {
+			mp->b_rptr += L1C_HEADROOM;
+			bufp = mp->b_rptr;
+			mp->b_wptr = bufp + totlen;
+			mp->b_next = NULL;
+
+			atgep->atge_ipackets++;
+			atgep->atge_rbytes += totlen;
+
+			/*
+			 * If there are more than one segments, then the first
+			 * segment should be of size MTU. We couldn't verify
+			 * this as our driver does not support changing MTU
+			 * or Jumbo Frames.
+			 */
+			if (nsegs > 1) {
+				slotlen = atgep->atge_mtu;
+			} else {
+				slotlen = totlen;
+			}
+		} else {
+			ATGE_DB(("%s: %s() PKT mp == NULL totlen : %d",
+			    atgep->atge_name, __func__, totlen));
+
+			if (slotlen > atgep->atge_rx_buf_len) {
+				atgep->atge_toolong_errors++;
+			} else if (mp == NULL) {
+				atgep->atge_norcvbuf++;
+			}
+
+			rx_rr->status = 0;
+			break;
+		}
+
+		for (cnt = 0, pktlen = 0; cnt < nsegs; cnt++) {
+			buf = l1c->atge_rx_ring->r_buf_tbl[rx_cons];
+
+			slotlen = min(atgep->atge_max_frame_size, totlen);
+
+			bcopy(buf->addr, (bufp + pktlen), slotlen);
+			pktlen += slotlen;
+			totlen -= slotlen;
+
+			ATGE_DB(("%s: %s() len : %d, rxcons : %d, pktlen : %d",
+			    atgep->atge_name, __func__, slotlen, rx_cons,
+			    pktlen));
+
+			ATGE_INC_SLOT(rx_cons, L1C_RX_RING_CNT);
+		}
+
+		if (rx_tail == NULL) {
+			rx_head = rx_tail = mp;
+		} else {
+			rx_tail->b_next = mp;
+			rx_tail = mp;
+		}
+
+		if (cnt != nsegs) {
+			l1c->atge_rx_ring->r_consumer += nsegs;
+			l1c->atge_rx_ring->r_consumer %= L1C_RX_RING_CNT;
+		} else {
+			l1c->atge_rx_ring->r_consumer = rx_cons;
+		}
+
+		/*
+		 * Tell the chip that this RR can be reused.
+		 */
+		rx_rr->status = 0;
+
+		ATGE_INC_SLOT(l1c->atge_l1c_rr_consumers, L1C_RR_RING_CNT);
+		sync++;
+	}
+
+	if (sync) {
+		DMA_SYNC(l1c->atge_rx_ring->r_desc_ring, 0, 0,
+		    DDI_DMA_SYNC_FORDEV);
+
+		DMA_SYNC(l1c->atge_l1c_rr, 0, 0, DDI_DMA_SYNC_FORDEV);
+		/*
+		 * Let controller know availability of new Rx buffers.
+		 */
+		OUTL(atgep, ATGE_MBOX_RD0_PROD_IDX,
+		    l1c->atge_rx_ring->r_consumer);
+
+		ATGE_DB(("%s: %s() PKT Recved -> r_consumer : %d, rx_cons : %d"
+		    " atge_l1c_rr_consumers : %d",
+		    atgep->atge_name, __func__, l1c->atge_rx_ring->r_consumer,
+		    rx_cons, l1c->atge_l1c_rr_consumers));
+	}
+
+
+	return (rx_head);
+}
+
+/*
+ * The interrupt handler for L1C chip.
+ */
+/*ARGSUSED*/
+uint_t
+atge_l1c_interrupt(caddr_t arg1, caddr_t arg2)
+{
+	atge_t *atgep = (void *)arg1;
+	mblk_t *rx_head = NULL;
+	uint32_t status;
+	int resched = 0;
+
+	ASSERT(atgep != NULL);
+
+	mutex_enter(&atgep->atge_intr_lock);
+
+	if (atgep->atge_chip_state & ATGE_CHIP_SUSPENDED) {
+		mutex_exit(&atgep->atge_intr_lock);
+		return (DDI_INTR_UNCLAIMED);
+	}
+
+	status = INL(atgep, ATGE_INTR_STATUS);
+	if (status == 0 || (status & atgep->atge_intrs) == 0) {
+		mutex_exit(&atgep->atge_intr_lock);
+
+		if (atgep->atge_flags & ATGE_FIXED_TYPE)
+			return (DDI_INTR_UNCLAIMED);
+
+		return (DDI_INTR_CLAIMED);
+	}
+
+	ATGE_DB(("%s: %s() entry status : %x",
+	    atgep->atge_name, __func__, status));
+
+	/*
+	 * Disable interrupts.
+	 */
+	if (status & L1C_INTR_GPHY) {
+		/* clear PHY interrupt source before we ack interrupts */
+		(void) atge_mii_read(atgep,
+		    atgep->atge_phyaddr, ATGE_ISR_ACK_GPHY);
+	}
+
+	OUTL(atgep, ATGE_INTR_STATUS, status | L1C_INTR_DIS_INT);
+	FLUSH(atgep, ATGE_INTR_STATUS);
+
+	/*
+	 * Check if chip is running, only then do the work.
+	 */
+	if (atgep->atge_chip_state & ATGE_CHIP_RUNNING) {
+		atge_l1c_data_t *l1c;
+
+		l1c = atgep->atge_private_data;
+
+		ATGE_DB(("%s: %s() atge_l1c_intr_status : %x, "
+		    "atge_l1c_rx_prod_cons : %d, atge_l1c_tx_prod_cons : %d"
+		    " atge_l1c_rr_consumers : %d",
+		    atgep->atge_name, __func__, l1c->atge_l1c_intr_status,
+		    l1c->atge_l1c_rx_prod_cons, l1c->atge_l1c_tx_prod_cons,
+		    l1c->atge_l1c_rr_consumers));
+
+		if (status & L1C_INTR_SMB)
+			atge_l1c_gather_stats(atgep);
+
+		/*
+		 * Check for errors.
+		 */
+		if (status & (L1C_INTR_DMA_RD_TO_RST |
+		    L1C_INTR_DMA_WR_TO_RST | L1C_INTR_TXQ_TO_RST)) {
+			/* This should be an FMA event. */
+			atge_error(atgep->atge_dip,
+			    "L1C chip detected a fatal error, "
+			    "interrupt status: %x", status);
+
+			if (status & L1C_INTR_DMA_RD_TO_RST) {
+				atge_error(atgep->atge_dip,
+				    "DMA read error");
+			}
+			if (status & L1C_INTR_DMA_WR_TO_RST) {
+				atge_error(atgep->atge_dip,
+				    "DMA write error");
+			}
+			if (status & L1C_INTR_TXQ_TO_RST) {
+				atge_error(atgep->atge_dip,
+				    "Transmit queue error");
+			}
+
+			/* This should be an FMA event. */
+			atge_device_stop(atgep);
+			/*
+			 * Device has failed fatally.
+			 * It will not be restarted by the driver.
+			 */
+			goto done;
+
+		}
+
+		rx_head = atge_l1c_rx(atgep);
+		if (status & L1C_INTR_TX_PKT) {
+			int cons;
+
+			mutex_enter(&atgep->atge_tx_lock);
+			cons = INL(atgep, ATGE_MBOX_TD_CONS_IDX) >> 16;
+			atge_tx_reclaim(atgep, cons);
+			if (atgep->atge_tx_resched) {
+				atgep->atge_tx_resched = 0;
+				resched = 1;
+			}
+
+			mutex_exit(&atgep->atge_tx_lock);
+		}
+	}
+
+	/* Re-enable interrupts. */
+	OUTL(atgep, ATGE_INTR_STATUS, 0);
+
+done:
+	mutex_exit(&atgep->atge_intr_lock);
+
+	if (status & L1C_INTR_GPHY) {
+		/* link down */
+		ATGE_DB(("%s: %s() MII_CHECK Performed",
+		    atgep->atge_name, __func__));
+		mii_check(atgep->atge_mii);
+	}
+
+	/*
+	 * Pass the list of packets received from chip to MAC layer.
+	 */
+	if (rx_head) {
+		mac_rx(atgep->atge_mh, 0, rx_head);
+	}
+
+	/*
+	 * Let MAC start sending pkts if the downstream was asked to pause.
+	 */
+	if (resched)
+		mac_tx_update(atgep->atge_mh);
+
+	return (DDI_INTR_CLAIMED);
+}
+
+void
+atge_l1c_send_packet(atge_ring_t *r)
+{
+	atge_t *atgep;
+
+	atgep = r->r_atge;
+
+	mutex_enter(&atgep->atge_mbox_lock);
+	/* Sync descriptors. */
+	DMA_SYNC(atgep->atge_tx_ring->r_desc_ring, 0, 0, DDI_DMA_SYNC_FORDEV);
+	/* Kick. Assume we're using normal Tx priority queue. */
+	OUTL(atgep, ATGE_MBOX_TD_PROD_IDX,
+	    (atgep->atge_tx_ring->r_producer << MBOX_TD_PROD_LO_IDX_SHIFT) &
+	    MBOX_TD_PROD_LO_IDX_MASK);
+	mutex_exit(&atgep->atge_mbox_lock);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/atge/atge_l1c_reg.h	Fri Aug 10 10:52:49 2012 -0400
@@ -0,0 +1,492 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2012 Gary Mills
+ *
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright (c) 2009, Pyun YongHyeon <yongari@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _ATGE_L1C_REG_H
+#define	_ATGE_L1C_REG_H
+
+#ifdef __cplusplus
+	extern "C" {
+#endif
+
+#pragma	pack(1)
+typedef	struct	l1c_cmb {
+	uint32_t	intr_status;
+	uint32_t	rx_prod_cons;
+	uint32_t	tx_prod_cons;
+} l1c_cmb_t;
+
+typedef	struct	l1c_rx_desc {
+	uint64_t	addr;
+	/* No length field. */
+} l1c_rx_desc_t;
+
+typedef	struct	l1c_rx_rdesc {
+	uint32_t	rdinfo;	/* word 0 */
+	uint32_t	rss;	/* word 1 */
+	uint32_t	vtag;	/* word 2 */
+	uint32_t	status;	/* word 3 */
+} l1c_rx_rdesc_t;
+
+/*
+ * Statistics counters collected by the MAC
+ */
+typedef	struct l1c_smb {
+	/* Rx stats. */
+	uint32_t rx_frames;
+	uint32_t rx_bcast_frames;
+	uint32_t rx_mcast_frames;
+	uint32_t rx_pause_frames;
+	uint32_t rx_control_frames;
+	uint32_t rx_crcerrs;
+	uint32_t rx_lenerrs;
+	uint32_t rx_bytes;
+	uint32_t rx_runts;
+	uint32_t rx_fragments;
+	uint32_t rx_pkts_64;
+	uint32_t rx_pkts_65_127;
+	uint32_t rx_pkts_128_255;
+	uint32_t rx_pkts_256_511;
+	uint32_t rx_pkts_512_1023;
+	uint32_t rx_pkts_1024_1518;
+	uint32_t rx_pkts_1519_max;
+	uint32_t rx_pkts_truncated;
+	uint32_t rx_fifo_oflows;
+	uint32_t rx_desc_oflows;
+	uint32_t rx_alignerrs;
+	uint32_t rx_bcast_bytes;
+	uint32_t rx_mcast_bytes;
+	uint32_t rx_pkts_filtered;
+	/* Tx stats. */
+	uint32_t tx_frames;
+	uint32_t tx_bcast_frames;
+	uint32_t tx_mcast_frames;
+	uint32_t tx_pause_frames;
+	uint32_t tx_excess_defer;
+	uint32_t tx_control_frames;
+	uint32_t tx_deferred;
+	uint32_t tx_bytes;
+	uint32_t tx_pkts_64;
+	uint32_t tx_pkts_65_127;
+	uint32_t tx_pkts_128_255;
+	uint32_t tx_pkts_256_511;
+	uint32_t tx_pkts_512_1023;
+	uint32_t tx_pkts_1024_1518;
+	uint32_t tx_pkts_1519_max;
+	uint32_t tx_single_colls;
+	uint32_t tx_multi_colls;
+	uint32_t tx_late_colls;
+	uint32_t tx_excess_colls;
+	uint32_t tx_underrun;
+	uint32_t tx_desc_underrun;
+	uint32_t tx_lenerrs;
+	uint32_t tx_pkts_truncated;
+	uint32_t tx_bcast_bytes;
+	uint32_t tx_mcast_bytes;
+	uint32_t updated;
+} atge_l1c_smb_t;
+#pragma	pack()
+
+#define	L1C_RX_RING_CNT		256
+#define	L1C_RR_RING_CNT		L1C_RX_RING_CNT
+#define	L1C_HEADROOM		6  /* Must be divisible by 2, but not 4. */
+
+#define	L1C_RING_ALIGN		16
+#define	L1C_TX_RING_ALIGN	16
+#define	L1C_RX_RING_ALIGN	16
+#define	L1C_RR_RING_ALIGN	16
+#define	L1C_CMB_ALIGN		16
+#define	L1C_SMB_ALIGN		16
+
+#define	L1C_CMB_BLOCK_SZ	sizeof (struct l1c_cmb)
+#define	L1C_SMB_BLOCK_SZ	sizeof (struct l1c_smb)
+
+#define	L1C_RX_RING_SZ		\
+	(sizeof (struct l1c_rx_desc) * L1C_RX_RING_CNT)
+
+#define	L1C_RR_RING_SZ		\
+	(sizeof (struct l1c_rx_rdesc) * L1C_RR_RING_CNT)
+
+/*
+ * For RX
+ */
+/* word 0 */
+#define	L1C_RRD_CSUM_MASK		0x0000FFFF
+#define	L1C_RRD_RD_CNT_MASK		0x000F0000
+#define	L1C_RRD_RD_IDX_MASK		0xFFF00000
+#define	L1C_RRD_CSUM_SHIFT		0
+#define	L1C_RRD_RD_CNT_SHIFT		16
+#define	L1C_RRD_RD_IDX_SHIFT		20
+#define	L1C_RRD_CSUM(x)			\
+	(((x) & L1C_RRD_CSUM_MASK) >> L1C_RRD_CSUM_SHIFT)
+#define	L1C_RRD_RD_CNT(x)			\
+	(((x) & L1C_RRD_RD_CNT_MASK) >> L1C_RRD_RD_CNT_SHIFT)
+#define	L1C_RRD_RD_IDX(x)			\
+	(((x) & L1C_RRD_RD_IDX_MASK) >> L1C_RRD_RD_IDX_SHIFT)
+
+/* word 2 */
+#define	L1C_RRD_VLAN_MASK		0x0000FFFF
+#define	L1C_RRD_HEAD_LEN_MASK		0x00FF0000
+#define	L1C_RRD_HDS_MASK		0x03000000
+#define	L1C_RRD_HDS_NONE		0x00000000
+#define	L1C_RRD_HDS_HEAD		0x01000000
+#define	L1C_RRD_HDS_DATA		0x02000000
+#define	L1C_RRD_CPU_MASK		0x0C000000
+#define	L1C_RRD_HASH_FLAG_MASK		0xF0000000
+#define	L1C_RRD_VLAN_SHIFT		0
+#define	L1C_RRD_HEAD_LEN_SHIFT		16
+#define	L1C_RRD_HDS_SHIFT		24
+#define	L1C_RRD_CPU_SHIFT		26
+#define	L1C_RRD_HASH_FLAG_SHIFT		28
+#define	L1C_RRD_VLAN(x)			\
+	(((x) & L1C_RRD_VLAN_MASK) >> L1C_RRD_VLAN_SHIFT)
+#define	L1C_RRD_HEAD_LEN(x)			\
+	(((x) & L1C_RRD_HEAD_LEN_MASK) >> L1C_RRD_HEAD_LEN_SHIFT)
+#define	L1C_RRD_CPU(x)			\
+	(((x) & L1C_RRD_CPU_MASK) >> L1C_RRD_CPU_SHIFT)
+
+	/* word3 */
+#define	L1C_RRD_LEN_MASK		0x00003FFF
+#define	L1C_RRD_LEN_SHIFT		0
+#define	L1C_RRD_TCP_UDPCSUM_NOK		0x00004000
+#define	L1C_RRD_IPCSUM_NOK		0x00008000
+#define	L1C_RRD_VLAN_TAG		0x00010000
+#define	L1C_RRD_PROTO_MASK		0x000E0000
+#define	L1C_RRD_PROTO_IPV4		0x00020000
+#define	L1C_RRD_PROTO_IPV6		0x000C0000
+#define	L1C_RRD_ERR_SUM			0x00100000
+#define	L1C_RRD_ERR_CRC			0x00200000
+#define	L1C_RRD_ERR_ALIGN		0x00400000
+#define	L1C_RRD_ERR_TRUNC		0x00800000
+#define	L1C_RRD_ERR_RUNT		0x01000000
+#define	L1C_RRD_ERR_ICMP		0x02000000
+#define	L1C_RRD_BCAST			0x04000000
+#define	L1C_RRD_MCAST			0x08000000
+#define	L1C_RRD_SNAP_LLC		0x10000000
+#define	L1C_RRD_ETHER			0x00000000
+#define	L1C_RRD_FIFO_FULL		0x20000000
+#define	L1C_RRD_ERR_LENGTH		0x40000000
+#define	L1C_RRD_VALID			0x80000000
+#define	L1C_RRD_BYTES(x)			\
+	(((x) & L1C_RRD_LEN_MASK) >> L1C_RRD_LEN_SHIFT)
+#define	L1C_RRD_IPV4(x)			\
+	(((x) & L1C_RRD_PROTO_MASK) == L1C_RRD_PROTO_IPV4)
+
+#define	RRD_PROD_MASK			0x0000FFFF
+#define	TPD_CONS_MASK			0xFFFF0000
+#define	TPD_CONS_SHIFT			16
+#define	CMB_UPDATED			0x00000001
+#define	RRD_PROD_SHIFT			0
+
+#pragma	pack(1)
+typedef struct l1c_tx_desc {
+	uint32_t len;
+#define	L1C_TD_BUFLEN_MASK		0x00003FFF
+#define	L1C_TD_VLAN_MASK		0xFFFF0000
+#define	L1C_TD_BUFLEN_SHIFT		0
+#define	L1C_TX_BYTES(x)			\
+	(((x) << L1C_TD_BUFLEN_SHIFT) & L1C_TD_BUFLEN_MASK)
+#define	L1C_TD_VLAN_SHIFT		16
+
+	uint32_t flags;
+#define	L1C_TD_L4HDR_OFFSET_MASK	0x000000FF	/* byte unit */
+#define	L1C_TD_TCPHDR_OFFSET_MASK	0x000000FF	/* byte unit */
+#define	L1C_TD_PLOAD_OFFSET_MASK	0x000000FF	/* 2 bytes unit */
+#define	L1C_TD_CUSTOM_CSUM		0x00000100
+#define	L1C_TD_IPCSUM			0x00000200
+#define	L1C_TD_TCPCSUM			0x00000400
+#define	L1C_TD_UDPCSUM			0x00000800
+#define	L1C_TD_TSO			0x00001000
+#define	L1C_TD_TSO_DESCV1		0x00000000
+#define	L1C_TD_TSO_DESCV2		0x00002000
+#define	L1C_TD_CON_VLAN_TAG		0x00004000
+#define	L1C_TD_INS_VLAN_TAG		0x00008000
+#define	L1C_TD_IPV4_DESCV2		0x00010000
+#define	L1C_TD_LLC_SNAP			0x00020000
+#define	L1C_TD_ETHERNET			0x00000000
+#define	L1C_TD_CUSTOM_CSUM_OFFSET_MASK	0x03FC0000	/* 2 bytes unit */
+#define	L1C_TD_CUSTOM_CSUM_EVEN_PAD	0x40000000
+#define	L1C_TD_MSS_MASK			0x7FFC0000
+#define	L1C_TD_EOP			0x80000000
+#define	L1C_TD_L4HDR_OFFSET_SHIFT	0
+#define	L1C_TD_TCPHDR_OFFSET_SHIFT	0
+#define	L1C_TD_PLOAD_OFFSET_SHIFT	0
+#define	L1C_TD_CUSTOM_CSUM_OFFSET_SHIFT	18
+#define	L1C_TD_MSS_SHIFT		18
+
+	uint64_t addr;
+} l1c_tx_desc_t;
+#pragma	pack()
+
+/*
+ * All descriptors and CMB/SMB share the same high address.
+ */
+
+/* From Freebsd if_alcreg.h */
+#define	L1C_RSS_IDT_TABLE0		0x14E0
+
+#define	L1C_RX_BASE_ADDR_HI		0x1540
+
+#define	L1C_TX_BASE_ADDR_HI		0x1544
+
+#define	L1C_SMB_BASE_ADDR_HI		0x1548
+
+#define	L1C_SMB_BASE_ADDR_LO		0x154C
+
+#define	L1C_RD0_HEAD_ADDR_LO		0x1550
+
+#define	L1C_RD1_HEAD_ADDR_LO		0x1554
+
+#define	L1C_RD2_HEAD_ADDR_LO		0x1558
+
+#define	L1C_RD3_HEAD_ADDR_LO		0x155C
+
+#define	L1C_RD_RING_CNT			0x1560
+#define	RD_RING_CNT_MASK		0x00000FFF
+#define	RD_RING_CNT_SHIFT		0
+
+#define	L1C_RX_BUF_SIZE			0x1564
+#define	RX_BUF_SIZE_MASK		0x0000FFFF
+/*
+ * If larger buffer size than 1536 is specified the controller
+ * will be locked up. This is hardware limitation.
+ */
+#define	RX_BUF_SIZE_MAX			1536
+
+#define	L1C_RRD0_HEAD_ADDR_LO		0x1568
+
+#define	L1C_RRD1_HEAD_ADDR_LO		0x156C
+
+#define	L1C_RRD2_HEAD_ADDR_LO		0x1570
+
+#define	L1C_RRD3_HEAD_ADDR_LO		0x1574
+
+#define	L1C_RRD_RING_CNT		0x1578
+#define	RRD_RING_CNT_MASK		0x00000FFF
+#define	RRD_RING_CNT_SHIFT		0
+
+#define	L1C_TDH_HEAD_ADDR_LO		0x157C
+
+#define	L1C_TDL_HEAD_ADDR_LO		0x1580
+
+#define	L1C_TD_RING_CNT			0x1584
+#define	TD_RING_CNT_MASK		0x0000FFFF
+#define	TD_RING_CNT_SHIFT		0
+
+#define	L1C_CMB_BASE_ADDR_LO		0x1588
+
+#define	L1C_RXQ_CFG			0x15A0
+#define	RXQ_CFG_ASPM_THROUGHPUT_LIMIT_MASK	0x00000003
+#define	RXQ_CFG_ASPM_THROUGHPUT_LIMIT_NONE	0x00000000
+#define	RXQ_CFG_ASPM_THROUGHPUT_LIMIT_1M	0x00000001
+#define	RXQ_CFG_ASPM_THROUGHPUT_LIMIT_10M	0x00000002
+#define	RXQ_CFG_ASPM_THROUGHPUT_LIMIT_100M	0x00000003
+
+#define	L1C_RSS_CPU			0x15B8
+
+/* End of Freebsd if_alcreg.h */
+
+/*
+ * PHY registers.
+ */
+#define	PHY_CDTS_STAT_OK	0x0000
+#define	PHY_CDTS_STAT_SHORT	0x0100
+#define	PHY_CDTS_STAT_OPEN	0x0200
+#define	PHY_CDTS_STAT_INVAL	0x0300
+#define	PHY_CDTS_STAT_MASK	0x0300
+
+/*
+ * MAC CFG registers (L1C specific)
+ */
+#define	L1C_CFG_SINGLE_PAUSE_ENB	0x10000000
+
+/*
+ * DMA CFG registers (L1C specific)
+ */
+#define	DMA_CFG_RD_ENB			0x00000400
+#define	DMA_CFG_WR_ENB			0x00000800
+#define	DMA_CFG_RD_BURST_MASK		0x07
+#define	DMA_CFG_RD_BURST_SHIFT		4
+#define	DMA_CFG_WR_BURST_MASK		0x07
+#define	DMA_CFG_WR_BURST_SHIFT		7
+#define	DMA_CFG_SMB_DIS			0x01000000
+
+#define	L1C_RD_LEN_MASK			0x0000FFFF
+#define	L1C_RD_LEN_SHIFT		0
+
+#define	L1C_SRAM_RD_ADDR		0x1500
+#define	L1C_SRAM_RD_LEN			0x1504
+#define	L1C_SRAM_RRD_ADDR		0x1508
+#define	L1C_SRAM_RRD_LEN		0x150C
+#define	L1C_SRAM_TPD_ADDR		0x1510
+#define	L1C_SRAM_TPD_LEN		0x1514
+#define	L1C_SRAM_TRD_ADDR		0x1518
+#define	L1C_SRAM_TRD_LEN		0x151C
+#define	L1C_SRAM_RX_FIFO_ADDR		0x1520
+#define	L1C_SRAM_RX_FIFO_LEN		0x1524
+#define	L1C_SRAM_TX_FIFO_ADDR		0x1528
+#define	L1C_SRAM_TX_FIFO_LEN		0x152C
+
+#define	L1C_RXQ_CFG_RD_BURST_MASK	0x03f00000
+#define	L1C_RXQ_CFG_RD_BURST_SHIFT	20
+
+#define	L1C_TXQ_CFG			0x1590
+#define	TXQ_CFG_TPD_FETCH_THRESH_MASK	0x00003F00
+#define	L1C_TXQ_CFG_TPD_BURST_DEFAULT	5
+#define	TXQ_CFG_TPD_FETCH_THRESH_SHIFT	8
+#define	TXQ_CFG_TPD_FETCH_DEFAULT	16
+
+#define	L1C_TXF_WATER_MARK		0x1598	/* 8 bytes unit */
+#define	TXF_WATER_MARK_HI_MASK		0x00000FFF
+#define	TXF_WATER_MARK_LO_MASK		0x0FFF0000
+#define	TXF_WATER_MARK_BURST_ENB	0x80000000
+#define	TXF_WATER_MARK_LO_SHIFT		0
+#define	TXF_WATER_MARK_HI_SHIFT		16
+
+#define	L1C_RD_DMA_CFG			0x15AC
+#define	RD_DMA_CFG_THRESH_MASK		0x00000FFF	/* 8 bytes unit */
+#define	RD_DMA_CFG_TIMER_MASK		0xFFFF0000
+#define	RD_DMA_CFG_THRESH_SHIFT		0
+#define	RD_DMA_CFG_TIMER_SHIFT		16
+#define	RD_DMA_CFG_THRESH_DEFAULT	0x100
+#define	RD_DMA_CFG_TIMER_DEFAULT	0
+#define	RD_DMA_CFG_TICK_USECS		8
+#define	L1C_RD_DMA_CFG_USECS(x)		((x) / RD_DMA_CFG_TICK_USECS)
+
+/* CMB DMA Write Threshold Register */
+#define	L1C_CMB_WR_THRESH		0x15D4
+#define	CMB_WR_THRESH_RRD_MASK		0x000007FF
+#define	CMB_WR_THRESH_TPD_MASK		0x07FF0000
+#define	CMB_WR_THRESH_RRD_SHIFT		0
+#define	CMB_WR_THRESH_RRD_DEFAULT	4
+#define	CMB_WR_THRESH_TPD_SHIFT		16
+#define	CMB_WR_THRESH_TPD_DEFAULT	4
+
+/* SMB auto DMA timer register */
+#define	L1C_SMB_TIMER			0x15E4
+
+#define	L1C_CSMB_CTRL			0x15D0
+#define	CSMB_CTRL_CMB_KICK		0x00000001
+#define	CSMB_CTRL_SMB_KICK		0x00000002
+#define	CSMB_CTRL_CMB_ENB		0x00000004
+#define	CSMB_CTRL_SMB_ENB		0x00000008
+
+/* From Freebsd if_alcreg.h */
+#define	L1C_INTR_SMB			0x00000001
+#define	L1C_INTR_TIMER			0x00000002
+#define	L1C_INTR_MANUAL_TIMER		0x00000004
+#define	L1C_INTR_RX_FIFO_OFLOW		0x00000008
+#define	L1C_INTR_RD0_UNDERRUN		0x00000010
+#define	L1C_INTR_RD1_UNDERRUN		0x00000020
+#define	L1C_INTR_RD2_UNDERRUN		0x00000040
+#define	L1C_INTR_RD3_UNDERRUN		0x00000080
+#define	L1C_INTR_TX_FIFO_UNDERRUN	0x00000100
+#define	L1C_INTR_DMA_RD_TO_RST		0x00000200
+#define	L1C_INTR_DMA_WR_TO_RST		0x00000400
+#define	L1C_INTR_TX_CREDIT		0x00000800
+#define	L1C_INTR_GPHY			0x00001000
+#define	L1C_INTR_GPHY_LOW_PW		0x00002000
+#define	L1C_INTR_TXQ_TO_RST		0x00004000
+#define	L1C_INTR_TX_PKT			0x00008000
+#define	L1C_INTR_RX_PKT0		0x00010000
+#define	L1C_INTR_RX_PKT1		0x00020000
+#define	L1C_INTR_RX_PKT2		0x00040000
+#define	L1C_INTR_RX_PKT3		0x00080000
+#define	L1C_INTR_MAC_RX			0x00100000
+#define	L1C_INTR_MAC_TX			0x00200000
+#define	L1C_INTR_UNDERRUN		0x00400000
+#define	L1C_INTR_FRAME_ERROR		0x00800000
+#define	L1C_INTR_FRAME_OK		0x01000000
+#define	L1C_INTR_CSUM_ERROR		0x02000000
+#define	L1C_INTR_PHY_LINK_DOWN		0x04000000
+#define	L1C_INTR_DIS_INT		0x80000000
+
+#define	L1C_INTR_RX_PKT			L1C_INTR_RX_PKT0
+#define	L1C_INTR_RD_UNDERRUN		L1C_INTR_RD0_UNDERRUN
+
+#define	L1C_INTRS				\
+	(L1C_INTR_DMA_RD_TO_RST | L1C_INTR_DMA_WR_TO_RST | \
+	L1C_INTR_TXQ_TO_RST| L1C_INTR_RX_PKT | L1C_INTR_TX_PKT | \
+	L1C_INTR_RX_FIFO_OFLOW | L1C_INTR_RD_UNDERRUN | \
+	L1C_INTR_TX_FIFO_UNDERRUN)
+
+#define	L1C_RXQ_RRD_PAUSE_THRESH	0x15AC
+#define	RXQ_RRD_PAUSE_THRESH_HI_MASK	0x00000FFF
+#define	RXQ_RRD_PAUSE_THRESH_LO_MASK	0x0FFF0000
+#define	RXQ_RRD_PAUSE_THRESH_HI_SHIFT	0
+#define	RXQ_RRD_PAUSE_THRESH_LO_SHIFT	16
+
+/* RX/TX count-down timer to trigger CMB-write. */
+#define	L1C_CMB_WR_TIMER			0x15D8
+#define	CMB_WR_TIMER_RX_MASK		0x0000FFFF
+#define	CMB_WR_TIMER_TX_MASK		0xFFFF0000
+#define	CMB_WR_TIMER_RX_SHIFT		0
+#define	CMB_WR_TIMER_TX_SHIFT		16
+
+/*
+ * Useful macros.
+ */
+#define	L1C_RX_NSEGS(x)	\
+	(((x) & L1C_RRD_NSEGS_MASK) >> L1C_RRD_NSEGS_SHIFT)
+#define	L1C_RX_CONS(x)	\
+	(((x) & L1C_RRD_CONS_MASK) >> L1C_RRD_CONS_SHIFT)
+#define	L1C_RX_CSUM(x)	\
+	(((x) & L1C_RRD_CSUM_MASK) >> L1C_RRD_CSUM_SHIFT)
+#define	L1C_RX_BYTES(x)	\
+	(((x) & L1C_RRD_LEN_MASK) >> L1C_RRD_LEN_SHIFT)
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _ATGE_L1C_REG_H */
--- a/usr/src/uts/common/io/atge/atge_l1e.c	Tue Aug 07 21:36:09 2012 -0500
+++ b/usr/src/uts/common/io/atge/atge_l1e.c	Fri Aug 10 10:52:49 2012 -0400
@@ -20,6 +20,8 @@
  */
 
 /*
+ * Copyright (c) 2012 Gary Mills
+ *
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
@@ -401,10 +403,10 @@
 	OUTL(atgep, ATGE_IM_TIMER, reg);
 
 	reg = INL(atgep, ATGE_MASTER_CFG);
-	reg &= ~(MASTER_CHIP_REV_MASK | MASTER_CHIP_ID_MASK);
-	reg &= ~(MASTER_IM_RX_TIMER_ENB | MASTER_IM_TX_TIMER_ENB);
-	reg |= MASTER_IM_RX_TIMER_ENB;
-	reg |= MASTER_IM_TX_TIMER_ENB;
+	reg &= ~(L1E_MASTER_CHIP_REV_MASK | L1E_MASTER_CHIP_ID_MASK);
+	reg &= ~(L1E_MASTER_IM_RX_TIMER_ENB | L1E_MASTER_IM_TX_TIMER_ENB);
+	reg |= L1E_MASTER_IM_RX_TIMER_ENB;
+	reg |= L1E_MASTER_IM_TX_TIMER_ENB;
 	OUTL(atgep, ATGE_MASTER_CFG, reg);
 
 	OUTW(atgep, RX_COALSC_PKT_1e, 0);
--- a/usr/src/uts/common/io/atge/atge_l1e_reg.h	Tue Aug 07 21:36:09 2012 -0500
+++ b/usr/src/uts/common/io/atge/atge_l1e_reg.h	Fri Aug 10 10:52:49 2012 -0400
@@ -19,6 +19,8 @@
  * CDDL HEADER END
  */
 /*
+ * Copyright (c) 2012 Gary Mills
+ *
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
@@ -48,22 +50,28 @@
 } rx_cmb_t;
 #pragma	pack()
 
+/* Master configuration */
+#define	L1E_MASTER_CFG			0x1400
+#define	L1E_MASTER_RESET		0x00000001
+#define	L1E_MASTER_MTIMER_ENB		0x00000002
+#define	L1E_MASTER_IM_TX_TIMER_ENB	0x00000004
+#define	L1E_MASTER_MANUAL_INT_ENB	0x00000008
+#define	L1E_MASTER_IM_RX_TIMER_ENB	0x00000020
+#define	L1E_MASTER_CHIP_REV_MASK	0x00FF0000
+#define	L1E_MASTER_CHIP_ID_MASK		0xFF000000
+#define	L1E_MASTER_CHIP_REV_SHIFT	16
+#define	L1E_MASTER_CHIP_ID_SHIFT	24
+
+
 /*
  * DMA CFG registers (L1E specific).
  */
 #define	DMA_CFG_RD_REQ_PRI		0x00000400
-#define	DMA_CFG_RD_DELAY_CNT_MASK	0x0000F800
-#define	DMA_CFG_WR_DELAY_CNT_MASK	0x000F0000
 #define	DMA_CFG_TXCMB_ENB		0x00100000
-#define	DMA_CFG_RXCMB_ENB		0x00200000
 #define	DMA_CFG_RD_BURST_MASK		0x07
 #define	DMA_CFG_RD_BURST_SHIFT		4
 #define	DMA_CFG_WR_BURST_MASK		0x07
 #define	DMA_CFG_WR_BURST_SHIFT		7
-#define	DMA_CFG_RD_DELAY_CNT_SHIFT	11
-#define	DMA_CFG_WR_DELAY_CNT_SHIFT	16
-#define	DMA_CFG_RD_DELAY_CNT_DEFAULT	15
-#define	DMA_CFG_WR_DELAY_CNT_DEFAULT	4
 
 #define	L1E_TX_RING_CNT_MIN		32
 #define	L1E_TX_RING_CNT_MAX		1020
--- a/usr/src/uts/common/io/atge/atge_main.c	Tue Aug 07 21:36:09 2012 -0500
+++ b/usr/src/uts/common/io/atge/atge_main.c	Fri Aug 10 10:52:49 2012 -0400
@@ -20,8 +20,36 @@
  */
 
 /*
+ * Copyright (c) 2012 Gary Mills
+ *
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  */
+/*
+ * Copyright (c) 2009, Pyun YongHyeon <yongari@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
 
 #include <sys/types.h>
 #include <sys/stream.h>
@@ -53,15 +81,16 @@
 
 #include "atge.h"
 #include "atge_cmn_reg.h"
+#include "atge_l1c_reg.h"
 #include "atge_l1e_reg.h"
 #include "atge_l1_reg.h"
 
 
 /*
- * Atheros/Attansic Ethernet chips are of three types - L1, L2 and L1E.
- * This driver is for L1E/L1 but can be extended to support other chips.
+ * Atheros/Attansic Ethernet chips are of four types - L1, L2, L1E and L1C.
+ * This driver is for L1E/L1/L1C but can be extended to support other chips.
  * L1E comes in 1Gigabit and Fast Ethernet flavors. L1 comes in 1Gigabit
- * flavors only.
+ * flavors only.  L1C comes in both flavours.
  *
  * Atheros/Attansic Ethernet controllers have descriptor based TX and RX
  * with an exception of L1E. L1E's RX side is not descriptor based ring.
@@ -152,6 +181,7 @@
  * L1 specific functions.
  */
 int	atge_l1_alloc_dma(atge_t *);
+void	atge_l1_free_dma(atge_t *);
 void	atge_l1_init_tx_ring(atge_t *);
 void	atge_l1_init_rx_ring(atge_t *);
 void	atge_l1_init_rr_ring(atge_t *);
@@ -163,14 +193,34 @@
 uint_t	atge_l1_interrupt(caddr_t, caddr_t);
 void	atge_l1_send_packet(atge_ring_t *);
 
+/*
+ * L1C specific functions.
+ */
+int	atge_l1c_alloc_dma(atge_t *);
+void	atge_l1c_free_dma(atge_t *);
+void	atge_l1c_init_tx_ring(atge_t *);
+void	atge_l1c_init_rx_ring(atge_t *);
+void	atge_l1c_init_rr_ring(atge_t *);
+void	atge_l1c_init_cmb(atge_t *);
+void	atge_l1c_init_smb(atge_t *);
+void	atge_l1c_program_dma(atge_t *);
+void	atge_l1c_stop_tx_mac(atge_t *);
+void	atge_l1c_stop_rx_mac(atge_t *);
+uint_t	atge_l1c_interrupt(caddr_t, caddr_t);
+void	atge_l1c_send_packet(atge_ring_t *);
+void	atge_l1c_gather_stats(atge_t *);
+void	atge_l1c_clear_stats(atge_t *);
 
 /*
  * Function prototyps for MII operations.
  */
 uint16_t	atge_mii_read(void *, uint8_t, uint8_t);
 void	atge_mii_write(void *, uint8_t, uint8_t, uint16_t);
+uint16_t	atge_l1c_mii_read(void *, uint8_t, uint8_t);
+void	atge_l1c_mii_write(void *, uint8_t, uint8_t, uint16_t);
 void	atge_l1e_mii_reset(void *);
 void	atge_l1_mii_reset(void *);
+void	atge_l1c_mii_reset(void *);
 static void	atge_mii_notify(void *, link_state_t);
 void	atge_tx_reclaim(atge_t *atgep, int cons);
 
@@ -197,6 +247,17 @@
 };
 
 /*
+ * L1C chip.
+ */
+static	mii_ops_t atge_l1c_mii_ops = {
+	MII_OPS_VERSION,
+	atge_l1c_mii_read,
+	atge_l1c_mii_write,
+	atge_mii_notify,
+	NULL
+};
+
+/*
  * Function Prototypes for MAC callbacks.
  */
 static int	atge_m_stat(void *, uint_t, uint64_t *);
@@ -272,11 +333,28 @@
  * Table of supported devices.
  */
 #define	ATGE_VENDOR_ID	0x1969
+#define	ATGE_L1_STR	"Attansic L1"
+#define	ATGE_L1CG_STR	"Atheros AR8131 Gigabit Ethernet"
+#define	ATGE_L1CF_STR	"Atheros AR8132 Fast Ethernet"
 #define	ATGE_L1E_STR	"Atheros AR8121/8113/8114"
+#define	ATGE_AR8151V1_STR	"Atheros AR8151 v1.0 Gigabit Ethernet"
+#define	ATGE_AR8151V2_STR	"Atheros AR8151 v2.0 Gigabit Ethernet"
+#define	ATGE_AR8152V1_STR	"Atheros AR8152 v1.1 Fast Ethernet"
+#define	ATGE_AR8152V2_STR	"Atheros AR8152 v2.0 Fast Ethernet"
 
 static atge_cards_t atge_cards[] = {
+	{ATGE_VENDOR_ID, ATGE_CHIP_AR8151V2_DEV_ID, ATGE_AR8151V2_STR,
+	    ATGE_CHIP_L1C},
+	{ATGE_VENDOR_ID, ATGE_CHIP_AR8151V1_DEV_ID, ATGE_AR8151V1_STR,
+	    ATGE_CHIP_L1C},
+	{ATGE_VENDOR_ID, ATGE_CHIP_AR8152V2_DEV_ID, ATGE_AR8152V2_STR,
+	    ATGE_CHIP_L1C},
+	{ATGE_VENDOR_ID, ATGE_CHIP_AR8152V1_DEV_ID, ATGE_AR8152V1_STR,
+	    ATGE_CHIP_L1C},
+	{ATGE_VENDOR_ID, ATGE_CHIP_L1CG_DEV_ID, ATGE_L1CG_STR, ATGE_CHIP_L1C},
+	{ATGE_VENDOR_ID, ATGE_CHIP_L1CF_DEV_ID, ATGE_L1CF_STR, ATGE_CHIP_L1C},
 	{ATGE_VENDOR_ID, ATGE_CHIP_L1E_DEV_ID, ATGE_L1E_STR, ATGE_CHIP_L1E},
-	{ATGE_VENDOR_ID, ATGE_CHIP_L1_DEV_ID, "Attansic L1", ATGE_CHIP_L1},
+	{ATGE_VENDOR_ID, ATGE_CHIP_L1_DEV_ID, ATGE_L1_STR, ATGE_CHIP_L1},
 };
 
 /*
@@ -300,22 +378,47 @@
 	DTRACE_PROBE1(atge__debug, char *, buf);
 }
 
+static
+void
+atge_message(dev_info_t *dip, int level, char *fmt, va_list ap)
+{
+	char	buf[256];
+	char	*p = "!%s%d: %s";
+	char	*q = "!atge: %s";
+
+	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
+
+	if (level != CE_NOTE) {
+		p++;
+		q++;
+	}
+
+	if (dip) {
+		cmn_err(level, p,
+		    ddi_driver_name(dip), ddi_get_instance(dip), buf);
+	} else {
+		cmn_err(level, q, buf);
+	}
+}
+
+void
+atge_notice(dev_info_t *dip, char *fmt, ...)
+{
+	va_list	ap;
+
+	va_start(ap, fmt);
+	(void) atge_message(dip, CE_NOTE, fmt, ap);
+	va_end(ap);
+}
+
 void
 atge_error(dev_info_t *dip, char *fmt, ...)
 {
 	va_list	ap;
-	char	buf[256];
 
 	va_start(ap, fmt);
-	(void) vsnprintf(buf, sizeof (buf), fmt, ap);
+	(void) atge_message(dip, CE_WARN, fmt, ap);
 	va_end(ap);
-
-	if (dip) {
-		cmn_err(CE_WARN, "%s%d: %s",
-		    ddi_driver_name(dip), ddi_get_instance(dip), buf);
-	} else {
-		cmn_err(CE_WARN, "atge: %s", buf);
-	}
 }
 
 void
@@ -325,10 +428,23 @@
 	int speed;
 	link_duplex_t ld;
 
+	/* Re-enable TX/RX MACs */
 	reg = INL(atgep, ATGE_MAC_CFG);
 	reg &= ~(ATGE_CFG_FULL_DUPLEX | ATGE_CFG_TX_FC | ATGE_CFG_RX_FC |
 	    ATGE_CFG_SPEED_MASK);
 
+	switch (ATGE_MODEL(atgep)) {
+	case ATGE_CHIP_L1C:
+		switch (ATGE_DID(atgep)) {
+		case ATGE_CHIP_AR8151V2_DEV_ID:
+		case ATGE_CHIP_AR8151V1_DEV_ID:
+		case ATGE_CHIP_AR8152V2_DEV_ID:
+			reg |= ATGE_CFG_HASH_ALG_CRC32 | ATGE_CFG_SPEED_MODE_SW;
+			break;
+		}
+		break;
+	}
+
 	speed = mii_get_speed(atgep->atge_mii);
 	switch (speed) {
 	case 10:
@@ -345,19 +461,43 @@
 		reg |= ATGE_CFG_FULL_DUPLEX;
 
 	/* Re-enable TX/RX MACs */
-	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
+	switch (ATGE_MODEL(atgep)) {
+	case ATGE_CHIP_L1E:
 		reg |= ATGE_CFG_TX_ENB | ATGE_CFG_RX_ENB | ATGE_CFG_RX_FC;
-	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
+		break;
+	case ATGE_CHIP_L1:
+	case ATGE_CHIP_L1C:
 		reg |= ATGE_CFG_TX_ENB | ATGE_CFG_RX_ENB;
+		break;
 	}
 
 	OUTL(atgep, ATGE_MAC_CFG, reg);
 
-	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
+	switch (ATGE_MODEL(atgep)) {
+	case ATGE_CHIP_L1E:
 		reg = ATGE_USECS(ATGE_IM_RX_TIMER_DEFAULT) << IM_TIMER_RX_SHIFT;
 		reg |= ATGE_USECS(ATGE_IM_TX_TIMER_DEFAULT) <<
 		    IM_TIMER_TX_SHIFT;
 		OUTL(atgep, ATGE_IM_TIMER, reg);
+		break;
+	case ATGE_CHIP_L1:
+		break;
+	case ATGE_CHIP_L1C:
+		/* Configure interrupt moderation timer. */
+		reg = ATGE_USECS(atgep->atge_int_rx_mod) << IM_TIMER_RX_SHIFT;
+		reg |= ATGE_USECS(atgep->atge_int_tx_mod) << IM_TIMER_TX_SHIFT;
+		OUTL(atgep, ATGE_IM_TIMER, reg);
+		/*
+		 * We don't want to automatic interrupt clear as task queue
+		 * for the interrupt should know interrupt status.
+		 */
+		reg = 0;
+		if (ATGE_USECS(atgep->atge_int_rx_mod) != 0)
+			reg |= MASTER_IM_RX_TIMER_ENB;
+		if (ATGE_USECS(atgep->atge_int_tx_mod) != 0)
+			reg |= MASTER_IM_TX_TIMER_ENB;
+		OUTL(atgep, ATGE_MASTER_CFG, reg);
+		break;
 	}
 
 	ATGE_DB(("%s: %s() mac_cfg is : %x",
@@ -523,12 +663,19 @@
 	 * Add interrupt handler now.
 	 */
 	for (i = 0; i < atgep->atge_intr_cnt; i++) {
-		if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
+		switch (ATGE_MODEL(atgep)) {
+		case ATGE_CHIP_L1E:
 			err = ddi_intr_add_handler(atgep->atge_intr_handle[i],
 			    atge_l1e_interrupt, atgep, (caddr_t)(uintptr_t)i);
-		} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
+			break;
+		case ATGE_CHIP_L1:
 			err = ddi_intr_add_handler(atgep->atge_intr_handle[i],
 			    atge_l1_interrupt, atgep, (caddr_t)(uintptr_t)i);
+			break;
+		case ATGE_CHIP_L1C:
+			err = ddi_intr_add_handler(atgep->atge_intr_handle[i],
+			    atge_l1c_interrupt, atgep, (caddr_t)(uintptr_t)i);
+			break;
 		}
 
 		if (err != DDI_SUCCESS) {
@@ -709,9 +856,14 @@
 		if (atge_cards[i].vendor_id == vid &&
 		    atge_cards[i].device_id == did) {
 			atgep->atge_model = atge_cards[i].model;
+			atgep->atge_vid = vid;
+			atgep->atge_did = did;
 			atgep->atge_revid =
 			    pci_config_get8(atgep->atge_conf_handle,
 			    PCI_CONF_REVID);
+			atge_notice(atgep->atge_dip, "PCI-ID pci%x,%x,%x: %s",
+			    vid, did, atgep->atge_revid,
+			    atge_cards[i].cardname);
 			ATGE_DB(("%s: %s : PCI-ID pci%x,%x and model : %d",
 			    atgep->atge_name, __func__, vid, did,
 			    atgep->atge_model));
@@ -721,12 +873,14 @@
 	}
 
 	atge_error(atgep->atge_dip, "atge driver is attaching to unknown"
-	    " pci%d,%d vendor/device-id card", vid, did);
+	    " pci%x,%x vendor/device-id card", vid, did);
 
 	/*
-	 * Assume it's L1 chip.
+	 * Assume it's L1C chip.
 	 */
-	atgep->atge_model = ATGE_CHIP_L1;
+	atgep->atge_model = ATGE_CHIP_L1C;
+	atgep->atge_vid = vid;
+	atgep->atge_did = did;
 	atgep->atge_revid = pci_config_get8(atgep->atge_conf_handle,
 	    PCI_CONF_REVID);
 
@@ -774,14 +928,18 @@
 }
 
 /*
- * Reset functionality for L1 and L1E. It's same.
+ * Reset functionality for L1, L1E, and L1C. It's same.
  */
 static void
 atge_device_reset(atge_t *atgep)
 {
-	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E ||
-	    ATGE_MODEL(atgep) == ATGE_CHIP_L1)
+	switch (ATGE_MODEL(atgep)) {
+	case ATGE_CHIP_L1E:
+	case ATGE_CHIP_L1:
+	case ATGE_CHIP_L1C:
 		atge_device_reset_l1_l1e(atgep);
+		break;
+	}
 }
 
 void
@@ -789,8 +947,14 @@
 {
 	uint32_t reg;
 	int t;
-
-	OUTL(atgep, ATGE_MASTER_CFG, MASTER_RESET);
+	switch (ATGE_MODEL(atgep)) {
+	case ATGE_CHIP_L1C:
+		OUTL(atgep, ATGE_MASTER_CFG, MASTER_RESET | 0x40);
+		break;
+	default:
+		OUTL(atgep, ATGE_MASTER_CFG, MASTER_RESET);
+		break;
+	}
 	reg = INL(atgep, ATGE_MASTER_CFG);
 	for (t = ATGE_RESET_TIMEOUT; t > 0; t--) {
 		drv_usecwait(10);
@@ -816,13 +980,20 @@
 		    reg);
 	}
 
-	/*
-	 * Initialize PCIe module. These values came from FreeBSD and
-	 * we don't know the meaning of it.
-	 */
-	OUTL(atgep, 0x12FC, 0x6500);
-	reg = INL(atgep, 0x1008) | 0x8000;
-	OUTL(atgep, 0x1008, reg);
+	switch (ATGE_MODEL(atgep)) {
+	case ATGE_CHIP_L1E:
+	case ATGE_CHIP_L1:
+		/*
+		 * Initialize PCIe module. These values came from FreeBSD and
+		 * we don't know the meaning of it.
+		 */
+		OUTL(atgep, ATGE_LTSSM_ID_CFG, 0x6500);
+		reg = INL(atgep, 0x1008) | 0x8000;
+		OUTL(atgep, 0x1008, reg);
+		break;
+	case ATGE_CHIP_L1C:
+		break;
+	}
 
 	/*
 	 * Get chip revision.
@@ -843,10 +1014,16 @@
 {
 	int err = DDI_FAILURE;
 
-	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
+	switch (ATGE_MODEL(atgep)) {
+	case ATGE_CHIP_L1E:
 		err = atge_l1e_alloc_dma(atgep);
-	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
+		break;
+	case ATGE_CHIP_L1:
 		err = atge_l1_alloc_dma(atgep);
+		break;
+	case ATGE_CHIP_L1C:
+		err = atge_l1c_alloc_dma(atgep);
+		break;
 	}
 
 	return (err);
@@ -855,8 +1032,16 @@
 static void
 atge_free_dma(atge_t *atgep)
 {
-	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
+	switch (ATGE_MODEL(atgep)) {
+	case ATGE_CHIP_L1E:
 		atge_l1e_free_dma(atgep);
+		break;
+	case ATGE_CHIP_L1:
+		atge_l1_free_dma(atgep);
+		break;
+	case ATGE_CHIP_L1C:
+		atge_l1c_free_dma(atgep);
+		break;
 	}
 }
 
@@ -877,15 +1062,15 @@
 	instance =  ddi_get_instance(devinfo);
 
 	switch (cmd) {
-	default:
-		return (DDI_FAILURE);
-
 	case DDI_RESUME:
 		return (atge_resume(devinfo));
 
 	case DDI_ATTACH:
 		ddi_set_driver_private(devinfo, NULL);
 		break;
+	default:
+		return (DDI_FAILURE);
+
 	}
 
 	atgep = kmem_zalloc(sizeof (atge_t), KM_SLEEP);
@@ -951,7 +1136,8 @@
 	atgep->atge_link_state = LINK_STATE_DOWN;
 	atgep->atge_mtu = ETHERMTU;
 
-	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
+	switch (ATGE_MODEL(atgep)) {
+	case ATGE_CHIP_L1E:
 		if (atgep->atge_revid > 0xF0) {
 			/* L2E Rev. B. AR8114 */
 			atgep->atge_flags |= ATGE_FLAG_FASTETHER;
@@ -965,6 +1151,45 @@
 				atgep->atge_flags |= ATGE_FLAG_FASTETHER;
 			}
 		}
+		break;
+	case ATGE_CHIP_L1:
+		break;
+	case ATGE_CHIP_L1C:
+		/*
+		 * One odd thing is AR8132 uses the same PHY hardware(F1
+		 * gigabit PHY) of AR8131. So atphy(4) of AR8132 reports
+		 * the PHY supports 1000Mbps but that's not true. The PHY
+		 * used in AR8132 can't establish gigabit link even if it
+		 * shows the same PHY model/revision number of AR8131.
+		 *
+		 * It seems that AR813x/AR815x has silicon bug for SMB. In
+		 * addition, Atheros said that enabling SMB wouldn't improve
+		 * performance. However I think it's bad to access lots of
+		 * registers to extract MAC statistics.
+		 *
+		 * Don't use Tx CMB. It is known to have silicon bug.
+		 */
+		switch (ATGE_DID(atgep)) {
+		case ATGE_CHIP_AR8152V2_DEV_ID:
+		case ATGE_CHIP_AR8152V1_DEV_ID:
+			atgep->atge_flags |= ATGE_FLAG_APS |
+			    ATGE_FLAG_FASTETHER |
+			    ATGE_FLAG_ASPM_MON | ATGE_FLAG_JUMBO |
+			    ATGE_FLAG_SMB_BUG | ATGE_FLAG_CMB_BUG;
+			break;
+		case ATGE_CHIP_AR8151V2_DEV_ID:
+		case ATGE_CHIP_AR8151V1_DEV_ID:
+			atgep->atge_flags |= ATGE_FLAG_APS |
+			    ATGE_FLAG_ASPM_MON | ATGE_FLAG_JUMBO |
+			    ATGE_FLAG_SMB_BUG | ATGE_FLAG_CMB_BUG;
+			break;
+		case ATGE_CHIP_L1CF_DEV_ID:
+			atgep->atge_flags |= ATGE_FLAG_FASTETHER;
+			break;
+		case ATGE_CHIP_L1CG_DEV_ID:
+			break;
+		}
+		break;
 	}
 
 	/*
@@ -999,6 +1224,20 @@
 		    (128 << ((burst >> 5) & 0x07))));
 	}
 
+	/* Clear data link and flow-control protocol error. */
+	switch (ATGE_MODEL(atgep)) {
+	case ATGE_CHIP_L1E:
+		break;
+	case ATGE_CHIP_L1:
+		break;
+	case ATGE_CHIP_L1C:
+		OUTL_AND(atgep, ATGE_PEX_UNC_ERR_SEV,
+		    ~(PEX_UNC_ERR_SEV_UC | PEX_UNC_ERR_SEV_FCP));
+		OUTL_AND(atgep, ATGE_LTSSM_ID_CFG, ~LTSSM_ID_WRO_ENB);
+		OUTL_OR(atgep, ATGE_PCIE_PHYMISC, PCIE_PHYMISC_FORCE_RCV_DET);
+		break;
+	}
+
 	/*
 	 * Allocate DMA resources.
 	 */
@@ -1016,10 +1255,16 @@
 	/*
 	 * Setup MII.
 	 */
-	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
+	switch (ATGE_MODEL(atgep)) {
+	case ATGE_CHIP_L1E:
 		mii_ops = &atge_l1e_mii_ops;
-	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
+		break;
+	case ATGE_CHIP_L1:
 		mii_ops = &atge_l1_mii_ops;
+		break;
+	case ATGE_CHIP_L1C:
+		mii_ops = &atge_l1c_mii_ops;
+		break;
 	}
 
 	if ((atgep->atge_mii = mii_alloc(atgep, devinfo,
@@ -1072,10 +1317,16 @@
 	/*
 	 * Reset the PHY before starting.
 	 */
-	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
+	switch (ATGE_MODEL(atgep)) {
+	case ATGE_CHIP_L1E:
 		atge_l1e_mii_reset(atgep);
-	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
+		break;
+	case ATGE_CHIP_L1:
 		atge_l1_mii_reset(atgep);
+		break;
+	case ATGE_CHIP_L1C:
+		atge_l1c_mii_reset(atgep);
+		break;
 	}
 
 	/*
@@ -1362,8 +1613,14 @@
 	/*
 	 * Reset the PHY before resuming MII.
 	 */
-	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
+	switch (ATGE_MODEL(atgep)) {
+	case ATGE_CHIP_L1E:
 		atge_l1e_mii_reset(atgep);
+		break;
+	case ATGE_CHIP_L1:
+		break;
+	case ATGE_CHIP_L1C:
+		break;
 	}
 
 	mii_resume(atgep->atge_mii);
@@ -1797,16 +2054,45 @@
 	 */
 	atge_program_ether(atgep);
 
-	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
+	switch (ATGE_MODEL(atgep)) {
+	case ATGE_CHIP_L1E:
 		atge_l1e_program_dma(atgep);
-	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
+		break;
+	case ATGE_CHIP_L1:
 		atge_l1_program_dma(atgep);
+		break;
+	case ATGE_CHIP_L1C:
+		atge_l1c_program_dma(atgep);
+		break;
 	}
 
 	ATGE_DB(("%s: %s() dma, counters programmed ", atgep->atge_name,
 	    __func__));
 
-	OUTW(atgep, ATGE_INTR_CLR_TIMER, 1*1000/2);
+	switch (ATGE_MODEL(atgep)) {
+	case ATGE_CHIP_L1E:
+	case ATGE_CHIP_L1:
+		OUTW(atgep, ATGE_INTR_CLR_TIMER, 1*1000/2);
+		break;
+	case ATGE_CHIP_L1C:
+		/*
+		 * Disable interrupt re-trigger timer. We don't want automatic
+		 * re-triggering of un-ACKed interrupts.
+		 */
+		OUTL(atgep, ATGE_INTR_RETRIG_TIMER, ATGE_USECS(0));
+		/* Configure CMB. */
+		OUTL(atgep, ATGE_CMB_TX_TIMER, ATGE_USECS(0));
+		/*
+		 * Hardware can be configured to issue SMB interrupt based
+		 * on programmed interval. Since there is a callout that is
+		 * invoked for every hz in driver we use that instead of
+		 * relying on periodic SMB interrupt.
+		 */
+		OUTL(atgep, ATGE_SMB_STAT_TIMER, ATGE_USECS(0));
+		/* Clear MAC statistics. */
+		atge_l1c_clear_stats(atgep);
+		break;
+	}
 
 	/*
 	 * Set Maximum frame size but don't let MTU be less than ETHER_MTU.
@@ -1820,6 +2106,16 @@
 	    VLAN_TAGSZ + ETHERFCSL;
 	OUTL(atgep, ATGE_FRAME_SIZE, atgep->atge_max_frame_size);
 
+	switch (ATGE_MODEL(atgep)) {
+	case ATGE_CHIP_L1E:
+		break;
+	case ATGE_CHIP_L1:
+		break;
+	case ATGE_CHIP_L1C:
+		/* Disable header split(?) */
+		OUTL(atgep, ATGE_HDS_CFG, 0);
+		break;
+	}
 
 	/*
 	 * Configure IPG/IFG parameters.
@@ -1846,7 +2142,23 @@
 	/*
 	 * Configure jumbo frame.
 	 */
-	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
+	switch (ATGE_MODEL(atgep)) {
+	case ATGE_CHIP_L1E:
+		if (atgep->atge_flags & ATGE_FLAG_JUMBO) {
+
+			if (atgep->atge_mtu < ETHERMTU)
+				reg = atgep->atge_max_frame_size;
+			else if (atgep->atge_mtu < 6 * 1024)
+				reg = (atgep->atge_max_frame_size * 2) / 3;
+			else
+				reg = atgep->atge_max_frame_size / 2;
+
+			OUTL(atgep, L1E_TX_JUMBO_THRESH,
+			    ROUNDUP(reg, TX_JUMBO_THRESH_UNIT) >>
+			    TX_JUMBO_THRESH_UNIT_SHIFT);
+		}
+		break;
+	case ATGE_CHIP_L1:
 		fsize = ROUNDUP(atgep->atge_max_frame_size, sizeof (uint64_t));
 		OUTL(atgep, ATGE_RXQ_JUMBO_CFG,
 		    (((fsize / sizeof (uint64_t)) <<
@@ -1856,37 +2168,46 @@
 		    RXQ_JUMBO_CFG_LKAH_SHIFT) & RXQ_JUMBO_CFG_LKAH_MASK) |
 		    ((ATGE_USECS(8) << RXQ_JUMBO_CFG_RRD_TIMER_SHIFT) &
 		    RXQ_JUMBO_CFG_RRD_TIMER_MASK));
-	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E &&
-	    atgep->atge_flags & ATGE_FLAG_JUMBO) {
-
-		if (atgep->atge_mtu < ETHERMTU)
-			reg = atgep->atge_max_frame_size;
-		else if (atgep->atge_mtu < 6 * 1024)
-			reg = (atgep->atge_max_frame_size * 2) / 3;
-		else
-			reg = atgep->atge_max_frame_size / 2;
-
-		OUTL(atgep, L1E_TX_JUMBO_THRESH,
-		    ROUNDUP(reg, TX_JUMBO_THRESH_UNIT) >>
-		    TX_JUMBO_THRESH_UNIT_SHIFT);
+		break;
+	case ATGE_CHIP_L1C:
+		break;
 	}
 
 	/*
 	 * Configure flow-control parameters.
 	 */
-	if ((atgep->atge_flags & ATGE_FLAG_PCIE) != 0) {
+	switch (ATGE_MODEL(atgep)) {
+	case ATGE_CHIP_L1E:
+	case ATGE_CHIP_L1:
+		if ((atgep->atge_flags & ATGE_FLAG_PCIE) != 0) {
 		/*
 		 * Some hardware version require this magic.
 		 */
-		OUTL(atgep, 0x12FC, 0x6500);
+		OUTL(atgep, ATGE_LTSSM_ID_CFG, 0x6500);
 		reg = INL(atgep, 0x1008);
 		OUTL(atgep, 0x1008, reg | 0x8000);
+		}
+		break;
+	case ATGE_CHIP_L1C:
+		break;
 	}
 
 	/*
 	 * These are all magic parameters which came from FreeBSD.
 	 */
-	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
+	switch (ATGE_MODEL(atgep)) {
+	case ATGE_CHIP_L1E:
+		reg = INL(atgep, L1E_SRAM_RX_FIFO_LEN);
+		rxf_hi = (reg * 4) / 5;
+		rxf_lo = reg/ 5;
+
+		OUTL(atgep, ATGE_RXQ_FIFO_PAUSE_THRESH,
+		    ((rxf_lo << RXQ_FIFO_PAUSE_THRESH_LO_SHIFT) &
+		    RXQ_FIFO_PAUSE_THRESH_LO_MASK) |
+		    ((rxf_hi << RXQ_FIFO_PAUSE_THRESH_HI_SHIFT) &
+		    RXQ_FIFO_PAUSE_THRESH_HI_MASK));
+		break;
+	case ATGE_CHIP_L1:
 		switch (atgep->atge_chip_rev) {
 		case 0x8001:
 		case 0x9001:
@@ -1926,54 +2247,46 @@
 		    RXQ_RRD_PAUSE_THRESH_LO_MASK) |
 		    ((rrd_hi << RXQ_RRD_PAUSE_THRESH_HI_SHIFT) &
 		    RXQ_RRD_PAUSE_THRESH_HI_MASK));
-	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
-		reg = INL(atgep, L1E_SRAM_RX_FIFO_LEN);
-		rxf_hi = (reg * 4) / 5;
-		rxf_lo = reg/ 5;
-
-		OUTL(atgep, ATGE_RXQ_FIFO_PAUSE_THRESH,
-		    ((rxf_lo << RXQ_FIFO_PAUSE_THRESH_LO_SHIFT) &
-		    RXQ_FIFO_PAUSE_THRESH_LO_MASK) |
-		    ((rxf_hi << RXQ_FIFO_PAUSE_THRESH_HI_SHIFT) &
-		    RXQ_FIFO_PAUSE_THRESH_HI_MASK));
+		break;
+	case ATGE_CHIP_L1C:
+		switch (ATGE_DID(atgep)) {
+		case ATGE_CHIP_AR8151V2_DEV_ID:
+		case ATGE_CHIP_AR8152V1_DEV_ID:
+			OUTL(atgep, ATGE_SERDES_LOCK,
+			    INL(atgep, ATGE_SERDES_LOCK) |
+			    SERDES_MAC_CLK_SLOWDOWN |
+			    SERDES_PHY_CLK_SLOWDOWN);
+			break;
+		case ATGE_CHIP_L1CG_DEV_ID:
+		case ATGE_CHIP_L1CF_DEV_ID:
+			/*
+			 * Configure flow control parameters.
+			 * XON	: 80% of Rx FIFO
+			 * XOFF : 30% of Rx FIFO
+			 */
+			reg = INL(atgep, L1C_SRAM_RX_FIFO_LEN);
+			rxf_hi = (reg * 8) / 10;
+			rxf_lo = (reg * 3) / 10;
+
+			OUTL(atgep, ATGE_RXQ_FIFO_PAUSE_THRESH,
+			    ((rxf_lo << RXQ_FIFO_PAUSE_THRESH_LO_SHIFT) &
+			    RXQ_FIFO_PAUSE_THRESH_LO_MASK) |
+			    ((rxf_hi << RXQ_FIFO_PAUSE_THRESH_HI_SHIFT) &
+			    RXQ_FIFO_PAUSE_THRESH_HI_MASK));
+			break;
+		}
+		break;
 	}
 
-	/* Configure RxQ. */
-	reg = 0;
-	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
-		reg =
-		    ((RXQ_CFG_RD_BURST_DEFAULT << RXQ_CFG_RD_BURST_SHIFT) &
-		    RXQ_CFG_RD_BURST_MASK) |
-		    ((RXQ_CFG_RRD_BURST_THRESH_DEFAULT <<
-		    RXQ_CFG_RRD_BURST_THRESH_SHIFT) &
-		    RXQ_CFG_RRD_BURST_THRESH_MASK) |
-		    ((RXQ_CFG_RD_PREF_MIN_IPG_DEFAULT <<
-		    RXQ_CFG_RD_PREF_MIN_IPG_SHIFT) &
-		    RXQ_CFG_RD_PREF_MIN_IPG_MASK) |
-		    RXQ_CFG_CUT_THROUGH_ENB | RXQ_CFG_ENB;
-		OUTL(atgep, ATGE_RXQ_CFG, reg);
-	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
+	switch (ATGE_MODEL(atgep)) {
+	case ATGE_CHIP_L1E:
+		/* Configure RxQ. */
 		reg = RXQ_CFG_ALIGN_32 | RXQ_CFG_CUT_THROUGH_ENB |
 		    RXQ_CFG_IPV6_CSUM_VERIFY | RXQ_CFG_ENB;
 		OUTL(atgep, ATGE_RXQ_CFG, reg);
-	}
-
-	/*
-	 * Configure TxQ.
-	 */
-	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
-		reg =
-		    (((TXQ_CFG_TPD_BURST_DEFAULT << TXQ_CFG_TPD_BURST_SHIFT) &
-		    TXQ_CFG_TPD_BURST_MASK) |
-		    ((TXQ_CFG_TX_FIFO_BURST_DEFAULT <<
-		    TXQ_CFG_TX_FIFO_BURST_SHIFT) &
-		    TXQ_CFG_TX_FIFO_BURST_MASK) |
-		    ((TXQ_CFG_TPD_FETCH_DEFAULT <<
-		    TXQ_CFG_TPD_FETCH_THRESH_SHIFT) &
-		    TXQ_CFG_TPD_FETCH_THRESH_MASK) |
-		    TXQ_CFG_ENB);
-		OUTL(atgep, ATGE_TXQ_CFG, reg);
-	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
+		/*
+		 * Configure TxQ.
+		 */
 		reg = (128 <<
 		    (atgep->atge_dma_rd_burst >> DMA_CFG_RD_BURST_SHIFT)) <<
 		    TXQ_CFG_TX_FIFO_BURST_SHIFT;
@@ -1984,38 +2297,12 @@
 		reg |= TXQ_CFG_ENHANCED_MODE | TXQ_CFG_ENB;
 
 		OUTL(atgep, ATGE_TXQ_CFG, reg);
-	}
-
-	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
-		OUTL(atgep, L1_TX_JUMBO_TPD_TH_IPG,
-		    (((fsize / sizeof (uint64_t) << TX_JUMBO_TPD_TH_SHIFT)) &
-		    TX_JUMBO_TPD_TH_MASK) |
-		    ((TX_JUMBO_TPD_IPG_DEFAULT << TX_JUMBO_TPD_IPG_SHIFT) &
-		    TX_JUMBO_TPD_IPG_MASK));
-	}
-
-	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
 		/* Disable RSS. */
 		OUTL(atgep, L1E_RSS_IDT_TABLE0, 0);
 		OUTL(atgep, L1E_RSS_CPU, 0);
-	}
-
-	/*
-	 * Configure DMA parameters.
-	 */
-	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
-		OUTL(atgep, ATGE_DMA_CFG,
-		    DMA_CFG_ENH_ORDER | DMA_CFG_RCB_64 |
-		    atgep->atge_dma_rd_burst | DMA_CFG_RD_ENB |
-		    atgep->atge_dma_wr_burst | DMA_CFG_WR_ENB);
-
-		/* Configure CMB DMA write threshold. */
-		OUTL(atgep, L1_CMB_WR_THRESH,
-		    ((CMB_WR_THRESH_RRD_DEFAULT << CMB_WR_THRESH_RRD_SHIFT) &
-		    CMB_WR_THRESH_RRD_MASK) |
-		    ((CMB_WR_THRESH_TPD_DEFAULT << CMB_WR_THRESH_TPD_SHIFT) &
-		    CMB_WR_THRESH_TPD_MASK));
-	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
+		/*
+		 * Configure DMA parameters.
+		 */
 		/*
 		 * Don't use Tx CMB. It is known to cause RRS update failure
 		 * under certain circumstances. Typical phenomenon of the
@@ -2030,12 +2317,62 @@
 		    DMA_CFG_RD_DELAY_CNT_SHIFT) & DMA_CFG_RD_DELAY_CNT_MASK) |
 		    ((DMA_CFG_WR_DELAY_CNT_DEFAULT <<
 		    DMA_CFG_WR_DELAY_CNT_SHIFT) & DMA_CFG_WR_DELAY_CNT_MASK));
-	}
-
-	/*
-	 * Enable CMB/SMB timer.
-	 */
-	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
+		/*
+		 * Enable CMB/SMB timer.
+		 */
+		OUTL(atgep, L1E_SMB_STAT_TIMER, 100000);
+		atge_l1e_clear_stats(atgep);
+		break;
+	case ATGE_CHIP_L1:
+		/* Configure RxQ. */
+		reg =
+		    ((RXQ_CFG_RD_BURST_DEFAULT << RXQ_CFG_RD_BURST_SHIFT) &
+		    RXQ_CFG_RD_BURST_MASK) |
+		    ((RXQ_CFG_RRD_BURST_THRESH_DEFAULT <<
+		    RXQ_CFG_RRD_BURST_THRESH_SHIFT) &
+		    RXQ_CFG_RRD_BURST_THRESH_MASK) |
+		    ((RXQ_CFG_RD_PREF_MIN_IPG_DEFAULT <<
+		    RXQ_CFG_RD_PREF_MIN_IPG_SHIFT) &
+		    RXQ_CFG_RD_PREF_MIN_IPG_MASK) |
+		    RXQ_CFG_CUT_THROUGH_ENB | RXQ_CFG_ENB;
+		OUTL(atgep, ATGE_RXQ_CFG, reg);
+		/*
+		 * Configure TxQ.
+		 */
+		reg =
+		    (((TXQ_CFG_TPD_BURST_DEFAULT << TXQ_CFG_TPD_BURST_SHIFT) &
+		    TXQ_CFG_TPD_BURST_MASK) |
+		    ((TXQ_CFG_TX_FIFO_BURST_DEFAULT <<
+		    TXQ_CFG_TX_FIFO_BURST_SHIFT) &
+		    TXQ_CFG_TX_FIFO_BURST_MASK) |
+		    ((TXQ_CFG_TPD_FETCH_DEFAULT <<
+		    TXQ_CFG_TPD_FETCH_THRESH_SHIFT) &
+		    TXQ_CFG_TPD_FETCH_THRESH_MASK) |
+		    TXQ_CFG_ENB);
+		OUTL(atgep, ATGE_TXQ_CFG, reg);
+		/* Jumbo frames */
+		OUTL(atgep, L1_TX_JUMBO_TPD_TH_IPG,
+		    (((fsize / sizeof (uint64_t) << TX_JUMBO_TPD_TH_SHIFT)) &
+		    TX_JUMBO_TPD_TH_MASK) |
+		    ((TX_JUMBO_TPD_IPG_DEFAULT << TX_JUMBO_TPD_IPG_SHIFT) &
+		    TX_JUMBO_TPD_IPG_MASK));
+		/*
+		 * Configure DMA parameters.
+		 */
+		OUTL(atgep, ATGE_DMA_CFG,
+		    DMA_CFG_ENH_ORDER | DMA_CFG_RCB_64 |
+		    atgep->atge_dma_rd_burst | DMA_CFG_RD_ENB |
+		    atgep->atge_dma_wr_burst | DMA_CFG_WR_ENB);
+
+		/* Configure CMB DMA write threshold. */
+		OUTL(atgep, L1_CMB_WR_THRESH,
+		    ((CMB_WR_THRESH_RRD_DEFAULT << CMB_WR_THRESH_RRD_SHIFT) &
+		    CMB_WR_THRESH_RRD_MASK) |
+		    ((CMB_WR_THRESH_TPD_DEFAULT << CMB_WR_THRESH_TPD_SHIFT) &
+		    CMB_WR_THRESH_TPD_MASK));
+		/*
+		 * Enable CMB/SMB timer.
+		 */
 		/* Set CMB/SMB timer and enable them. */
 		OUTL(atgep, L1_CMB_WR_TIMER,
 		    ((ATGE_USECS(2) << CMB_WR_TIMER_TX_SHIFT) &
@@ -2047,12 +2384,54 @@
 		OUTL(atgep, L1_SMB_TIMER, ATGE_USECS(1000 * 1000));
 		OUTL(atgep, L1_CSMB_CTRL,
 		    CSMB_CTRL_SMB_ENB | CSMB_CTRL_CMB_ENB);
-	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
-		OUTL(atgep, L1E_SMB_STAT_TIMER, 100000);
-		atge_l1e_clear_stats(atgep);
+		break;
+	case ATGE_CHIP_L1C:
+		/* Configure RxQ. */
+		reg =
+		    RXQ_CFG_RD_BURST_DEFAULT << L1C_RXQ_CFG_RD_BURST_SHIFT |
+		    RXQ_CFG_IPV6_CSUM_VERIFY | RXQ_CFG_ENB;
+		if ((atgep->atge_flags & ATGE_FLAG_ASPM_MON) != 0)
+			reg |= RXQ_CFG_ASPM_THROUGHPUT_LIMIT_1M;
+		OUTL(atgep, ATGE_RXQ_CFG, reg);
+		/*
+		 * Configure TxQ.
+		 */
+		reg = (128 <<
+		    (atgep->atge_dma_rd_burst >> DMA_CFG_RD_BURST_SHIFT)) <<
+		    TXQ_CFG_TX_FIFO_BURST_SHIFT;
+
+		switch (ATGE_DID(atgep)) {
+		case ATGE_CHIP_AR8152V2_DEV_ID:
+		case ATGE_CHIP_AR8152V1_DEV_ID:
+			reg >>= 1;
+			break;
+		}
+
+		reg |= (L1C_TXQ_CFG_TPD_BURST_DEFAULT <<
+		    TXQ_CFG_TPD_BURST_SHIFT) & TXQ_CFG_TPD_BURST_MASK;
+
+		reg |= TXQ_CFG_ENHANCED_MODE | TXQ_CFG_ENB;
+
+		OUTL(atgep, L1C_TXQ_CFG, reg);
+		/* Disable RSS until I understand L1C/L2C's RSS logic. */
+		OUTL(atgep, L1C_RSS_IDT_TABLE0, 0xe4e4e4e4);
+		OUTL(atgep, L1C_RSS_CPU, 0);
+		/*
+		 * Configure DMA parameters.
+		 */
+		OUTL(atgep, ATGE_DMA_CFG,
+		    DMA_CFG_SMB_DIS |
+		    DMA_CFG_OUT_ORDER | DMA_CFG_RD_REQ_PRI | DMA_CFG_RCB_64 |
+		    DMA_CFG_RD_DELAY_CNT_DEFAULT << DMA_CFG_RD_DELAY_CNT_SHIFT |
+		    DMA_CFG_WR_DELAY_CNT_DEFAULT << DMA_CFG_WR_DELAY_CNT_SHIFT |
+
+		    atgep->atge_dma_rd_burst | DMA_CFG_RD_ENB |
+		    atgep->atge_dma_wr_burst | DMA_CFG_WR_ENB);
+		/* Configure CMB DMA write threshold not required. */
+		/* Set CMB/SMB timer and enable them not required. */
+		break;
 	}
 
-
 	/*
 	 * Disable all WOL bits as WOL can interfere normal Rx
 	 * operation.
@@ -2072,6 +2451,22 @@
 	    ((ATGE_CFG_PREAMBLE_DEFAULT << ATGE_CFG_PREAMBLE_SHIFT) &
 	    ATGE_CFG_PREAMBLE_MASK));
 
+	/*
+	 *  AR813x/AR815x always does checksum computation regardless
+	 *  of MAC_CFG_RXCSUM_ENB bit. Also the controller is known to
+	 *  have bug in protocol field in Rx return structure so
+	 *  these controllers can't handle fragmented frames. Disable
+	 *  Rx checksum offloading until there is a newer controller
+	 *  that has sane implementation.
+	 */
+	switch (ATGE_DID(atgep)) {
+	case ATGE_CHIP_AR8151V2_DEV_ID:
+	case ATGE_CHIP_AR8151V1_DEV_ID:
+	case ATGE_CHIP_AR8152V2_DEV_ID:
+		reg |= ATGE_CFG_HASH_ALG_CRC32 | ATGE_CFG_SPEED_MODE_SW;
+		break;
+	}
+
 	if ((atgep->atge_flags & ATGE_FLAG_FASTETHER) != 0) {
 		reg |= ATGE_CFG_SPEED_10_100;
 		ATGE_DB(("%s: %s() Fast Ethernet", atgep->atge_name, __func__));
@@ -2079,6 +2474,11 @@
 		reg |= ATGE_CFG_SPEED_1000;
 		ATGE_DB(("%s: %s() 1G speed", atgep->atge_name, __func__));
 	}
+	switch (ATGE_MODEL(atgep)) {
+	case ATGE_CHIP_L1C:
+		reg |= L1C_CFG_SINGLE_PAUSE_ENB;
+		break;
+	}
 
 	OUTL(atgep, ATGE_MAC_CFG, reg);
 
@@ -2092,13 +2492,17 @@
 	/*
 	 * Acknowledge all pending interrupts and clear it.
 	 */
-	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
-		OUTL(atgep, ATGE_INTR_STATUS, 0);
-		OUTL(atgep, ATGE_INTR_MASK, atgep->atge_intrs);
-	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
+	switch (ATGE_MODEL(atgep)) {
+	case ATGE_CHIP_L1E:
 		OUTL(atgep, ATGE_INTR_MASK, L1E_INTRS);
 		OUTL(atgep, ATGE_INTR_STATUS, 0xFFFFFFFF);
 		OUTL(atgep, ATGE_INTR_STATUS, 0);
+		break;
+	case ATGE_CHIP_L1:
+	case ATGE_CHIP_L1C:
+		OUTL(atgep, ATGE_INTR_STATUS, 0);
+		OUTL(atgep, ATGE_INTR_MASK, atgep->atge_intrs);
+		break;
 	}
 
 	atge_mac_config(atgep);
@@ -2194,8 +2598,13 @@
 	/*
 	 * Collect stats for L1E. L1 chip's stats are collected by interrupt.
 	 */
-	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
+	switch (ATGE_MODEL(atgep)) {
+	case ATGE_CHIP_L1E:
 		atge_l1e_gather_stats(atgep);
+		break;
+	case ATGE_CHIP_L1:
+	case ATGE_CHIP_L1C:
+		break;
 	}
 
 	/*
@@ -2203,40 +2612,70 @@
 	 */
 	atge_disable_intrs(atgep);
 
-	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1)
-		OUTL(atgep, L1_CSMB_CTRL, 0);
-
-	/* Stop DMA Engine */
-	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
-		atge_l1_stop_tx_mac(atgep);
-		atge_l1_stop_rx_mac(atgep);
-
-		reg = INL(atgep, ATGE_DMA_CFG);
-		reg &= ~(DMA_CFG_RD_ENB | DMA_CFG_WR_ENB);
-		OUTL(atgep, ATGE_DMA_CFG, reg);
-
-	}
-
-	/*
-	 * Disable queue processing.
-	 */
-	/* Stop TxQ */
-	reg = INL(atgep, ATGE_TXQ_CFG);
-	reg = reg & ~TXQ_CFG_ENB;
-	OUTL(atgep, ATGE_TXQ_CFG, reg);
-
-	/* Stop RxQ */
-	reg = INL(atgep, ATGE_RXQ_CFG);
-	reg = reg & ~RXQ_CFG_ENB;
-	OUTL(atgep, ATGE_RXQ_CFG, reg);
-
-	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
+	switch (ATGE_MODEL(atgep)) {
+	case ATGE_CHIP_L1E:
+		/* Clear CTRL not required. */
+		/* Stop DMA Engine not required. */
+		/*
+		 * Disable queue processing.
+		 */
+		/* Stop TxQ */
+		reg = INL(atgep, ATGE_TXQ_CFG);
+		reg = reg & ~TXQ_CFG_ENB;
+		OUTL(atgep, ATGE_TXQ_CFG, reg);
+		/* Stop RxQ */
+		reg = INL(atgep, ATGE_RXQ_CFG);
+		reg = reg & ~RXQ_CFG_ENB;
+		OUTL(atgep, ATGE_RXQ_CFG, reg);
+		/* Stop DMA */
 		reg = INL(atgep, ATGE_DMA_CFG);
 		reg = reg & ~(DMA_CFG_TXCMB_ENB | DMA_CFG_RXCMB_ENB);
 		OUTL(atgep, ATGE_DMA_CFG, reg);
 		drv_usecwait(1000);
 		atge_l1e_stop_mac(atgep);
 		OUTL(atgep, ATGE_INTR_STATUS, 0xFFFFFFFF);
+		break;
+	case ATGE_CHIP_L1:
+		/* Clear CTRL. */
+		OUTL(atgep, L1_CSMB_CTRL, 0);
+		/* Stop DMA Engine */
+		atge_l1_stop_tx_mac(atgep);
+		atge_l1_stop_rx_mac(atgep);
+		reg = INL(atgep, ATGE_DMA_CFG);
+		reg &= ~(DMA_CFG_RD_ENB | DMA_CFG_WR_ENB);
+		OUTL(atgep, ATGE_DMA_CFG, reg);
+		/*
+		 * Disable queue processing.
+		 */
+		/* Stop TxQ */
+		reg = INL(atgep, ATGE_TXQ_CFG);
+		reg = reg & ~TXQ_CFG_ENB;
+		OUTL(atgep, ATGE_TXQ_CFG, reg);
+		/* Stop RxQ */
+		reg = INL(atgep, ATGE_RXQ_CFG);
+		reg = reg & ~RXQ_CFG_ENB;
+		OUTL(atgep, ATGE_RXQ_CFG, reg);
+		break;
+	case ATGE_CHIP_L1C:
+		/* Clear CTRL not required. */
+		/* Stop DMA Engine */
+		atge_l1c_stop_tx_mac(atgep);
+		atge_l1c_stop_rx_mac(atgep);
+		reg = INL(atgep, ATGE_DMA_CFG);
+		reg &= ~(DMA_CFG_RD_ENB | DMA_CFG_WR_ENB);
+		OUTL(atgep, ATGE_DMA_CFG, reg);
+		/*
+		 * Disable queue processing.
+		 */
+		/* Stop TxQ */
+		reg = INL(atgep, L1C_TXQ_CFG);
+		reg = reg & ~TXQ_CFG_ENB;
+		OUTL(atgep, L1C_TXQ_CFG, reg);
+		/* Stop RxQ */
+		reg = INL(atgep, ATGE_RXQ_CFG);
+		reg = reg & ~RXQ_CFG_ENB;
+		OUTL(atgep, ATGE_RXQ_CFG, reg);
+		break;
 	}
 
 	for (t = ATGE_RESET_TIMEOUT; t > 0; t--) {
@@ -2261,13 +2700,15 @@
 void
 atge_device_init(atge_t *atgep)
 {
-	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
+	switch (ATGE_MODEL(atgep)) {
+	case ATGE_CHIP_L1E:
 		atgep->atge_intrs = L1E_INTRS;
 		atgep->atge_int_mod = ATGE_IM_TIMER_DEFAULT;
 
 		atge_l1e_init_tx_ring(atgep);
 		atge_l1e_init_rx_pages(atgep);
-	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
+		break;
+	case ATGE_CHIP_L1:
 		atgep->atge_intrs = L1_INTRS | INTR_GPHY | INTR_PHY_LINK_DOWN |
 		    INTR_LINK_CHG;
 		atgep->atge_int_mod = ATGE_IM_TIMER_DEFAULT;
@@ -2277,6 +2718,22 @@
 		atge_l1_init_rr_ring(atgep);
 		atge_l1_init_cmb(atgep);
 		atge_l1_init_smb(atgep);
+		break;
+	case ATGE_CHIP_L1C:
+		atgep->atge_intrs = L1C_INTRS | L1C_INTR_GPHY |
+		    L1C_INTR_PHY_LINK_DOWN;
+		atgep->atge_int_rx_mod = 400/2;
+		atgep->atge_int_tx_mod = 2000/1;
+
+		atge_l1c_init_tx_ring(atgep);
+		atge_l1c_init_rx_ring(atgep);
+		atge_l1c_init_rr_ring(atgep);
+		atge_l1c_init_cmb(atgep);
+		atge_l1c_init_smb(atgep);
+
+		/* Enable all clocks. */
+		OUTL(atgep, ATGE_CLK_GATING_CFG, 0);
+		break;
 	}
 }
 
@@ -2311,7 +2768,6 @@
 static int
 atge_send_a_packet(atge_t *atgep, mblk_t *mp)
 {
-	atge_tx_desc_t	*txd;
 	uchar_t *c;
 	uint32_t cflags = 0;
 	atge_ring_t *r;
@@ -2361,17 +2817,40 @@
 	r->r_avail_desc--;
 
 	c = (uchar_t *)r->r_desc_ring->addr;
-	c += (sizeof (atge_tx_desc_t) * start);
-	txd = (atge_tx_desc_t *)c;
-
-	ATGE_PUT64(r->r_desc_ring, &txd->addr,
-	    r->r_buf_tbl[start]->cookie.dmac_laddress);
-
-	ATGE_PUT32(r->r_desc_ring, &txd->len, ATGE_TX_BYTES(pktlen));
-
-	cflags |= ATGE_TD_EOP;
-	ATGE_PUT32(r->r_desc_ring, &txd->flags, cflags);
-
+	switch (ATGE_MODEL(atgep)) {
+	case ATGE_CHIP_L1C:
+		{
+		l1c_tx_desc_t	*txd;
+
+		c += (sizeof (l1c_tx_desc_t) * start);
+		txd = (l1c_tx_desc_t *)c;
+
+		ATGE_PUT64(r->r_desc_ring, &txd->addr,
+		    r->r_buf_tbl[start]->cookie.dmac_laddress);
+
+		ATGE_PUT32(r->r_desc_ring, &txd->len, L1C_TX_BYTES(pktlen));
+
+		cflags |= L1C_TD_EOP;
+		ATGE_PUT32(r->r_desc_ring, &txd->flags, cflags);
+		break;
+		}
+	default:
+		{
+		atge_tx_desc_t	*txd;
+
+		c += (sizeof (atge_tx_desc_t) * start);
+		txd = (atge_tx_desc_t *)c;
+
+		ATGE_PUT64(r->r_desc_ring, &txd->addr,
+		    r->r_buf_tbl[start]->cookie.dmac_laddress);
+
+		ATGE_PUT32(r->r_desc_ring, &txd->len, ATGE_TX_BYTES(pktlen));
+
+		cflags |= ATGE_TD_EOP;
+		ATGE_PUT32(r->r_desc_ring, &txd->flags, cflags);
+		break;
+		}
+	}
 	/*
 	 * Sync buffer first.
 	 */
@@ -2390,10 +2869,16 @@
 	/*
 	 * Program TX descriptor to send a packet.
 	 */
-	if (ATGE_MODEL(atgep) == ATGE_CHIP_L1E) {
+	switch (ATGE_MODEL(atgep)) {
+	case ATGE_CHIP_L1E:
 		atge_l1e_send_packet(r);
-	} else if (ATGE_MODEL(atgep) == ATGE_CHIP_L1) {
+		break;
+	case ATGE_CHIP_L1:
 		atge_l1_send_packet(r);
+		break;
+	case ATGE_CHIP_L1C:
+		atge_l1c_send_packet(r);
+		break;
 	}
 
 	r->r_atge->atge_opackets++;
--- a/usr/src/uts/common/io/atge/atge_mii.c	Tue Aug 07 21:36:09 2012 -0500
+++ b/usr/src/uts/common/io/atge/atge_mii.c	Fri Aug 10 10:52:49 2012 -0400
@@ -1,3 +1,29 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2012 Gary Mills
+ *
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
 /*
  * Copyright (c) 2008, Pyun YongHyeon <yongari@FreeBSD.org>
  * All rights reserved.
@@ -30,6 +56,7 @@
 
 #include "atge.h"
 #include "atge_cmn_reg.h"
+#include "atge_l1c_reg.h"
 #include "atge_l1e_reg.h"
 #include "atge_l1_reg.h"
 
@@ -90,7 +117,7 @@
 	    MDIO_SUP_PREAMBLE | MDIO_CLK_25_4 | MDIO_REG_ADDR(reg));
 
 	for (i = PHY_TIMEOUT; i > 0; i--) {
-		drv_usecwait(1);
+		drv_usecwait(5);
 		v = INL(atgep, ATGE_MDIO);
 		if ((v & (MDIO_OP_EXECUTE | MDIO_OP_BUSY)) == 0)
 			break;
@@ -210,3 +237,147 @@
 		atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, 0x024E);
 	}
 }
+
+void
+atge_l1c_mii_reset(void *arg)
+{
+	atge_t *atgep = arg;
+	uint16_t data;
+	int phyaddr;
+
+	phyaddr = mii_get_addr(atgep->atge_mii);
+
+	/* Reset magic from Linux, via Freebsd */
+	OUTW(atgep, ATGE_GPHY_CTRL,
+	    GPHY_CTRL_HIB_EN | GPHY_CTRL_HIB_PULSE | GPHY_CTRL_SEL_ANA_RESET);
+	(void) INW(atgep, ATGE_GPHY_CTRL);
+	drv_usecwait(10 * 1000);
+
+	OUTW(atgep, ATGE_GPHY_CTRL,
+	    GPHY_CTRL_EXT_RESET | GPHY_CTRL_HIB_EN | GPHY_CTRL_HIB_PULSE |
+	    GPHY_CTRL_SEL_ANA_RESET);
+	(void) INW(atgep, ATGE_GPHY_CTRL);
+	drv_usecwait(10 * 1000);
+
+	/*
+	 * Some fast ethernet chips may not be able to auto-nego with
+	 * switches even though they have 1000T based PHY. Hence we need
+	 * to write 0 to MII_MSCONTROL control register.
+	 */
+	if (atgep->atge_flags & ATGE_FLAG_FASTETHER)
+		atge_mii_write(atgep, phyaddr, MII_MSCONTROL, 0x0);
+
+	/* DSP fixup, Vendor magic. */
+	switch (ATGE_DID(atgep)) {
+		uint16_t reg;
+
+	case ATGE_CHIP_AR8152V1_DEV_ID:
+		atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0x000A);
+		reg = atge_mii_read(atgep, phyaddr, ATPHY_DBG_DATA);
+		atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, reg & 0xDFFF);
+		/* FALLTHROUGH */
+	case ATGE_CHIP_AR8151V2_DEV_ID:
+	case ATGE_CHIP_AR8151V1_DEV_ID:
+	case ATGE_CHIP_AR8152V2_DEV_ID:
+		atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0x003B);
+		reg = atge_mii_read(atgep, phyaddr, ATPHY_DBG_DATA);
+		atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, reg & 0xFFF7);
+		drv_usecwait(20 * 1000);
+		break;
+	}
+
+	switch (ATGE_DID(atgep)) {
+	case ATGE_CHIP_AR8151V1_DEV_ID:
+		atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0x0029);
+		atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, 0x929D);
+		break;
+	case ATGE_CHIP_AR8151V2_DEV_ID:
+	case ATGE_CHIP_AR8152V2_DEV_ID:
+	case ATGE_CHIP_L1CG_DEV_ID:
+	case ATGE_CHIP_L1CF_DEV_ID:
+		atge_mii_write(atgep, phyaddr, ATPHY_DBG_ADDR, 0x0029);
+		atge_mii_write(atgep, phyaddr, ATPHY_DBG_DATA, 0xB6DD);
+		break;
+	}
+
+	/* Load DSP codes, vendor magic. */
+	data = ANA_LOOP_SEL_10BT | ANA_EN_MASK_TB | ANA_EN_10BT_IDLE |
+	    ((1 << ANA_INTERVAL_SEL_TIMER_SHIFT) &
+	    ANA_INTERVAL_SEL_TIMER_MASK);
+	atge_mii_write(atgep, phyaddr,
+	    ATPHY_DBG_ADDR, MII_ANA_CFG18);
+	atge_mii_write(atgep, phyaddr,
+	    ATPHY_DBG_DATA, data);
+
+	data = ((2 << ANA_SERDES_CDR_BW_SHIFT) & ANA_SERDES_CDR_BW_MASK) |
+	    ANA_MS_PAD_DBG | ANA_SERDES_EN_DEEM | ANA_SERDES_SEL_HSP |
+	    ANA_SERDES_EN_PLL | ANA_SERDES_EN_LCKDT;
+	atge_mii_write(atgep, phyaddr,
+	    ATPHY_DBG_ADDR, MII_ANA_CFG5);
+	atge_mii_write(atgep, phyaddr,
+	    ATPHY_DBG_DATA, data);
+
+	data = ((44 << ANA_LONG_CABLE_TH_100_SHIFT) &
+	    ANA_LONG_CABLE_TH_100_MASK) |
+	    ((33 << ANA_SHORT_CABLE_TH_100_SHIFT) &
+	    ANA_SHORT_CABLE_TH_100_SHIFT) |
+	    ANA_BP_BAD_LINK_ACCUM | ANA_BP_SMALL_BW;
+	atge_mii_write(atgep, phyaddr,
+	    ATPHY_DBG_ADDR, MII_ANA_CFG54);
+	atge_mii_write(atgep, phyaddr,
+	    ATPHY_DBG_DATA, data);
+
+	data = ((11 << ANA_IECHO_ADJ_3_SHIFT) & ANA_IECHO_ADJ_3_MASK) |
+	    ((11 << ANA_IECHO_ADJ_2_SHIFT) & ANA_IECHO_ADJ_2_MASK) |
+	    ((8 << ANA_IECHO_ADJ_1_SHIFT) & ANA_IECHO_ADJ_1_MASK) |
+	    ((8 << ANA_IECHO_ADJ_0_SHIFT) & ANA_IECHO_ADJ_0_MASK);
+	atge_mii_write(atgep, phyaddr,
+	    ATPHY_DBG_ADDR, MII_ANA_CFG4);
+	atge_mii_write(atgep, phyaddr,
+	    ATPHY_DBG_DATA, data);
+
+	data = ((7 & ANA_MANUL_SWICH_ON_SHIFT) & ANA_MANUL_SWICH_ON_MASK) |
+	    ANA_RESTART_CAL | ANA_MAN_ENABLE | ANA_SEL_HSP | ANA_EN_HB |
+	    ANA_OEN_125M;
+	atge_mii_write(atgep, phyaddr,
+	    ATPHY_DBG_ADDR, MII_ANA_CFG0);
+	atge_mii_write(atgep, phyaddr,
+	    ATPHY_DBG_DATA, data);
+	drv_usecwait(1000);
+}
+
+uint16_t
+atge_l1c_mii_read(void *arg, uint8_t phy, uint8_t reg)
+{
+
+	if (phy != 0) {
+		/* avoid PHY address alias */
+		return (0xffffU);
+	}
+
+	return (atge_mii_read(arg, phy, reg));
+}
+
+void
+atge_l1c_mii_write(void *arg, uint8_t phy, uint8_t reg, uint16_t val)
+{
+
+	if (phy != 0) {
+		/* avoid PHY address alias */
+		return;
+	}
+
+	if (reg == MII_CONTROL) {
+		/*
+		 * Don't issue a reset if MII_CONTROL_RESET is set.
+		 * Otherwise it occasionally
+		 * advertises incorrect capability.
+		 */
+		if ((val & MII_CONTROL_RESET) == 0) {
+			/* RESET bit is required to set mode */
+			atge_mii_write(arg, phy, reg, val | MII_CONTROL_RESET);
+		}
+	} else {
+		atge_mii_write(arg, phy, reg, val);
+	}
+}