⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pm3393.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/***************************************************************************** *                                                                           * * File: pm3393.c                                                            * * $Revision: 1.16 $                                                         * * $Date: 2005/05/14 00:59:32 $                                              * * Description:                                                              * *  PMC/SIERRA (pm3393) MAC-PHY functionality.                               * *  part of the Chelsio 10Gb Ethernet Driver.                                * *                                                                           * * This program is free software; you can redistribute it and/or modify      * * it under the terms of the GNU General Public License, version 2, as       * * published by the Free Software Foundation.                                * *                                                                           * * You should have received a copy of the GNU General Public License along   * * with this program; if not, write to the Free Software Foundation, Inc.,   * * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.                 * *                                                                           * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED    * * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF      * * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.                     * *                                                                           * * http://www.chelsio.com                                                    * *                                                                           * * Copyright (c) 2003 - 2005 Chelsio Communications, Inc.                    * * All rights reserved.                                                      * *                                                                           * * Maintainers: maintainers@chelsio.com                                      * *                                                                           * * Authors: Dimitrios Michailidis   <dm@chelsio.com>                         * *          Tina Yang               <tainay@chelsio.com>                     * *          Felix Marti             <felix@chelsio.com>                      * *          Scott Bardone           <sbardone@chelsio.com>                   * *          Kurt Ottaway            <kottaway@chelsio.com>                   * *          Frank DiMambro          <frank@chelsio.com>                      * *                                                                           * * History:                                                                  * *                                                                           * ****************************************************************************/#include "common.h"#include "regs.h"#include "gmac.h"#include "elmer0.h"#include "suni1x10gexp_regs.h"/* 802.3ae 10Gb/s MDIO Manageable Device(MMD) */enum {    MMD_RESERVED,    MMD_PMAPMD,    MMD_WIS,    MMD_PCS,    MMD_PHY_XGXS,	/* XGMII Extender Sublayer */    MMD_DTE_XGXS,};enum {    PHY_XGXS_CTRL_1,    PHY_XGXS_STATUS_1};#define OFFSET(REG_ADDR)    (REG_ADDR << 2)/* Max frame size PM3393 can handle. Includes Ethernet header and CRC. */#define MAX_FRAME_SIZE  9600#define IPG 12#define TXXG_CONF1_VAL ((IPG << SUNI1x10GEXP_BITOFF_TXXG_IPGT) | \	SUNI1x10GEXP_BITMSK_TXXG_32BIT_ALIGN | SUNI1x10GEXP_BITMSK_TXXG_CRCEN | \	SUNI1x10GEXP_BITMSK_TXXG_PADEN)#define RXXG_CONF1_VAL (SUNI1x10GEXP_BITMSK_RXXG_PUREP | 0x14 | \	SUNI1x10GEXP_BITMSK_RXXG_FLCHK | SUNI1x10GEXP_BITMSK_RXXG_CRC_STRIP)/* Update statistics every 15 minutes */#define STATS_TICK_SECS (15 * 60)enum {                     /* RMON registers */	RxOctetsReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_1_LOW,	RxUnicastFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_4_LOW,	RxMulticastFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_5_LOW,	RxBroadcastFramesReceivedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_6_LOW,	RxPAUSEMACCtrlFramesReceived = SUNI1x10GEXP_REG_MSTAT_COUNTER_8_LOW,	RxFrameCheckSequenceErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_10_LOW,	RxFramesLostDueToInternalMACErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_11_LOW,	RxSymbolErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_12_LOW,	RxInRangeLengthErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_13_LOW,	RxFramesTooLongErrors = SUNI1x10GEXP_REG_MSTAT_COUNTER_15_LOW,	RxJabbers = SUNI1x10GEXP_REG_MSTAT_COUNTER_16_LOW,	RxFragments = SUNI1x10GEXP_REG_MSTAT_COUNTER_17_LOW,	RxUndersizedFrames =  SUNI1x10GEXP_REG_MSTAT_COUNTER_18_LOW,	TxOctetsTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_33_LOW,	TxFramesLostDueToInternalMACTransmissionError = SUNI1x10GEXP_REG_MSTAT_COUNTER_35_LOW,	TxTransmitSystemError = SUNI1x10GEXP_REG_MSTAT_COUNTER_36_LOW,	TxUnicastFramesTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_38_LOW,	TxMulticastFramesTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_40_LOW,	TxBroadcastFramesTransmittedOK = SUNI1x10GEXP_REG_MSTAT_COUNTER_42_LOW,	TxPAUSEMACCtrlFramesTransmitted = SUNI1x10GEXP_REG_MSTAT_COUNTER_43_LOW};struct _cmac_instance {	u8 enabled;	u8 fc;	u8 mac_addr[6];};static int pmread(struct cmac *cmac, u32 reg, u32 * data32){	t1_tpi_read(cmac->adapter, OFFSET(reg), data32);	return 0;}static int pmwrite(struct cmac *cmac, u32 reg, u32 data32){	t1_tpi_write(cmac->adapter, OFFSET(reg), data32);	return 0;}/* Port reset. */static int pm3393_reset(struct cmac *cmac){	return 0;}/* * Enable interrupts for the PM3393	1. Enable PM3393 BLOCK interrupts.	2. Enable PM3393 Master Interrupt bit(INTE)	3. Enable ELMER's PM3393 bit.	4. Enable Terminator external interrupt.*/static int pm3393_interrupt_enable(struct cmac *cmac){	u32 pl_intr;	/* PM3393 - Enabling all hardware block interrupts.	 */	pmwrite(cmac, SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_ENABLE, 0xffff);	pmwrite(cmac, SUNI1x10GEXP_REG_XRF_INTERRUPT_ENABLE, 0xffff);	pmwrite(cmac, SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_ENABLE, 0xffff);	pmwrite(cmac, SUNI1x10GEXP_REG_RXOAM_INTERRUPT_ENABLE, 0xffff);	/* Don't interrupt on statistics overflow, we are polling */	pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_0, 0);	pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_1, 0);	pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_2, 0);	pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_3, 0);	pmwrite(cmac, SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_ENABLE, 0xffff);	pmwrite(cmac, SUNI1x10GEXP_REG_PL4ODP_INTERRUPT_MASK, 0xffff);	pmwrite(cmac, SUNI1x10GEXP_REG_XTEF_INTERRUPT_ENABLE, 0xffff);	pmwrite(cmac, SUNI1x10GEXP_REG_TXOAM_INTERRUPT_ENABLE, 0xffff);	pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_3, 0xffff);	pmwrite(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_MASK, 0xffff);	pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_3, 0xffff);	pmwrite(cmac, SUNI1x10GEXP_REG_PL4IDU_INTERRUPT_MASK, 0xffff);	pmwrite(cmac, SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_ENABLE, 0xffff);	/* PM3393 - Global interrupt enable	 */	/* TBD XXX Disable for now until we figure out why error interrupts keep asserting. */	pmwrite(cmac, SUNI1x10GEXP_REG_GLOBAL_INTERRUPT_ENABLE,		0 /*SUNI1x10GEXP_BITMSK_TOP_INTE */ );	/* TERMINATOR - PL_INTERUPTS_EXT */	pl_intr = readl(cmac->adapter->regs + A_PL_ENABLE);	pl_intr |= F_PL_INTR_EXT;	writel(pl_intr, cmac->adapter->regs + A_PL_ENABLE);	return 0;}static int pm3393_interrupt_disable(struct cmac *cmac){	u32 elmer;	/* PM3393 - Enabling HW interrupt blocks. */	pmwrite(cmac, SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_ENABLE, 0);	pmwrite(cmac, SUNI1x10GEXP_REG_XRF_INTERRUPT_ENABLE, 0);	pmwrite(cmac, SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_ENABLE, 0);	pmwrite(cmac, SUNI1x10GEXP_REG_RXOAM_INTERRUPT_ENABLE, 0);	pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_0, 0);	pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_1, 0);	pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_2, 0);	pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_3, 0);	pmwrite(cmac, SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_ENABLE, 0);	pmwrite(cmac, SUNI1x10GEXP_REG_PL4ODP_INTERRUPT_MASK, 0);	pmwrite(cmac, SUNI1x10GEXP_REG_XTEF_INTERRUPT_ENABLE, 0);	pmwrite(cmac, SUNI1x10GEXP_REG_TXOAM_INTERRUPT_ENABLE, 0);	pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_3, 0);	pmwrite(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_MASK, 0);	pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_3, 0);	pmwrite(cmac, SUNI1x10GEXP_REG_PL4IDU_INTERRUPT_MASK, 0);	pmwrite(cmac, SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_ENABLE, 0);	/* PM3393 - Global interrupt enable */	pmwrite(cmac, SUNI1x10GEXP_REG_GLOBAL_INTERRUPT_ENABLE, 0);	/* ELMER - External chip interrupts. */	t1_tpi_read(cmac->adapter, A_ELMER0_INT_ENABLE, &elmer);	elmer &= ~ELMER0_GP_BIT1;	t1_tpi_write(cmac->adapter, A_ELMER0_INT_ENABLE, elmer);	/* TERMINATOR - PL_INTERUPTS_EXT */	/* DO NOT DISABLE TERMINATOR's EXTERNAL INTERRUPTS. ANOTHER CHIP	 * COULD WANT THEM ENABLED. We disable PM3393 at the ELMER level.	 */	return 0;}static int pm3393_interrupt_clear(struct cmac *cmac){	u32 elmer;	u32 pl_intr;	u32 val32;	/* PM3393 - Clearing HW interrupt blocks. Note, this assumes	 *          bit WCIMODE=0 for a clear-on-read.	 */	pmread(cmac, SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_STATUS, &val32);	pmread(cmac, SUNI1x10GEXP_REG_XRF_INTERRUPT_STATUS, &val32);	pmread(cmac, SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_STATUS, &val32);	pmread(cmac, SUNI1x10GEXP_REG_RXOAM_INTERRUPT_STATUS, &val32);	pmread(cmac, SUNI1x10GEXP_REG_PL4ODP_INTERRUPT, &val32);	pmread(cmac, SUNI1x10GEXP_REG_XTEF_INTERRUPT_STATUS, &val32);	pmread(cmac, SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_INTERRUPT, &val32);	pmread(cmac, SUNI1x10GEXP_REG_TXOAM_INTERRUPT_STATUS, &val32);	pmread(cmac, SUNI1x10GEXP_REG_RXXG_INTERRUPT, &val32);	pmread(cmac, SUNI1x10GEXP_REG_TXXG_INTERRUPT, &val32);	pmread(cmac, SUNI1x10GEXP_REG_PL4IDU_INTERRUPT, &val32);	pmread(cmac, SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_INDICATION,	       &val32);	pmread(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_STATUS, &val32);	pmread(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_CHANGE, &val32);	/* PM3393 - Global interrupt status	 */	pmread(cmac, SUNI1x10GEXP_REG_MASTER_INTERRUPT_STATUS, &val32);	/* ELMER - External chip interrupts.	 */	t1_tpi_read(cmac->adapter, A_ELMER0_INT_CAUSE, &elmer);	elmer |= ELMER0_GP_BIT1;	t1_tpi_write(cmac->adapter, A_ELMER0_INT_CAUSE, elmer);	/* TERMINATOR - PL_INTERUPTS_EXT	 */	pl_intr = readl(cmac->adapter->regs + A_PL_CAUSE);	pl_intr |= F_PL_INTR_EXT;	writel(pl_intr, cmac->adapter->regs + A_PL_CAUSE);	return 0;}/* Interrupt handler */static int pm3393_interrupt_handler(struct cmac *cmac){	u32 master_intr_status;/*	1. Read master interrupt register.	2. Read BLOCK's interrupt status registers.	3. Handle BLOCK interrupts.*/	/* Read the master interrupt status register. */	pmread(cmac, SUNI1x10GEXP_REG_MASTER_INTERRUPT_STATUS,	       &master_intr_status);	/* TBD XXX Lets just clear everything for now */	pm3393_interrupt_clear(cmac);	return 0;}static int pm3393_enable(struct cmac *cmac, int which){	if (which & MAC_DIRECTION_RX)		pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_1,			(RXXG_CONF1_VAL | SUNI1x10GEXP_BITMSK_RXXG_RXEN));	if (which & MAC_DIRECTION_TX) {		u32 val = TXXG_CONF1_VAL | SUNI1x10GEXP_BITMSK_TXXG_TXEN0;		if (cmac->instance->fc & PAUSE_RX)			val |= SUNI1x10GEXP_BITMSK_TXXG_FCRX;		if (cmac->instance->fc & PAUSE_TX)			val |= SUNI1x10GEXP_BITMSK_TXXG_FCTX;		pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_1, val);	}	cmac->instance->enabled |= which;	return 0;}static int pm3393_enable_port(struct cmac *cmac, int which){	/* Clear port statistics */	pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_CONTROL,		SUNI1x10GEXP_BITMSK_MSTAT_CLEAR);	udelay(2);	memset(&cmac->stats, 0, sizeof(struct cmac_statistics));	pm3393_enable(cmac, which);	/*	 * XXX This should be done by the PHY and preferrably not at all.	 * The PHY doesn't give us link status indication on its own so have	 * the link management code query it instead.	 */	{		extern void link_changed(adapter_t *adapter, int port_id);		link_changed(cmac->adapter, 0);	}	return 0;}static int pm3393_disable(struct cmac *cmac, int which){	if (which & MAC_DIRECTION_RX)		pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_1, RXXG_CONF1_VAL);	if (which & MAC_DIRECTION_TX)		pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_1, TXXG_CONF1_VAL);	/*	 * The disable is graceful. Give the PM3393 time.  Can't wait very	 * long here, we may be holding locks.	 */	udelay(20);	cmac->instance->enabled &= ~which;	return 0;}static int pm3393_loopback_enable(struct cmac *cmac){	return 0;}static int pm3393_loopback_disable(struct cmac *cmac){	return 0;}static int pm3393_set_mtu(struct cmac *cmac, int mtu){	int enabled = cmac->instance->enabled;	/* MAX_FRAME_SIZE includes header + FCS, mtu doesn't */	mtu += 14 + 4;	if (mtu > MAX_FRAME_SIZE)		return -EINVAL;	/* Disable Rx/Tx MAC before configuring it. */	if (enabled)		pm3393_disable(cmac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);	pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MAX_FRAME_LENGTH, mtu);	pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_MAX_FRAME_SIZE, mtu);	if (enabled)		pm3393_enable(cmac, enabled);	return 0;}static u32 calc_crc(u8 *b, int len){	int i;	u32 crc = (u32)~0;	/* calculate crc one bit at a time */	while (len--) {		crc ^= *b++;		for (i = 0; i < 8; i++) {			if (crc & 0x1)				crc = (crc >> 1) ^ 0xedb88320;			else				crc = (crc >> 1);		}	}	/* reverse bits */	crc = ((crc >> 4) & 0x0f0f0f0f) | ((crc << 4) & 0xf0f0f0f0);	crc = ((crc >> 2) & 0x33333333) | ((crc << 2) & 0xcccccccc);	crc = ((crc >> 1) & 0x55555555) | ((crc << 1) & 0xaaaaaaaa);	/* swap bytes */	crc = (crc >> 16) | (crc << 16);	crc = (crc >> 8 & 0x00ff00ff) | (crc << 8 & 0xff00ff00);	return crc;}static int pm3393_set_rx_mode(struct cmac *cmac, struct t1_rx_mode *rm){	int enabled = cmac->instance->enabled & MAC_DIRECTION_RX;	u32 rx_mode;	/* Disable MAC RX before reconfiguring it */	if (enabled)		pm3393_disable(cmac, MAC_DIRECTION_RX);	pmread(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_2, &rx_mode);	rx_mode &= ~(SUNI1x10GEXP_BITMSK_RXXG_PMODE |		     SUNI1x10GEXP_BITMSK_RXXG_MHASH_EN);	pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_2,		(u16)rx_mode);	if (t1_rx_mode_promisc(rm)) {		/* Promiscuous mode. */		rx_mode |= SUNI1x10GEXP_BITMSK_RXXG_PMODE;	}	if (t1_rx_mode_allmulti(rm)) {		/* Accept all multicast. */		pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_LOW, 0xffff);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -