# HG changeset patch # User Gary Mills # Date 1344610369 14400 # Node ID ed21ea5d20cf78f030fa40efc56b75cdea0014bb # Parent 8c906b14afbda10c82dad7eb1e3514118ee8347a 212 Atheros AR8132 / L1c Gigabit Ethernet Adapter Reviewed by: Garrett D'Amore Reviewed by: Milan Jurik Approved by: Dan McDonald diff -r 8c906b14afbd -r ed21ea5d20cf usr/src/man/man7d/atge.7d --- 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 diff -r 8c906b14afbd -r ed21ea5d20cf usr/src/pkg/manifests/driver-network-atge.mf --- 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 diff -r 8c906b14afbd -r ed21ea5d20cf usr/src/uts/common/Makefile.files --- 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 diff -r 8c906b14afbd -r ed21ea5d20cf usr/src/uts/common/io/atge/atge.h --- 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 #include #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; diff -r 8c906b14afbd -r ed21ea5d20cf usr/src/uts/common/io/atge/atge_cmn_reg.h --- 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 + * 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 diff -r 8c906b14afbd -r ed21ea5d20cf usr/src/uts/common/io/atge/atge_l1_reg.h --- 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 | \ diff -r 8c906b14afbd -r ed21ea5d20cf usr/src/uts/common/io/atge/atge_l1c.c --- /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 + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); +} diff -r 8c906b14afbd -r ed21ea5d20cf usr/src/uts/common/io/atge/atge_l1c_reg.h --- /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 + * 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 */ diff -r 8c906b14afbd -r ed21ea5d20cf usr/src/uts/common/io/atge/atge_l1e.c --- 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); diff -r 8c906b14afbd -r ed21ea5d20cf usr/src/uts/common/io/atge/atge_l1e_reg.h --- 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 diff -r 8c906b14afbd -r ed21ea5d20cf usr/src/uts/common/io/atge/atge_main.c --- 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 + * 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 #include @@ -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++; diff -r 8c906b14afbd -r ed21ea5d20cf usr/src/uts/common/io/atge/atge_mii.c --- 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 * 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); + } +}