From: Felix Fietkau Date: Sun, 15 Jun 2008 11:11:28 +0000 (+0000) Subject: (6/6) bcm57xx: package X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=ddd809f9e56e3a30d459d6189a1582808d204821;p=openwrt%2Fstaging%2Fjow.git (6/6) bcm57xx: package This is the bcm57xx package. I have tested default vlan functions, but I dont have the equipment to test more advanced setups. The default vlan setup seems to be working fine. I also added the activate_gpio parameter which will make the driver activate the switch via gpio before probing for it. I'm not sure which method is best for autoload. For the wrt350n, I need the activate_gpio parameter. But its probably not a good idea to add that to the autoload file. On a system without a bcm57xx switch, isn't it a bad idea to mess with the gpios looking for the switch? Ideally, wouldn't it be best to load the bcm57xx module from broadcom-diag, after it has determined which router its on? I tried using 'request_module' from there, but had no success. For now, I am relying on preinit to load the bcm57xx module with activate_gpio param, after it has failed to load switch_robo and switch_adm. Signed-off-by: Ben Pfountz SVN-Revision: 11471 --- diff --git a/package/broadcom-57xx/Makefile b/package/broadcom-57xx/Makefile new file mode 100644 index 0000000000..172074ca35 --- /dev/null +++ b/package/broadcom-57xx/Makefile @@ -0,0 +1,51 @@ +# +# Copyright (C) 2006 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# +# $Id: Makefile 8694 2007-09-08 19:55:42Z nbd $ + +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/kernel.mk + +PKG_NAME:=broadcom-57xx +PKG_RELEASE:=1 + +include $(INCLUDE_DIR)/package.mk + +define KernelPackage/brcm-57xx + SUBMENU:=Network Devices + DEPENDS:=@TARGET_brcm_2_4 +kmod-switch + TITLE:=Broadcom 57xx ethernet support + FILES:=$(PKG_BUILD_DIR)/bcm57xx.$(LINUX_KMOD_SUFFIX) + AUTOLOAD:=$(call AutoLoad,30,bcm57xx) +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ +endef + +ifeq ($(BOARD),brcm-2.4) + BUILDFLAGS = -DBCMDRIVER -I$(LINUX_DIR)/arch/mips/bcm947xx/include -I$(STAGING_DIR)/usr/include + BUILDFLAGS += -DDBG=0 -DBCM_PROC_FS=1 -DT3_JUMBO_RCV_RCB_ENTRY_COUNT=256 -DNICE_SUPPORT + BUILDFLAGS += -DPCIX_TARGET_WORKAROUND=1 -DINCLUDE_TBI_SUPPORT=1 -DINCLUDE_5701_AX_FIX=1 +endif + +define Build/Compile + $(MAKE) -C "$(LINUX_DIR)" \ + CROSS_COMPILE="$(TARGET_CROSS)" \ + ARCH="$(LINUX_KARCH)" \ + SUBDIRS="$(PKG_BUILD_DIR)" \ + EXTRA_CFLAGS="$(BUILDFLAGS)" \ + modules +endef + +define KernelPackage/brcm-57xx/install + $(call Package/brcm-57xx/install/Default,$(1)) + #$(INSTALL_DIR) $(1)/etc/modules.d + #echo "bcm57xx activate_gpio=1" > $(1)/etc/modules.d/30-bcm57xx +endef + +$(eval $(call KernelPackage,brcm-57xx)) diff --git a/package/broadcom-57xx/src/5701rls.c b/package/broadcom-57xx/src/5701rls.c new file mode 100644 index 0000000000..6b7d49c7a8 --- /dev/null +++ b/package/broadcom-57xx/src/5701rls.c @@ -0,0 +1,46 @@ +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 - 2004 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* History: */ +/* */ +/******************************************************************************/ + +#ifdef INCLUDE_5701_AX_FIX + +#include "mm.h" +#include "5701rls.h" + +LM_STATUS LM_LoadRlsFirmware(PLM_DEVICE_BLOCK pDevice) +{ + T3_FWIMG_INFO FwImgInfo; + + FwImgInfo.StartAddress = t3FwStartAddr; + FwImgInfo.Text.Buffer = (PLM_UINT8)t3FwText; + FwImgInfo.Text.Offset = t3FwTextAddr; + FwImgInfo.Text.Length = t3FwTextLen; + FwImgInfo.ROnlyData.Buffer = (PLM_UINT8)t3FwRodata; + FwImgInfo.ROnlyData.Offset = t3FwRodataAddr; + FwImgInfo.ROnlyData.Length = t3FwRodataLen; + FwImgInfo.Data.Buffer = (PLM_UINT8)t3FwData; + FwImgInfo.Data.Offset = t3FwDataAddr; + FwImgInfo.Data.Length = t3FwDataLen; + + if (LM_LoadFirmware(pDevice, + &FwImgInfo, + T3_RX_CPU_ID | T3_TX_CPU_ID, + T3_RX_CPU_ID) != LM_STATUS_SUCCESS) + { + return LM_STATUS_FAILURE; + } + + return LM_STATUS_SUCCESS; +} + +#endif /* INCLUDE_5701_AX_FIX */ diff --git a/package/broadcom-57xx/src/5701rls.h b/package/broadcom-57xx/src/5701rls.h new file mode 100644 index 0000000000..793726d287 --- /dev/null +++ b/package/broadcom-57xx/src/5701rls.h @@ -0,0 +1,198 @@ +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 - 2004 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* History: */ +/******************************************************************************/ + +typedef unsigned long U32; +int t3FwReleaseMajor = 0x0; +int t3FwReleaseMinor = 0x0; +int t3FwReleaseFix = 0x0; +U32 t3FwStartAddr = 0x08000000; +U32 t3FwTextAddr = 0x08000000; +int t3FwTextLen = 0x9c0; +U32 t3FwRodataAddr = 0x080009c0; +int t3FwRodataLen = 0x60; +U32 t3FwDataAddr = 0x08000a40; +int t3FwDataLen = 0x20; +U32 t3FwSbssAddr = 0x08000a60; +int t3FwSbssLen = 0xc; +U32 t3FwBssAddr = 0x08000a70; +int t3FwBssLen = 0x10; +U32 t3FwText[(0x9c0/4) + 1] = { +0x0, +0x10000003, 0x0, 0xd, 0xd, +0x3c1d0800, 0x37bd3ffc, 0x3a0f021, 0x3c100800, +0x26100000, 0xe000018, 0x0, 0xd, +0x3c1d0800, 0x37bd3ffc, 0x3a0f021, 0x3c100800, +0x26100034, 0xe00021c, 0x0, 0xd, +0x0, 0x0, 0x0, 0x27bdffe0, +0x3c1cc000, 0xafbf0018, 0xaf80680c, 0xe00004c, +0x241b2105, 0x97850000, 0x97870002, 0x9782002c, +0x9783002e, 0x3c040800, 0x248409c0, 0xafa00014, +0x21400, 0x621825, 0x52c00, 0xafa30010, +0x8f860010, 0xe52825, 0xe000060, 0x24070102, +0x3c02ac00, 0x34420100, 0x3c03ac01, 0x34630100, +0xaf820490, 0x3c02ffff, 0xaf820494, 0xaf830498, +0xaf82049c, 0x24020001, 0xaf825ce0, 0xe00003f, +0xaf825d00, 0xe000140, 0x0, 0x8fbf0018, +0x3e00008, 0x27bd0020, 0x2402ffff, 0xaf825404, +0x8f835400, 0x34630400, 0xaf835400, 0xaf825404, +0x3c020800, 0x24420034, 0xaf82541c, 0x3e00008, +0xaf805400, 0x0, 0x0, 0x3c020800, +0x34423000, 0x3c030800, 0x34633000, 0x3c040800, +0x348437ff, 0x3c010800, 0xac220a64, 0x24020040, +0x3c010800, 0xac220a68, 0x3c010800, 0xac200a60, +0xac600000, 0x24630004, 0x83102b, 0x5040fffd, +0xac600000, 0x3e00008, 0x0, 0x804821, +0x8faa0010, 0x3c020800, 0x8c420a60, 0x3c040800, +0x8c840a68, 0x8fab0014, 0x24430001, 0x44102b, +0x3c010800, 0xac230a60, 0x14400003, 0x4021, +0x3c010800, 0xac200a60, 0x3c020800, 0x8c420a60, +0x3c030800, 0x8c630a64, 0x91240000, 0x21140, +0x431021, 0x481021, 0x25080001, 0xa0440000, +0x29020008, 0x1440fff4, 0x25290001, 0x3c020800, +0x8c420a60, 0x3c030800, 0x8c630a64, 0x8f84680c, +0x21140, 0x431021, 0xac440008, 0xac45000c, +0xac460010, 0xac470014, 0xac4a0018, 0x3e00008, +0xac4b001c, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x2000008, +0x0, 0xa0001e3, 0x3c0a0001, 0xa0001e3, +0x3c0a0002, 0xa0001e3, 0x0, 0xa0001e3, +0x0, 0xa0001e3, 0x0, 0xa0001e3, +0x0, 0xa0001e3, 0x0, 0xa0001e3, +0x0, 0xa0001e3, 0x0, 0xa0001e3, +0x0, 0xa0001e3, 0x0, 0xa0001e3, +0x3c0a0007, 0xa0001e3, 0x3c0a0008, 0xa0001e3, +0x3c0a0009, 0xa0001e3, 0x0, 0xa0001e3, +0x0, 0xa0001e3, 0x3c0a000b, 0xa0001e3, +0x3c0a000c, 0xa0001e3, 0x3c0a000d, 0xa0001e3, +0x0, 0xa0001e3, 0x0, 0xa0001e3, +0x3c0a000e, 0xa0001e3, 0x0, 0xa0001e3, +0x0, 0xa0001e3, 0x0, 0xa0001e3, +0x0, 0xa0001e3, 0x0, 0xa0001e3, +0x0, 0xa0001e3, 0x0, 0xa0001e3, +0x0, 0xa0001e3, 0x3c0a0013, 0xa0001e3, +0x3c0a0014, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x27bdffe0, +0x1821, 0x1021, 0xafbf0018, 0xafb10014, +0xafb00010, 0x3c010800, 0x220821, 0xac200a70, +0x3c010800, 0x220821, 0xac200a74, 0x3c010800, +0x220821, 0xac200a78, 0x24630001, 0x1860fff5, +0x2442000c, 0x24110001, 0x8f906810, 0x32020004, +0x14400005, 0x24040001, 0x3c020800, 0x8c420a78, +0x18400003, 0x2021, 0xe000182, 0x0, +0x32020001, 0x10400003, 0x0, 0xe000169, +0x0, 0xa000153, 0xaf915028, 0x8fbf0018, +0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0020, +0x3c050800, 0x8ca50a70, 0x3c060800, 0x8cc60a80, +0x3c070800, 0x8ce70a78, 0x27bdffe0, 0x3c040800, +0x248409d0, 0xafbf0018, 0xafa00010, 0xe000060, +0xafa00014, 0xe00017b, 0x2021, 0x8fbf0018, +0x3e00008, 0x27bd0020, 0x24020001, 0x8f836810, +0x821004, 0x21027, 0x621824, 0x3e00008, +0xaf836810, 0x27bdffd8, 0xafbf0024, 0x1080002e, +0xafb00020, 0x8f825cec, 0xafa20018, 0x8f825cec, +0x3c100800, 0x26100a78, 0xafa2001c, 0x34028000, +0xaf825cec, 0x8e020000, 0x18400016, 0x0, +0x3c020800, 0x94420a74, 0x8fa3001c, 0x221c0, +0xac830004, 0x8fa2001c, 0x3c010800, 0xe000201, +0xac220a74, 0x10400005, 0x0, 0x8e020000, +0x24420001, 0xa0001df, 0xae020000, 0x3c020800, +0x8c420a70, 0x21c02, 0x321c0, 0xa0001c5, +0xafa2001c, 0xe000201, 0x0, 0x1040001f, +0x0, 0x8e020000, 0x8fa3001c, 0x24420001, +0x3c010800, 0xac230a70, 0x3c010800, 0xac230a74, +0xa0001df, 0xae020000, 0x3c100800, 0x26100a78, +0x8e020000, 0x18400028, 0x0, 0xe000201, +0x0, 0x14400024, 0x0, 0x8e020000, +0x3c030800, 0x8c630a70, 0x2442ffff, 0xafa3001c, +0x18400006, 0xae020000, 0x31402, 0x221c0, +0x8c820004, 0x3c010800, 0xac220a70, 0x97a2001e, +0x2442ff00, 0x2c420300, 0x1440000b, 0x24024000, +0x3c040800, 0x248409dc, 0xafa00010, 0xafa00014, +0x8fa6001c, 0x24050008, 0xe000060, 0x3821, +0xa0001df, 0x0, 0xaf825cf8, 0x3c020800, +0x8c420a40, 0x8fa3001c, 0x24420001, 0xaf835cf8, +0x3c010800, 0xac220a40, 0x8fbf0024, 0x8fb00020, +0x3e00008, 0x27bd0028, 0x27bdffe0, 0x3c040800, +0x248409e8, 0x2821, 0x3021, 0x3821, +0xafbf0018, 0xafa00010, 0xe000060, 0xafa00014, +0x8fbf0018, 0x3e00008, 0x27bd0020, 0x8f82680c, +0x8f85680c, 0x21827, 0x3182b, 0x31823, +0x431024, 0x441021, 0xa2282b, 0x10a00006, +0x0, 0x401821, 0x8f82680c, 0x43102b, +0x1440fffd, 0x0, 0x3e00008, 0x0, +0x3c040800, 0x8c840000, 0x3c030800, 0x8c630a40, +0x64102b, 0x54400002, 0x831023, 0x641023, +0x2c420008, 0x3e00008, 0x38420001, 0x27bdffe0, +0x802821, 0x3c040800, 0x24840a00, 0x3021, +0x3821, 0xafbf0018, 0xafa00010, 0xe000060, +0xafa00014, 0xa000216, 0x0, 0x8fbf0018, +0x3e00008, 0x27bd0020, 0x0, 0x27bdffe0, +0x3c1cc000, 0xafbf0018, 0xe00004c, 0xaf80680c, +0x3c040800, 0x24840a10, 0x3802821, 0x3021, +0x3821, 0xafa00010, 0xe000060, 0xafa00014, +0x2402ffff, 0xaf825404, 0x3c0200aa, 0xe000234, +0xaf825434, 0x8fbf0018, 0x3e00008, 0x27bd0020, +0x0, 0x0, 0x0, 0x27bdffe8, +0xafb00010, 0x24100001, 0xafbf0014, 0x3c01c003, +0xac200000, 0x8f826810, 0x30422000, 0x10400003, +0x0, 0xe000246, 0x0, 0xa00023a, +0xaf905428, 0x8fbf0014, 0x8fb00010, 0x3e00008, +0x27bd0018, 0x27bdfff8, 0x8f845d0c, 0x3c0200ff, +0x3c030800, 0x8c630a50, 0x3442fff8, 0x821024, +0x1043001e, 0x3c0500ff, 0x34a5fff8, 0x3c06c003, +0x3c074000, 0x851824, 0x8c620010, 0x3c010800, +0xac230a50, 0x30420008, 0x10400005, 0x871025, +0x8cc20000, 0x24420001, 0xacc20000, 0x871025, +0xaf825d0c, 0x8fa20000, 0x24420001, 0xafa20000, +0x8fa20000, 0x8fa20000, 0x24420001, 0xafa20000, +0x8fa20000, 0x8f845d0c, 0x3c030800, 0x8c630a50, +0x851024, 0x1443ffe8, 0x851824, 0x27bd0008, +0x3e00008, 0x0, 0x0, 0x0 }; +U32 t3FwRodata[(0x60/4) + 1] = { +0x35373031, 0x726c7341, 0x0, +0x0, 0x53774576, 0x656e7430, 0x0, +0x726c7045, 0x76656e74, 0x31000000, 0x556e6b6e, +0x45766e74, 0x0, 0x0, 0x0, +0x0, 0x66617461, 0x6c457272, 0x0, +0x0, 0x4d61696e, 0x43707542, 0x0, +0x0, 0x0 }; +U32 t3FwData[(0x20/4) + 1] = { +0x0, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0 }; diff --git a/package/broadcom-57xx/src/Makefile b/package/broadcom-57xx/src/Makefile new file mode 100644 index 0000000000..08a7914879 --- /dev/null +++ b/package/broadcom-57xx/src/Makefile @@ -0,0 +1,17 @@ +# +# Broadcom BCM57XX Gigabit Ethernet driver make file. +# +# $Id: Makefile,v 1.1.1.4 2006/09/26 02:17:12 michael Exp $ +# + +O_TARGET = bcm57xx.o + +EXTRA_CFLAGS += -DDBG=0 -DBCM_PROC_FS=1 -DT3_JUMBO_RCV_RCB_ENTRY_COUNT=256 +EXTRA_CFLAGS += -DPCIX_TARGET_WORKAROUND=1 -DINCLUDE_TBI_SUPPORT=1 -DINCLUDE_5701_AX_FIX=1 + +export-objs := + +obj-y := b57um.o tigon3.o autoneg.o 5701rls.o tcp_seg.o hndgige.o bcmrobo.o +obj-m := $(O_TARGET) + +include $(TOPDIR)/Rules.make diff --git a/package/broadcom-57xx/src/autoneg.c b/package/broadcom-57xx/src/autoneg.c new file mode 100644 index 0000000000..d467f0347f --- /dev/null +++ b/package/broadcom-57xx/src/autoneg.c @@ -0,0 +1,438 @@ +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 - 2004 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* History: */ +/******************************************************************************/ + +#ifdef INCLUDE_TBI_SUPPORT +#include "mm.h" + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +void +MM_AnTxConfig( + PAN_STATE_INFO pAnInfo) +{ + PLM_DEVICE_BLOCK pDevice; + + pDevice = (PLM_DEVICE_BLOCK) pAnInfo->pContext; + + REG_WR(pDevice, MacCtrl.TxAutoNeg, (LM_UINT32) pAnInfo->TxConfig.AsUSHORT); + + pDevice->MacMode |= MAC_MODE_SEND_CONFIGS; + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode); +} + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +void +MM_AnTxIdle( + PAN_STATE_INFO pAnInfo) +{ + PLM_DEVICE_BLOCK pDevice; + + pDevice = (PLM_DEVICE_BLOCK) pAnInfo->pContext; + + pDevice->MacMode &= ~MAC_MODE_SEND_CONFIGS; + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode); +} + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +char +MM_AnRxConfig( + PAN_STATE_INFO pAnInfo, + unsigned short *pRxConfig) +{ + PLM_DEVICE_BLOCK pDevice; + LM_UINT32 Value32; + char Retcode; + + Retcode = AN_FALSE; + + pDevice = (PLM_DEVICE_BLOCK) pAnInfo->pContext; + + Value32 = REG_RD(pDevice, MacCtrl.Status); + if(Value32 & MAC_STATUS_RECEIVING_CFG) + { + Value32 = REG_RD(pDevice, MacCtrl.RxAutoNeg); + *pRxConfig = (unsigned short) Value32; + + Retcode = AN_TRUE; + } + + return Retcode; +} + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +void +AutonegInit( + PAN_STATE_INFO pAnInfo) +{ + unsigned long j; + + for(j = 0; j < sizeof(AN_STATE_INFO); j++) + { + ((unsigned char *) pAnInfo)[j] = 0; + } + + /* Initialize the default advertisement register. */ + pAnInfo->mr_adv_full_duplex = 1; + pAnInfo->mr_adv_sym_pause = 1; + pAnInfo->mr_adv_asym_pause = 1; + pAnInfo->mr_an_enable = 1; +} + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +AUTONEG_STATUS +Autoneg8023z( + PAN_STATE_INFO pAnInfo) +{ + unsigned short RxConfig; + unsigned long Delta_us; + AUTONEG_STATUS AnRet; + + /* Get the current time. */ + if(pAnInfo->State == AN_STATE_UNKNOWN) + { + pAnInfo->RxConfig.AsUSHORT = 0; + pAnInfo->CurrentTime_us = 0; + pAnInfo->LinkTime_us = 0; + pAnInfo->AbilityMatchCfg = 0; + pAnInfo->AbilityMatchCnt = 0; + pAnInfo->AbilityMatch = AN_FALSE; + pAnInfo->IdleMatch = AN_FALSE; + pAnInfo->AckMatch = AN_FALSE; + } + + /* Increment the timer tick. This function is called every microsecon. */ +// pAnInfo->CurrentTime_us++; + + /* Set the AbilityMatch, IdleMatch, and AckMatch flags if their */ + /* corresponding conditions are satisfied. */ + if(MM_AnRxConfig(pAnInfo, &RxConfig)) + { + if(RxConfig != pAnInfo->AbilityMatchCfg) + { + pAnInfo->AbilityMatchCfg = RxConfig; + pAnInfo->AbilityMatch = AN_FALSE; + pAnInfo->AbilityMatchCnt = 0; + } + else + { + pAnInfo->AbilityMatchCnt++; + if(pAnInfo->AbilityMatchCnt > 1) + { + pAnInfo->AbilityMatch = AN_TRUE; + pAnInfo->AbilityMatchCfg = RxConfig; + } + } + + if(RxConfig & AN_CONFIG_ACK) + { + pAnInfo->AckMatch = AN_TRUE; + } + else + { + pAnInfo->AckMatch = AN_FALSE; + } + + pAnInfo->IdleMatch = AN_FALSE; + } + else + { + pAnInfo->IdleMatch = AN_TRUE; + + pAnInfo->AbilityMatchCfg = 0; + pAnInfo->AbilityMatchCnt = 0; + pAnInfo->AbilityMatch = AN_FALSE; + pAnInfo->AckMatch = AN_FALSE; + + RxConfig = 0; + } + + /* Save the last Config. */ + pAnInfo->RxConfig.AsUSHORT = RxConfig; + + /* Default return code. */ + AnRet = AUTONEG_STATUS_OK; + + /* Autoneg state machine as defined in 802.3z section 37.3.1.5. */ + switch(pAnInfo->State) + { + case AN_STATE_UNKNOWN: + if(pAnInfo->mr_an_enable || pAnInfo->mr_restart_an) + { + pAnInfo->CurrentTime_us = 0; + pAnInfo->State = AN_STATE_AN_ENABLE; + } + + /* Fall through.*/ + + case AN_STATE_AN_ENABLE: + pAnInfo->mr_an_complete = AN_FALSE; + pAnInfo->mr_page_rx = AN_FALSE; + + if(pAnInfo->mr_an_enable) + { + pAnInfo->LinkTime_us = 0; + pAnInfo->AbilityMatchCfg = 0; + pAnInfo->AbilityMatchCnt = 0; + pAnInfo->AbilityMatch = AN_FALSE; + pAnInfo->IdleMatch = AN_FALSE; + pAnInfo->AckMatch = AN_FALSE; + + pAnInfo->State = AN_STATE_AN_RESTART_INIT; + } + else + { + pAnInfo->State = AN_STATE_DISABLE_LINK_OK; + } + break; + + case AN_STATE_AN_RESTART_INIT: + pAnInfo->LinkTime_us = pAnInfo->CurrentTime_us; + pAnInfo->mr_np_loaded = AN_FALSE; + + pAnInfo->TxConfig.AsUSHORT = 0; + MM_AnTxConfig(pAnInfo); + + AnRet = AUTONEG_STATUS_TIMER_ENABLED; + + pAnInfo->State = AN_STATE_AN_RESTART; + + /* Fall through.*/ + + case AN_STATE_AN_RESTART: + /* Get the current time and compute the delta with the saved */ + /* link timer. */ + Delta_us = pAnInfo->CurrentTime_us - pAnInfo->LinkTime_us; + if(Delta_us > AN_LINK_TIMER_INTERVAL_US) + { + pAnInfo->State = AN_STATE_ABILITY_DETECT_INIT; + } + else + { + AnRet = AUTONEG_STATUS_TIMER_ENABLED; + } + break; + + case AN_STATE_DISABLE_LINK_OK: + AnRet = AUTONEG_STATUS_DONE; + break; + + case AN_STATE_ABILITY_DETECT_INIT: + /* Note: in the state diagram, this variable is set to */ + /* mr_adv_ability<12>. Is this right?. */ + pAnInfo->mr_toggle_tx = AN_FALSE; + + /* Send the config as advertised in the advertisement register. */ + pAnInfo->TxConfig.AsUSHORT = 0; + pAnInfo->TxConfig.D5_FD = pAnInfo->mr_adv_full_duplex; + pAnInfo->TxConfig.D6_HD = pAnInfo->mr_adv_half_duplex; + pAnInfo->TxConfig.D7_PS1 = pAnInfo->mr_adv_sym_pause; + pAnInfo->TxConfig.D8_PS2 = pAnInfo->mr_adv_asym_pause; + pAnInfo->TxConfig.D12_RF1 = pAnInfo->mr_adv_remote_fault1; + pAnInfo->TxConfig.D13_RF2 = pAnInfo->mr_adv_remote_fault2; + pAnInfo->TxConfig.D15_NP = pAnInfo->mr_adv_next_page; + + MM_AnTxConfig(pAnInfo); + + pAnInfo->State = AN_STATE_ABILITY_DETECT; + + break; + + case AN_STATE_ABILITY_DETECT: + if(pAnInfo->AbilityMatch == AN_TRUE && + pAnInfo->RxConfig.AsUSHORT != 0) + { + pAnInfo->State = AN_STATE_ACK_DETECT_INIT; + } + + break; + + case AN_STATE_ACK_DETECT_INIT: + pAnInfo->TxConfig.D14_ACK = 1; + MM_AnTxConfig(pAnInfo); + + pAnInfo->State = AN_STATE_ACK_DETECT; + + /* Fall through. */ + + case AN_STATE_ACK_DETECT: + if(pAnInfo->AckMatch == AN_TRUE) + { + if((pAnInfo->RxConfig.AsUSHORT & ~AN_CONFIG_ACK) == + (pAnInfo->AbilityMatchCfg & ~AN_CONFIG_ACK)) + { + pAnInfo->State = AN_STATE_COMPLETE_ACK_INIT; + } + else + { + pAnInfo->State = AN_STATE_AN_ENABLE; + } + } + else if(pAnInfo->AbilityMatch == AN_TRUE && + pAnInfo->RxConfig.AsUSHORT == 0) + { + pAnInfo->State = AN_STATE_AN_ENABLE; + } + + break; + + case AN_STATE_COMPLETE_ACK_INIT: + /* Make sure invalid bits are not set. */ + if(pAnInfo->RxConfig.bits.D0 || pAnInfo->RxConfig.bits.D1 || + pAnInfo->RxConfig.bits.D2 || pAnInfo->RxConfig.bits.D3 || + pAnInfo->RxConfig.bits.D4 || pAnInfo->RxConfig.bits.D9 || + pAnInfo->RxConfig.bits.D10 || pAnInfo->RxConfig.bits.D11) + { + AnRet = AUTONEG_STATUS_FAILED; + break; + } + + /* Set up the link partner advertisement register. */ + pAnInfo->mr_lp_adv_full_duplex = pAnInfo->RxConfig.D5_FD; + pAnInfo->mr_lp_adv_half_duplex = pAnInfo->RxConfig.D6_HD; + pAnInfo->mr_lp_adv_sym_pause = pAnInfo->RxConfig.D7_PS1; + pAnInfo->mr_lp_adv_asym_pause = pAnInfo->RxConfig.D8_PS2; + pAnInfo->mr_lp_adv_remote_fault1 = pAnInfo->RxConfig.D12_RF1; + pAnInfo->mr_lp_adv_remote_fault2 = pAnInfo->RxConfig.D13_RF2; + pAnInfo->mr_lp_adv_next_page = pAnInfo->RxConfig.D15_NP; + + pAnInfo->LinkTime_us = pAnInfo->CurrentTime_us; + + pAnInfo->mr_toggle_tx = !pAnInfo->mr_toggle_tx; + pAnInfo->mr_toggle_rx = pAnInfo->RxConfig.bits.D11; + pAnInfo->mr_np_rx = pAnInfo->RxConfig.D15_NP; + pAnInfo->mr_page_rx = AN_TRUE; + + pAnInfo->State = AN_STATE_COMPLETE_ACK; + AnRet = AUTONEG_STATUS_TIMER_ENABLED; + + break; + + case AN_STATE_COMPLETE_ACK: + if(pAnInfo->AbilityMatch == AN_TRUE && + pAnInfo->RxConfig.AsUSHORT == 0) + { + pAnInfo->State = AN_STATE_AN_ENABLE; + break; + } + + Delta_us = pAnInfo->CurrentTime_us - pAnInfo->LinkTime_us; + + if(Delta_us > AN_LINK_TIMER_INTERVAL_US) + { + if(pAnInfo->mr_adv_next_page == 0 || + pAnInfo->mr_lp_adv_next_page == 0) + { + pAnInfo->State = AN_STATE_IDLE_DETECT_INIT; + } + else + { + if(pAnInfo->TxConfig.bits.D15 == 0 && + pAnInfo->mr_np_rx == 0) + { + pAnInfo->State = AN_STATE_IDLE_DETECT_INIT; + } + else + { + AnRet = AUTONEG_STATUS_FAILED; + } + } + } + + break; + + case AN_STATE_IDLE_DETECT_INIT: + pAnInfo->LinkTime_us = pAnInfo->CurrentTime_us; + + MM_AnTxIdle(pAnInfo); + + pAnInfo->State = AN_STATE_IDLE_DETECT; + + AnRet = AUTONEG_STATUS_TIMER_ENABLED; + + break; + + case AN_STATE_IDLE_DETECT: + if(pAnInfo->AbilityMatch == AN_TRUE && + pAnInfo->RxConfig.AsUSHORT == 0) + { + pAnInfo->State = AN_STATE_AN_ENABLE; + break; + } + + Delta_us = pAnInfo->CurrentTime_us - pAnInfo->LinkTime_us; + if(Delta_us > AN_LINK_TIMER_INTERVAL_US) + { +// if(pAnInfo->IdleMatch == AN_TRUE) +// { + pAnInfo->State = AN_STATE_LINK_OK; +// } +// else +// { +// AnRet = AUTONEG_STATUS_FAILED; +// break; +// } + } + + break; + + case AN_STATE_LINK_OK: + pAnInfo->mr_an_complete = AN_TRUE; + pAnInfo->mr_link_ok = AN_TRUE; + AnRet = AUTONEG_STATUS_DONE; + + break; + + case AN_STATE_NEXT_PAGE_WAIT_INIT: + break; + + case AN_STATE_NEXT_PAGE_WAIT: + break; + + default: + AnRet = AUTONEG_STATUS_FAILED; + break; + } + + return AnRet; +} +#endif /* INCLUDE_TBI_SUPPORT */ + diff --git a/package/broadcom-57xx/src/autoneg.h b/package/broadcom-57xx/src/autoneg.h new file mode 100644 index 0000000000..5d9be8709c --- /dev/null +++ b/package/broadcom-57xx/src/autoneg.h @@ -0,0 +1,418 @@ +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 - 2004 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* History: */ +/******************************************************************************/ + + +#ifndef AUTONEG_H +#define AUTONEG_H + + + +/******************************************************************************/ +/* Constants. */ +/******************************************************************************/ + +#define AN_LINK_TIMER_INTERVAL_US 12000 /* 10ms */ + +/* TRUE, FALSE */ +#define AN_TRUE 1 +#define AN_FALSE 0 + + + +/******************************************************************************/ +/* Main data structure for keeping track of 802.3z auto-negotation state */ +/* variables as shown in Figure 37-6 of the IEEE 802.3z specification. */ +/******************************************************************************/ + +typedef struct +{ + /* Pointer to the operating system specific data structure. */ + void *pContext; + + /* Current auto-negotiation state. */ + unsigned long State; + #define AN_STATE_UNKNOWN 0 + #define AN_STATE_AN_ENABLE 1 + #define AN_STATE_AN_RESTART_INIT 2 + #define AN_STATE_AN_RESTART 3 + #define AN_STATE_DISABLE_LINK_OK 4 + #define AN_STATE_ABILITY_DETECT_INIT 5 + #define AN_STATE_ABILITY_DETECT 6 + #define AN_STATE_ACK_DETECT_INIT 7 + #define AN_STATE_ACK_DETECT 8 + #define AN_STATE_COMPLETE_ACK_INIT 9 + #define AN_STATE_COMPLETE_ACK 10 + #define AN_STATE_IDLE_DETECT_INIT 11 + #define AN_STATE_IDLE_DETECT 12 + #define AN_STATE_LINK_OK 13 + #define AN_STATE_NEXT_PAGE_WAIT_INIT 14 + #define AN_STATE_NEXT_PAGE_WAIT 16 + + /* Link timer. */ + unsigned long LinkTime_us; + + /* Current time. */ + unsigned long CurrentTime_us; + + /* Ability, idle, and ack match functions. */ + unsigned long AbilityMatchCnt; + + /* Need these values for consistency check. */ + unsigned short AbilityMatchCfg; + + unsigned short reserved; + + char AbilityMatch; + char IdleMatch; + char AckMatch; + char reserved1; + + /* Tx config data */ + union + { + /* The TxConfig register is arranged as follows: */ + /* */ + /* MSB LSB */ + /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ */ + /* | D7| D6| D5| D4| D3| D2| D1| D0|D15|D14|D13|D12|D11|D10| D9| D8| */ + /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ */ + struct + { +#ifdef BIG_ENDIAN_HOST + unsigned short D7:1; /* PS1 */ + unsigned short D6:1; /* HD */ + unsigned short D5:1; /* FD */ + unsigned short D4:1; + unsigned short D3:1; + unsigned short D2:1; + unsigned short D1:1; + unsigned short D0:1; + unsigned short D15:1; /* NP */ + unsigned short D14:1; /* ACK */ + unsigned short D13:1; /* RF2 */ + unsigned short D12:1; /* RF1 */ + unsigned short D11:1; + unsigned short D10:1; + unsigned short D9:1; + unsigned short D8:1; /* PS2 */ +#else /* BIG_ENDIAN_HOST */ + unsigned int D8:1; /* PS2 */ + unsigned int D9:1; + unsigned int D10:1; + unsigned int D11:1; + unsigned int D12:1; /* RF1 */ + unsigned int D13:1; /* RF2 */ + unsigned int D14:1; /* ACK */ + unsigned int D15:1; /* NP */ + unsigned int D0:1; + unsigned int D1:1; + unsigned int D2:1; + unsigned int D3:1; + unsigned int D4:1; + unsigned int D5:1; /* FD */ + unsigned int D6:1; /* HD */ + unsigned int D7:1; /* PS1 */ +#endif + } bits; + + unsigned short AsUSHORT; + + #define D8_PS2 bits.D8 + #define D12_RF1 bits.D12 + #define D13_RF2 bits.D13 + #define D14_ACK bits.D14 + #define D15_NP bits.D15 + #define D5_FD bits.D5 + #define D6_HD bits.D6 + #define D7_PS1 bits.D7 + } TxConfig; + + /* Rx config data */ + union + { + /* The RxConfig register is arranged as follows: */ + /* */ + /* MSB LSB */ + /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ */ + /* | D7| D6| D5| D4| D3| D2| D1| D0|D15|D14|D13|D12|D11|D10| D9| D8| */ + /* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ */ + struct + { +#ifdef BIG_ENDIAN_HOST + unsigned short D7:1; /* PS1 */ + unsigned short D6:1; /* HD */ + unsigned short D5:1; /* FD */ + unsigned short D4:1; + unsigned short D3:1; + unsigned short D2:1; + unsigned short D1:1; + unsigned short D0:1; + unsigned short D15:1; /* NP */ + unsigned short D14:1; /* ACK */ + unsigned short D13:1; /* RF2 */ + unsigned short D12:1; /* RF1 */ + unsigned short D11:1; + unsigned short D10:1; + unsigned short D9:1; + unsigned short D8:1; /* PS2 */ +#else /* BIG_ENDIAN_HOST */ + unsigned int D8:1; /* PS2 */ + unsigned int D9:1; + unsigned int D10:1; + unsigned int D11:1; + unsigned int D12:1; /* RF1 */ + unsigned int D13:1; /* RF2 */ + unsigned int D14:1; /* ACK */ + unsigned int D15:1; /* NP */ + unsigned int D0:1; + unsigned int D1:1; + unsigned int D2:1; + unsigned int D3:1; + unsigned int D4:1; + unsigned int D5:1; /* FD */ + unsigned int D6:1; /* HD */ + unsigned int D7:1; /* PS1 */ +#endif + } bits; + + unsigned short AsUSHORT; + } RxConfig; + + #define AN_CONFIG_NP 0x0080 + #define AN_CONFIG_ACK 0x0040 + #define AN_CONFIG_RF2 0x0020 + #define AN_CONFIG_RF1 0x0010 + #define AN_CONFIG_PS2 0x0001 + #define AN_CONFIG_PS1 0x8000 + #define AN_CONFIG_HD 0x4000 + #define AN_CONFIG_FD 0x2000 + + + /* Management registers. */ + + /* Control register. */ + union + { + struct + { + unsigned int an_enable:1; + unsigned int loopback:1; + unsigned int reset:1; + unsigned int restart_an:1; + } bits; + + unsigned short AsUSHORT; + + #define mr_an_enable Mr0.bits.an_enable + #define mr_loopback Mr0.bits.loopback + #define mr_main_reset Mr0.bits.reset + #define mr_restart_an Mr0.bits.restart_an + } Mr0; + + /* Status register. */ + union + { + struct + { + unsigned int an_complete:1; + unsigned int link_ok:1; + } bits; + + unsigned short AsUSHORT; + + #define mr_an_complete Mr1.bits.an_complete + #define mr_link_ok Mr1.bits.link_ok + } Mr1; + + /* Advertisement register. */ + union + { + struct + { + unsigned int reserved_4:5; + unsigned int full_duplex:1; + unsigned int half_duplex:1; + unsigned int sym_pause:1; + unsigned int asym_pause:1; + unsigned int reserved_11:3; + unsigned int remote_fault1:1; + unsigned int remote_fault2:1; + unsigned int reserved_14:1; + unsigned int next_page:1; + } bits; + + unsigned short AsUSHORT; + + #define mr_adv_full_duplex Mr4.bits.full_duplex + #define mr_adv_half_duplex Mr4.bits.half_duplex + #define mr_adv_sym_pause Mr4.bits.sym_pause + #define mr_adv_asym_pause Mr4.bits.asym_pause + #define mr_adv_remote_fault1 Mr4.bits.remote_fault1 + #define mr_adv_remote_fault2 Mr4.bits.remote_fault2 + #define mr_adv_next_page Mr4.bits.next_page + } Mr4; + + /* Link partner advertisement register. */ + union + { + struct + { + unsigned int reserved_4:5; + unsigned int lp_full_duplex:1; + unsigned int lp_half_duplex:1; + unsigned int lp_sym_pause:1; + unsigned int lp_asym_pause:1; + unsigned int reserved_11:3; + unsigned int lp_remote_fault1:1; + unsigned int lp_remote_fault2:1; + unsigned int lp_ack:1; + unsigned int lp_next_page:1; + } bits; + + unsigned short AsUSHORT; + + #define mr_lp_adv_full_duplex Mr5.bits.lp_full_duplex + #define mr_lp_adv_half_duplex Mr5.bits.lp_half_duplex + #define mr_lp_adv_sym_pause Mr5.bits.lp_sym_pause + #define mr_lp_adv_asym_pause Mr5.bits.lp_asym_pause + #define mr_lp_adv_remote_fault1 Mr5.bits.lp_remote_fault1 + #define mr_lp_adv_remote_fault2 Mr5.bits.lp_remote_fault2 + #define mr_lp_adv_next_page Mr5.bits.lp_next_page + } Mr5; + + /* Auto-negotiation expansion register. */ + union + { + struct + { + unsigned int reserved_0:1; + unsigned int page_received:1; + unsigned int next_pageable:1; + unsigned int reserved_15:13; + } bits; + + unsigned short AsUSHORT; + } Mr6; + + /* Auto-negotiation next page transmit register. */ + union + { + struct + { + unsigned int code_field:11; + unsigned int toggle:1; + unsigned int ack2:1; + unsigned int message_page:1; + unsigned int reserved_14:1; + unsigned int next_page:1; + } bits; + + unsigned short AsUSHORT; + + #define mr_np_tx Mr7.AsUSHORT + } Mr7; + + /* Auto-negotiation link partner ability register. */ + union + { + struct + { + unsigned int code_field:11; + unsigned int toggle:1; + unsigned int ack2:1; + unsigned int message_page:1; + unsigned int ack:1; + unsigned int next_page:1; + } bits; + + unsigned short AsUSHORT; + + #define mr_lp_np_rx Mr8.AsUSHORT + } Mr8; + + /* Extended status register. */ + union + { + struct + { + unsigned int reserved_11:12; + unsigned int base1000_t_hd:1; + unsigned int base1000_t_fd:1; + unsigned int base1000_x_hd:1; + unsigned int base1000_x_fd:1; + } bits; + + unsigned short AsUSHORT; + } Mr15; + + /* Miscellaneous state variables. */ + union + { + struct + { + unsigned int toggle_tx:1; + unsigned int toggle_rx:1; + unsigned int np_rx:1; + unsigned int page_rx:1; + unsigned int np_loaded:1; + } bits; + + unsigned short AsUSHORT; + + #define mr_toggle_tx MrMisc.bits.toggle_tx + #define mr_toggle_rx MrMisc.bits.toggle_rx + #define mr_np_rx MrMisc.bits.np_rx + #define mr_page_rx MrMisc.bits.page_rx + #define mr_np_loaded MrMisc.bits.np_loaded + } MrMisc; + +} AN_STATE_INFO, *PAN_STATE_INFO; + + + +/******************************************************************************/ +/* Return code of Autoneg8023z. */ +/******************************************************************************/ + +typedef enum +{ + AUTONEG_STATUS_OK = 0, + AUTONEG_STATUS_DONE = 1, + AUTONEG_STATUS_TIMER_ENABLED = 2, +// AUTONEG_STATUS_FAILED = 0xffffffff, + AUTONEG_STATUS_FAILED = 0xfffffff +} AUTONEG_STATUS, *PAUTONEG_STATUS; + + + +/******************************************************************************/ +/* Function prototypes. */ +/******************************************************************************/ + +AUTONEG_STATUS Autoneg8023z(PAN_STATE_INFO pAnInfo); +void AutonegInit(PAN_STATE_INFO pAnInfo); + + + +/******************************************************************************/ +/* The following functions are defined in the os-dependent module. */ +/******************************************************************************/ + +void MM_AnTxConfig(PAN_STATE_INFO pAnInfo); +void MM_AnTxIdle(PAN_STATE_INFO pAnInfo); +char MM_AnRxConfig(PAN_STATE_INFO pAnInfo, unsigned short *pRxConfig); + + + +#endif /* AUTONEG_H */ + diff --git a/package/broadcom-57xx/src/b57um.c b/package/broadcom-57xx/src/b57um.c new file mode 100644 index 0000000000..752241dd4b --- /dev/null +++ b/package/broadcom-57xx/src/b57um.c @@ -0,0 +1,5563 @@ +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 - 2005 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/******************************************************************************/ + +/* $Id: b57um.c,v 1.32 2007/09/06 07:28:06 yogo Exp $ */ + +char bcm5700_driver[] = "bcm57xx"; +char bcm5700_version[] = "8.3.14"; +char bcm5700_date[] = "(11/2/05)"; + +#define B57UM +#include "mm.h" +#include "linux/mii.h" //@.@jack add it 2006/06/28. +#include "typedefs.h" +#include "osl.h" +#include "bcmdefs.h" +#include "bcmdevs.h" +#include "sbconfig.h" +#include "sbutils.h" +#include "hndgige.h" +#include "bcmrobo.h" +#include "robo_register.c" + +#include "bcmendian.h" +#include "bcmnvram.h" +#include "proto/ethernet.h" +#include "proto/vlan.h" +#include "proto/bcmtcp.h" +#include "proto/bcmip.h" +#define PKTDATA(osh, skb) (((struct sk_buff*)(skb))->data) + +/* this is needed to get good and stable performances */ +#define EXTRA_HDR BCMEXTRAHDROOM + +#define SIOCGREG_STATUS 0x8996 /* Read Switch register (for debug)*/ +#define SIOCSREG_STATUS 0x8997 /* Write Switch register(for debug)*/ + +/* This structure is used in SIOCXREG_STATUS ioctl calls*/ +struct reg_ioctl_data { + u16 page_num; + u16 addr_num; + u16 len; + u16 val_in[4]; + u16 val_out[4]; +}; + +/* A few user-configurable values. */ + +#define MAX_UNITS 16 +/* Used to pass the full-duplex flag, etc. */ +static int line_speed[MAX_UNITS] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +static int auto_speed[MAX_UNITS] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; +static int full_duplex[MAX_UNITS] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; +static int rx_flow_control[MAX_UNITS] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; +static int tx_flow_control[MAX_UNITS] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; +static int auto_flow_control[MAX_UNITS] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT +static int mtu[MAX_UNITS] = {1500,1500,1500,1500,1500,1500,1500,1500,1500,1500,1500,1500,1500,1500,1500,1500}; /* Jumbo MTU for interfaces. */ +#endif +static int tx_checksum[MAX_UNITS] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; +static int rx_checksum[MAX_UNITS] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; +static int scatter_gather[MAX_UNITS] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; +static int activate_gpio = -1; + +#define TX_DESC_CNT DEFAULT_TX_PACKET_DESC_COUNT +static unsigned int tx_pkt_desc_cnt[MAX_UNITS] = + {TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT, + TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT, + TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT,TX_DESC_CNT, + TX_DESC_CNT}; + +#define RX_DESC_CNT DEFAULT_STD_RCV_DESC_COUNT +static unsigned int rx_std_desc_cnt[MAX_UNITS] = + {RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT, + RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT, + RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT,RX_DESC_CNT, + RX_DESC_CNT }; + +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT +#define JBO_DESC_CNT DEFAULT_JUMBO_RCV_DESC_COUNT +static unsigned int rx_jumbo_desc_cnt[MAX_UNITS] = + {JBO_DESC_CNT,JBO_DESC_CNT,JBO_DESC_CNT,JBO_DESC_CNT,JBO_DESC_CNT, + JBO_DESC_CNT,JBO_DESC_CNT,JBO_DESC_CNT,JBO_DESC_CNT,JBO_DESC_CNT, + JBO_DESC_CNT,JBO_DESC_CNT,JBO_DESC_CNT,JBO_DESC_CNT,JBO_DESC_CNT, + JBO_DESC_CNT }; +#endif + +#ifdef BCM_INT_COAL +#ifdef BCM_NAPI_RXPOLL +static unsigned int adaptive_coalesce[MAX_UNITS] = + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +#else +static unsigned int adaptive_coalesce[MAX_UNITS] = + {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; +#endif + +#define RX_COAL_TK DEFAULT_RX_COALESCING_TICKS +static unsigned int rx_coalesce_ticks[MAX_UNITS] = + {RX_COAL_TK,RX_COAL_TK,RX_COAL_TK,RX_COAL_TK,RX_COAL_TK, + RX_COAL_TK, RX_COAL_TK,RX_COAL_TK,RX_COAL_TK,RX_COAL_TK, + RX_COAL_TK,RX_COAL_TK, RX_COAL_TK,RX_COAL_TK,RX_COAL_TK, + RX_COAL_TK}; + +#define RX_COAL_FM DEFAULT_RX_MAX_COALESCED_FRAMES +static unsigned int rx_max_coalesce_frames[MAX_UNITS] = + {RX_COAL_FM,RX_COAL_FM,RX_COAL_FM,RX_COAL_FM,RX_COAL_FM, + RX_COAL_FM,RX_COAL_FM,RX_COAL_FM,RX_COAL_FM,RX_COAL_FM, + RX_COAL_FM,RX_COAL_FM,RX_COAL_FM,RX_COAL_FM,RX_COAL_FM, + RX_COAL_FM}; + +#define TX_COAL_TK DEFAULT_TX_COALESCING_TICKS +static unsigned int tx_coalesce_ticks[MAX_UNITS] = + {TX_COAL_TK,TX_COAL_TK,TX_COAL_TK,TX_COAL_TK,TX_COAL_TK, + TX_COAL_TK, TX_COAL_TK,TX_COAL_TK,TX_COAL_TK,TX_COAL_TK, + TX_COAL_TK,TX_COAL_TK, TX_COAL_TK,TX_COAL_TK,TX_COAL_TK, + TX_COAL_TK}; + +#define TX_COAL_FM DEFAULT_TX_MAX_COALESCED_FRAMES +static unsigned int tx_max_coalesce_frames[MAX_UNITS] = + {TX_COAL_FM,TX_COAL_FM,TX_COAL_FM,TX_COAL_FM,TX_COAL_FM, + TX_COAL_FM,TX_COAL_FM,TX_COAL_FM,TX_COAL_FM,TX_COAL_FM, + TX_COAL_FM,TX_COAL_FM,TX_COAL_FM,TX_COAL_FM,TX_COAL_FM, + TX_COAL_FM}; + +#define ST_COAL_TK DEFAULT_STATS_COALESCING_TICKS +static unsigned int stats_coalesce_ticks[MAX_UNITS] = + {ST_COAL_TK,ST_COAL_TK,ST_COAL_TK,ST_COAL_TK,ST_COAL_TK, + ST_COAL_TK,ST_COAL_TK,ST_COAL_TK,ST_COAL_TK,ST_COAL_TK, + ST_COAL_TK,ST_COAL_TK,ST_COAL_TK,ST_COAL_TK,ST_COAL_TK, + ST_COAL_TK,}; + +#endif +#ifdef BCM_WOL +static int enable_wol[MAX_UNITS] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +#endif +#ifdef BCM_TSO +static int enable_tso[MAX_UNITS] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; +#endif +#ifdef BCM_NIC_SEND_BD +static int nic_tx_bd[MAX_UNITS] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +#endif +#ifdef BCM_ASF +static int vlan_tag_mode[MAX_UNITS] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +#endif +static int delay_link[MAX_UNITS] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +static int disable_d3hot[MAX_UNITS] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + +#if defined(CONFIG_PCI_MSI) || defined(CONFIG_PCI_USE_VECTOR) +static int disable_msi[MAX_UNITS] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +static int bcm_msi_chipset_bug = 0; +#endif + +#define BCM_TIMER_GRANULARITY (1000000 / HZ) + +/* Hack to hook the data path to the BCM WL dirver */ +#ifdef BCM_WL_EMULATOR +#include "bcmnvram.h" +#include "wl_bcm57emu.h" +#ifdef SKB_MANAGER +int skb_old_alloc = 0; +#endif +#endif /* BCM_WL_EMULATOR */ + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (2*HZ) + +#if (LINUX_VERSION_CODE < 0x02030d) +#define pci_resource_start(dev, bar) (dev->base_address[bar] & PCI_BASE_ADDRESS_MEM_MASK) +#elif (LINUX_VERSION_CODE < 0x02032b) +#define pci_resource_start(dev, bar) (dev->resource[bar] & PCI_BASE_ADDRESS_MEM_MASK) +#endif + +#if (LINUX_VERSION_CODE < 0x02032b) +#define dev_kfree_skb_irq(skb) dev_kfree_skb(skb) +#define netif_wake_queue(dev) clear_bit(0, &dev->tbusy); mark_bh(NET_BH) +#define netif_stop_queue(dev) set_bit(0, &dev->tbusy) + +static inline void netif_start_queue(struct net_device *dev) +{ + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; +} + +#define netif_queue_stopped(dev) dev->tbusy +#define netif_running(dev) dev->start + +static inline void tasklet_schedule(struct tasklet_struct *tasklet) +{ + queue_task(tasklet, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + +static inline void tasklet_init(struct tasklet_struct *tasklet, + void (*func)(unsigned long), + unsigned long data) +{ + tasklet->next = NULL; + tasklet->sync = 0; + tasklet->routine = (void (*)(void *))func; + tasklet->data = (void *)data; +} + +#define tasklet_kill(tasklet) + +#endif + +#if (LINUX_VERSION_CODE < 0x020300) +struct pci_device_id { + unsigned int vendor, device; /* Vendor and device ID or PCI_ANY_ID */ + unsigned int subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */ + unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */ + unsigned long driver_data; /* Data private to the driver */ +}; + +#define PCI_ANY_ID 0 + +#define pci_set_drvdata(pdev, dev) +#define pci_get_drvdata(pdev) 0 + +#define pci_enable_device(pdev) 0 + +#define __devinit __init +#define __devinitdata __initdata +#define __devexit + +#define SET_MODULE_OWNER(dev) +#define MODULE_DEVICE_TABLE(pci, pci_tbl) + +#endif + +#if (LINUX_VERSION_CODE < 0x020411) +#ifndef __devexit_p +#define __devexit_p(x) x +#endif +#endif + +#ifndef MODULE_LICENSE +#define MODULE_LICENSE(license) +#endif + +#ifndef IRQ_RETVAL +typedef void irqreturn_t; +#define IRQ_RETVAL(x) +#endif + +#if (LINUX_VERSION_CODE < 0x02032a) +static inline void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, + dma_addr_t *dma_handle) +{ + void *virt_ptr; + + /* Maximum in slab.c */ + if (size > 131072) + return 0; + + virt_ptr = kmalloc(size, GFP_KERNEL); + *dma_handle = virt_to_bus(virt_ptr); + return virt_ptr; +} +#define pci_free_consistent(dev, size, ptr, dma_ptr) kfree(ptr) + +#endif /*#if (LINUX_VERSION_CODE < 0x02032a) */ + + +#if (LINUX_VERSION_CODE < 0x02040d) + +#if (LINUX_VERSION_CODE >= 0x020409) && defined(RED_HAT_LINUX_KERNEL) + +#define BCM_32BIT_DMA_MASK ((u64) 0x00000000ffffffffULL) +#define BCM_64BIT_DMA_MASK ((u64) 0xffffffffffffffffULL) + +#else +/* pci_set_dma_mask is using dma_addr_t */ + +#define BCM_32BIT_DMA_MASK ((dma_addr_t) 0xffffffff) +#define BCM_64BIT_DMA_MASK ((dma_addr_t) 0xffffffff) + +#endif + +#else /* (LINUX_VERSION_CODE < 0x02040d) */ + +#define BCM_32BIT_DMA_MASK ((u64) 0x00000000ffffffffULL) +#define BCM_64BIT_DMA_MASK ((u64) 0xffffffffffffffffULL) +#endif + +#if (LINUX_VERSION_CODE < 0x020329) +#define pci_set_dma_mask(pdev, mask) (0) +#else +#if (LINUX_VERSION_CODE < 0x020403) +int +pci_set_dma_mask(struct pci_dev *dev, dma_addr_t mask) +{ + if(! pci_dma_supported(dev, mask)) + return -EIO; + + dev->dma_mask = mask; + + return 0; +} +#endif +#endif + +#if (LINUX_VERSION_CODE < 0x020547) +#define pci_set_consistent_dma_mask(pdev, mask) (0) +#endif + +#if (LINUX_VERSION_CODE < 0x020402) +#define pci_request_regions(pdev, name) (0) +#define pci_release_regions(pdev) +#endif + +#if !defined(spin_is_locked) +#define spin_is_locked(lock) (test_bit(0,(lock))) +#endif + +#define BCM5700_LOCK(pUmDevice, flags) \ + if ((pUmDevice)->do_global_lock) { \ + spin_lock_irqsave(&(pUmDevice)->global_lock, flags); \ + } + +#define BCM5700_UNLOCK(pUmDevice, flags) \ + if ((pUmDevice)->do_global_lock) { \ + spin_unlock_irqrestore(&(pUmDevice)->global_lock, flags);\ + } + +inline void +bcm5700_intr_lock(PUM_DEVICE_BLOCK pUmDevice) +{ + if (pUmDevice->do_global_lock) { + spin_lock(&pUmDevice->global_lock); + } +} + +inline void +bcm5700_intr_unlock(PUM_DEVICE_BLOCK pUmDevice) +{ + if (pUmDevice->do_global_lock) { + spin_unlock(&pUmDevice->global_lock); + } +} + +void +bcm5700_intr_off(PUM_DEVICE_BLOCK pUmDevice) +{ + atomic_inc(&pUmDevice->intr_sem); + LM_DisableInterrupt(&pUmDevice->lm_dev); +#if (LINUX_VERSION_CODE >= 0x2051c) + synchronize_irq(pUmDevice->dev->irq); +#else + synchronize_irq(); +#endif + LM_DisableInterrupt(&pUmDevice->lm_dev); +} + +void +bcm5700_intr_on(PUM_DEVICE_BLOCK pUmDevice) +{ + if (atomic_dec_and_test(&pUmDevice->intr_sem)) { + LM_EnableInterrupt(&pUmDevice->lm_dev); + } +} + + +int MM_Packet_Desc_Size = sizeof(UM_PACKET); + +#if defined(MODULE) +MODULE_AUTHOR("Michael Chan and Gary Zambrano "); +MODULE_DESCRIPTION("BCM5700 Driver"); +MODULE_LICENSE("GPL"); + +#if (LINUX_VERSION_CODE < 0x020605) + +MODULE_PARM(debug, "i"); +MODULE_PARM(msglevel, "i"); +MODULE_PARM(activate_gpio, "0-15i"); +MODULE_PARM(line_speed, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(auto_speed, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(rx_flow_control, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(tx_flow_control, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(auto_flow_control, "1-" __MODULE_STRING(MAX_UNITS) "i"); +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT +MODULE_PARM(mtu, "1-" __MODULE_STRING(MAX_UNITS) "i"); +#endif +MODULE_PARM(tx_checksum, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(rx_checksum, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(scatter_gather, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(tx_pkt_desc_cnt, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(rx_std_desc_cnt, "1-" __MODULE_STRING(MAX_UNITS) "i"); +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT +MODULE_PARM(rx_jumbo_desc_cnt, "1-" __MODULE_STRING(MAX_UNITS) "i"); +#endif +#ifdef BCM_INT_COAL +MODULE_PARM(adaptive_coalesce, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(rx_coalesce_ticks, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(rx_max_coalesce_frames, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(tx_coalesce_ticks, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(tx_max_coalesce_frames, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(stats_coalesce_ticks, "1-" __MODULE_STRING(MAX_UNITS) "i"); +#endif +#ifdef BCM_WOL +MODULE_PARM(enable_wol, "1-" __MODULE_STRING(MAX_UNITS) "i"); +#endif +#ifdef BCM_TSO +MODULE_PARM(enable_tso, "1-" __MODULE_STRING(MAX_UNITS) "i"); +#endif +#ifdef BCM_NIC_SEND_BD +MODULE_PARM(nic_tx_bd, "1-" __MODULE_STRING(MAX_UNITS) "i"); +#endif +#ifdef BCM_ASF +MODULE_PARM(vlan_tag_mode, "1-" __MODULE_STRING(MAX_UNITS) "i"); +#endif +MODULE_PARM(delay_link, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(disable_d3hot, "1-" __MODULE_STRING(MAX_UNITS) "i"); + +#if defined(CONFIG_PCI_MSI) || defined(CONFIG_PCI_USE_VECTOR) +MODULE_PARM(disable_msi, "1-" __MODULE_STRING(MAX_UNITS) "i"); +#endif + +#else /* parms*/ + +#if (LINUX_VERSION_CODE >= 0x020605) && (LINUX_VERSION_CODE < 0x02060a) + +static int var; + +#define numvar var + +#endif + +#if (LINUX_VERSION_CODE >= 0x2060a) + +#define numvar NULL + +#endif + +module_param_array(line_speed, int, numvar, 0); +module_param_array(auto_speed, int, numvar, 0); +module_param_array(full_duplex, int, numvar, 0); +module_param_array(rx_flow_control, int, numvar, 0); +module_param_array(tx_flow_control, int, numvar, 0); +module_param_array(auto_flow_control, int, numvar, 0); +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT +module_param_array(mtu, int, numvar, 0); +#endif +module_param_array(tx_checksum, int, numvar, 0); +module_param_array(rx_checksum, int, numvar, 0); +module_param_array(scatter_gather, int, numvar, 0); +module_param_array(tx_pkt_desc_cnt, int, numvar, 0); +module_param_array(rx_std_desc_cnt, int, numvar, 0); +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT +module_param_array(rx_jumbo_desc_cnt, int, numvar, 0); +#endif +#ifdef BCM_INT_COAL +module_param_array(adaptive_coalesce, int, numvar, 0); +module_param_array(rx_coalesce_ticks, int, numvar, 0); +module_param_array(rx_max_coalesce_frames, int, numvar, 0); +module_param_array(tx_coalesce_ticks, int, numvar, 0); +module_param_array(tx_max_coalesce_frames, int, numvar, 0); +module_param_array(stats_coalesce_ticks, int, numvar, 0); +#endif +#ifdef BCM_WOL +module_param_array(enable_wol, int, numvar, 0); +#endif +#ifdef BCM_TSO +module_param_array(enable_tso, int, numvar, 0); +#endif +#ifdef BCM_NIC_SEND_BD +module_param_array(nic_tx_bd, int, numvar, 0); +#endif +#ifdef BCM_ASF +module_param_array(vlan_tag_mode, int, numvar, 0); +#endif +module_param_array(delay_link, int, numvar, 0); +module_param_array(disable_d3hot, int, numvar, 0); + +#if defined(CONFIG_PCI_MSI) || defined(CONFIG_PCI_USE_VECTOR) +module_param_array(disable_msi, int, numvar, 0); +#endif + + +#endif /* params */ + + +#endif + +#define RUN_AT(x) (jiffies + (x)) + +char kernel_version[] = UTS_RELEASE; + +#define PCI_SUPPORT_VER2 + +#if !defined(CAP_NET_ADMIN) +#define capable(CAP_XXX) (suser()) +#endif + +#define tigon3_debug debug +#if TIGON3_DEBUG +static int tigon3_debug = TIGON3_DEBUG; +#else +static int tigon3_debug = 0; +#endif +static int msglevel = 0xdeadbeef; +int b57_msg_level; + +int bcm5700_open(struct net_device *dev); +STATIC void bcm5700_timer(unsigned long data); +STATIC void bcm5700_stats_timer(unsigned long data); +STATIC void bcm5700_reset(struct net_device *dev); +STATIC int bcm5700_start_xmit(struct sk_buff *skb, struct net_device *dev); +STATIC irqreturn_t bcm5700_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +#ifdef BCM_TASKLET +STATIC void bcm5700_tasklet(unsigned long data); +#endif +STATIC int bcm5700_close(struct net_device *dev); +STATIC struct net_device_stats *bcm5700_get_stats(struct net_device *dev); +STATIC int bcm5700_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +STATIC void bcm5700_do_rx_mode(struct net_device *dev); +STATIC void bcm5700_set_rx_mode(struct net_device *dev); +STATIC int bcm5700_set_mac_addr(struct net_device *dev, void *p); +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT +STATIC int bcm5700_change_mtu(struct net_device *dev, int new_mtu); +#endif +#ifdef BCM_NAPI_RXPOLL +STATIC int bcm5700_poll(struct net_device *dev, int *budget); +#endif +STATIC int replenish_rx_buffers(PUM_DEVICE_BLOCK pUmDevice, int max); +STATIC int bcm5700_freemem(struct net_device *dev); +#ifdef BCM_INT_COAL +#ifndef BCM_NAPI_RXPOLL +STATIC int bcm5700_adapt_coalesce(PUM_DEVICE_BLOCK pUmDevice); +#endif +#endif +STATIC void bcm5700_set_vlan_mode(UM_DEVICE_BLOCK *pUmDevice); +STATIC int bcm5700_init_counters(PUM_DEVICE_BLOCK pUmDevice); +#ifdef BCM_VLAN +STATIC void bcm5700_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp); +STATIC void bcm5700_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid); +#endif +void bcm5700_shutdown(UM_DEVICE_BLOCK *pUmDevice); +void bcm5700_free_remaining_rx_bufs(UM_DEVICE_BLOCK *pUmDevice); +void bcm5700_validate_param_range(UM_DEVICE_BLOCK *pUmDevice, int *param, + char *param_name, int min, int max, int deflt); + +static int bcm5700_notify_reboot(struct notifier_block *this, unsigned long event, void *unused); +static struct notifier_block bcm5700_reboot_notifier = { + bcm5700_notify_reboot, + NULL, + 0 +}; + +#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) +STATIC void poll_bcm5700(struct net_device *dev); +#endif + +/* A list of all installed bcm5700 devices. */ +static struct net_device *root_tigon3_dev = NULL; + +#if defined(CONFIG_SPARC64) || defined(CONFIG_X86_64) ||defined(CONFIG_PPC64) + +#endif + +typedef enum { + BCM5700A6 = 0, + BCM5700T6, + BCM5700A9, + BCM5700T9, + BCM5700, + BCM5701A5, + BCM5701T1, + BCM5701T8, + BCM5701A7, + BCM5701A10, + BCM5701A12, + BCM5701, + BCM5702, + BCM5703, + BCM5703A31, + BCM5703ARBUCKLE, + TC996T, + TC996ST, + TC996SSX, + TC996SX, + TC996BT, + TC997T, + TC997SX, + TC1000T, + TC1000BT, + TC940BR01, + TC942BR01, + TC998T, + TC998SX, + TC999T, + NC6770, + NC1020, + NC150T, + NC7760, + NC7761, + NC7770, + NC7771, + NC7780, + NC7781, + NC7772, + NC7782, + NC7783, + NC320T, + NC320I, + NC325I, + NC324I, + NC326I, + BCM5704CIOBE, + BCM5704, + BCM5704S, + BCM5705, + BCM5705M, + BCM5705F, + BCM5901, + BCM5782, + BCM5788, + BCM5789, + BCM5750, + BCM5750M, + BCM5720, + BCM5751, + BCM5751M, + BCM5751F, + BCM5721, + BCM5753, + BCM5753M, + BCM5753F, + BCM5781, + BCM5752, + BCM5752M, + BCM5714, + BCM5780, + BCM5780S, + BCM5715, + BCM4785, + BCM5903M, + UNK5788 +} board_t; + + +/* indexed by board_t, above */ +static struct { + char *name; +} board_info[] __devinitdata = { + { "Broadcom BCM5700 1000Base-T" }, + { "Broadcom BCM5700 1000Base-SX" }, + { "Broadcom BCM5700 1000Base-SX" }, + { "Broadcom BCM5700 1000Base-T" }, + { "Broadcom BCM5700" }, + { "Broadcom BCM5701 1000Base-T" }, + { "Broadcom BCM5701 1000Base-T" }, + { "Broadcom BCM5701 1000Base-T" }, + { "Broadcom BCM5701 1000Base-SX" }, + { "Broadcom BCM5701 1000Base-T" }, + { "Broadcom BCM5701 1000Base-T" }, + { "Broadcom BCM5701" }, + { "Broadcom BCM5702 1000Base-T" }, + { "Broadcom BCM5703 1000Base-T" }, + { "Broadcom BCM5703 1000Base-SX" }, + { "Broadcom B5703 1000Base-SX" }, + { "3Com 3C996 10/100/1000 Server NIC" }, + { "3Com 3C996 10/100/1000 Server NIC" }, + { "3Com 3C996 Gigabit Fiber-SX Server NIC" }, + { "3Com 3C996 Gigabit Fiber-SX Server NIC" }, + { "3Com 3C996B Gigabit Server NIC" }, + { "3Com 3C997 Gigabit Server NIC" }, + { "3Com 3C997 Gigabit Fiber-SX Server NIC" }, + { "3Com 3C1000 Gigabit NIC" }, + { "3Com 3C1000B-T 10/100/1000 PCI" }, + { "3Com 3C940 Gigabit LOM (21X21)" }, + { "3Com 3C942 Gigabit LOM (31X31)" }, + { "3Com 3C998-T Dual Port 10/100/1000 PCI-X Server NIC" }, + { "3Com 3C998-SX Dual Port 1000-SX PCI-X Server NIC" }, + { "3Com 3C999-T Quad Port 10/100/1000 PCI-X Server NIC" }, + { "HP NC6770 Gigabit Server Adapter" }, + { "NC1020 HP ProLiant Gigabit Server Adapter 32 PCI" }, + { "HP ProLiant NC 150T PCI 4-port Gigabit Combo Switch Adapter" }, + { "HP NC7760 Gigabit Server Adapter" }, + { "HP NC7761 Gigabit Server Adapter" }, + { "HP NC7770 Gigabit Server Adapter" }, + { "HP NC7771 Gigabit Server Adapter" }, + { "HP NC7780 Gigabit Server Adapter" }, + { "HP NC7781 Gigabit Server Adapter" }, + { "HP NC7772 Gigabit Server Adapter" }, + { "HP NC7782 Gigabit Server Adapter" }, + { "HP NC7783 Gigabit Server Adapter" }, + { "HP ProLiant NC 320T PCI Express Gigabit Server Adapter" }, + { "HP ProLiant NC 320i PCI Express Gigabit Server Adapter" }, + { "HP NC325i Integrated Dual Port PCI Express Gigabit Server Adapter" }, + { "HP NC324i Integrated Dual Port PCI Express Gigabit Server Adapter" }, + { "HP NC326i Integrated Dual Port PCI Express Gigabit Server Adapter" }, + { "Broadcom BCM5704 CIOB-E 1000Base-T" }, + { "Broadcom BCM5704 1000Base-T" }, + { "Broadcom BCM5704 1000Base-SX" }, + { "Broadcom BCM5705 1000Base-T" }, + { "Broadcom BCM5705M 1000Base-T" }, + { "Broadcom 570x 10/100 Integrated Controller" }, + { "Broadcom BCM5901 100Base-TX" }, + { "Broadcom NetXtreme Gigabit Ethernet for hp" }, + { "Broadcom BCM5788 NetLink 1000Base-T" }, + { "Broadcom BCM5789 NetLink 1000Base-T PCI Express" }, + { "Broadcom BCM5750 1000Base-T PCI" }, + { "Broadcom BCM5750M 1000Base-T PCI" }, + { "Broadcom BCM5720 1000Base-T PCI" }, + { "Broadcom BCM5751 1000Base-T PCI Express" }, + { "Broadcom BCM5751M 1000Base-T PCI Express" }, + { "Broadcom BCM5751F 100Base-TX PCI Express" }, + { "Broadcom BCM5721 1000Base-T PCI Express" }, + { "Broadcom BCM5753 1000Base-T PCI Express" }, + { "Broadcom BCM5753M 1000Base-T PCI Express" }, + { "Broadcom BCM5753F 100Base-TX PCI Express" }, + { "Broadcom BCM5781 NetLink 1000Base-T PCI Express" }, + { "Broadcom BCM5752 1000Base-T PCI Express" }, + { "Broadcom BCM5752M 1000Base-T PCI Express" }, + { "Broadcom BCM5714 1000Base-T " }, + { "Broadcom BCM5780 1000Base-T" }, + { "Broadcom BCM5780S 1000Base-SX" }, + { "Broadcom BCM5715 1000Base-T " }, + { "Broadcom BCM4785 10/100/1000 Integrated Controller" }, + { "Broadcom BCM5903M Gigabit Ethernet " }, + { "Unknown BCM5788 Gigabit Ethernet " }, + { 0 } + }; + +static struct pci_device_id bcm5700_pci_tbl[] __devinitdata = { + {0x14e4, 0x1644, 0x14e4, 0x1644, 0, 0, BCM5700A6 }, + {0x14e4, 0x1644, 0x14e4, 0x2, 0, 0, BCM5700T6 }, + {0x14e4, 0x1644, 0x14e4, 0x3, 0, 0, BCM5700A9 }, + {0x14e4, 0x1644, 0x14e4, 0x4, 0, 0, BCM5700T9 }, + {0x14e4, 0x1644, 0x1028, 0xd1, 0, 0, BCM5700 }, + {0x14e4, 0x1644, 0x1028, 0x0106, 0, 0, BCM5700 }, + {0x14e4, 0x1644, 0x1028, 0x0109, 0, 0, BCM5700 }, + {0x14e4, 0x1644, 0x1028, 0x010a, 0, 0, BCM5700 }, + {0x14e4, 0x1644, 0x10b7, 0x1000, 0, 0, TC996T }, + {0x14e4, 0x1644, 0x10b7, 0x1001, 0, 0, TC996ST }, + {0x14e4, 0x1644, 0x10b7, 0x1002, 0, 0, TC996SSX }, + {0x14e4, 0x1644, 0x10b7, 0x1003, 0, 0, TC997T }, + {0x14e4, 0x1644, 0x10b7, 0x1005, 0, 0, TC997SX }, + {0x14e4, 0x1644, 0x10b7, 0x1008, 0, 0, TC942BR01 }, + {0x14e4, 0x1644, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5700 }, + {0x14e4, 0x1645, 0x14e4, 1, 0, 0, BCM5701A5 }, + {0x14e4, 0x1645, 0x14e4, 5, 0, 0, BCM5701T1 }, + {0x14e4, 0x1645, 0x14e4, 6, 0, 0, BCM5701T8 }, + {0x14e4, 0x1645, 0x14e4, 7, 0, 0, BCM5701A7 }, + {0x14e4, 0x1645, 0x14e4, 8, 0, 0, BCM5701A10 }, + {0x14e4, 0x1645, 0x14e4, 0x8008, 0, 0, BCM5701A12 }, + {0x14e4, 0x1645, 0x0e11, 0xc1, 0, 0, NC6770 }, + {0x14e4, 0x1645, 0x0e11, 0x7c, 0, 0, NC7770 }, + {0x14e4, 0x1645, 0x0e11, 0x85, 0, 0, NC7780 }, + {0x14e4, 0x1645, 0x1028, 0x0121, 0, 0, BCM5701 }, + {0x14e4, 0x1645, 0x10b7, 0x1004, 0, 0, TC996SX }, + {0x14e4, 0x1645, 0x10b7, 0x1006, 0, 0, TC996BT }, + {0x14e4, 0x1645, 0x10b7, 0x1007, 0, 0, TC1000T }, + {0x14e4, 0x1645, 0x10b7, 0x1008, 0, 0, TC940BR01 }, + {0x14e4, 0x1645, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5701 }, + {0x14e4, 0x1646, 0x14e4, 0x8009, 0, 0, BCM5702 }, + {0x14e4, 0x1646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5702 }, + {0x14e4, 0x16a6, 0x14e4, 0x8009, 0, 0, BCM5702 }, + {0x14e4, 0x16a6, 0x14e4, 0x000c, 0, 0, BCM5702 }, + {0x14e4, 0x16a6, 0x0e11, 0xbb, 0, 0, NC7760 }, + {0x14e4, 0x16a6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5702 }, + {0x14e4, 0x16c6, 0x10b7, 0x1100, 0, 0, TC1000BT }, + {0x14e4, 0x16c6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5702 }, + {0x14e4, 0x1647, 0x14e4, 0x0009, 0, 0, BCM5703 }, + {0x14e4, 0x1647, 0x14e4, 0x000a, 0, 0, BCM5703A31 }, + {0x14e4, 0x1647, 0x14e4, 0x000b, 0, 0, BCM5703 }, + {0x14e4, 0x1647, 0x14e4, 0x800a, 0, 0, BCM5703 }, + {0x14e4, 0x1647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5703 }, + {0x14e4, 0x16a7, 0x14e4, 0x0009, 0, 0, BCM5703 }, + {0x14e4, 0x16a7, 0x14e4, 0x000a, 0, 0, BCM5703A31 }, + {0x14e4, 0x16a7, 0x14e4, 0x000b, 0, 0, BCM5703 }, + {0x14e4, 0x16a7, 0x14e4, 0x800a, 0, 0, BCM5703 }, + {0x14e4, 0x16a7, 0x0e11, 0xca, 0, 0, NC7771 }, + {0x14e4, 0x16a7, 0x0e11, 0xcb, 0, 0, NC7781 }, + {0x14e4, 0x16a7, 0x1014, 0x0281, 0, 0, BCM5703ARBUCKLE }, + {0x14e4, 0x16a7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5703 }, + {0x14e4, 0x16c7, 0x14e4, 0x000a, 0, 0, BCM5703A31 }, + {0x14e4, 0x16c7, 0x0e11, 0xca, 0, 0, NC7771 }, + {0x14e4, 0x16c7, 0x0e11, 0xcb, 0, 0, NC7781 }, + {0x14e4, 0x16c7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5703 }, + {0x14e4, 0x1648, 0x0e11, 0xcf, 0, 0, NC7772 }, + {0x14e4, 0x1648, 0x0e11, 0xd0, 0, 0, NC7782 }, + {0x14e4, 0x1648, 0x0e11, 0xd1, 0, 0, NC7783 }, + {0x14e4, 0x1648, 0x10b7, 0x2000, 0, 0, TC998T }, + {0x14e4, 0x1648, 0x10b7, 0x3000, 0, 0, TC999T }, + {0x14e4, 0x1648, 0x1166, 0x1648, 0, 0, BCM5704CIOBE }, + {0x14e4, 0x1648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5704 }, + {0x14e4, 0x1649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5704S }, + {0x14e4, 0x16a8, 0x14e4, 0x16a8, 0, 0, BCM5704S }, + {0x14e4, 0x16a8, 0x10b7, 0x2001, 0, 0, TC998SX }, + {0x14e4, 0x16a8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5704S }, + {0x14e4, 0x1653, 0x0e11, 0x00e3, 0, 0, NC7761 }, + {0x14e4, 0x1653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5705 }, + {0x14e4, 0x1654, 0x0e11, 0x00e3, 0, 0, NC7761 }, + {0x14e4, 0x1654, 0x103c, 0x3100, 0, 0, NC1020 }, + {0x14e4, 0x1654, 0x103c, 0x3226, 0, 0, NC150T }, + {0x14e4, 0x1654, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5705 }, + {0x14e4, 0x165d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5705M }, + {0x14e4, 0x165e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5705M }, + {0x14e4, 0x166e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5705F }, + {0x14e4, 0x1696, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5782 }, + {0x14e4, 0x169c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5788 }, + {0x14e4, 0x169d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5789 }, + {0x14e4, 0x170d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5901 }, + {0x14e4, 0x170e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5901 }, + {0x14e4, 0x1676, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5750 }, + {0x14e4, 0x167c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5750M }, + {0x14e4, 0x1677, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5751 }, + {0x14e4, 0x167d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5751M }, + {0x14e4, 0x167e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5751F }, + {0x14e4, 0x1658, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5720 }, + {0x14e4, 0x1659, 0x103c, 0x7031, 0, 0, NC320T }, + {0x14e4, 0x1659, 0x103c, 0x7032, 0, 0, NC320T }, + {0x14e4, 0x166a, 0x103c, 0x7035, 0, 0, NC325I }, + {0x14e4, 0x166b, 0x103c, 0x7036, 0, 0, NC325I }, + {0x14e4, 0x1668, 0x103c, 0x7039, 0, 0, NC324I }, + {0x14e4, 0x1669, 0x103c, 0x703a, 0, 0, NC324I }, + {0x14e4, 0x1678, 0x103c, 0x703e, 0, 0, NC326I }, + {0x14e4, 0x1679, 0x103c, 0x703c, 0, 0, NC326I }, + {0x14e4, 0x1659, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5721 }, + {0x14e4, 0x16f7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5753 }, + {0x14e4, 0x16fd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5753M }, + {0x14e4, 0x16fe, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5753F }, + {0x14e4, 0x16dd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5781 }, + {0x14e4, 0x1600, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5752 }, + {0x14e4, 0x1601, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5752M }, + {0x14e4, 0x1668, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5714 }, + {0x14e4, 0x166a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5780 }, + {0x14e4, 0x166b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5780S }, + {0x14e4, 0x1678, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5715 }, + {0x14e4, 0x471f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM4785 }, + {0x14e4, 0x16ff, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5903M }, + {0x173b, 0x03ed, PCI_ANY_ID, PCI_ANY_ID, 0, 0, UNK5788 }, + {0,} + }; + +MODULE_DEVICE_TABLE(pci, bcm5700_pci_tbl); + +#if (LINUX_VERSION_CODE >= 0x2060a) + static struct pci_device_id pci_AMD762id[]={ + { PCI_DEVICE(PCI_VENDOR_ID_AMD, + PCI_DEVICE_ID_AMD_FE_GATE_700C) }, + { } + }; +#endif + +static int sbgige = -1; + +/******************************************************************************* + ******************************************************************************* +*/ + +int get_csum_flag(LM_UINT32 ChipRevId) +{ + return NETIF_F_IP_CSUM; +} + +/******************************************************************************* + ******************************************************************************* + + This function returns true if the device passed to it is attached to an + ICH-ICH4. If the chip is not attached to an ICH, or is attached to an ICH5 + or newer, it returns false. + + This function determines which bridge it is attached to by scaning the pci + bus looking for bridge chips (hdr_type=1). When a bridge chip is detected, + the bridge's subordinate's secondary bus number is compared with this + devices bus number. If they match, then the device is attached to this + bridge. The bridge's device id is compared to a list of known device ids for + ICH-ICH4. Since many older ICH's (ICH2-ICH7) share the same device id, the + chip revision must also be checked to determine if the chip is older than an + ICH5. + + To scan the bus, one of two functions is used depending on the kernel + version. For 2.4 kernels, the pci_find_device function is used. This + function has been depricated in the 2.6 kernel and replaced with the + fucntion pci_get_device. The macro walk_pci_bus determines which function to + use when the driver is built. +*/ + +#if (LINUX_VERSION_CODE >= 0x2060a) +#define walk_pci_bus(d) while ((d = pci_get_device( \ + PCI_ANY_ID, PCI_ANY_ID, d)) != NULL) + +#define unwalk_pci_bus(d) pci_dev_put(d) + +#else +#define walk_pci_bus(d) while ((d = pci_find_device( \ + PCI_ANY_ID, PCI_ANY_ID, d)) != NULL) +#define unwalk_pci_bus(d) + +#endif + +#define ICH5_CHIP_VERSION 0xc0 + +static struct pci_device_id pci_ICHtable[] = { + {0x8086, 0x2418}, /* PCI_DEVICE_ID_INTEL_82801AA_8 */ + {0x8086, 0x2428}, /* PCI_DEVICE_ID_INTEL_82801AB_8 */ + {0x8086, 0x244e}, /* PCI_DEVICE_ID_INTEL_82801BA_6 */ + {0x8086, 0x2448}, /* PCI_DEVICE_ID_INTEL_82801BA_11 */ + {0, 0} +}; + +int attached_to_ICH4_or_older( struct pci_dev *pdev) +{ + struct pci_dev *tmp_pdev = NULL; + struct pci_device_id *ich_table; + u8 chip_rev; + + walk_pci_bus (tmp_pdev) { + if ((tmp_pdev->hdr_type == 1) && + (tmp_pdev->subordinate != NULL) && + (tmp_pdev->subordinate->secondary == pdev->bus->number)) { + + ich_table = pci_ICHtable; + + while (ich_table->vendor) { + if ((ich_table->vendor == tmp_pdev->vendor) && + (ich_table->device == tmp_pdev->device)) { + + pci_read_config_byte( tmp_pdev, + PCI_REVISION_ID, &chip_rev); + + if (chip_rev < ICH5_CHIP_VERSION) { + unwalk_pci_bus( tmp_pdev); + return 1; + } + } + ich_table++; + } + } + } + return 0; +} + +static void robo_set_power_mode(void *h) +{ + //int status = 0; + int i; + //uint8 mode8; + //uint16 mode16; + uint32 flags = 0, temp32 = 0,val32 = 0, savephyaddr = 0; + PUM_DEVICE_BLOCK pudev = (PUM_DEVICE_BLOCK)h; + PLM_DEVICE_BLOCK pdev = &pudev->lm_dev; + + /*Brcm,Alex,2006.7.20. Adding Phy power mode setting*/ + BCM5700_PHY_LOCK(pudev, flags); + savephyaddr = pdev->PhyAddr; + + for(i = 0; i < 8; i++) + { + pdev->PhyAddr = i; + temp32 = 0x2007; + LM_WritePhy(pdev, 0x18, temp32); + LM_ReadPhy(pdev, 0x18, &val32); +// printk(KERN_DEBUG "Alex: port = %x, read value =%x\n",i, val32); + temp32 = 0xc042; + LM_WritePhy(pdev, 0x18, temp32); + /*Read back*/ + temp32 = 0x2007; + val32 = 0; + LM_WritePhy(pdev, 0x18, temp32); + LM_ReadPhy(pdev, 0x18, &val32); +// printk(KERN_ERR "Alex: read back value =%x\n",val32); + } + + pdev->PhyAddr = savephyaddr; + BCM5700_PHY_UNLOCK(pudev, flags); + + /*end of Brcm,Alex,2006.7.20. Adding Phy power mode setting*/ + +} + +static int +__devinit bcm5700_init_board(struct pci_dev *pdev, struct net_device **dev_out, int board_idx) +{ + struct net_device *dev; + PUM_DEVICE_BLOCK pUmDevice; + PLM_DEVICE_BLOCK pDevice; + bool rgmii = FALSE; + sb_t *sbh = NULL; + int rc; + + *dev_out = NULL; + + /* dev zeroed in init_etherdev */ +#if (LINUX_VERSION_CODE >= 0x20600) + dev = alloc_etherdev(sizeof(*pUmDevice)); +#else + dev = init_etherdev(NULL, sizeof(*pUmDevice)); +#endif + if (dev == NULL) { + printk(KERN_ERR "%s: unable to alloc new ethernet\n", bcm5700_driver); + return -ENOMEM; + } + SET_MODULE_OWNER(dev); +#if (LINUX_VERSION_CODE >= 0x20600) + SET_NETDEV_DEV(dev, &pdev->dev); +#endif + pUmDevice = (PUM_DEVICE_BLOCK) dev->priv; + + /* enable device (incl. PCI PM wakeup), and bus-mastering */ + rc = pci_enable_device(pdev); + if (rc) + goto err_out; + + /* init core specific stuff */ + if (pdev->device == T3_PCI_DEVICE_ID(T3_PCI_ID_BCM471F)) { + sbh = sb_kattach(SB_OSH); + sb_gige_init(sbh, ++sbgige, &rgmii); + } + + rc = pci_request_regions(pdev, bcm5700_driver); + if (rc) { + if (!sbh) + goto err_out; + printk(KERN_INFO "bcm5700_init_board: pci_request_regions returned error %d\n" + "This may be because the region is already requested by" + " the SMBus driver. Ignore the PCI error messages.\n", rc); + } + + pci_set_master(pdev); + + if (pci_set_dma_mask(pdev, BCM_64BIT_DMA_MASK) == 0) { + pUmDevice->using_dac = 1; + if (pci_set_consistent_dma_mask(pdev, BCM_64BIT_DMA_MASK) != 0) { + printk(KERN_ERR "pci_set_consistent_dma_mask failed\n"); + pci_release_regions(pdev); + goto err_out; + } + } else if (pci_set_dma_mask(pdev, BCM_32BIT_DMA_MASK) == 0) { + pUmDevice->using_dac = 0; + } else { + printk(KERN_ERR "System does not support DMA\n"); + pci_release_regions(pdev); + goto err_out; + } + + pUmDevice->dev = dev; + pUmDevice->pdev = pdev; + pUmDevice->mem_list_num = 0; + pUmDevice->next_module = root_tigon3_dev; + pUmDevice->index = board_idx; + pUmDevice->sbh = (void *)sbh; + root_tigon3_dev = dev; + + spin_lock_init(&pUmDevice->global_lock); + + spin_lock_init(&pUmDevice->undi_lock); + + spin_lock_init(&pUmDevice->phy_lock); + + pDevice = &pUmDevice->lm_dev; + pDevice->Flags = 0; + pDevice->FunctNum = PCI_FUNC(pUmDevice->pdev->devfn); + pUmDevice->boardflags = getintvar(NULL, "boardflags"); + if (sbh) { + if (pUmDevice->boardflags & BFL_ENETROBO) + pDevice->Flags |= ROBO_SWITCH_FLAG; + pDevice->Flags |= rgmii ? RGMII_MODE_FLAG : 0; + if (sb_chip(sbh) == BCM4785_CHIP_ID && sb_chiprev(sbh) < 2) + pDevice->Flags |= ONE_DMA_AT_ONCE_FLAG; + pDevice->Flags |= SB_CORE_FLAG; + if (sb_chip(sbh) == BCM4785_CHIP_ID) + pDevice->Flags |= FLUSH_POSTED_WRITE_FLAG; + } + +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + if (board_idx < MAX_UNITS) { + bcm5700_validate_param_range(pUmDevice, &mtu[board_idx], "mtu", 1500, 9000, 1500); + dev->mtu = mtu[board_idx]; + } +#endif + + if (attached_to_ICH4_or_older(pdev)) { + pDevice->Flags |= UNDI_FIX_FLAG; + } + +#if (LINUX_VERSION_CODE >= 0x2060a) + if (pci_dev_present(pci_AMD762id)) { + pDevice->Flags |= FLUSH_POSTED_WRITE_FLAG; + pDevice->Flags &= ~NIC_SEND_BD_FLAG; + } +#else + if (pci_find_device(0x1022, 0x700c, NULL)) { + /* AMD762 writes I/O out of order */ + /* Setting bit 1 in 762's register 0x4C still doesn't work */ + /* in all cases */ + pDevice->Flags |= FLUSH_POSTED_WRITE_FLAG; + pDevice->Flags &= ~NIC_SEND_BD_FLAG; + } +#endif + if (LM_GetAdapterInfo(pDevice) != LM_STATUS_SUCCESS) { + rc = -ENODEV; + goto err_out_unmap; + } + + if (pDevice->Flags & ROBO_SWITCH_FLAG) { + robo_info_t *robo; + + if ((robo = bcm_robo_attach(sbh, pDevice, dev->name, NULL, + robo_miird, robo_miiwr)) == NULL) { + B57_ERR(("robo_setup: failed to attach robo switch \n")); + goto robo_fail; + } + + if (bcm_robo_enable_device(robo)) { + B57_ERR(("robo_setup: failed to enable robo switch \n")); +robo_fail: + bcm_robo_detach(robo); + rc = -ENODEV; + goto err_out_unmap; + } + + /* 5397 power mode setting */ + robo_set_power_mode(robo->h); + + pUmDevice->robo = (void *)robo; + } + + if ((pDevice->Flags & JUMBO_CAPABLE_FLAG) == 0) { + if (dev->mtu > 1500) { + dev->mtu = 1500; + printk(KERN_WARNING + "%s-%d: Jumbo mtu sizes not supported, using mtu=1500\n", + bcm5700_driver, pUmDevice->index); + } + } + + pUmDevice->do_global_lock = 0; + if (T3_ASIC_REV(pUmDevice->lm_dev.ChipRevId) == T3_ASIC_REV_5700) { + /* The 5700 chip works best without interleaved register */ + /* accesses on certain machines. */ + pUmDevice->do_global_lock = 1; + } + + if ((T3_ASIC_REV(pUmDevice->lm_dev.ChipRevId) == T3_ASIC_REV_5701) && + ((pDevice->PciState & T3_PCI_STATE_NOT_PCI_X_BUS) == 0)) { + + pUmDevice->rx_buf_align = 0; + } else { + pUmDevice->rx_buf_align = 2; + } + dev->mem_start = pci_resource_start(pdev, 0); + dev->mem_end = dev->mem_start + sizeof(T3_STD_MEM_MAP); + dev->irq = pdev->irq; + + *dev_out = dev; + return 0; + +err_out_unmap: + pci_release_regions(pdev); + bcm5700_freemem(dev); + +err_out: +#if (LINUX_VERSION_CODE < 0x020600) + unregister_netdev(dev); + kfree(dev); +#else + free_netdev(dev); +#endif + return rc; +} + +static int __devinit +bcm5700_print_ver(void) +{ + printk(KERN_INFO "Broadcom Gigabit Ethernet Driver %s ", + bcm5700_driver); + printk("ver. %s %s\n", bcm5700_version, bcm5700_date); + return 0; +} + +static int __devinit +bcm5700_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct net_device *dev = NULL; + PUM_DEVICE_BLOCK pUmDevice; + PLM_DEVICE_BLOCK pDevice; + int i; + static int board_idx = -1; + static int printed_version = 0; + struct pci_dev *pci_dev; + + board_idx++; + + if (!printed_version) { + bcm5700_print_ver(); + printed_version = 1; + } + + i = bcm5700_init_board(pdev, &dev, board_idx); + if (i < 0) { + return i; + } + + if (dev == NULL) + return -ENOMEM; + +#ifdef BCM_IOCTL32 + if (atomic_read(&bcm5700_load_count) == 0) { + register_ioctl32_conversion(SIOCNICE, bcm5700_ioctl32); + } + atomic_inc(&bcm5700_load_count); +#endif + dev->open = bcm5700_open; + dev->hard_start_xmit = bcm5700_start_xmit; + dev->stop = bcm5700_close; + dev->get_stats = bcm5700_get_stats; + dev->set_multicast_list = bcm5700_set_rx_mode; + dev->do_ioctl = bcm5700_ioctl; + dev->set_mac_address = &bcm5700_set_mac_addr; +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + dev->change_mtu = &bcm5700_change_mtu; +#endif +#if (LINUX_VERSION_CODE >= 0x20400) + dev->tx_timeout = bcm5700_reset; + dev->watchdog_timeo = TX_TIMEOUT; +#endif +#ifdef BCM_VLAN + dev->vlan_rx_register = &bcm5700_vlan_rx_register; + dev->vlan_rx_kill_vid = &bcm5700_vlan_rx_kill_vid; +#endif +#ifdef BCM_NAPI_RXPOLL + dev->poll = bcm5700_poll; + dev->weight = 64; +#endif + + pUmDevice = (PUM_DEVICE_BLOCK) dev->priv; + pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + + dev->base_addr = pci_resource_start(pdev, 0); + dev->irq = pdev->irq; +#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) + dev->poll_controller = poll_bcm5700; +#endif + +#if (LINUX_VERSION_CODE >= 0x20600) + if ((i = register_netdev(dev))) { + printk(KERN_ERR "%s: Cannot register net device\n", + bcm5700_driver); + if (pUmDevice->lm_dev.pMappedMemBase) + iounmap(pUmDevice->lm_dev.pMappedMemBase); + pci_release_regions(pdev); + bcm5700_freemem(dev); + free_netdev(dev); + return i; + } +#endif + + + pci_set_drvdata(pdev, dev); + + memcpy(dev->dev_addr, pDevice->NodeAddress, 6); + pUmDevice->name = board_info[ent->driver_data].name, + printk(KERN_INFO "%s: %s found at mem %lx, IRQ %d, ", + dev->name, pUmDevice->name, dev->base_addr, + dev->irq); + printk("node addr "); + for (i = 0; i < 6; i++) { + printk("%2.2x", dev->dev_addr[i]); + } + printk("\n"); + + printk(KERN_INFO "%s: ", dev->name); + if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5400_PHY_ID) + printk("Broadcom BCM5400 Copper "); + else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5401_PHY_ID) + printk("Broadcom BCM5401 Copper "); + else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5411_PHY_ID) + printk("Broadcom BCM5411 Copper "); + else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5461_PHY_ID) + printk("Broadcom BCM5461 Copper "); + else if (((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5701_PHY_ID) && + !(pDevice->TbiFlags & ENABLE_TBI_FLAG)) { + printk("Broadcom BCM5701 Integrated Copper "); + } + else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5703_PHY_ID) { + printk("Broadcom BCM5703 Integrated "); + if (pDevice->TbiFlags & ENABLE_TBI_FLAG) + printk("SerDes "); + else + printk("Copper "); + } + else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5704_PHY_ID) { + printk("Broadcom BCM5704 Integrated "); + if (pDevice->TbiFlags & ENABLE_TBI_FLAG) + printk("SerDes "); + else + printk("Copper "); + } + else if (pDevice->PhyFlags & PHY_IS_FIBER){ + if(( pDevice->PhyId & PHY_ID_MASK ) == PHY_BCM5780_PHY_ID) + printk("Broadcom BCM5780S Integrated Serdes "); + + } + else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5705_PHY_ID) + printk("Broadcom BCM5705 Integrated Copper "); + else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5750_PHY_ID) + printk("Broadcom BCM5750 Integrated Copper "); + + else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5714_PHY_ID) + printk("Broadcom BCM5714 Integrated Copper "); + else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5780_PHY_ID) + printk("Broadcom BCM5780 Integrated Copper "); + + else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5752_PHY_ID) + printk("Broadcom BCM5752 Integrated Copper "); + else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM8002_PHY_ID) + printk("Broadcom BCM8002 SerDes "); + else if (pDevice->TbiFlags & ENABLE_TBI_FLAG) { + if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5703) { + printk("Broadcom BCM5703 Integrated SerDes "); + } + else if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5704) { + printk("Broadcom BCM5704 Integrated SerDes "); + } + else { + printk("Agilent HDMP-1636 SerDes "); + } + } + else { + printk("Unknown "); + } + printk("transceiver found\n"); + +#if (LINUX_VERSION_CODE >= 0x20400) + if (scatter_gather[board_idx]) { + dev->features |= NETIF_F_SG; + if (pUmDevice->using_dac && !(pDevice->Flags & BCM5788_FLAG)) + dev->features |= NETIF_F_HIGHDMA; + } + if ((pDevice->TaskOffloadCap & LM_TASK_OFFLOAD_TX_TCP_CHECKSUM) && + tx_checksum[board_idx]) { + + dev->features |= get_csum_flag( pDevice->ChipRevId); + } +#ifdef BCM_VLAN + dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; +#endif +#ifdef BCM_TSO + /* On 5714/15/80 chips, Jumbo Frames and TSO cannot both be enabled at + the same time. Since only one of these features can be enable at a + time, we'll enable only Jumbo Frames and disable TSO when the user + tries to enable both. + */ + dev->features &= ~NETIF_F_TSO; + + if ((pDevice->TaskToOffload & LM_TASK_OFFLOAD_TCP_SEGMENTATION) && + (enable_tso[board_idx])) { + if (T3_ASIC_5714_FAMILY(pDevice->ChipRevId) && + (dev->mtu > 1500)) { + printk(KERN_ALERT "%s: Jumbo Frames and TSO cannot simultaneously be enabled. Jumbo Frames enabled. TSO disabled.\n", dev->name); + } else { + dev->features |= NETIF_F_TSO; + } + } +#endif + printk(KERN_INFO "%s: Scatter-gather %s, 64-bit DMA %s, Tx Checksum %s, ", + dev->name, + (char *) ((dev->features & NETIF_F_SG) ? "ON" : "OFF"), + (char *) ((dev->features & NETIF_F_HIGHDMA) ? "ON" : "OFF"), + (char *) ((dev->features & get_csum_flag( pDevice->ChipRevId)) ? "ON" : "OFF")); +#endif + if ((pDevice->ChipRevId != T3_CHIP_ID_5700_B0) && + rx_checksum[board_idx]) + printk("Rx Checksum ON"); + else + printk("Rx Checksum OFF"); +#ifdef BCM_VLAN + printk(", 802.1Q VLAN ON"); +#endif +#ifdef BCM_TSO + if (dev->features & NETIF_F_TSO) { + printk(", TSO ON"); + } + else +#endif +#ifdef BCM_NAPI_RXPOLL + printk(", NAPI ON"); +#endif + printk("\n"); + + register_reboot_notifier(&bcm5700_reboot_notifier); +#ifdef BCM_TASKLET + tasklet_init(&pUmDevice->tasklet, bcm5700_tasklet, + (unsigned long) pUmDevice); +#endif + if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5704) { + if ((REG_RD(pDevice, PciCfg.DualMacCtrl) & + T3_DUAL_MAC_CH_CTRL_MASK) == 3) { + +printk(KERN_WARNING "%s: Device is configured for Hardware Based Teaming which is not supported with this operating system. Please consult the user diagnostic guide to disable Turbo Teaming.\n", dev->name); + } + } + +#if (LINUX_VERSION_CODE > 0x20605) + + if ((pci_dev = pci_get_device(0x1022, 0x700c, NULL))) +#else + if ((pci_dev = pci_find_device(0x1022, 0x700c, NULL))) +#endif + { + u32 val; + + /* Found AMD 762 North bridge */ + pci_read_config_dword(pci_dev, 0x4c, &val); + if ((val & 0x02) == 0) { + pci_write_config_dword(pci_dev, 0x4c, val | 0x02); + printk(KERN_INFO "%s: Setting AMD762 Northbridge to enable PCI ordering compliance\n", bcm5700_driver); + } + } + +#if (LINUX_VERSION_CODE > 0x20605) + + pci_dev_put(pci_dev); + +#if defined(CONFIG_PCI_MSI) || defined(CONFIG_PCI_USE_VECTOR) + + if ((pci_dev = pci_get_device(0x1066, 0x0017, NULL))) { + bcm_msi_chipset_bug = 1; + } + pci_dev_put(pci_dev); +#endif +#endif + + return 0; +} + + +static void __devexit +bcm5700_remove_one (struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata (pdev); + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + +#ifdef BCM_IOCTL32 + atomic_dec(&bcm5700_load_count); + if (atomic_read(&bcm5700_load_count) == 0) + unregister_ioctl32_conversion(SIOCNICE); +#endif + unregister_netdev(dev); + + if (pUmDevice->lm_dev.pMappedMemBase) + iounmap(pUmDevice->lm_dev.pMappedMemBase); + + pci_release_regions(pdev); + +#if (LINUX_VERSION_CODE < 0x020600) + kfree(dev); +#else + free_netdev(dev); +#endif + + pci_set_drvdata(pdev, NULL); + +} + +int b57_test_intr(UM_DEVICE_BLOCK *pUmDevice); + +#ifdef BCM_WL_EMULATOR +/* new transmit callback */ +static int bcm5700emu_start_xmit(struct sk_buff *skb, struct net_device *dev); +/* keep track of the 2 gige devices */ +static PLM_DEVICE_BLOCK pDev1; +static PLM_DEVICE_BLOCK pDev2; + +static void +bcm5700emu_open(struct net_device *dev) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + static int instance = 0; + static char *wlemu_if = NULL; + char *wlemu_mode = NULL; + //int wlemu_idx = 0; + static int rx_enable = 0; + static int tx_enable = 0; + + /* which interface is the emulator ? */ + if(instance == 0) { + wlemu_if = nvram_get("wlemu_if"); + /* do we emulate rx, tx or both */ + wlemu_mode = nvram_get("wlemu_mode"); + if(wlemu_mode) { + if (!strcmp(wlemu_mode,"rx")) + { + rx_enable = 1; + } + else if (!strcmp(wlemu_mode,"tx")) + { + + tx_enable = 1; + + } + else if (!strcmp(wlemu_mode,"rx_tx")) + { + + rx_enable = 1; + tx_enable = 1; + } + } + } + + instance++; + + /* The context is used for accessing the OSL for emulating devices */ + pDevice->wlc = NULL; + + /* determines if this device is an emulator */ + pDevice->wl_emulate_rx = 0; + pDevice->wl_emulate_tx = 0; + + if(wlemu_if && !strcmp(dev->name,wlemu_if)) + { + /* create an emulator context. */ + pDevice->wlc = (void *)wlcemu_wlccreate((void *)dev); + B57_INFO(("Using %s for wl emulation \n", dev->name)); + if(rx_enable) + { + B57_INFO(("Enabling wl RX emulation \n")); + pDevice->wl_emulate_rx = 1; + } + /* re-direct transmit callback to emulator */ + if(tx_enable) + { + pDevice->wl_emulate_tx = 1; + dev->hard_start_xmit = bcm5700emu_start_xmit; + B57_INFO(("Enabling wl TX emulation \n")); + } + } + /* for debug access to configured devices only */ + if(instance == 1) + pDev1 = pDevice; + else if (instance == 2) + pDev2 = pDevice; +} + +/* Public API to get current emulation info */ +int bcm5700emu_get_info(char *buf) +{ + int len = 0; + PLM_DEVICE_BLOCK p; + + /* look for an emulating device */ + if(pDev1->wlc) { + p = pDev1; + len += sprintf(buf+len,"emulation device : eth0\n"); + } + else if (pDev2->wlc) { + p = pDev2; + len += sprintf(buf+len,"emulation device : eth1\n"); + } + else { + len += sprintf(buf+len,"emulation not activated\n"); + return len; + } + if(p->wl_emulate_rx) + len += sprintf(buf+len,"RX emulation enabled\n"); + else + len += sprintf(buf+len,"RX emulation disabled\n"); + if(p->wl_emulate_tx) + len += sprintf(buf+len,"TX emulation enabled\n"); + else + len += sprintf(buf+len,"TX emulation disabled\n"); + return len; + +} + + +/* Public API to access the bcm5700_start_xmit callback */ + +int +bcm5700emu_forward_xmit(struct sk_buff *skb, struct net_device *dev) +{ + return bcm5700_start_xmit(skb, dev); +} + + +/* hook to kernel txmit callback */ +STATIC int +bcm5700emu_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + return wlcemu_start_xmit(skb,pDevice->wlc); +} + +#endif /* BCM_WL_EMULATOR */ + +int +bcm5700_open(struct net_device *dev) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + int rc; + + if (pUmDevice->suspended){ + return -EAGAIN; + } + +#ifdef BCM_WL_EMULATOR + bcm5700emu_open(dev); +#endif + + /* delay for 6 seconds */ + pUmDevice->delayed_link_ind = (6 * HZ) / pUmDevice->timer_interval; + +#ifdef BCM_INT_COAL +#ifndef BCM_NAPI_RXPOLL + pUmDevice->adaptive_expiry = HZ / pUmDevice->timer_interval; +#endif +#endif + +#ifdef INCLUDE_TBI_SUPPORT + if ((pDevice->TbiFlags & ENABLE_TBI_FLAG) && + (pDevice->TbiFlags & TBI_POLLING_FLAGS)) { + pUmDevice->poll_tbi_interval = HZ / pUmDevice->timer_interval; + if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5703) { + pUmDevice->poll_tbi_interval /= 4; + } + pUmDevice->poll_tbi_expiry = pUmDevice->poll_tbi_interval; + } +#endif + /* set this timer for 2 seconds */ + pUmDevice->asf_heartbeat = (2 * HZ) / pUmDevice->timer_interval; + +#if defined(CONFIG_PCI_MSI) || defined(CONFIG_PCI_USE_VECTOR) + + + if ( ( (T3_ASIC_IS_575X_PLUS(pDevice->ChipRevId) ) && + (T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5714_A0 ) && + (T3_CHIP_REV(pDevice->ChipRevId) != T3_CHIP_REV_5750_AX ) && + (T3_CHIP_REV(pDevice->ChipRevId) != T3_CHIP_REV_5750_BX ) ) && + !bcm_msi_chipset_bug ){ + + if (disable_msi[pUmDevice->index]==1){ + /* do nothing-it's not turned on */ + }else{ + pDevice->Flags |= USING_MSI_FLAG; + + REG_WR(pDevice, Msi.Mode, 2 ); + + rc = pci_enable_msi(pUmDevice->pdev); + + if(rc!=0){ + pDevice->Flags &= ~ USING_MSI_FLAG; + REG_WR(pDevice, Msi.Mode, 1 ); + } + } + } + + +#endif + + if ((rc= request_irq(pUmDevice->pdev->irq, &bcm5700_interrupt, SA_SHIRQ, dev->name, dev))) + { + +#if defined(CONFIG_PCI_MSI) || defined(CONFIG_PCI_USE_VECTOR) + + if(pDevice->Flags & USING_MSI_FLAG) { + + pci_disable_msi(pUmDevice->pdev); + pDevice->Flags &= ~USING_MSI_FLAG; + REG_WR(pDevice, Msi.Mode, 1 ); + + } +#endif + return rc; + } + + pUmDevice->opened = 1; + if (LM_InitializeAdapter(pDevice) != LM_STATUS_SUCCESS) { + pUmDevice->opened = 0; + free_irq(dev->irq, dev); + bcm5700_freemem(dev); + return -EAGAIN; + } + + bcm5700_set_vlan_mode(pUmDevice); + bcm5700_init_counters(pUmDevice); + + if (pDevice->Flags & UNDI_FIX_FLAG) { + printk(KERN_INFO "%s: Using indirect register access\n", dev->name); + } + + if (memcmp(dev->dev_addr, pDevice->NodeAddress, 6)) + { + /* Do not use invalid eth addrs: any multicast & all zeros */ + if( is_valid_ether_addr(dev->dev_addr) ){ + LM_SetMacAddress(pDevice, dev->dev_addr); + } + else + { + printk(KERN_INFO "%s: Invalid administered node address\n",dev->name); + memcpy(dev->dev_addr, pDevice->NodeAddress, 6); + } + } + + if (tigon3_debug > 1) + printk(KERN_DEBUG "%s: tigon3_open() irq %d.\n", dev->name, dev->irq); + + QQ_InitQueue(&pUmDevice->rx_out_of_buf_q.Container, + MAX_RX_PACKET_DESC_COUNT); + + +#if (LINUX_VERSION_CODE < 0x020300) + MOD_INC_USE_COUNT; +#endif + + atomic_set(&pUmDevice->intr_sem, 0); + + LM_EnableInterrupt(pDevice); + +#if defined(CONFIG_PCI_MSI) || defined(CONFIG_PCI_USE_VECTOR) + + if (pDevice->Flags & USING_MSI_FLAG){ + + /* int test to check support on older machines */ + if (b57_test_intr(pUmDevice) != 1) { + + LM_DisableInterrupt(pDevice); + free_irq(pUmDevice->pdev->irq, dev); + pci_disable_msi(pUmDevice->pdev); + REG_WR(pDevice, Msi.Mode, 1 ); + pDevice->Flags &= ~USING_MSI_FLAG; + + rc = LM_ResetAdapter(pDevice); +printk(KERN_ALERT " The MSI support in this system is not functional.\n"); + + if (rc == LM_STATUS_SUCCESS) + rc = 0; + else + rc = -ENODEV; + + if(rc == 0){ + rc = request_irq(pUmDevice->pdev->irq, &bcm5700_interrupt, + SA_SHIRQ, dev->name, dev); + } + + if(rc){ + LM_Halt(pDevice); + bcm5700_freemem(dev); + pUmDevice->opened = 0; + return rc; + } + + + pDevice->InitDone = TRUE; + atomic_set(&pUmDevice->intr_sem, 0); + LM_EnableInterrupt(pDevice); + } + } +#endif + + init_timer(&pUmDevice->timer); + pUmDevice->timer.expires = RUN_AT(pUmDevice->timer_interval); + pUmDevice->timer.data = (unsigned long)dev; + pUmDevice->timer.function = &bcm5700_timer; + add_timer(&pUmDevice->timer); + + if (T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) { + init_timer(&pUmDevice->statstimer); + pUmDevice->statstimer.expires = RUN_AT(pUmDevice->statstimer_interval); + pUmDevice->statstimer.data = (unsigned long)dev; + pUmDevice->statstimer.function = &bcm5700_stats_timer; + add_timer(&pUmDevice->statstimer); + } + + if(pDevice->Flags & USING_MSI_FLAG) + printk(KERN_INFO "%s: Using Message Signaled Interrupt (MSI) \n", dev->name); + else + printk(KERN_INFO "%s: Using PCI INTX interrupt \n", dev->name); + + netif_start_queue(dev); + + return 0; +} + + +STATIC void +bcm5700_stats_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + unsigned long flags = 0; + + if (!pUmDevice->opened) + return; + + if (!atomic_read(&pUmDevice->intr_sem) && + !pUmDevice->suspended && + (pDevice->LinkStatus == LM_STATUS_LINK_ACTIVE)) { + BCM5700_LOCK(pUmDevice, flags); + LM_GetStats(pDevice); + BCM5700_UNLOCK(pUmDevice, flags); + } + + pUmDevice->statstimer.expires = RUN_AT(pUmDevice->statstimer_interval); + + add_timer(&pUmDevice->statstimer); +} + + +STATIC void +bcm5700_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + unsigned long flags = 0; + LM_UINT32 value32; + + if (!pUmDevice->opened) + return; + + /* BCM4785: Flush posted writes from GbE to host memory. */ + if (pDevice->Flags & FLUSH_POSTED_WRITE_FLAG) + REG_RD(pDevice, HostCoalesce.Mode); + + if (atomic_read(&pUmDevice->intr_sem) || pUmDevice->suspended) { + pUmDevice->timer.expires = RUN_AT(pUmDevice->timer_interval); + add_timer(&pUmDevice->timer); + return; + } + +#ifdef INCLUDE_TBI_SUPPORT + if ((pDevice->TbiFlags & TBI_POLLING_FLAGS) && + (--pUmDevice->poll_tbi_expiry <= 0)) { + + BCM5700_PHY_LOCK(pUmDevice, flags); + value32 = REG_RD(pDevice, MacCtrl.Status); + if (((pDevice->LinkStatus == LM_STATUS_LINK_ACTIVE) && + ((value32 & (MAC_STATUS_LINK_STATE_CHANGED | + MAC_STATUS_CFG_CHANGED)) || + !(value32 & MAC_STATUS_PCS_SYNCED))) + || + ((pDevice->LinkStatus != LM_STATUS_LINK_ACTIVE) && + (value32 & (MAC_STATUS_PCS_SYNCED | + MAC_STATUS_SIGNAL_DETECTED)))) + { + LM_SetupPhy(pDevice); + } + BCM5700_PHY_UNLOCK(pUmDevice, flags); + pUmDevice->poll_tbi_expiry = pUmDevice->poll_tbi_interval; + + } +#endif + + if (pUmDevice->delayed_link_ind > 0) { + if (pUmDevice->delayed_link_ind == 1) + MM_IndicateStatus(pDevice, pDevice->LinkStatus); + else + pUmDevice->delayed_link_ind--; + } + + if (pUmDevice->crc_counter_expiry > 0) + pUmDevice->crc_counter_expiry--; + + if (!pUmDevice->interrupt) { + if (!(pDevice->Flags & USE_TAGGED_STATUS_FLAG)) { + BCM5700_LOCK(pUmDevice, flags); + if (pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) { + /* This will generate an interrupt */ + REG_WR(pDevice, Grc.LocalCtrl, + pDevice->GrcLocalCtrl | + GRC_MISC_LOCAL_CTRL_SET_INT); + } + else { + REG_WR(pDevice, HostCoalesce.Mode, + pDevice->CoalesceMode | + HOST_COALESCE_ENABLE | + HOST_COALESCE_NOW); + } + if (!(REG_RD(pDevice, DmaWrite.Mode) & + DMA_WRITE_MODE_ENABLE)) { + BCM5700_UNLOCK(pUmDevice, flags); + bcm5700_reset(dev); + } + else { + BCM5700_UNLOCK(pUmDevice, flags); + } + if (pUmDevice->tx_queued) { + pUmDevice->tx_queued = 0; + netif_wake_queue(dev); + } + } +#if (LINUX_VERSION_CODE < 0x02032b) + if ((QQ_GetEntryCnt(&pDevice->TxPacketFreeQ.Container) != + pDevice->TxPacketDescCnt) && + ((jiffies - dev->trans_start) > TX_TIMEOUT)) { + + printk(KERN_WARNING "%s: Tx hung\n", dev->name); + bcm5700_reset(dev); + } +#endif + } +#ifdef BCM_INT_COAL +#ifndef BCM_NAPI_RXPOLL + if (pUmDevice->adaptive_coalesce) { + pUmDevice->adaptive_expiry--; + if (pUmDevice->adaptive_expiry == 0) { + pUmDevice->adaptive_expiry = HZ / + pUmDevice->timer_interval; + bcm5700_adapt_coalesce(pUmDevice); + } + } +#endif +#endif + if (QQ_GetEntryCnt(&pUmDevice->rx_out_of_buf_q.Container) > + (unsigned int) pUmDevice->rx_buf_repl_panic_thresh) { + /* Generate interrupt and let isr allocate buffers */ + REG_WR(pDevice, HostCoalesce.Mode, pDevice->CoalesceMode | + HOST_COALESCE_ENABLE | HOST_COALESCE_NOW); + } + +#ifdef BCM_ASF + if (pDevice->AsfFlags & ASF_ENABLED) { + pUmDevice->asf_heartbeat--; + if (pUmDevice->asf_heartbeat == 0) { + if( (pDevice->Flags & UNDI_FIX_FLAG) || + (pDevice->Flags & ENABLE_PCIX_FIX_FLAG)) { + MEM_WR_OFFSET(pDevice, T3_CMD_MAILBOX, + T3_CMD_NICDRV_ALIVE2); + MEM_WR_OFFSET(pDevice, T3_CMD_LENGTH_MAILBOX, + 4); + MEM_WR_OFFSET(pDevice, T3_CMD_DATA_MAILBOX, 5); + } else { + LM_RegWr(pDevice, + (T3_NIC_MBUF_POOL_ADDR + + T3_CMD_MAILBOX), + T3_CMD_NICDRV_ALIVE2, 1); + LM_RegWr(pDevice, + (T3_NIC_MBUF_POOL_ADDR + + T3_CMD_LENGTH_MAILBOX),4,1); + LM_RegWr(pDevice, + (T3_NIC_MBUF_POOL_ADDR + + T3_CMD_DATA_MAILBOX),5,1); + } + + value32 = REG_RD(pDevice, Grc.RxCpuEvent); + REG_WR(pDevice, Grc.RxCpuEvent, value32 | BIT_14); + pUmDevice->asf_heartbeat = (2 * HZ) / + pUmDevice->timer_interval; + } + } +#endif + + if (pDevice->PhyFlags & PHY_IS_FIBER){ + BCM5700_PHY_LOCK(pUmDevice, flags); + LM_5714_FamFiberCheckLink(pDevice); + BCM5700_PHY_UNLOCK(pUmDevice, flags); + } + + pUmDevice->timer.expires = RUN_AT(pUmDevice->timer_interval); + add_timer(&pUmDevice->timer); +} + +STATIC int +bcm5700_init_counters(PUM_DEVICE_BLOCK pUmDevice) +{ +#ifdef BCM_INT_COAL +#ifndef BCM_NAPI_RXPOLL + LM_DEVICE_BLOCK *pDevice = &pUmDevice->lm_dev; + + pUmDevice->rx_curr_coalesce_frames = pDevice->RxMaxCoalescedFrames; + pUmDevice->rx_curr_coalesce_ticks = pDevice->RxCoalescingTicks; + pUmDevice->tx_curr_coalesce_frames = pDevice->TxMaxCoalescedFrames; + pUmDevice->rx_last_cnt = 0; + pUmDevice->tx_last_cnt = 0; +#endif +#endif + pUmDevice->phy_crc_count = 0; +#if TIGON3_DEBUG + pUmDevice->tx_zc_count = 0; + pUmDevice->tx_chksum_count = 0; + pUmDevice->tx_himem_count = 0; + pUmDevice->rx_good_chksum_count = 0; + pUmDevice->rx_bad_chksum_count = 0; +#endif +#ifdef BCM_TSO + pUmDevice->tso_pkt_count = 0; +#endif + return 0; +} + +#ifdef BCM_INT_COAL +#ifndef BCM_NAPI_RXPOLL +STATIC int +bcm5700_do_adapt_coalesce(PUM_DEVICE_BLOCK pUmDevice, + int rx_frames, int rx_ticks, int tx_frames, int rx_frames_intr) +{ + unsigned long flags = 0; + LM_DEVICE_BLOCK *pDevice = &pUmDevice->lm_dev; + + if (pUmDevice->do_global_lock) { + if (spin_is_locked(&pUmDevice->global_lock)) + return 0; + spin_lock_irqsave(&pUmDevice->global_lock, flags); + } + pUmDevice->rx_curr_coalesce_frames = rx_frames; + pUmDevice->rx_curr_coalesce_ticks = rx_ticks; + pUmDevice->tx_curr_coalesce_frames = tx_frames; + pUmDevice->rx_curr_coalesce_frames_intr = rx_frames_intr; + REG_WR(pDevice, HostCoalesce.RxMaxCoalescedFrames, rx_frames); + + REG_WR(pDevice, HostCoalesce.RxCoalescingTicks, rx_ticks); + + REG_WR(pDevice, HostCoalesce.TxMaxCoalescedFrames, tx_frames); + + REG_WR(pDevice, HostCoalesce.RxMaxCoalescedFramesDuringInt, + rx_frames_intr); + + BCM5700_UNLOCK(pUmDevice, flags); + return 0; +} + +STATIC int +bcm5700_adapt_coalesce(PUM_DEVICE_BLOCK pUmDevice) +{ + PLM_DEVICE_BLOCK pDevice = &pUmDevice->lm_dev; + uint rx_curr_cnt, tx_curr_cnt, rx_delta, tx_delta, total_delta; + + rx_curr_cnt = pDevice->pStatsBlkVirt->ifHCInUcastPkts.Low; + tx_curr_cnt = pDevice->pStatsBlkVirt->ifHCOutUcastPkts.Low; + if ((rx_curr_cnt <= pUmDevice->rx_last_cnt) || + (tx_curr_cnt < pUmDevice->tx_last_cnt)) { + + /* skip if there is counter rollover */ + pUmDevice->rx_last_cnt = rx_curr_cnt; + pUmDevice->tx_last_cnt = tx_curr_cnt; + return 0; + } + + rx_delta = rx_curr_cnt - pUmDevice->rx_last_cnt; + tx_delta = tx_curr_cnt - pUmDevice->tx_last_cnt; + total_delta = (((rx_delta + rx_delta) + tx_delta) / 3) << 1; + + pUmDevice->rx_last_cnt = rx_curr_cnt; + pUmDevice->tx_last_cnt = tx_curr_cnt; + + if (total_delta < ADAPTIVE_LO_PKT_THRESH) { + if (pUmDevice->rx_curr_coalesce_frames != + ADAPTIVE_LO_RX_MAX_COALESCED_FRAMES) { + + bcm5700_do_adapt_coalesce(pUmDevice, + ADAPTIVE_LO_RX_MAX_COALESCED_FRAMES, + ADAPTIVE_LO_RX_COALESCING_TICKS, + ADAPTIVE_LO_TX_MAX_COALESCED_FRAMES, + ADAPTIVE_LO_RX_MAX_COALESCED_FRAMES_DURING_INT); + } + } + else if (total_delta < ADAPTIVE_HI_PKT_THRESH) { + if (pUmDevice->rx_curr_coalesce_frames != + DEFAULT_RX_MAX_COALESCED_FRAMES) { + + bcm5700_do_adapt_coalesce(pUmDevice, + DEFAULT_RX_MAX_COALESCED_FRAMES, + DEFAULT_RX_COALESCING_TICKS, + DEFAULT_TX_MAX_COALESCED_FRAMES, + DEFAULT_RX_MAX_COALESCED_FRAMES_DURING_INT); + } + } + else { + if (pUmDevice->rx_curr_coalesce_frames != + ADAPTIVE_HI_RX_MAX_COALESCED_FRAMES) { + + bcm5700_do_adapt_coalesce(pUmDevice, + ADAPTIVE_HI_RX_MAX_COALESCED_FRAMES, + ADAPTIVE_HI_RX_COALESCING_TICKS, + ADAPTIVE_HI_TX_MAX_COALESCED_FRAMES, + ADAPTIVE_HI_RX_MAX_COALESCED_FRAMES_DURING_INT); + } + } + return 0; +} +#endif +#endif + +STATIC void +bcm5700_reset(struct net_device *dev) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + unsigned long flags; + +#ifdef BCM_TSO + + if( (dev->features & NETIF_F_TSO) && + (pUmDevice->tx_full) ) { + + dev->features &= ~NETIF_F_TSO; + } +#endif + + netif_stop_queue(dev); + bcm5700_intr_off(pUmDevice); + BCM5700_PHY_LOCK(pUmDevice, flags); + LM_ResetAdapter(pDevice); + pDevice->InitDone = TRUE; + bcm5700_do_rx_mode(dev); + bcm5700_set_vlan_mode(pUmDevice); + bcm5700_init_counters(pUmDevice); + if (memcmp(dev->dev_addr, pDevice->NodeAddress, 6)) { + LM_SetMacAddress(pDevice, dev->dev_addr); + } + BCM5700_PHY_UNLOCK(pUmDevice, flags); + atomic_set(&pUmDevice->intr_sem, 1); + bcm5700_intr_on(pUmDevice); + netif_wake_queue(dev); +} + +STATIC void +bcm5700_set_vlan_mode(UM_DEVICE_BLOCK *pUmDevice) +{ + LM_DEVICE_BLOCK *pDevice = &pUmDevice->lm_dev; + LM_UINT32 ReceiveMask = pDevice->ReceiveMask; + int vlan_tag_mode = pUmDevice->vlan_tag_mode; + + if (vlan_tag_mode == VLAN_TAG_MODE_AUTO_STRIP) { + if (pDevice->AsfFlags & ASF_ENABLED) { + vlan_tag_mode = VLAN_TAG_MODE_FORCED_STRIP; + } + else { + vlan_tag_mode = VLAN_TAG_MODE_NORMAL_STRIP; + } + } + if (vlan_tag_mode == VLAN_TAG_MODE_NORMAL_STRIP) { + ReceiveMask |= LM_KEEP_VLAN_TAG; +#ifdef BCM_VLAN + if (pUmDevice->vlgrp) + ReceiveMask &= ~LM_KEEP_VLAN_TAG; +#endif + } + else if (vlan_tag_mode == VLAN_TAG_MODE_FORCED_STRIP) { + ReceiveMask &= ~LM_KEEP_VLAN_TAG; + } + if (ReceiveMask != pDevice->ReceiveMask) + { + LM_SetReceiveMask(pDevice, ReceiveMask); + } +} + +static void +bcm5700_poll_wait(UM_DEVICE_BLOCK *pUmDevice) +{ +#ifdef BCM_NAPI_RXPOLL + while (pUmDevice->lm_dev.RxPoll) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } +#endif +} + + +#ifdef BCM_VLAN +STATIC void +bcm5700_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) dev->priv; + + bcm5700_intr_off(pUmDevice); + bcm5700_poll_wait(pUmDevice); + pUmDevice->vlgrp = vlgrp; + bcm5700_set_vlan_mode(pUmDevice); + bcm5700_intr_on(pUmDevice); +} + +STATIC void +bcm5700_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) dev->priv; + + bcm5700_intr_off(pUmDevice); + bcm5700_poll_wait(pUmDevice); + if (pUmDevice->vlgrp) { + pUmDevice->vlgrp->vlan_devices[vid] = NULL; + } + bcm5700_intr_on(pUmDevice); +} +#endif + +STATIC int +bcm5700_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + PLM_PACKET pPacket; + PUM_PACKET pUmPacket; + unsigned long flags = 0; + int frag_no; +#ifdef BCM_TSO + LM_UINT32 mss = 0 ; + uint16_t ip_tcp_len, tcp_opt_len, tcp_seg_flags; +#endif + + if ((pDevice->LinkStatus == LM_STATUS_LINK_DOWN) || + !pDevice->InitDone || pUmDevice->suspended) + { + dev_kfree_skb(skb); + return 0; + } + +#if (LINUX_VERSION_CODE < 0x02032b) + if (test_and_set_bit(0, &dev->tbusy)) { + return 1; + } +#endif + + if (pUmDevice->do_global_lock && pUmDevice->interrupt) { + netif_stop_queue(dev); + pUmDevice->tx_queued = 1; + if (!pUmDevice->interrupt) { + netif_wake_queue(dev); + pUmDevice->tx_queued = 0; + } + return 1; + } + + pPacket = (PLM_PACKET) + QQ_PopHead(&pDevice->TxPacketFreeQ.Container); + if (pPacket == 0) { + netif_stop_queue(dev); + pUmDevice->tx_full = 1; + if (QQ_GetEntryCnt(&pDevice->TxPacketFreeQ.Container)) { + netif_wake_queue(dev); + pUmDevice->tx_full = 0; + } + return 1; + } + pUmPacket = (PUM_PACKET) pPacket; + pUmPacket->skbuff = skb; + pUmDevice->stats.tx_bytes += skb->len; + + if (skb->ip_summed == CHECKSUM_HW) { + pPacket->Flags = SND_BD_FLAG_TCP_UDP_CKSUM; +#if TIGON3_DEBUG + pUmDevice->tx_chksum_count++; +#endif + } + else { + pPacket->Flags = 0; + } +#if MAX_SKB_FRAGS + frag_no = skb_shinfo(skb)->nr_frags; +#else + frag_no = 0; +#endif + if (atomic_read(&pDevice->SendBdLeft) < (frag_no + 1)) { + netif_stop_queue(dev); + pUmDevice->tx_full = 1; + QQ_PushHead(&pDevice->TxPacketFreeQ.Container, pPacket); + if (atomic_read(&pDevice->SendBdLeft) >= (frag_no + 1)) { + netif_wake_queue(dev); + pUmDevice->tx_full = 0; + } + return 1; + } + + pPacket->u.Tx.FragCount = frag_no + 1; +#if TIGON3_DEBUG + if (pPacket->u.Tx.FragCount > 1) + pUmDevice->tx_zc_count++; +#endif + +#ifdef BCM_VLAN + if (pUmDevice->vlgrp && vlan_tx_tag_present(skb)) { + pPacket->VlanTag = vlan_tx_tag_get(skb); + pPacket->Flags |= SND_BD_FLAG_VLAN_TAG; + } +#endif + +#ifdef BCM_TSO + if ((mss = (LM_UINT32) skb_shinfo(skb)->tso_size) && + (skb->len > pDevice->TxMtu)) { + +#if (LINUX_VERSION_CODE >= 0x02060c) + + if (skb_header_cloned(skb) && + pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) { + + dev_kfree_skb(skb); + return 0; + } +#endif + pUmDevice->tso_pkt_count++; + + pPacket->Flags |= SND_BD_FLAG_CPU_PRE_DMA | + SND_BD_FLAG_CPU_POST_DMA; + + tcp_opt_len = 0; + if (skb->h.th->doff > 5) { + tcp_opt_len = (skb->h.th->doff - 5) << 2; + } + ip_tcp_len = (skb->nh.iph->ihl << 2) + sizeof(struct tcphdr); + skb->nh.iph->check = 0; + + if ( T3_ASIC_IS_575X_PLUS(pDevice->ChipRevId) ){ + skb->h.th->check = 0; + pPacket->Flags &= ~SND_BD_FLAG_TCP_UDP_CKSUM; + } + else { + skb->h.th->check = ~csum_tcpudp_magic( + skb->nh.iph->saddr, skb->nh.iph->daddr, + 0, IPPROTO_TCP, 0); + } + + skb->nh.iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len); + tcp_seg_flags = 0; + + if (tcp_opt_len || (skb->nh.iph->ihl > 5)) { + if ( T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId) ){ + tcp_seg_flags = + ((skb->nh.iph->ihl - 5) + + (tcp_opt_len >> 2)) << 11; + } + else { + pPacket->Flags |= + ((skb->nh.iph->ihl - 5) + + (tcp_opt_len >> 2)) << 12; + } + } + pPacket->u.Tx.MaxSegmentSize = mss | tcp_seg_flags; + } + else + { + pPacket->u.Tx.MaxSegmentSize = 0; + } +#endif + BCM5700_LOCK(pUmDevice, flags); + LM_SendPacket(pDevice, pPacket); + BCM5700_UNLOCK(pUmDevice, flags); + +#if (LINUX_VERSION_CODE < 0x02032b) + netif_wake_queue(dev); +#endif + dev->trans_start = jiffies; + + + return 0; +} + +#ifdef BCM_NAPI_RXPOLL +STATIC int +bcm5700_poll(struct net_device *dev, int *budget) +{ + int orig_budget = *budget; + int work_done; + UM_DEVICE_BLOCK *pUmDevice = (UM_DEVICE_BLOCK *) dev->priv; + LM_DEVICE_BLOCK *pDevice = &pUmDevice->lm_dev; + unsigned long flags = 0; + LM_UINT32 tag; + + if (orig_budget > dev->quota) + orig_budget = dev->quota; + + BCM5700_LOCK(pUmDevice, flags); + /* BCM4785: Flush posted writes from GbE to host memory. */ + if (pDevice->Flags & FLUSH_POSTED_WRITE_FLAG) + REG_RD(pDevice, HostCoalesce.Mode); + work_done = LM_ServiceRxPoll(pDevice, orig_budget); + *budget -= work_done; + dev->quota -= work_done; + + if (QQ_GetEntryCnt(&pUmDevice->rx_out_of_buf_q.Container)) { + replenish_rx_buffers(pUmDevice, 0); + } + BCM5700_UNLOCK(pUmDevice, flags); + if (work_done) { + MM_IndicateRxPackets(pDevice); + BCM5700_LOCK(pUmDevice, flags); + LM_QueueRxPackets(pDevice); + BCM5700_UNLOCK(pUmDevice, flags); + } + if ((work_done < orig_budget) || atomic_read(&pUmDevice->intr_sem) || + pUmDevice->suspended) { + + netif_rx_complete(dev); + BCM5700_LOCK(pUmDevice, flags); + REG_WR(pDevice, Grc.Mode, pDevice->GrcMode); + pDevice->RxPoll = FALSE; + if (pDevice->RxPoll) { + BCM5700_UNLOCK(pUmDevice, flags); + return 0; + } + /* Take care of possible missed rx interrupts */ + REG_RD_BACK(pDevice, Grc.Mode); /* flush the register write */ + tag = pDevice->pStatusBlkVirt->StatusTag; + if ((pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) || + (pDevice->pStatusBlkVirt->Idx[0].RcvProdIdx != + pDevice->RcvRetConIdx)) { + + REG_WR(pDevice, HostCoalesce.Mode, + pDevice->CoalesceMode | HOST_COALESCE_ENABLE | + HOST_COALESCE_NOW); + } + /* If a new status block is pending in the WDMA state machine */ + /* before the register write to enable the rx interrupt, */ + /* the new status block may DMA with no interrupt. In this */ + /* scenario, the tag read above will be older than the tag in */ + /* the pending status block and writing the older tag will */ + /* cause interrupt to be generated. */ + else if (pDevice->Flags & USE_TAGGED_STATUS_FLAG) { + MB_REG_WR(pDevice, Mailbox.Interrupt[0].Low, + tag << 24); + /* Make sure we service tx in case some tx interrupts */ + /* are cleared */ + if (atomic_read(&pDevice->SendBdLeft) < + (T3_SEND_RCB_ENTRY_COUNT / 2)) { + REG_WR(pDevice, HostCoalesce.Mode, + pDevice->CoalesceMode | + HOST_COALESCE_ENABLE | + HOST_COALESCE_NOW); + } + } + BCM5700_UNLOCK(pUmDevice, flags); + return 0; + } + return 1; +} +#endif /* BCM_NAPI_RXPOLL */ + +STATIC irqreturn_t +bcm5700_interrupt(int irq, void *dev_instance, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *)dev_instance; + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + LM_UINT32 oldtag, newtag; + int i, max_intr_loop; +#ifdef BCM_TASKLET + int repl_buf_count; +#endif + unsigned int handled = 1; + + if (!pDevice->InitDone) { + handled = 0; + return IRQ_RETVAL(handled); + } + + bcm5700_intr_lock(pUmDevice); + if (atomic_read(&pUmDevice->intr_sem)) { + MB_REG_WR(pDevice, Mailbox.Interrupt[0].Low, 1); + bcm5700_intr_unlock(pUmDevice); + handled = 0; + return IRQ_RETVAL(handled); + } + + if (test_and_set_bit(0, (void*)&pUmDevice->interrupt)) { + printk(KERN_ERR "%s: Duplicate entry of the interrupt handler\n", + dev->name); + bcm5700_intr_unlock(pUmDevice); + handled = 0; + return IRQ_RETVAL(handled); + } + + /* BCM4785: Flush posted writes from GbE to host memory. */ + if (pDevice->Flags & FLUSH_POSTED_WRITE_FLAG) + REG_RD(pDevice, HostCoalesce.Mode); + + if ((pDevice->Flags & USING_MSI_FLAG) || + (pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) || + !(REG_RD(pDevice,PciCfg.PciState) & T3_PCI_STATE_INTERRUPT_NOT_ACTIVE) ) + { + + if (pUmDevice->intr_test) { + if (!(REG_RD(pDevice, PciCfg.PciState) & + T3_PCI_STATE_INTERRUPT_NOT_ACTIVE) || + pDevice->Flags & USING_MSI_FLAG ) { + pUmDevice->intr_test_result = 1; + } + pUmDevice->intr_test = 0; + } + +#ifdef BCM_NAPI_RXPOLL + max_intr_loop = 1; +#else + max_intr_loop = 50; +#endif + if (pDevice->Flags & USE_TAGGED_STATUS_FLAG) { + MB_REG_WR(pDevice, Mailbox.Interrupt[0].Low, 1); + oldtag = pDevice->pStatusBlkVirt->StatusTag; + + for (i = 0; ; i++) { + pDevice->pStatusBlkVirt->Status &= ~STATUS_BLOCK_UPDATED; + + LM_ServiceInterrupts(pDevice); + /* BCM4785: Flush GbE posted writes to host memory. */ + if (pDevice->Flags & FLUSH_POSTED_WRITE_FLAG) + MB_REG_RD(pDevice, Mailbox.Interrupt[0].Low); + newtag = pDevice->pStatusBlkVirt->StatusTag; + if ((newtag == oldtag) || (i > max_intr_loop)) { + MB_REG_WR(pDevice, Mailbox.Interrupt[0].Low, oldtag << 24); + pDevice->LastTag = oldtag; + if (pDevice->Flags & UNDI_FIX_FLAG) { + REG_WR(pDevice, Grc.LocalCtrl, + pDevice->GrcLocalCtrl | 0x2); + } + break; + } + oldtag = newtag; + } + } + else + { + i = 0; + do { + uint dummy; + + MB_REG_WR(pDevice, Mailbox.Interrupt[0].Low, 1); + pDevice->pStatusBlkVirt->Status &= ~STATUS_BLOCK_UPDATED; + LM_ServiceInterrupts(pDevice); + MB_REG_WR(pDevice, Mailbox.Interrupt[0].Low, 0); + dummy = MB_REG_RD(pDevice, Mailbox.Interrupt[0].Low); + i++; + } + while ((pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_UPDATED) && + (i < max_intr_loop)); + + if (pDevice->Flags & UNDI_FIX_FLAG) { + REG_WR(pDevice, Grc.LocalCtrl, + pDevice->GrcLocalCtrl | 0x2); + } + } + } + else + { + /* not my interrupt */ + handled = 0; + } + +#ifdef BCM_TASKLET + repl_buf_count = QQ_GetEntryCnt(&pUmDevice->rx_out_of_buf_q.Container); + if (((repl_buf_count > pUmDevice->rx_buf_repl_panic_thresh) || + pDevice->QueueAgain) && + (!test_and_set_bit(0, &pUmDevice->tasklet_busy))) { + + replenish_rx_buffers(pUmDevice, pUmDevice->rx_buf_repl_isr_limit); + clear_bit(0, (void*)&pUmDevice->tasklet_busy); + } + else if ((repl_buf_count > pUmDevice->rx_buf_repl_thresh) && + !pUmDevice->tasklet_pending) { + + pUmDevice->tasklet_pending = 1; + tasklet_schedule(&pUmDevice->tasklet); + } +#else +#ifdef BCM_NAPI_RXPOLL + if (!pDevice->RxPoll && + QQ_GetEntryCnt(&pUmDevice->rx_out_of_buf_q.Container)) { + pDevice->RxPoll = 1; + MM_ScheduleRxPoll(pDevice); + } +#else + if (QQ_GetEntryCnt(&pUmDevice->rx_out_of_buf_q.Container)) { + replenish_rx_buffers(pUmDevice, 0); + } + + if (QQ_GetEntryCnt(&pDevice->RxPacketFreeQ.Container) || + pDevice->QueueAgain) { + + LM_QueueRxPackets(pDevice); + } +#endif +#endif + + clear_bit(0, (void*)&pUmDevice->interrupt); + bcm5700_intr_unlock(pUmDevice); + if (pUmDevice->tx_queued) { + pUmDevice->tx_queued = 0; + netif_wake_queue(dev); + } + return IRQ_RETVAL(handled); +} + + +#ifdef BCM_TASKLET +STATIC void +bcm5700_tasklet(unsigned long data) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)data; + unsigned long flags = 0; + + /* RH 7.2 Beta 3 tasklets are reentrant */ + if (test_and_set_bit(0, &pUmDevice->tasklet_busy)) { + pUmDevice->tasklet_pending = 0; + return; + } + + pUmDevice->tasklet_pending = 0; + if (pUmDevice->opened && !pUmDevice->suspended) { + BCM5700_LOCK(pUmDevice, flags); + replenish_rx_buffers(pUmDevice, 0); + BCM5700_UNLOCK(pUmDevice, flags); + } + + clear_bit(0, &pUmDevice->tasklet_busy); +} +#endif + +STATIC int +bcm5700_close(struct net_device *dev) +{ + + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + +#if (LINUX_VERSION_CODE < 0x02032b) + dev->start = 0; +#endif + netif_stop_queue(dev); + pUmDevice->opened = 0; + +#ifdef BCM_ASF + if( !(pDevice->AsfFlags & ASF_ENABLED) ) +#endif +#ifdef BCM_WOL + if( enable_wol[pUmDevice->index] == 0 ) +#endif + B57_INFO(("%s: %s NIC Link is DOWN\n", bcm5700_driver, dev->name)); + + if (tigon3_debug > 1) + printk(KERN_DEBUG "%s: Shutting down Tigon3\n", + dev->name); + + LM_MulticastClear(pDevice); + bcm5700_shutdown(pUmDevice); + + if (T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) { + del_timer_sync(&pUmDevice->statstimer); + } + + del_timer_sync(&pUmDevice->timer); + + free_irq(pUmDevice->pdev->irq, dev); + +#if defined(CONFIG_PCI_MSI) || defined(CONFIG_PCI_USE_VECTOR) + + if(pDevice->Flags & USING_MSI_FLAG) { + pci_disable_msi(pUmDevice->pdev); + REG_WR(pDevice, Msi.Mode, 1 ); + pDevice->Flags &= ~USING_MSI_FLAG; + } + +#endif + + +#if (LINUX_VERSION_CODE < 0x020300) + MOD_DEC_USE_COUNT; +#endif + { + /* BCM4785: Don't go to low-power state because it will power down the smbus block. */ + if (!(pDevice->Flags & SB_CORE_FLAG)) + LM_SetPowerState(pDevice, LM_POWER_STATE_D3); + } + + bcm5700_freemem(dev); + + QQ_InitQueue(&pDevice->RxPacketFreeQ.Container, + MAX_RX_PACKET_DESC_COUNT); + + return 0; +} + +STATIC int +bcm5700_freemem(struct net_device *dev) +{ + int i; + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + LM_DEVICE_BLOCK *pDevice = &pUmDevice->lm_dev; + + for (i = 0; i < pUmDevice->mem_list_num; i++) { + if (pUmDevice->mem_size_list[i] == 0) { + kfree(pUmDevice->mem_list[i]); + } + else { + pci_free_consistent(pUmDevice->pdev, + (size_t) pUmDevice->mem_size_list[i], + pUmDevice->mem_list[i], + pUmDevice->dma_list[i]); + } + } + + pDevice->pStatusBlkVirt = 0; + pDevice->pStatsBlkVirt = 0; + pUmDevice->mem_list_num = 0; + + return 0; +} + +uint64_t +bcm5700_crc_count(PUM_DEVICE_BLOCK pUmDevice) +{ + PLM_DEVICE_BLOCK pDevice = &pUmDevice->lm_dev; + LM_UINT32 Value32; + PT3_STATS_BLOCK pStats = (PT3_STATS_BLOCK) pDevice->pStatsBlkVirt; + unsigned long flags; + + if ((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700 || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) && + !(pDevice->TbiFlags & ENABLE_TBI_FLAG)) { + + if (!pUmDevice->opened || !pDevice->InitDone) + { + + return 0; + } + + /* regulate MDIO access during run time */ + if (pUmDevice->crc_counter_expiry > 0) + return pUmDevice->phy_crc_count; + + pUmDevice->crc_counter_expiry = (5 * HZ) / + pUmDevice->timer_interval; + + BCM5700_PHY_LOCK(pUmDevice, flags); + LM_ReadPhy(pDevice, 0x1e, &Value32); + if ((Value32 & 0x8000) == 0) + LM_WritePhy(pDevice, 0x1e, Value32 | 0x8000); + LM_ReadPhy(pDevice, 0x14, &Value32); + BCM5700_PHY_UNLOCK(pUmDevice, flags); + /* Sometimes data on the MDIO bus can be corrupted */ + if (Value32 != 0xffff) + pUmDevice->phy_crc_count += Value32; + return pUmDevice->phy_crc_count; + } + else if (pStats == 0) { + return 0; + } + else { + return (MM_GETSTATS64(pStats->dot3StatsFCSErrors)); + } +} + +uint64_t +bcm5700_rx_err_count(UM_DEVICE_BLOCK *pUmDevice) +{ + LM_DEVICE_BLOCK *pDevice = &pUmDevice->lm_dev; + T3_STATS_BLOCK *pStats = (T3_STATS_BLOCK *) pDevice->pStatsBlkVirt; + + if (pStats == 0) + return 0; + return (bcm5700_crc_count(pUmDevice) + + MM_GETSTATS64(pStats->dot3StatsAlignmentErrors) + + MM_GETSTATS64(pStats->etherStatsUndersizePkts) + + MM_GETSTATS64(pStats->etherStatsFragments) + + MM_GETSTATS64(pStats->dot3StatsFramesTooLong) + + MM_GETSTATS64(pStats->etherStatsJabbers)); +} + +STATIC struct net_device_stats * +bcm5700_get_stats(struct net_device *dev) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + PT3_STATS_BLOCK pStats = (PT3_STATS_BLOCK) pDevice->pStatsBlkVirt; + struct net_device_stats *p_netstats = &pUmDevice->stats; + + if (pStats == 0) + return p_netstats; + + /* Get stats from LM */ + p_netstats->rx_packets = + MM_GETSTATS(pStats->ifHCInUcastPkts) + + MM_GETSTATS(pStats->ifHCInMulticastPkts) + + MM_GETSTATS(pStats->ifHCInBroadcastPkts); + p_netstats->tx_packets = + MM_GETSTATS(pStats->ifHCOutUcastPkts) + + MM_GETSTATS(pStats->ifHCOutMulticastPkts) + + MM_GETSTATS(pStats->ifHCOutBroadcastPkts); + /* There counters seem to be innacurate. Use byte number accumulation + instead. + p_netstats->rx_bytes = MM_GETSTATS(pStats->ifHCInOctets); + p_netstats->tx_bytes = MM_GETSTATS(pStats->ifHCOutOctets); + */ + p_netstats->tx_errors = + MM_GETSTATS(pStats->dot3StatsInternalMacTransmitErrors) + + MM_GETSTATS(pStats->dot3StatsCarrierSenseErrors) + + MM_GETSTATS(pStats->ifOutDiscards) + + MM_GETSTATS(pStats->ifOutErrors); + p_netstats->multicast = MM_GETSTATS(pStats->ifHCInMulticastPkts); + p_netstats->collisions = MM_GETSTATS(pStats->etherStatsCollisions); + p_netstats->rx_length_errors = + MM_GETSTATS(pStats->dot3StatsFramesTooLong) + + MM_GETSTATS(pStats->etherStatsUndersizePkts); + p_netstats->rx_over_errors = MM_GETSTATS(pStats->nicNoMoreRxBDs); + p_netstats->rx_frame_errors = + MM_GETSTATS(pStats->dot3StatsAlignmentErrors); + p_netstats->rx_crc_errors = (unsigned long) + bcm5700_crc_count(pUmDevice); + p_netstats->rx_errors = (unsigned long) + bcm5700_rx_err_count(pUmDevice); + + p_netstats->tx_aborted_errors = MM_GETSTATS(pStats->ifOutDiscards); + p_netstats->tx_carrier_errors = + MM_GETSTATS(pStats->dot3StatsCarrierSenseErrors); + + return p_netstats; +} + +void +b57_suspend_chip(UM_DEVICE_BLOCK *pUmDevice) +{ + LM_DEVICE_BLOCK *pDevice = &pUmDevice->lm_dev; + + if (pUmDevice->opened) { + bcm5700_intr_off(pUmDevice); + netif_carrier_off(pUmDevice->dev); + netif_stop_queue(pUmDevice->dev); +#ifdef BCM_TASKLET + tasklet_kill(&pUmDevice->tasklet); +#endif + bcm5700_poll_wait(pUmDevice); + } + pUmDevice->suspended = 1; + LM_ShutdownChip(pDevice, LM_SUSPEND_RESET); +} + +void +b57_resume_chip(UM_DEVICE_BLOCK *pUmDevice) +{ + LM_DEVICE_BLOCK *pDevice = &pUmDevice->lm_dev; + + if (pUmDevice->suspended) { + pUmDevice->suspended = 0; + if (pUmDevice->opened) { + bcm5700_reset(pUmDevice->dev); + } + else { + LM_ShutdownChip(pDevice, LM_SHUTDOWN_RESET); + } + } +} + +/* Returns 0 on failure, 1 on success */ +int +b57_test_intr(UM_DEVICE_BLOCK *pUmDevice) +{ + LM_DEVICE_BLOCK *pDevice = &pUmDevice->lm_dev; + int j; + + if (!pUmDevice->opened) + return 0; + pUmDevice->intr_test_result = 0; + pUmDevice->intr_test = 1; + + REG_WR(pDevice, HostCoalesce.Mode, + pDevice->CoalesceMode | HOST_COALESCE_ENABLE | + HOST_COALESCE_NOW); + + for (j = 0; j < 10; j++) { + if (pUmDevice->intr_test_result){ + break; + } + + REG_WR(pDevice, HostCoalesce.Mode, + pDevice->CoalesceMode | HOST_COALESCE_ENABLE | + HOST_COALESCE_NOW); + + MM_Sleep(pDevice, 1); + } + + return pUmDevice->intr_test_result; + +} + +#ifdef SIOCETHTOOL + +#ifdef ETHTOOL_GSTRINGS + +#define ETH_NUM_STATS 30 +#define RX_CRC_IDX 5 +#define RX_MAC_ERR_IDX 14 + +struct { + char string[ETH_GSTRING_LEN]; +} bcm5700_stats_str_arr[ETH_NUM_STATS] = { + { "rx_unicast_packets" }, + { "rx_multicast_packets" }, + { "rx_broadcast_packets" }, + { "rx_bytes" }, + { "rx_fragments" }, + { "rx_crc_errors" }, /* this needs to be calculated */ + { "rx_align_errors" }, + { "rx_xon_frames" }, + { "rx_xoff_frames" }, + { "rx_long_frames" }, + { "rx_short_frames" }, + { "rx_jabber" }, + { "rx_discards" }, + { "rx_errors" }, + { "rx_mac_errors" }, /* this needs to be calculated */ + { "tx_unicast_packets" }, + { "tx_multicast_packets" }, + { "tx_broadcast_packets" }, + { "tx_bytes" }, + { "tx_deferred" }, + { "tx_single_collisions" }, + { "tx_multi_collisions" }, + { "tx_total_collisions" }, + { "tx_excess_collisions" }, + { "tx_late_collisions" }, + { "tx_xon_frames" }, + { "tx_xoff_frames" }, + { "tx_internal_mac_errors" }, + { "tx_carrier_errors" }, + { "tx_errors" }, +}; + +#define STATS_OFFSET(offset_name) ((OFFSETOF(T3_STATS_BLOCK, offset_name)) / sizeof(uint64_t)) + +#ifdef __BIG_ENDIAN +#define SWAP_DWORD_64(x) (x) +#else +#define SWAP_DWORD_64(x) ((x << 32) | (x >> 32)) +#endif + +unsigned long bcm5700_stats_offset_arr[ETH_NUM_STATS] = { + STATS_OFFSET(ifHCInUcastPkts), + STATS_OFFSET(ifHCInMulticastPkts), + STATS_OFFSET(ifHCInBroadcastPkts), + STATS_OFFSET(ifHCInOctets), + STATS_OFFSET(etherStatsFragments), + 0, + STATS_OFFSET(dot3StatsAlignmentErrors), + STATS_OFFSET(xonPauseFramesReceived), + STATS_OFFSET(xoffPauseFramesReceived), + STATS_OFFSET(dot3StatsFramesTooLong), + STATS_OFFSET(etherStatsUndersizePkts), + STATS_OFFSET(etherStatsJabbers), + STATS_OFFSET(ifInDiscards), + STATS_OFFSET(ifInErrors), + 0, + STATS_OFFSET(ifHCOutUcastPkts), + STATS_OFFSET(ifHCOutMulticastPkts), + STATS_OFFSET(ifHCOutBroadcastPkts), + STATS_OFFSET(ifHCOutOctets), + STATS_OFFSET(dot3StatsDeferredTransmissions), + STATS_OFFSET(dot3StatsSingleCollisionFrames), + STATS_OFFSET(dot3StatsMultipleCollisionFrames), + STATS_OFFSET(etherStatsCollisions), + STATS_OFFSET(dot3StatsExcessiveCollisions), + STATS_OFFSET(dot3StatsLateCollisions), + STATS_OFFSET(outXonSent), + STATS_OFFSET(outXoffSent), + STATS_OFFSET(dot3StatsInternalMacTransmitErrors), + STATS_OFFSET(dot3StatsCarrierSenseErrors), + STATS_OFFSET(ifOutErrors), +}; + +#endif /* ETHTOOL_GSTRINGS */ + + +#ifdef ETHTOOL_GREGS +#if (LINUX_VERSION_CODE >= 0x02040f) +static void +bcm5700_get_reg_blk(UM_DEVICE_BLOCK *pUmDevice, u32 **buf, u32 start, u32 end, + int reserved) +{ + u32 offset; + LM_DEVICE_BLOCK *pDevice = &pUmDevice->lm_dev; + + if (reserved) { + memset(*buf, 0, end - start); + *buf = *buf + (end - start)/4; + return; + } + for (offset = start; offset < end; offset+=4, *buf = *buf + 1) { + if (T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)){ + if (((offset >= 0x3400) && (offset < 0x3c00)) || + ((offset >= 0x5400) && (offset < 0x5800)) || + ((offset >= 0x6400) && (offset < 0x6800))) { + **buf = 0; + continue; + } + } + **buf = REG_RD_OFFSET(pDevice, offset); + } +} +#endif +#endif + +static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + struct ethtool_cmd ethcmd; + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + + if (mm_copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + + switch (ethcmd.cmd) { +#ifdef ETHTOOL_GDRVINFO + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; + + strcpy(info.driver, bcm5700_driver); +#ifdef INCLUDE_5701_AX_FIX + if(pDevice->ChipRevId == T3_CHIP_ID_5701_A0) { + extern int t3FwReleaseMajor; + extern int t3FwReleaseMinor; + extern int t3FwReleaseFix; + + sprintf(info.fw_version, "%i.%i.%i", + t3FwReleaseMajor, t3FwReleaseMinor, + t3FwReleaseFix); + } +#endif + strcpy(info.fw_version, pDevice->BootCodeVer); + strcpy(info.version, bcm5700_version); +#if (LINUX_VERSION_CODE <= 0x020422) + strcpy(info.bus_info, pUmDevice->pdev->slot_name); +#else + strcpy(info.bus_info, pci_name(pUmDevice->pdev)); +#endif + + + +#ifdef ETHTOOL_GEEPROM + BCM_EEDUMP_LEN(&info, pDevice->NvramSize); +#endif +#ifdef ETHTOOL_GREGS + /* dump everything, including holes in the register space */ + info.regdump_len = 0x6c00; +#endif +#ifdef ETHTOOL_GSTATS + info.n_stats = ETH_NUM_STATS; +#endif + if (mm_copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + } +#endif + case ETHTOOL_GSET: { + if ((pDevice->TbiFlags & ENABLE_TBI_FLAG)|| + (pDevice->PhyFlags & PHY_IS_FIBER)) { + ethcmd.supported = + (SUPPORTED_1000baseT_Full | + SUPPORTED_Autoneg); + ethcmd.supported |= SUPPORTED_FIBRE; + ethcmd.port = PORT_FIBRE; + } else { + ethcmd.supported = + (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full | + SUPPORTED_Autoneg); + ethcmd.supported |= SUPPORTED_TP; + ethcmd.port = PORT_TP; + } + + ethcmd.transceiver = XCVR_INTERNAL; + ethcmd.phy_address = 0; + + if (pDevice->LineSpeed == LM_LINE_SPEED_1000MBPS) + ethcmd.speed = SPEED_1000; + else if (pDevice->LineSpeed == LM_LINE_SPEED_100MBPS) + ethcmd.speed = SPEED_100; + else if (pDevice->LineSpeed == LM_LINE_SPEED_10MBPS) + ethcmd.speed = SPEED_10; + else + ethcmd.speed = 0; + + if (pDevice->DuplexMode == LM_DUPLEX_MODE_FULL) + ethcmd.duplex = DUPLEX_FULL; + else + ethcmd.duplex = DUPLEX_HALF; + + if (pDevice->DisableAutoNeg == FALSE) { + ethcmd.autoneg = AUTONEG_ENABLE; + ethcmd.advertising = ADVERTISED_Autoneg; + if ((pDevice->TbiFlags & ENABLE_TBI_FLAG) || + (pDevice->PhyFlags & PHY_IS_FIBER)) { + ethcmd.advertising |= + ADVERTISED_1000baseT_Full | + ADVERTISED_FIBRE; + } + else { + ethcmd.advertising |= + ADVERTISED_TP; + if (pDevice->advertising & + PHY_AN_AD_10BASET_HALF) { + + ethcmd.advertising |= + ADVERTISED_10baseT_Half; + } + if (pDevice->advertising & + PHY_AN_AD_10BASET_FULL) { + + ethcmd.advertising |= + ADVERTISED_10baseT_Full; + } + if (pDevice->advertising & + PHY_AN_AD_100BASETX_HALF) { + + ethcmd.advertising |= + ADVERTISED_100baseT_Half; + } + if (pDevice->advertising & + PHY_AN_AD_100BASETX_FULL) { + + ethcmd.advertising |= + ADVERTISED_100baseT_Full; + } + if (pDevice->advertising1000 & + BCM540X_AN_AD_1000BASET_HALF) { + + ethcmd.advertising |= + ADVERTISED_1000baseT_Half; + } + if (pDevice->advertising1000 & + BCM540X_AN_AD_1000BASET_FULL) { + + ethcmd.advertising |= + ADVERTISED_1000baseT_Full; + } + } + } + else { + ethcmd.autoneg = AUTONEG_DISABLE; + ethcmd.advertising = 0; + } + + ethcmd.maxtxpkt = pDevice->TxMaxCoalescedFrames; + ethcmd.maxrxpkt = pDevice->RxMaxCoalescedFrames; + + if(mm_copy_to_user(useraddr, ðcmd, sizeof(ethcmd))) + return -EFAULT; + return 0; + } + case ETHTOOL_SSET: { + unsigned long flags; + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + if (ethcmd.autoneg == AUTONEG_ENABLE) { + pDevice->RequestedLineSpeed = LM_LINE_SPEED_AUTO; + pDevice->RequestedDuplexMode = LM_DUPLEX_MODE_UNKNOWN; + pDevice->DisableAutoNeg = FALSE; + } + else { + if (ethcmd.speed == SPEED_1000 && + pDevice->PhyFlags & PHY_NO_GIGABIT) + return -EINVAL; + + if (ethcmd.speed == SPEED_1000 && + (pDevice->TbiFlags & ENABLE_TBI_FLAG || + pDevice->PhyFlags & PHY_IS_FIBER ) ) { + + pDevice->RequestedLineSpeed = + LM_LINE_SPEED_1000MBPS; + + pDevice->RequestedDuplexMode = + LM_DUPLEX_MODE_FULL; + } + else if (ethcmd.speed == SPEED_100 && + !(pDevice->TbiFlags & ENABLE_TBI_FLAG) && + !(pDevice->PhyFlags & PHY_IS_FIBER)) { + + pDevice->RequestedLineSpeed = + LM_LINE_SPEED_100MBPS; + } + else if (ethcmd.speed == SPEED_10 && + !(pDevice->TbiFlags & ENABLE_TBI_FLAG) && + !(pDevice->PhyFlags & PHY_IS_FIBER)) { + + pDevice->RequestedLineSpeed = + LM_LINE_SPEED_10MBPS; + } + else { + return -EINVAL; + } + + pDevice->DisableAutoNeg = TRUE; + if (ethcmd.duplex == DUPLEX_FULL) { + pDevice->RequestedDuplexMode = + LM_DUPLEX_MODE_FULL; + } + else { + if (!(pDevice->TbiFlags & ENABLE_TBI_FLAG) && + !(pDevice->PhyFlags & PHY_IS_FIBER) ) { + + pDevice->RequestedDuplexMode = + LM_DUPLEX_MODE_HALF; + } + } + } + if (netif_running(dev)) { + BCM5700_PHY_LOCK(pUmDevice, flags); + LM_SetupPhy(pDevice); + BCM5700_PHY_UNLOCK(pUmDevice, flags); + } + return 0; + } +#ifdef ETHTOOL_GWOL +#ifdef BCM_WOL + case ETHTOOL_GWOL: { + struct ethtool_wolinfo wol = {ETHTOOL_GWOL}; + + if (((pDevice->TbiFlags & ENABLE_TBI_FLAG) && + !(pDevice->Flags & FIBER_WOL_CAPABLE_FLAG)) || + (pDevice->Flags & DISABLE_D3HOT_FLAG)) { + wol.supported = 0; + wol.wolopts = 0; + } + else { + wol.supported = WAKE_MAGIC; + if (pDevice->WakeUpMode == LM_WAKE_UP_MODE_MAGIC_PACKET) + { + wol.wolopts = WAKE_MAGIC; + } + else { + wol.wolopts = 0; + } + } + if (mm_copy_to_user(useraddr, &wol, sizeof(wol))) + return -EFAULT; + return 0; + } + case ETHTOOL_SWOL: { + struct ethtool_wolinfo wol; + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + if (mm_copy_from_user(&wol, useraddr, sizeof(wol))) + return -EFAULT; + if ((((pDevice->TbiFlags & ENABLE_TBI_FLAG) && + !(pDevice->Flags & FIBER_WOL_CAPABLE_FLAG)) || + (pDevice->Flags & DISABLE_D3HOT_FLAG)) && + wol.wolopts) { + return -EINVAL; + } + + if ((wol.wolopts & ~WAKE_MAGIC) != 0) { + return -EINVAL; + } + if (wol.wolopts & WAKE_MAGIC) { + pDevice->WakeUpModeCap = LM_WAKE_UP_MODE_MAGIC_PACKET; + pDevice->WakeUpMode = LM_WAKE_UP_MODE_MAGIC_PACKET; + } + else { + pDevice->WakeUpModeCap = LM_WAKE_UP_MODE_NONE; + pDevice->WakeUpMode = LM_WAKE_UP_MODE_NONE; + } + return 0; + } +#endif +#endif +#ifdef ETHTOOL_GLINK + case ETHTOOL_GLINK: { + struct ethtool_value edata = {ETHTOOL_GLINK}; + + /* ifup only waits for 5 seconds for link up */ + /* NIC may take more than 5 seconds to establish link */ + if ((pUmDevice->delayed_link_ind > 0) && + delay_link[pUmDevice->index]) + return -EOPNOTSUPP; + + if (pDevice->LinkStatus == LM_STATUS_LINK_ACTIVE) { + edata.data = 1; + } + else { + edata.data = 0; + } + if (mm_copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } +#endif +#ifdef ETHTOOL_NWAY_RST + case ETHTOOL_NWAY_RST: { + LM_UINT32 phyctrl; + unsigned long flags; + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + if (pDevice->DisableAutoNeg) { + return -EINVAL; + } + if (!netif_running(dev)) + return -EAGAIN; + BCM5700_PHY_LOCK(pUmDevice, flags); + if (pDevice->TbiFlags & ENABLE_TBI_FLAG) { + pDevice->RequestedLineSpeed = LM_LINE_SPEED_1000MBPS; + pDevice->DisableAutoNeg = TRUE; + LM_SetupPhy(pDevice); + + pDevice->RequestedLineSpeed = LM_LINE_SPEED_AUTO; + pDevice->DisableAutoNeg = FALSE; + LM_SetupPhy(pDevice); + } + else { + if ((T3_ASIC_REV(pDevice->ChipRevId) == + T3_ASIC_REV_5703) || + (T3_ASIC_REV(pDevice->ChipRevId) == + T3_ASIC_REV_5704) || + (T3_ASIC_REV(pDevice->ChipRevId) == + T3_ASIC_REV_5705)) + { + LM_ResetPhy(pDevice); + LM_SetupPhy(pDevice); + } + pDevice->PhyFlags &= ~PHY_FIBER_FALLBACK; + LM_ReadPhy(pDevice, PHY_CTRL_REG, &phyctrl); + LM_WritePhy(pDevice, PHY_CTRL_REG, phyctrl | + PHY_CTRL_AUTO_NEG_ENABLE | + PHY_CTRL_RESTART_AUTO_NEG); + } + BCM5700_PHY_UNLOCK(pUmDevice, flags); + return 0; + } +#endif +#ifdef ETHTOOL_GEEPROM + case ETHTOOL_GEEPROM: { + struct ethtool_eeprom eeprom; + LM_UINT32 *buf = 0; + LM_UINT32 buf1[64/4]; + int i, j, offset, len; + + if (mm_copy_from_user(&eeprom, useraddr, sizeof(eeprom))) + return -EFAULT; + + if (eeprom.offset >= pDevice->NvramSize) + return -EFAULT; + + /* maximum data limited */ + /* to read more, call again with a different offset */ + if (eeprom.len > 0x800) { + eeprom.len = 0x800; + if (mm_copy_to_user(useraddr, &eeprom, sizeof(eeprom))) + return -EFAULT; + } + + if (eeprom.len > 64) { + buf = kmalloc(eeprom.len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + } + else { + buf = buf1; + } + useraddr += offsetof(struct ethtool_eeprom, data); + + offset = eeprom.offset; + len = eeprom.len; + if (offset & 3) { + offset &= 0xfffffffc; + len += (offset & 3); + } + len = (len + 3) & 0xfffffffc; + for (i = 0, j = 0; j < len; i++, j += 4) { + if (LM_NvramRead(pDevice, offset + j, buf + i) != + LM_STATUS_SUCCESS) { + break; + } + } + if (j >= len) { + buf += (eeprom.offset & 3); + i = mm_copy_to_user(useraddr, buf, eeprom.len); + } + if (eeprom.len > 64) { + kfree(buf); + } + if ((j < len) || i) + return -EFAULT; + return 0; + } + case ETHTOOL_SEEPROM: { + struct ethtool_eeprom eeprom; + LM_UINT32 buf[64/4]; + int i, offset, len; + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + if (mm_copy_from_user(&eeprom, useraddr, sizeof(eeprom))) + return -EFAULT; + + if ((eeprom.offset & 3) || (eeprom.len & 3) || + (eeprom.offset >= pDevice->NvramSize)) { + return -EFAULT; + } + + if ((eeprom.offset + eeprom.len) >= pDevice->NvramSize) { + eeprom.len = pDevice->NvramSize - eeprom.offset; + } + + useraddr += offsetof(struct ethtool_eeprom, data); + + len = eeprom.len; + offset = eeprom.offset; + for (; len > 0; ) { + if (len < 64) + i = len; + else + i = 64; + if (mm_copy_from_user(&buf, useraddr, i)) + return -EFAULT; + + bcm5700_intr_off(pUmDevice); + /* Prevent race condition on Grc.Mode register */ + bcm5700_poll_wait(pUmDevice); + + if (LM_NvramWriteBlock(pDevice, offset, buf, i/4) != + LM_STATUS_SUCCESS) { + bcm5700_intr_on(pUmDevice); + return -EFAULT; + } + bcm5700_intr_on(pUmDevice); + len -= i; + offset += i; + useraddr += i; + } + return 0; + } +#endif +#ifdef ETHTOOL_GREGS +#if (LINUX_VERSION_CODE >= 0x02040f) + case ETHTOOL_GREGS: { + struct ethtool_regs eregs; + LM_UINT32 *buf, *buf1; + unsigned int i; + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + if (pDevice->Flags & UNDI_FIX_FLAG) + return -EOPNOTSUPP; + if (mm_copy_from_user(&eregs, useraddr, sizeof(eregs))) + return -EFAULT; + if (eregs.len > 0x6c00) + eregs.len = 0x6c00; + eregs.version = 0x0; + if (mm_copy_to_user(useraddr, &eregs, sizeof(eregs))) + return -EFAULT; + buf = buf1 = kmalloc(eregs.len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + bcm5700_get_reg_blk(pUmDevice, &buf, 0, 0xb0, 0); + bcm5700_get_reg_blk(pUmDevice, &buf, 0xb0, 0x200, 1); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x200, 0x8f0, 0); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x8f0, 0xc00, 1); + bcm5700_get_reg_blk(pUmDevice, &buf, 0xc00, 0xce0, 0); + bcm5700_get_reg_blk(pUmDevice, &buf, 0xce0, 0x1000, 1); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x1000, 0x1004, 0); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x1004, 0x1400, 1); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x1400, 0x1480, 0); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x1480, 0x1800, 1); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x1800, 0x1848, 0); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x1848, 0x1c00, 1); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x1c00, 0x1c04, 0); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x1c04, 0x2000, 1); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x2000, 0x225c, 0); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x225c, 0x2400, 1); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x2400, 0x24c4, 0); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x24c4, 0x2800, 1); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x2800, 0x2804, 0); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x2804, 0x2c00, 1); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x2c00, 0x2c20, 0); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x2c20, 0x3000, 1); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x3000, 0x3014, 0); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x3014, 0x3400, 1); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x3400, 0x3408, 0); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x3408, 0x3800, 1); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x3800, 0x3808, 0); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x3808, 0x3c00, 1); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x3c00, 0x3d00, 0); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x3d00, 0x4000, 1); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x4000, 0x4010, 0); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x4010, 0x4400, 1); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x4400, 0x4458, 0); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x4458, 0x4800, 1); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x4800, 0x4808, 0); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x4808, 0x4c00, 1); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x4c00, 0x4c08, 0); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x4c08, 0x5000, 1); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x5000, 0x5050, 0); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x5050, 0x5400, 1); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x5400, 0x5450, 0); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x5450, 0x5800, 1); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x5800, 0x5a10, 0); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x5a10, 0x6000, 1); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x6000, 0x600c, 0); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x600c, 0x6400, 1); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x6400, 0x6404, 0); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x6404, 0x6800, 1); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x6800, 0x6848, 0); + bcm5700_get_reg_blk(pUmDevice, &buf, 0x6848, 0x6c00, 1); + + i = mm_copy_to_user(useraddr + sizeof(eregs), buf1, eregs.len); + kfree(buf1); + if (i) + return -EFAULT; + return 0; + } +#endif +#endif +#ifdef ETHTOOL_GPAUSEPARAM + case ETHTOOL_GPAUSEPARAM: { + struct ethtool_pauseparam epause = { ETHTOOL_GPAUSEPARAM }; + + if (!pDevice->DisableAutoNeg) { + epause.autoneg = (pDevice->FlowControlCap & + LM_FLOW_CONTROL_AUTO_PAUSE) != 0; + } + else { + epause.autoneg = 0; + } + epause.rx_pause = + (pDevice->FlowControl & + LM_FLOW_CONTROL_RECEIVE_PAUSE) != 0; + epause.tx_pause = + (pDevice->FlowControl & + LM_FLOW_CONTROL_TRANSMIT_PAUSE) != 0; + if (mm_copy_to_user(useraddr, &epause, sizeof(epause))) + return -EFAULT; + + return 0; + } + case ETHTOOL_SPAUSEPARAM: { + struct ethtool_pauseparam epause; + unsigned long flags; + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + if (mm_copy_from_user(&epause, useraddr, sizeof(epause))) + return -EFAULT; + pDevice->FlowControlCap = 0; + if (epause.autoneg && !pDevice->DisableAutoNeg) { + pDevice->FlowControlCap |= LM_FLOW_CONTROL_AUTO_PAUSE; + } + if (epause.rx_pause) { + pDevice->FlowControlCap |= + LM_FLOW_CONTROL_RECEIVE_PAUSE; + } + if (epause.tx_pause) { + pDevice->FlowControlCap |= + LM_FLOW_CONTROL_TRANSMIT_PAUSE; + } + if (netif_running(dev)) { + BCM5700_PHY_LOCK(pUmDevice, flags); + LM_SetupPhy(pDevice); + BCM5700_PHY_UNLOCK(pUmDevice, flags); + } + + return 0; + } +#endif +#ifdef ETHTOOL_GRXCSUM + case ETHTOOL_GRXCSUM: { + struct ethtool_value edata = { ETHTOOL_GRXCSUM }; + + edata.data = + (pDevice->TaskToOffload & + LM_TASK_OFFLOAD_RX_TCP_CHECKSUM) != 0; + if (mm_copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + + return 0; + } + case ETHTOOL_SRXCSUM: { + struct ethtool_value edata; + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + if (mm_copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + if (edata.data) { + if (!(pDevice->TaskOffloadCap & + LM_TASK_OFFLOAD_TX_TCP_CHECKSUM)) { + + return -EINVAL; + } + pDevice->TaskToOffload |= + LM_TASK_OFFLOAD_RX_TCP_CHECKSUM | + LM_TASK_OFFLOAD_RX_UDP_CHECKSUM; + } + else { + pDevice->TaskToOffload &= + ~(LM_TASK_OFFLOAD_RX_TCP_CHECKSUM | + LM_TASK_OFFLOAD_RX_UDP_CHECKSUM); + } + return 0; + } + case ETHTOOL_GTXCSUM: { + struct ethtool_value edata = { ETHTOOL_GTXCSUM }; + + edata.data = + (dev->features & get_csum_flag( pDevice->ChipRevId)) != 0; + if (mm_copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + + return 0; + } + case ETHTOOL_STXCSUM: { + struct ethtool_value edata; + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + if (mm_copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + if (edata.data) { + if (!(pDevice->TaskOffloadCap & + LM_TASK_OFFLOAD_TX_TCP_CHECKSUM)) { + + return -EINVAL; + } + dev->features |= get_csum_flag( pDevice->ChipRevId); + pDevice->TaskToOffload |= + LM_TASK_OFFLOAD_TX_TCP_CHECKSUM | + LM_TASK_OFFLOAD_TX_UDP_CHECKSUM; + } + else { + dev->features &= ~get_csum_flag( pDevice->ChipRevId); + pDevice->TaskToOffload &= + ~(LM_TASK_OFFLOAD_TX_TCP_CHECKSUM | + LM_TASK_OFFLOAD_TX_UDP_CHECKSUM); + } + return 0; + } + case ETHTOOL_GSG: { + struct ethtool_value edata = { ETHTOOL_GSG }; + + edata.data = + (dev->features & NETIF_F_SG) != 0; + if (mm_copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } + case ETHTOOL_SSG: { + struct ethtool_value edata; + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + if (mm_copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + if (edata.data) { + dev->features |= NETIF_F_SG; + } + else { + dev->features &= ~NETIF_F_SG; + } + return 0; + } +#endif +#ifdef ETHTOOL_GRINGPARAM + case ETHTOOL_GRINGPARAM: { + struct ethtool_ringparam ering = { ETHTOOL_GRINGPARAM }; + + ering.rx_max_pending = T3_STD_RCV_RCB_ENTRY_COUNT - 1; + ering.rx_pending = pDevice->RxStdDescCnt; + ering.rx_mini_max_pending = 0; + ering.rx_mini_pending = 0; +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + ering.rx_jumbo_max_pending = T3_JUMBO_RCV_RCB_ENTRY_COUNT - 1; + ering.rx_jumbo_pending = pDevice->RxJumboDescCnt; +#else + ering.rx_jumbo_max_pending = 0; + ering.rx_jumbo_pending = 0; +#endif + ering.tx_max_pending = MAX_TX_PACKET_DESC_COUNT - 1; + ering.tx_pending = pDevice->TxPacketDescCnt; + if (mm_copy_to_user(useraddr, &ering, sizeof(ering))) + return -EFAULT; + return 0; + } +#endif +#ifdef ETHTOOL_PHYS_ID + case ETHTOOL_PHYS_ID: { + struct ethtool_value edata; + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + if (mm_copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + if (LM_BlinkLED(pDevice, edata.data) == LM_STATUS_SUCCESS) + return 0; + return -EINTR; + } +#endif +#ifdef ETHTOOL_GSTRINGS + case ETHTOOL_GSTRINGS: { + struct ethtool_gstrings egstr = { ETHTOOL_GSTRINGS }; + + if (mm_copy_from_user(&egstr, useraddr, sizeof(egstr))) + return -EFAULT; + switch(egstr.string_set) { +#ifdef ETHTOOL_GSTATS + case ETH_SS_STATS: + egstr.len = ETH_NUM_STATS; + if (mm_copy_to_user(useraddr, &egstr, sizeof(egstr))) + return -EFAULT; + if (mm_copy_to_user(useraddr + sizeof(egstr), + bcm5700_stats_str_arr, + sizeof(bcm5700_stats_str_arr))) + return -EFAULT; + return 0; +#endif + default: + return -EOPNOTSUPP; + } + } +#endif +#ifdef ETHTOOL_GSTATS + case ETHTOOL_GSTATS: { + struct ethtool_stats estats = { ETHTOOL_GSTATS }; + uint64_t stats[ETH_NUM_STATS]; + int i; + uint64_t *pStats = + (uint64_t *) pDevice->pStatsBlkVirt; + + estats.n_stats = ETH_NUM_STATS; + if (pStats == 0) { + memset(stats, 0, sizeof(stats)); + } + else { + + for (i = 0; i < ETH_NUM_STATS; i++) { + if (bcm5700_stats_offset_arr[i] != 0) { + stats[i] = SWAP_DWORD_64(*(pStats + + bcm5700_stats_offset_arr[i])); + } + else if (i == RX_CRC_IDX) { + stats[i] = + bcm5700_crc_count(pUmDevice); + } + else if (i == RX_MAC_ERR_IDX) { + stats[i] = + bcm5700_rx_err_count(pUmDevice); + } + } + } + if (mm_copy_to_user(useraddr, &estats, sizeof(estats))) { + return -EFAULT; + } + if (mm_copy_to_user(useraddr + sizeof(estats), &stats, + sizeof(stats))) { + return -EFAULT; + } + return 0; + } +#endif +#ifdef ETHTOOL_GTSO + case ETHTOOL_GTSO: { + struct ethtool_value edata = { ETHTOOL_GTSO }; + +#ifdef BCM_TSO + edata.data = + (dev->features & NETIF_F_TSO) != 0; +#else + edata.data = 0; +#endif + if (mm_copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; + } +#endif +#ifdef ETHTOOL_STSO + case ETHTOOL_STSO: { +#ifdef BCM_TSO + struct ethtool_value edata; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + if (mm_copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + + if (!(pDevice->TaskToOffload & + LM_TASK_OFFLOAD_TCP_SEGMENTATION)) { + return -EINVAL; + } + + dev->features &= ~NETIF_F_TSO; + + if (edata.data) { + if (T3_ASIC_5714_FAMILY(pDevice->ChipRevId) && + (dev->mtu > 1500)) { + printk(KERN_ALERT "%s: Jumbo Frames and TSO cannot simultaneously be enabled. Jumbo Frames enabled. TSO disabled.\n", dev->name); + return -EINVAL; + } else { + dev->features |= NETIF_F_TSO; + } + } + return 0; +#else + return -EINVAL; +#endif + } +#endif + } + + return -EOPNOTSUPP; +} +#endif /* #ifdef SIOCETHTOOL */ + +#if (LINUX_VERSION_CODE >= 0x20400) && (LINUX_VERSION_CODE < 0x20600) +#include +#endif + +/* Provide ioctl() calls to examine the MII xcvr state. */ +STATIC int bcm5700_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + u16 *data = (u16 *)&rq->ifr_data; + u32 value = 0; + u16 page_num =0, addr_num =0, len =0; + unsigned long flags; + + switch(cmd) { + case SIOCGREG_STATUS: //Get register + { + struct reg_ioctl_data *rdata =(struct reg_ioctl_data *)rq->ifr_data; + robo_info_t *robo = (robo_info_t *)pUmDevice->robo; + page_num = rdata->page_num; + addr_num = rdata->addr_num; + len = rdata->len; + printk("b57um SIOCGREG_STATUS cmd page[0x%x]addr[0x%x]len[%d].\n",page_num,addr_num,len); + if (len == 6) + { + ReadDataFromRegister(robo,page_num,addr_num,len,(void *)&rdata->val_out); + printk("val[0x%04x-0x%04x-0x%04x].\n",rdata->val_out[0],rdata->val_out[1],rdata->val_out[2]); + } + else if (len == 8) + { + ReadDataFromRegister(robo,page_num,addr_num,len,(void *)&rdata->val_out); + printk("val[0x%04x%04x-0x%04x%04x].\n",rdata->val_out[0],rdata->val_out[1], + rdata->val_out[2],rdata->val_out[3]); + } + else if (len == 4) + { + ReadDataFromRegister(robo,page_num,addr_num,len,(void *)&rdata->val_out); + printk("val[0x%04x%04x].\n",rdata->val_out[0],rdata->val_out[1]); + } + else + { + ReadDataFromRegister(robo,page_num,addr_num,len,(void *)&rdata->val_out); + printk("val[0x%04x].\n",rdata->val_out[0]); + + } + if (mm_copy_to_user(rq->ifr_data, rdata, sizeof(struct reg_ioctl_data))) + { + printk("Fail mm_copy_to_user.\n"); + return -EFAULT; + } + return 0; + } + break; + case SIOCSREG_STATUS://Set register + { + struct reg_ioctl_data * wdata =(struct reg_ioctl_data *)rq->ifr_data; + len = wdata->len; + page_num = wdata->page_num; + addr_num = wdata->addr_num; + robo_info_t *robo = (robo_info_t *)pUmDevice->robo; + if (len == 6) + { + WriteDataToRegister(robo,page_num,addr_num,len,(void *)&wdata->val_in); + //printk("val[0x%04x-0x%04x-0x%04x].\n",val48[0],val48[1],val48[2]); + } + else if (len == 8) + { + WriteDataToRegister(robo,page_num,addr_num,len,(void *)&wdata->val_in); + //printk("val[0x%04x-0x%04x-0x%04x-0x%04x].\n",val64[0],val64[1],val64[2],val64[3]); + } + else if (len == 4) + { + WriteDataToRegister(robo,page_num,addr_num,len,(void *)&wdata->val_in); + //printk("val[0x%08x].\n",value); + } + else + { + WriteDataToRegister(robo,page_num,addr_num,len,(void *)&wdata->val_in); + //printk("len[%d] val[0x%04x].\n",len,val16); + } + + return 0; + } + break; +#ifdef SIOCGMIIPHY + case SIOCGMIIPHY: /* Get the address of the PHY in use. */ + + data[0] = pDevice->PhyAddr; + return 0; +#endif + +#ifdef SIOCGMIIREG + case SIOCGMIIREG: /* Read the specified MII register. */ + { + uint32 savephyaddr = 0; + + if (pDevice->TbiFlags & ENABLE_TBI_FLAG) + return -EOPNOTSUPP; + + /* ifup only waits for 5 seconds for link up */ + /* NIC may take more than 5 seconds to establish link */ + if ((pUmDevice->delayed_link_ind > 0) && + delay_link[pUmDevice->index]) { + return -EAGAIN; + } + + BCM5700_PHY_LOCK(pUmDevice, flags); + if (data[0] != 0xffff) { + savephyaddr = pDevice->PhyAddr; + pDevice->PhyAddr = data[0]; + } + LM_ReadPhy(pDevice, data[1] & 0x1f, (LM_UINT32 *)&value); + if (data[0] != 0xffff) + pDevice->PhyAddr = savephyaddr; + BCM5700_PHY_UNLOCK(pUmDevice, flags); + data[3] = value & 0xffff; + return 0; + } +#endif + +#ifdef SIOCSMIIREG + case SIOCSMIIREG: /* Write the specified MII register */ + { + uint32 savephyaddr = 0; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + if (pDevice->TbiFlags & ENABLE_TBI_FLAG) + return -EOPNOTSUPP; + + BCM5700_PHY_LOCK(pUmDevice, flags); + if (data[0] != 0xffff) { + savephyaddr = pDevice->PhyAddr; + pDevice->PhyAddr = data[0]; + } + LM_WritePhy(pDevice, data[1] & 0x1f, data[2]); + if (data[0] != 0xffff) + pDevice->PhyAddr = savephyaddr; + BCM5700_PHY_UNLOCK(pUmDevice, flags); + data[3] = 0; + return 0; + } +#endif + +#ifdef SIOCETHTOOL + case SIOCETHTOOL: + return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); +#endif + default: + return -EOPNOTSUPP; + } + return -EOPNOTSUPP; +} + +STATIC void bcm5700_do_rx_mode(struct net_device *dev) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + int i; + struct dev_mc_list *mclist; + + LM_MulticastClear(pDevice); + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) { + LM_MulticastAdd(pDevice, (PLM_UINT8) &mclist->dmi_addr); + } + if (dev->flags & IFF_ALLMULTI) { + if (!(pDevice->ReceiveMask & LM_ACCEPT_ALL_MULTICAST)) { + LM_SetReceiveMask(pDevice, + pDevice->ReceiveMask | LM_ACCEPT_ALL_MULTICAST); + } + } + else if (pDevice->ReceiveMask & LM_ACCEPT_ALL_MULTICAST) { + LM_SetReceiveMask(pDevice, + pDevice->ReceiveMask & ~LM_ACCEPT_ALL_MULTICAST); + } + if (dev->flags & IFF_PROMISC) { + if (!(pDevice->ReceiveMask & LM_PROMISCUOUS_MODE)) { + LM_SetReceiveMask(pDevice, + pDevice->ReceiveMask | LM_PROMISCUOUS_MODE); + } + } + else if (pDevice->ReceiveMask & LM_PROMISCUOUS_MODE) { + LM_SetReceiveMask(pDevice, + pDevice->ReceiveMask & ~LM_PROMISCUOUS_MODE); + } + +} + +STATIC void bcm5700_set_rx_mode(struct net_device *dev) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + int i; + struct dev_mc_list *mclist; + unsigned long flags; + + BCM5700_PHY_LOCK(pUmDevice, flags); + + LM_MulticastClear(pDevice); + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) { + LM_MulticastAdd(pDevice, (PLM_UINT8) &mclist->dmi_addr); + } + if (dev->flags & IFF_ALLMULTI) { + if (!(pDevice->ReceiveMask & LM_ACCEPT_ALL_MULTICAST)) { + LM_SetReceiveMask(pDevice, + pDevice->ReceiveMask | LM_ACCEPT_ALL_MULTICAST); + } + } + else if (pDevice->ReceiveMask & LM_ACCEPT_ALL_MULTICAST) { + LM_SetReceiveMask(pDevice, + pDevice->ReceiveMask & ~LM_ACCEPT_ALL_MULTICAST); + } + if (dev->flags & IFF_PROMISC) { + if (!(pDevice->ReceiveMask & LM_PROMISCUOUS_MODE)) { + LM_SetReceiveMask(pDevice, + pDevice->ReceiveMask | LM_PROMISCUOUS_MODE); + } + } + else if (pDevice->ReceiveMask & LM_PROMISCUOUS_MODE) { + LM_SetReceiveMask(pDevice, + pDevice->ReceiveMask & ~LM_PROMISCUOUS_MODE); + } + + BCM5700_PHY_UNLOCK(pUmDevice, flags); +} + +/* + * Set the hardware MAC address. + */ +STATIC int bcm5700_set_mac_addr(struct net_device *dev, void *p) +{ + struct sockaddr *addr=p; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) dev->priv; + UM_DEVICE_BLOCK *pUmDevice = (UM_DEVICE_BLOCK *) pDevice; + + if(is_valid_ether_addr(addr->sa_data)){ + + memcpy(dev->dev_addr, addr->sa_data,dev->addr_len); + if (pUmDevice->opened) + LM_SetMacAddress(pDevice, dev->dev_addr); + bcm_robo_set_macaddr(pUmDevice->robo, dev->dev_addr); + return 0; + } + return -EINVAL; +} + +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT +STATIC int bcm5700_change_mtu(struct net_device *dev, int new_mtu) +{ + int pkt_size = new_mtu + ETHERNET_PACKET_HEADER_SIZE; + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK)dev->priv; + PLM_DEVICE_BLOCK pDevice = &pUmDevice->lm_dev; + unsigned long flags; + int reinit = 0; + + if ((pkt_size < MIN_ETHERNET_PACKET_SIZE_NO_CRC) || + (pkt_size > MAX_ETHERNET_JUMBO_PACKET_SIZE_NO_CRC)) { + + return -EINVAL; + } + if ( !(pDevice->Flags & JUMBO_CAPABLE_FLAG) && + (pkt_size > MAX_ETHERNET_PACKET_SIZE_NO_CRC) ) { + + return -EINVAL; + } + if (pUmDevice->suspended) + return -EAGAIN; + + if (pUmDevice->opened && (new_mtu != dev->mtu) && + (pDevice->Flags & JUMBO_CAPABLE_FLAG)) { + reinit = 1; + } + + BCM5700_PHY_LOCK(pUmDevice, flags); + if (reinit) { + netif_stop_queue(dev); + bcm5700_shutdown(pUmDevice); + bcm5700_freemem(dev); + } + + dev->mtu = new_mtu; + if (pkt_size < MAX_ETHERNET_PACKET_SIZE_NO_CRC) { + pDevice->RxMtu = pDevice->TxMtu = + MAX_ETHERNET_PACKET_SIZE_NO_CRC; + } + else { + pDevice->RxMtu = pDevice->TxMtu = pkt_size; + } + + if (dev->mtu <= 1514) { + pDevice->RxJumboDescCnt = 0; + } + else if (pDevice->Flags & JUMBO_CAPABLE_FLAG){ + pDevice->RxJumboDescCnt = + rx_jumbo_desc_cnt[pUmDevice->index]; + } + pDevice->RxPacketDescCnt = pDevice->RxJumboDescCnt + + pDevice->RxStdDescCnt; + + pDevice->RxJumboBufferSize = (pDevice->RxMtu + 8 /* CRC + VLAN */ + + COMMON_CACHE_LINE_SIZE-1) & ~COMMON_CACHE_LINE_MASK; + +#ifdef BCM_TSO + if (T3_ASIC_5714_FAMILY(pDevice->ChipRevId) && + (dev->mtu > 1514) ) { + if (dev->features & NETIF_F_TSO) { + dev->features &= ~NETIF_F_TSO; + printk(KERN_ALERT "%s: TSO previously enabled. Jumbo Frames and TSO cannot simultaneously be enabled. Jumbo Frames enabled. TSO disabled.\n", dev->name); + } + } +#endif + + if (reinit) { + LM_InitializeAdapter(pDevice); + bcm5700_do_rx_mode(dev); + bcm5700_set_vlan_mode(pUmDevice); + bcm5700_init_counters(pUmDevice); + if (memcmp(dev->dev_addr, pDevice->NodeAddress, 6)) { + LM_SetMacAddress(pDevice, dev->dev_addr); + } + netif_start_queue(dev); + bcm5700_intr_on(pUmDevice); + } + BCM5700_PHY_UNLOCK(pUmDevice, flags); + + return 0; +} +#endif + + +#if (LINUX_VERSION_CODE < 0x020300) +int +bcm5700_probe(struct net_device *dev) +{ + int cards_found = 0; + struct pci_dev *pdev = NULL; + struct pci_device_id *pci_tbl; + u16 ssvid, ssid; + + if ( ! pci_present()) + return -ENODEV; + + pci_tbl = bcm5700_pci_tbl; + while ((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET << 8, pdev))) { + int idx; + + pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &ssvid); + pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &ssid); + for (idx = 0; pci_tbl[idx].vendor; idx++) { + if ((pci_tbl[idx].vendor == PCI_ANY_ID || + pci_tbl[idx].vendor == pdev->vendor) && + (pci_tbl[idx].device == PCI_ANY_ID || + pci_tbl[idx].device == pdev->device) && + (pci_tbl[idx].subvendor == PCI_ANY_ID || + pci_tbl[idx].subvendor == ssvid) && + (pci_tbl[idx].subdevice == PCI_ANY_ID || + pci_tbl[idx].subdevice == ssid)) + { + + break; + } + } + if (pci_tbl[idx].vendor == 0) + continue; + + + if (bcm5700_init_one(pdev, &pci_tbl[idx]) == 0) + cards_found++; + } + + return cards_found ? 0 : -ENODEV; +} + +#ifdef MODULE +int init_module(void) +{ + return bcm5700_probe(NULL); +} + +void cleanup_module(void) +{ + struct net_device *next_dev; + PUM_DEVICE_BLOCK pUmDevice; + + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + while (root_tigon3_dev) { + pUmDevice = (PUM_DEVICE_BLOCK)root_tigon3_dev->priv; + next_dev = pUmDevice->next_module; + unregister_netdev(root_tigon3_dev); + if (pUmDevice->lm_dev.pMappedMemBase) + iounmap(pUmDevice->lm_dev.pMappedMemBase); +#if (LINUX_VERSION_CODE < 0x020600) + kfree(root_tigon3_dev); +#else + free_netdev(root_tigon3_dev); +#endif + root_tigon3_dev = next_dev; + } +#ifdef BCM_IOCTL32 + unregister_ioctl32_conversion(SIOCNICE); +#endif +} + +#endif /* MODULE */ +#else /* LINUX_VERSION_CODE < 0x020300 */ + +#if (LINUX_VERSION_CODE >= 0x020406) +static int bcm5700_suspend (struct pci_dev *pdev, u32 state) +#else +static void bcm5700_suspend (struct pci_dev *pdev) +#endif +{ + struct net_device *dev = (struct net_device *) pci_get_drvdata(pdev); + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) dev->priv; + PLM_DEVICE_BLOCK pDevice = &pUmDevice->lm_dev; + + if (!netif_running(dev)) +#if (LINUX_VERSION_CODE >= 0x020406) + return 0; +#else + return; +#endif + + netif_device_detach (dev); + bcm5700_shutdown(pUmDevice); + + LM_SetPowerState(pDevice, LM_POWER_STATE_D3); + +/* pci_power_off(pdev, -1);*/ +#if (LINUX_VERSION_CODE >= 0x020406) + return 0; +#endif +} + + +#if (LINUX_VERSION_CODE >= 0x020406) +static int bcm5700_resume(struct pci_dev *pdev) +#else +static void bcm5700_resume(struct pci_dev *pdev) +#endif +{ + struct net_device *dev = (struct net_device *) pci_get_drvdata(pdev); + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) dev->priv; + PLM_DEVICE_BLOCK pDevice = &pUmDevice->lm_dev; + + if (!netif_running(dev)) +#if (LINUX_VERSION_CODE >= 0x020406) + return 0; +#else + return; +#endif +/* pci_power_on(pdev);*/ + netif_device_attach(dev); + LM_SetPowerState(pDevice, LM_POWER_STATE_D0); + MM_InitializeUmPackets(pDevice); + bcm5700_reset(dev); +#if (LINUX_VERSION_CODE >= 0x020406) + return 0; +#endif +} + + +static struct pci_driver bcm5700_pci_driver = { + name: bcm5700_driver, + id_table: bcm5700_pci_tbl, + probe: bcm5700_init_one, + remove: __devexit_p(bcm5700_remove_one), + suspend: bcm5700_suspend, + resume: bcm5700_resume, +}; + +static int +bcm5700_notify_reboot(struct notifier_block *this, unsigned long event, void *unused) +{ + switch (event) { + case SYS_HALT: + case SYS_POWER_OFF: + case SYS_RESTART: + break; + default: + return NOTIFY_DONE; + } + + B57_INFO(("bcm5700 reboot notification\n")); + pci_unregister_driver(&bcm5700_pci_driver); + return NOTIFY_DONE; +} + +static int __init bcm5700_init_module (void) +{ + int pin = 1 << 2; + + if (nvram_match("disabled_5397", "1") || (activate_gpio != -1)) { + if ( activate_gpio != -1 ) pin = activate_gpio; + printk("5397 switch GPIO-Reset (pin %d)\n", pin); + sb_t *gpio_sbh; + if (!(gpio_sbh = sb_kattach(SB_OSH))) return -ENODEV; + sb_gpiosetcore(gpio_sbh); +// sb_gpioreserve(gpio_sbh, 0x4, GPIO_HI_PRIORITY); + sb_gpioouten(gpio_sbh, 0x4, 0x4, GPIO_HI_PRIORITY); + sb_gpioout(gpio_sbh, 0x4, 0x4, GPIO_HI_PRIORITY); + sb_detach(gpio_sbh); + } + + if (msglevel != 0xdeadbeef) { + b57_msg_level = msglevel; + printf("%s: msglevel set to 0x%x\n", __FUNCTION__, b57_msg_level); + } else + b57_msg_level = B57_ERR_VAL; + + return pci_module_init(&bcm5700_pci_driver); +} + +static void __exit bcm5700_cleanup_module (void) +{ + unregister_reboot_notifier(&bcm5700_reboot_notifier); + pci_unregister_driver(&bcm5700_pci_driver); +} + +module_init(bcm5700_init_module); +module_exit(bcm5700_cleanup_module); +#endif + +/* + * Middle Module + * + */ + + +#ifdef BCM_NAPI_RXPOLL +LM_STATUS +MM_ScheduleRxPoll(LM_DEVICE_BLOCK *pDevice) +{ + struct net_device *dev = ((UM_DEVICE_BLOCK *) pDevice)->dev; + + if (netif_rx_schedule_prep(dev)) { + __netif_rx_schedule(dev); + return LM_STATUS_SUCCESS; + } + return LM_STATUS_FAILURE; +} +#endif + +LM_STATUS +MM_ReadConfig16(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, + LM_UINT16 *pValue16) +{ + UM_DEVICE_BLOCK *pUmDevice; + + pUmDevice = (UM_DEVICE_BLOCK *) pDevice; + pci_read_config_word(pUmDevice->pdev, Offset, (u16 *) pValue16); + return LM_STATUS_SUCCESS; +} + +LM_STATUS +MM_ReadConfig32(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, + LM_UINT32 *pValue32) +{ + UM_DEVICE_BLOCK *pUmDevice; + + pUmDevice = (UM_DEVICE_BLOCK *) pDevice; + pci_read_config_dword(pUmDevice->pdev, Offset, (u32 *) pValue32); + return LM_STATUS_SUCCESS; +} + +LM_STATUS +MM_WriteConfig16(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, + LM_UINT16 Value16) +{ + UM_DEVICE_BLOCK *pUmDevice; + + pUmDevice = (UM_DEVICE_BLOCK *) pDevice; + pci_write_config_word(pUmDevice->pdev, Offset, Value16); + return LM_STATUS_SUCCESS; +} + +LM_STATUS +MM_WriteConfig32(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, + LM_UINT32 Value32) +{ + UM_DEVICE_BLOCK *pUmDevice; + + pUmDevice = (UM_DEVICE_BLOCK *) pDevice; + pci_write_config_dword(pUmDevice->pdev, Offset, Value32); + return LM_STATUS_SUCCESS; +} + +LM_STATUS +MM_AllocateSharedMemory(PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize, + PLM_VOID *pMemoryBlockVirt, PLM_PHYSICAL_ADDRESS pMemoryBlockPhy, + LM_BOOL Cached) +{ + PLM_VOID pvirt; + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice; + dma_addr_t mapping; + + pvirt = pci_alloc_consistent(pUmDevice->pdev, BlockSize, + &mapping); + if (!pvirt) { + return LM_STATUS_FAILURE; + } + pUmDevice->mem_list[pUmDevice->mem_list_num] = pvirt; + pUmDevice->dma_list[pUmDevice->mem_list_num] = mapping; + pUmDevice->mem_size_list[pUmDevice->mem_list_num++] = BlockSize; + memset(pvirt, 0, BlockSize); + *pMemoryBlockVirt = (PLM_VOID) pvirt; + MM_SetAddr(pMemoryBlockPhy, mapping); + return LM_STATUS_SUCCESS; +} + +LM_STATUS +MM_AllocateMemory(PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize, + PLM_VOID *pMemoryBlockVirt) +{ + PLM_VOID pvirt; + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice; + + + /* Maximum in slab.c */ + if (BlockSize > 131072) { + goto MM_Alloc_error; + } + + pvirt = kmalloc(BlockSize, GFP_ATOMIC); + if (!pvirt) { + goto MM_Alloc_error; + } + pUmDevice->mem_list[pUmDevice->mem_list_num] = pvirt; + pUmDevice->dma_list[pUmDevice->mem_list_num] = 0; + pUmDevice->mem_size_list[pUmDevice->mem_list_num++] = 0; + /* mem_size_list[i] == 0 indicates that the memory should be freed */ + /* using kfree */ + memset(pvirt, 0, BlockSize); + *pMemoryBlockVirt = pvirt; + return LM_STATUS_SUCCESS; + +MM_Alloc_error: + printk(KERN_WARNING "%s: Memory allocation failed - buffer parameters may be set too high\n", pUmDevice->dev->name); + return LM_STATUS_FAILURE; +} + +LM_STATUS +MM_MapMemBase(PLM_DEVICE_BLOCK pDevice) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice; + + pDevice->pMappedMemBase = ioremap_nocache( + pci_resource_start(pUmDevice->pdev, 0), sizeof(T3_STD_MEM_MAP)); + if (pDevice->pMappedMemBase == 0) + return LM_STATUS_FAILURE; + + return LM_STATUS_SUCCESS; +} + +LM_STATUS +MM_InitializeUmPackets(PLM_DEVICE_BLOCK pDevice) +{ + unsigned int i; + struct sk_buff *skb; + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice; + PUM_PACKET pUmPacket; + PLM_PACKET pPacket; + + for (i = 0; i < pDevice->RxPacketDescCnt; i++) { + pPacket = QQ_PopHead(&pDevice->RxPacketFreeQ.Container); + pUmPacket = (PUM_PACKET) pPacket; + if (pPacket == 0) { + printk(KERN_DEBUG "Bad RxPacketFreeQ\n"); + } + if (pUmPacket->skbuff == 0) { +#ifdef BCM_WL_EMULATOR + skb = (struct sk_buff *)wlcemu_pktget(pDevice->wlc,pPacket->u.Rx.RxBufferSize + 2); +#else + skb = dev_alloc_skb(pPacket->u.Rx.RxBufferSize + 2 + EXTRA_HDR); +#endif + if (skb == 0) { + pUmPacket->skbuff = 0; + QQ_PushTail( + &pUmDevice->rx_out_of_buf_q.Container, + pPacket); + continue; + } + pUmPacket->skbuff = skb; + skb->dev = pUmDevice->dev; +#ifndef BCM_WL_EMULATOR + skb_reserve(skb, EXTRA_HDR - pUmDevice->rx_buf_align); +#endif + } + QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket); + } + if (T3_ASIC_REV(pUmDevice->lm_dev.ChipRevId) == T3_ASIC_REV_5700) { + /* reallocate buffers in the ISR */ + pUmDevice->rx_buf_repl_thresh = 0; + pUmDevice->rx_buf_repl_panic_thresh = 0; + pUmDevice->rx_buf_repl_isr_limit = 0; + } + else { + pUmDevice->rx_buf_repl_thresh = pDevice->RxPacketDescCnt / 8; + pUmDevice->rx_buf_repl_panic_thresh = + pDevice->RxPacketDescCnt * 7 / 8; + + /* This limits the time spent in the ISR when the receiver */ + /* is in a steady state of being overrun. */ + pUmDevice->rx_buf_repl_isr_limit = pDevice->RxPacketDescCnt / 8; + +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + if (pDevice->RxJumboDescCnt != 0) { + if (pUmDevice->rx_buf_repl_thresh >= + pDevice->RxJumboDescCnt) { + + pUmDevice->rx_buf_repl_thresh = + pUmDevice->rx_buf_repl_panic_thresh = + pDevice->RxJumboDescCnt - 1; + } + if (pUmDevice->rx_buf_repl_thresh >= + pDevice->RxStdDescCnt) { + + pUmDevice->rx_buf_repl_thresh = + pUmDevice->rx_buf_repl_panic_thresh = + pDevice->RxStdDescCnt - 1; + } + } +#endif + } + return LM_STATUS_SUCCESS; +} + +LM_STATUS +MM_GetConfig(PLM_DEVICE_BLOCK pDevice) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice; + int index = pUmDevice->index; + struct net_device *dev = pUmDevice->dev; + + if (index >= MAX_UNITS) + return LM_STATUS_SUCCESS; + +#if LINUX_KERNEL_VERSION < 0x0020609 + + bcm5700_validate_param_range(pUmDevice, &auto_speed[index], "auto_speed", + 0, 1, 1); + if (auto_speed[index] == 0) + pDevice->DisableAutoNeg = TRUE; + else + pDevice->DisableAutoNeg = FALSE; + + if (line_speed[index] == 0) { + pDevice->RequestedLineSpeed = LM_LINE_SPEED_AUTO; + pDevice->DisableAutoNeg = FALSE; + } + else { + bcm5700_validate_param_range(pUmDevice, &full_duplex[index], + "full_duplex", 0, 1, 1); + if (full_duplex[index]) { + pDevice->RequestedDuplexMode = LM_DUPLEX_MODE_FULL; + } + else { + pDevice->RequestedDuplexMode = LM_DUPLEX_MODE_HALF; + } + + if (line_speed[index] == 1000) { + pDevice->RequestedLineSpeed = LM_LINE_SPEED_1000MBPS; + if (pDevice->PhyFlags & PHY_NO_GIGABIT) { + pDevice->RequestedLineSpeed = + LM_LINE_SPEED_100MBPS; + printk(KERN_WARNING "%s-%d: Invalid line_speed parameter (1000), using 100\n", bcm5700_driver, index); + } + else { + if ((pDevice->TbiFlags & ENABLE_TBI_FLAG) && + !full_duplex[index]) { + printk(KERN_WARNING "%s-%d: Invalid full_duplex parameter (0) for fiber, using 1\n", bcm5700_driver, index); + pDevice->RequestedDuplexMode = + LM_DUPLEX_MODE_FULL; + } + + if (!(pDevice->TbiFlags & ENABLE_TBI_FLAG) && + !auto_speed[index] && !(pDevice->PhyFlags & PHY_IS_FIBER) ) { + printk(KERN_WARNING "%s-%d: Invalid auto_speed parameter (0) for copper, using 1\n", bcm5700_driver, index); + pDevice->DisableAutoNeg = FALSE; + } + } + } + else if ((pDevice->TbiFlags & ENABLE_TBI_FLAG) || + (pDevice->PhyFlags & PHY_IS_FIBER)){ + pDevice->RequestedLineSpeed = LM_LINE_SPEED_AUTO; + pDevice->RequestedDuplexMode = LM_DUPLEX_MODE_FULL; + pDevice->DisableAutoNeg = FALSE; + printk(KERN_WARNING "%s-%d: Invalid line_speed parameter (%d), using auto\n", bcm5700_driver, index, line_speed[index]); + } + else if (line_speed[index] == 100) { + + pDevice->RequestedLineSpeed = LM_LINE_SPEED_100MBPS; + } + else if (line_speed[index] == 10) { + + pDevice->RequestedLineSpeed = LM_LINE_SPEED_10MBPS; + } + else { + pDevice->RequestedLineSpeed = LM_LINE_SPEED_AUTO; + pDevice->DisableAutoNeg = FALSE; + printk(KERN_WARNING "%s-%d: Invalid line_speed parameter (%d), using 0\n", bcm5700_driver, index, line_speed[index]); + } + + } + +#endif /* LINUX_KERNEL_VERSION */ + + /* This is an unmanageable switch nic and will have link problems if + not set to auto + */ + if(pDevice->SubsystemVendorId==0x103c && pDevice->SubsystemId==0x3226) + { + if(pDevice->RequestedLineSpeed != LM_LINE_SPEED_AUTO) + { + printk(KERN_WARNING "%s-%d: Invalid line_speed parameter (%d), using 0\n", + bcm5700_driver, index, line_speed[index]); + } + pDevice->RequestedLineSpeed = LM_LINE_SPEED_AUTO; + pDevice->DisableAutoNeg = FALSE; + } + +#if LINUX_KERNEL_VERSION < 0x0020609 + + pDevice->FlowControlCap = 0; + bcm5700_validate_param_range(pUmDevice, &rx_flow_control[index], + "rx_flow_control", 0, 1, 0); + if (rx_flow_control[index] != 0) { + pDevice->FlowControlCap |= LM_FLOW_CONTROL_RECEIVE_PAUSE; + } + bcm5700_validate_param_range(pUmDevice, &tx_flow_control[index], + "tx_flow_control", 0, 1, 0); + if (tx_flow_control[index] != 0) { + pDevice->FlowControlCap |= LM_FLOW_CONTROL_TRANSMIT_PAUSE; + } + bcm5700_validate_param_range(pUmDevice, &auto_flow_control[index], + "auto_flow_control", 0, 1, 0); + if (auto_flow_control[index] != 0) { + if (pDevice->DisableAutoNeg == FALSE) { + + pDevice->FlowControlCap |= LM_FLOW_CONTROL_AUTO_PAUSE; + if ((tx_flow_control[index] == 0) && + (rx_flow_control[index] == 0)) { + + pDevice->FlowControlCap |= + LM_FLOW_CONTROL_TRANSMIT_PAUSE | + LM_FLOW_CONTROL_RECEIVE_PAUSE; + } + } + } + + if (dev->mtu > 1500) { +#ifdef BCM_TSO + if (T3_ASIC_5714_FAMILY(pDevice->ChipRevId) && + (dev->features & NETIF_F_TSO)) { + dev->features &= ~NETIF_F_TSO; + printk(KERN_ALERT "%s: TSO previously enabled. Jumbo Frames and TSO cannot simultaneously be enabled. Jumbo Frames enabled. TSO disabled.\n", dev->name); + } +#endif + pDevice->RxMtu = dev->mtu + 14; + } + + if ((T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5700) && + !(pDevice->Flags & BCM5788_FLAG)) { + pDevice->Flags |= USE_TAGGED_STATUS_FLAG; + pUmDevice->timer_interval = HZ; + if ((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5703) && + (pDevice->TbiFlags & ENABLE_TBI_FLAG)) { + pUmDevice->timer_interval = HZ/4; + } + } + else { + pUmDevice->timer_interval = HZ/10; + } + + bcm5700_validate_param_range(pUmDevice, &tx_pkt_desc_cnt[index], + "tx_pkt_desc_cnt", 1, MAX_TX_PACKET_DESC_COUNT-1, TX_DESC_CNT); + pDevice->TxPacketDescCnt = tx_pkt_desc_cnt[index]; + bcm5700_validate_param_range(pUmDevice, &rx_std_desc_cnt[index], + "rx_std_desc_cnt", 1, T3_STD_RCV_RCB_ENTRY_COUNT-1, + RX_DESC_CNT); + pDevice->RxStdDescCnt = rx_std_desc_cnt[index]; + +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + bcm5700_validate_param_range(pUmDevice, &rx_jumbo_desc_cnt[index], + "rx_jumbo_desc_cnt", 1, T3_JUMBO_RCV_RCB_ENTRY_COUNT-1, + JBO_DESC_CNT); + + if (mtu[index] <= 1514) + pDevice->RxJumboDescCnt = 0; + else if(!T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)){ + pDevice->RxJumboDescCnt = rx_jumbo_desc_cnt[index]; + } +#endif + +#ifdef BCM_INT_COAL + bcm5700_validate_param_range(pUmDevice, &adaptive_coalesce[index], + "adaptive_coalesce", 0, 1, 1); +#ifdef BCM_NAPI_RXPOLL + if (adaptive_coalesce[index]) { + printk(KERN_WARNING "%s-%d: adaptive_coalesce not used in NAPI mode\n", bcm5700_driver, index); + adaptive_coalesce[index] = 0; + + } +#endif + pUmDevice->adaptive_coalesce = adaptive_coalesce[index]; + if (!pUmDevice->adaptive_coalesce) { + bcm5700_validate_param_range(pUmDevice, + &rx_coalesce_ticks[index], "rx_coalesce_ticks", 0, + MAX_RX_COALESCING_TICKS, RX_COAL_TK); + if ((rx_coalesce_ticks[index] == 0) && + (rx_max_coalesce_frames[index] == 0)) { + + printk(KERN_WARNING "%s-%d: Conflicting rx_coalesce_ticks (0) and rx_max_coalesce_frames (0) parameters, using %d and %d respectively\n", + bcm5700_driver, index, RX_COAL_TK, RX_COAL_FM); + + rx_coalesce_ticks[index] = RX_COAL_TK; + rx_max_coalesce_frames[index] = RX_COAL_FM; + } + pDevice->RxCoalescingTicks = pUmDevice->rx_curr_coalesce_ticks = + rx_coalesce_ticks[index]; +#ifdef BCM_NAPI_RXPOLL + pDevice->RxCoalescingTicksDuringInt = rx_coalesce_ticks[index]; +#endif + + bcm5700_validate_param_range(pUmDevice, + &rx_max_coalesce_frames[index], + "rx_max_coalesce_frames", 0, + MAX_RX_MAX_COALESCED_FRAMES, RX_COAL_FM); + + pDevice->RxMaxCoalescedFrames = + pUmDevice->rx_curr_coalesce_frames = + rx_max_coalesce_frames[index]; +#ifdef BCM_NAPI_RXPOLL + pDevice->RxMaxCoalescedFramesDuringInt = + rx_max_coalesce_frames[index]; +#endif + + bcm5700_validate_param_range(pUmDevice, + &tx_coalesce_ticks[index], "tx_coalesce_ticks", 0, + MAX_TX_COALESCING_TICKS, TX_COAL_TK); + if ((tx_coalesce_ticks[index] == 0) && + (tx_max_coalesce_frames[index] == 0)) { + + printk(KERN_WARNING "%s-%d: Conflicting tx_coalesce_ticks (0) and tx_max_coalesce_frames (0) parameters, using %d and %d respectively\n", + bcm5700_driver, index, TX_COAL_TK, TX_COAL_FM); + + tx_coalesce_ticks[index] = TX_COAL_TK; + tx_max_coalesce_frames[index] = TX_COAL_FM; + } + pDevice->TxCoalescingTicks = tx_coalesce_ticks[index]; + bcm5700_validate_param_range(pUmDevice, + &tx_max_coalesce_frames[index], + "tx_max_coalesce_frames", 0, + MAX_TX_MAX_COALESCED_FRAMES, TX_COAL_FM); + pDevice->TxMaxCoalescedFrames = tx_max_coalesce_frames[index]; + pUmDevice->tx_curr_coalesce_frames = + pDevice->TxMaxCoalescedFrames; + + bcm5700_validate_param_range(pUmDevice, + &stats_coalesce_ticks[index], "stats_coalesce_ticks", + 0, MAX_STATS_COALESCING_TICKS, ST_COAL_TK); + if (adaptive_coalesce[index]) { + printk(KERN_WARNING "%s-%d: Invalid stats_coalesce_ticks parameter set with with adaptive_coalesce parameter. Using adaptive_coalesce.\n", bcm5700_driver, index); + }else{ + if ((stats_coalesce_ticks[index] > 0) && + (stats_coalesce_ticks[index] < 100)) { + printk(KERN_WARNING "%s-%d: Invalid stats_coalesce_ticks parameter (%u), using 100\n", bcm5700_driver, index, (unsigned int) stats_coalesce_ticks[index]); + stats_coalesce_ticks[index] = 100; + pDevice->StatsCoalescingTicks = stats_coalesce_ticks[index]; + pDevice->StatsCoalescingTicks = stats_coalesce_ticks[index]; + } + } + } + else { + pUmDevice->rx_curr_coalesce_frames = RX_COAL_FM; + pUmDevice->rx_curr_coalesce_ticks = RX_COAL_TK; + pUmDevice->tx_curr_coalesce_frames = TX_COAL_FM; + } +#endif + + if (T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) { + unsigned int tmpvar; + + tmpvar = pDevice->StatsCoalescingTicks / BCM_TIMER_GRANULARITY; + + /* + * If the result is zero, the request is too demanding. + */ + if (tmpvar == 0) { + tmpvar = 1; + } + + pDevice->StatsCoalescingTicks = tmpvar * BCM_TIMER_GRANULARITY; + + pUmDevice->statstimer_interval = tmpvar; + } + +#ifdef BCM_WOL + bcm5700_validate_param_range(pUmDevice, &enable_wol[index], + "enable_wol", 0, 1, 0); + if (enable_wol[index]) { + pDevice->WakeUpModeCap = LM_WAKE_UP_MODE_MAGIC_PACKET; + pDevice->WakeUpMode = LM_WAKE_UP_MODE_MAGIC_PACKET; + } +#endif +#ifdef INCLUDE_TBI_SUPPORT + if (pDevice->TbiFlags & ENABLE_TBI_FLAG) { + if ((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5704) || + (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5703)) { + /* just poll since we have hardware autoneg. in 5704 */ + pDevice->TbiFlags |= TBI_PURE_POLLING_FLAG; + } + else { + pDevice->TbiFlags |= TBI_POLLING_INTR_FLAG; + } + } +#endif + bcm5700_validate_param_range(pUmDevice, &scatter_gather[index], + "scatter_gather", 0, 1, 1); + bcm5700_validate_param_range(pUmDevice, &tx_checksum[index], + "tx_checksum", 0, 1, 1); + bcm5700_validate_param_range(pUmDevice, &rx_checksum[index], + "rx_checksum", 0, 1, 1); + if (!(pDevice->TaskOffloadCap & LM_TASK_OFFLOAD_TX_TCP_CHECKSUM)) { + if (tx_checksum[index] || rx_checksum[index]) { + + pDevice->TaskToOffload = LM_TASK_OFFLOAD_NONE; + printk(KERN_WARNING "%s-%d: Checksum offload not available on this NIC\n", bcm5700_driver, index); + } + } + else { + if (rx_checksum[index]) { + pDevice->TaskToOffload |= + LM_TASK_OFFLOAD_RX_TCP_CHECKSUM | + LM_TASK_OFFLOAD_RX_UDP_CHECKSUM; + } + if (tx_checksum[index]) { + pDevice->TaskToOffload |= + LM_TASK_OFFLOAD_TX_TCP_CHECKSUM | + LM_TASK_OFFLOAD_TX_UDP_CHECKSUM; + pDevice->Flags |= NO_TX_PSEUDO_HDR_CSUM_FLAG; + } + } +#ifdef BCM_TSO + bcm5700_validate_param_range(pUmDevice, &enable_tso[index], + "enable_tso", 0, 1, 1); + + /* Always enable TSO firmware if supported */ + /* This way we can turn it on or off on the fly */ + if (pDevice->TaskOffloadCap & LM_TASK_OFFLOAD_TCP_SEGMENTATION) + { + pDevice->TaskToOffload |= + LM_TASK_OFFLOAD_TCP_SEGMENTATION; + } + if (enable_tso[index] && + !(pDevice->TaskToOffload & LM_TASK_OFFLOAD_TCP_SEGMENTATION)) + { + printk(KERN_WARNING "%s-%d: TSO not available on this NIC\n", bcm5700_driver, index); + } +#endif +#ifdef BCM_ASF + bcm5700_validate_param_range(pUmDevice, &vlan_tag_mode[index], + "vlan_strip_mode", 0, 2, 0); + pUmDevice->vlan_tag_mode = vlan_tag_mode[index]; +#else + pUmDevice->vlan_tag_mode = VLAN_TAG_MODE_NORMAL_STRIP; +#endif + +#endif /* LINUX_KERNEL_VERSION */ + +#ifdef BCM_NIC_SEND_BD + bcm5700_validate_param_range(pUmDevice, &nic_tx_bd[index], "nic_tx_bd", + 0, 1, 0); + if (nic_tx_bd[index]) + pDevice->Flags |= NIC_SEND_BD_FLAG; + if ((pDevice->Flags & ENABLE_PCIX_FIX_FLAG) || + (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5705)) { + if (pDevice->Flags & NIC_SEND_BD_FLAG) { + pDevice->Flags &= ~NIC_SEND_BD_FLAG; + printk(KERN_WARNING "%s-%d: Nic Send BDs not available on this NIC or not possible on this system\n", bcm5700_driver, index); + } + } +#endif +#if defined(CONFIG_PCI_MSI) || defined(CONFIG_PCI_USE_VECTOR) + bcm5700_validate_param_range(pUmDevice, &disable_msi[pUmDevice->index], + "disable_msi", 0, 1, 0); +#endif + + bcm5700_validate_param_range(pUmDevice, &delay_link[index], + "delay_link", 0, 1, 0); + + bcm5700_validate_param_range(pUmDevice, &disable_d3hot[index], + "disable_d3hot", 0, 1, 0); + if (disable_d3hot[index]) { + +#ifdef BCM_WOL + if (enable_wol[index]) { + pDevice->WakeUpModeCap = LM_WAKE_UP_MODE_NONE; + pDevice->WakeUpMode = LM_WAKE_UP_MODE_NONE; + printk(KERN_WARNING "%s-%d: Wake-On-Lan disabled because D3Hot is disabled\n", bcm5700_driver, index); + } +#endif + pDevice->Flags |= DISABLE_D3HOT_FLAG; + } + + return LM_STATUS_SUCCESS; +} + +/* From include/proto/ethernet.h */ +#define ETHER_TYPE_8021Q 0x8100 /* 802.1Q */ + +/* From include/proto/vlan.h */ +#define VLAN_PRI_MASK 7 /* 3 bits of priority */ +#define VLAN_PRI_SHIFT 13 + +/* Replace the priority in a vlan tag */ +#define UPD_VLANTAG_PRIO(tag, prio) do { \ + tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT); \ + tag |= prio << VLAN_PRI_SHIFT; \ +} while (0) + +/* Takes an Ethernet frame and sets out-of-bound PKTPRIO. + * Also updates the inplace vlan tag if requested. + * For debugging, it returns an indication of what it did. + */ +#define PKTPRIO_VDSCP 0x100 /* DSCP prio found after VLAN tag */ +#define PKTPRIO_VLAN 0x200 /* VLAN prio found */ +#define PKTPRIO_UPD 0x400 /* DSCP used to update VLAN prio */ +#define PKTPRIO_DSCP 0x800 /* DSCP prio found */ +#define PKTSETPRIO(skb, x) (((struct sk_buff*)(skb))->priority = (x)) +static uint +pktsetprio(void *pkt, bool update_vtag) +{ + struct ether_header *eh; + struct ethervlan_header *evh; + uint8 *pktdata; + int priority = 0; + int rc = 0; + + pktdata = (uint8 *) PKTDATA(NULL, pkt); + ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16))); + + eh = (struct ether_header *) pktdata; + + if (ntoh16(eh->ether_type) == ETHER_TYPE_8021Q) { + uint16 vlan_tag; + int vlan_prio, dscp_prio = 0; + + evh = (struct ethervlan_header *)eh; + + vlan_tag = ntoh16(evh->vlan_tag); + vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK; + + if (ntoh16(evh->ether_type) == ETHER_TYPE_IP) { + uint8 *ip_body = pktdata + sizeof(struct ethervlan_header); + uint8 tos_tc = IP_TOS(ip_body); + dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); + if ((IP_VER(ip_body) == IP_VER_4) && (IPV4_PROT(ip_body) == IP_PROT_TCP)) { + int ip_len; + int src_port; + bool src_port_exc; + uint8 *tcp_hdr; + + ip_len = IPV4_PAYLOAD_LEN(ip_body); + tcp_hdr = IPV4_NO_OPTIONS_PAYLOAD(ip_body); + src_port = TCP_SRC_PORT(tcp_hdr); + src_port_exc = (src_port == 10110) || (src_port == 10120) || + (src_port == 10130) || (src_port == 10140); + + if ((ip_len == 40) && src_port_exc && TCP_IS_ACK(tcp_hdr)) { + dscp_prio = 7; + } + } + } + + /* DSCP priority gets precedence over 802.1P (vlan tag) */ + if (dscp_prio != 0) { + priority = dscp_prio; + rc |= PKTPRIO_VDSCP; + } else { + priority = vlan_prio; + rc |= PKTPRIO_VLAN; + } + /* + * If the DSCP priority is not the same as the VLAN priority, + * then overwrite the priority field in the vlan tag, with the + * DSCP priority value. This is required for Linux APs because + * the VLAN driver on Linux, overwrites the skb->priority field + * with the priority value in the vlan tag + */ + if (update_vtag && (priority != vlan_prio)) { + vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT); + vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT; + evh->vlan_tag = hton16(vlan_tag); + rc |= PKTPRIO_UPD; + } + } else if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) { + uint8 *ip_body = pktdata + sizeof(struct ether_header); + uint8 tos_tc = IP_TOS(ip_body); + priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT); + rc |= PKTPRIO_DSCP; + if ((IP_VER(ip_body) == IP_VER_4) && (IPV4_PROT(ip_body) == IP_PROT_TCP)) { + int ip_len; + int src_port; + bool src_port_exc; + uint8 *tcp_hdr; + + ip_len = IPV4_PAYLOAD_LEN(ip_body); + tcp_hdr = IPV4_NO_OPTIONS_PAYLOAD(ip_body); + src_port = TCP_SRC_PORT(tcp_hdr); + src_port_exc = (src_port == 10110) || (src_port == 10120) || + (src_port == 10130) || (src_port == 10140); + + if ((ip_len == 40) && src_port_exc && TCP_IS_ACK(tcp_hdr)) { + priority = 7; + } + } + } + + ASSERT(priority >= 0 && priority <= MAXPRIO); + PKTSETPRIO(pkt, priority); + return (rc | priority); +} + +LM_STATUS +MM_IndicateRxPackets(PLM_DEVICE_BLOCK pDevice) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice; + PLM_PACKET pPacket; + PUM_PACKET pUmPacket; + struct sk_buff *skb; + int size; + int vlan_tag_size = 0; + uint16 dscp_prio; + + if (pDevice->ReceiveMask & LM_KEEP_VLAN_TAG) + vlan_tag_size = 4; + + while (1) { + pPacket = (PLM_PACKET) + QQ_PopHead(&pDevice->RxPacketReceivedQ.Container); + if (pPacket == 0) + break; + pUmPacket = (PUM_PACKET) pPacket; +#if !defined(NO_PCI_UNMAP) + pci_unmap_single(pUmDevice->pdev, + pci_unmap_addr(pUmPacket, map[0]), + pPacket->u.Rx.RxBufferSize, + PCI_DMA_FROMDEVICE); +#endif + if ((pPacket->PacketStatus != LM_STATUS_SUCCESS) || + ((size = pPacket->PacketSize) > + (pDevice->RxMtu + vlan_tag_size))) { + + /* reuse skb */ +#ifdef BCM_TASKLET + QQ_PushTail(&pUmDevice->rx_out_of_buf_q.Container, pPacket); +#else + QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket); +#endif + pUmDevice->rx_misc_errors++; + continue; + } + skb = pUmPacket->skbuff; + skb_put(skb, size); + skb->pkt_type = 0; + /* Extract priority from payload and put it in skb->priority */ + dscp_prio = 0; + if (pUmDevice->qos) { + uint rc; + + rc = pktsetprio(skb, TRUE); + if (rc & (PKTPRIO_VDSCP | PKTPRIO_DSCP)) + dscp_prio = rc & VLAN_PRI_MASK; + if (rc != 0) + B57_INFO(("pktsetprio returned 0x%x, skb->priority: %d\n", + rc, skb->priority)); + } + skb->protocol = eth_type_trans(skb, skb->dev); + if (size > pDevice->RxMtu) { + /* Make sure we have a valid VLAN tag */ + if (htons(skb->protocol) != ETHER_TYPE_8021Q) { + dev_kfree_skb_irq(skb); + pUmDevice->rx_misc_errors++; + goto drop_rx; + } + } + + pUmDevice->stats.rx_bytes += skb->len; + + if ((pPacket->Flags & RCV_BD_FLAG_TCP_UDP_CHKSUM_FIELD) && + (pDevice->TaskToOffload & + LM_TASK_OFFLOAD_RX_TCP_CHECKSUM)) { + if (pPacket->u.Rx.TcpUdpChecksum == 0xffff) { + + skb->ip_summed = CHECKSUM_UNNECESSARY; +#if TIGON3_DEBUG + pUmDevice->rx_good_chksum_count++; +#endif + } + else { + skb->ip_summed = CHECKSUM_NONE; + pUmDevice->rx_bad_chksum_count++; + } + } + else { + skb->ip_summed = CHECKSUM_NONE; + } + { +#ifdef BCM_VLAN + if (pUmDevice->vlgrp && + (pPacket->Flags & RCV_BD_FLAG_VLAN_TAG)) { + /* Override vlan priority with dscp priority */ + if (dscp_prio) + UPD_VLANTAG_PRIO(pPacket->VlanTag, dscp_prio); +#ifdef BCM_NAPI_RXPOLL + vlan_hwaccel_receive_skb(skb, pUmDevice->vlgrp, + pPacket->VlanTag); +#else + vlan_hwaccel_rx(skb, pUmDevice->vlgrp, + pPacket->VlanTag); +#endif + } else +#endif + { +#ifdef BCM_WL_EMULATOR + if(pDevice->wl_emulate_rx) { + /* bcmstats("emu recv %d %d"); */ + wlcemu_receive_skb(pDevice->wlc, skb); + /* bcmstats("emu recv end %d %d"); */ + } + else +#endif /* BCM_WL_EMULATOR */ + { +#ifdef BCM_NAPI_RXPOLL + netif_receive_skb(skb); +#else + netif_rx(skb); +#endif + } + } + } + pUmDevice->dev->last_rx = jiffies; + +drop_rx: +#ifdef BCM_TASKLET + pUmPacket->skbuff = 0; + QQ_PushTail(&pUmDevice->rx_out_of_buf_q.Container, pPacket); +#else +#ifdef BCM_WL_EMULATOR + skb = (struct sk_buff *)wlcemu_pktget(pDevice->wlc,pPacket->u.Rx.RxBufferSize + 2); +#else + skb = dev_alloc_skb(pPacket->u.Rx.RxBufferSize + 2 + EXTRA_HDR); +#endif /* BCM_WL_EMULATOR */ + if (skb == 0) { + pUmPacket->skbuff = 0; + QQ_PushTail(&pUmDevice->rx_out_of_buf_q.Container, pPacket); + } + else { + pUmPacket->skbuff = skb; + skb->dev = pUmDevice->dev; +#ifndef BCM_WL_EMULATOR + skb_reserve(skb, EXTRA_HDR - pUmDevice->rx_buf_align); +#endif + QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket); + } +#endif + } + return LM_STATUS_SUCCESS; +} + +LM_STATUS +MM_CoalesceTxBuffer(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket) +{ + PUM_PACKET pUmPacket = (PUM_PACKET) pPacket; + struct sk_buff *skb = pUmPacket->skbuff; + struct sk_buff *nskb; +#if !defined(NO_PCI_UNMAP) + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice; + + pci_unmap_single(pUmDevice->pdev, + pci_unmap_addr(pUmPacket, map[0]), + pci_unmap_len(pUmPacket, map_len[0]), + PCI_DMA_TODEVICE); +#if MAX_SKB_FRAGS + { + int i; + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + pci_unmap_page(pUmDevice->pdev, + pci_unmap_addr(pUmPacket, map[i + 1]), + pci_unmap_len(pUmPacket, map_len[i + 1]), + PCI_DMA_TODEVICE); + } + } +#endif +#endif + if ((nskb = skb_copy(skb, GFP_ATOMIC))) { + pUmPacket->lm_packet.u.Tx.FragCount = 1; + dev_kfree_skb(skb); + pUmPacket->skbuff = nskb; + return LM_STATUS_SUCCESS; + } + dev_kfree_skb(skb); + pUmPacket->skbuff = 0; + return LM_STATUS_FAILURE; +} + +/* Returns 1 if not all buffers are allocated */ +STATIC int +replenish_rx_buffers(PUM_DEVICE_BLOCK pUmDevice, int max) +{ + PLM_PACKET pPacket; + PUM_PACKET pUmPacket; + PLM_DEVICE_BLOCK pDevice = (PLM_DEVICE_BLOCK) pUmDevice; + struct sk_buff *skb; + int queue_rx = 0; + int alloc_cnt = 0; + int ret = 0; + + while ((pUmPacket = (PUM_PACKET) + QQ_PopHead(&pUmDevice->rx_out_of_buf_q.Container)) != 0) { + pPacket = (PLM_PACKET) pUmPacket; + if (pUmPacket->skbuff) { + /* reuse an old skb */ + QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket); + queue_rx = 1; + continue; + } +#ifdef BCM_WL_EMULATOR + if ((skb = (struct sk_buff *)wlcemu_pktget(pDevice->wlc,pPacket->u.Rx.RxBufferSize + 2)) == 0) +#else + if ((skb = dev_alloc_skb(pPacket->u.Rx.RxBufferSize + 2 + EXTRA_HDR)) == 0) +#endif /* BCM_WL_EMULATOR */ + { + QQ_PushHead(&pUmDevice->rx_out_of_buf_q.Container, + pPacket); + ret = 1; + break; + } + pUmPacket->skbuff = skb; + skb->dev = pUmDevice->dev; +#ifndef BCM_WL_EMULATOR + skb_reserve(skb, EXTRA_HDR - pUmDevice->rx_buf_align); +#endif + QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket); + queue_rx = 1; + if (max > 0) { + alloc_cnt++; + if (alloc_cnt >= max) + break; + } + } + if (queue_rx || pDevice->QueueAgain) { + LM_QueueRxPackets(pDevice); + } + return ret; +} + +LM_STATUS +MM_IndicateTxPackets(PLM_DEVICE_BLOCK pDevice) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice; + PLM_PACKET pPacket; + PUM_PACKET pUmPacket; + struct sk_buff *skb; +#if !defined(NO_PCI_UNMAP) && MAX_SKB_FRAGS + int i; +#endif + + while (1) { + pPacket = (PLM_PACKET) + QQ_PopHead(&pDevice->TxPacketXmittedQ.Container); + if (pPacket == 0) + break; + pUmPacket = (PUM_PACKET) pPacket; + skb = pUmPacket->skbuff; +#if !defined(NO_PCI_UNMAP) + pci_unmap_single(pUmDevice->pdev, + pci_unmap_addr(pUmPacket, map[0]), + pci_unmap_len(pUmPacket, map_len[0]), + PCI_DMA_TODEVICE); +#if MAX_SKB_FRAGS + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + pci_unmap_page(pUmDevice->pdev, + pci_unmap_addr(pUmPacket, map[i + 1]), + pci_unmap_len(pUmPacket, map_len[i + 1]), + PCI_DMA_TODEVICE); + } +#endif +#endif + dev_kfree_skb_irq(skb); + pUmPacket->skbuff = 0; + QQ_PushTail(&pDevice->TxPacketFreeQ.Container, pPacket); + } + if (pUmDevice->tx_full) { + if (QQ_GetEntryCnt(&pDevice->TxPacketFreeQ.Container) >= + (pDevice->TxPacketDescCnt >> 1)) { + + pUmDevice->tx_full = 0; + netif_wake_queue(pUmDevice->dev); + } + } + return LM_STATUS_SUCCESS; +} + +LM_STATUS +MM_IndicateStatus(PLM_DEVICE_BLOCK pDevice, LM_STATUS Status) +{ + PUM_DEVICE_BLOCK pUmDevice = (PUM_DEVICE_BLOCK) pDevice; + struct net_device *dev = pUmDevice->dev; + LM_FLOW_CONTROL flow_control; + int speed = 0; + + if (!pUmDevice->opened) + return LM_STATUS_SUCCESS; + + if (!pUmDevice->suspended) { + if (Status == LM_STATUS_LINK_DOWN) { + netif_carrier_off(dev); + } + else if (Status == LM_STATUS_LINK_ACTIVE) { + netif_carrier_on(dev); + } + } + + if (pUmDevice->delayed_link_ind > 0) { + pUmDevice->delayed_link_ind = 0; + if (Status == LM_STATUS_LINK_DOWN) { + B57_INFO(("%s: %s NIC Link is DOWN\n", bcm5700_driver, dev->name)); + } + else if (Status == LM_STATUS_LINK_ACTIVE) { + B57_INFO(("%s: %s NIC Link is UP, ", bcm5700_driver, dev->name)); + } + } + else { + if (Status == LM_STATUS_LINK_DOWN) { + B57_INFO(("%s: %s NIC Link is Down\n", bcm5700_driver, dev->name)); + } + else if (Status == LM_STATUS_LINK_ACTIVE) { + B57_INFO(("%s: %s NIC Link is Up, ", bcm5700_driver, dev->name)); + } + } + + if (Status == LM_STATUS_LINK_ACTIVE) { + if (pDevice->LineSpeed == LM_LINE_SPEED_1000MBPS) + speed = 1000; + else if (pDevice->LineSpeed == LM_LINE_SPEED_100MBPS) + speed = 100; + else if (pDevice->LineSpeed == LM_LINE_SPEED_10MBPS) + speed = 10; + + B57_INFO(("%d Mbps ", speed)); + + if (pDevice->DuplexMode == LM_DUPLEX_MODE_FULL) + B57_INFO(("full duplex")); + else + B57_INFO(("half duplex")); + + flow_control = pDevice->FlowControl & + (LM_FLOW_CONTROL_RECEIVE_PAUSE | + LM_FLOW_CONTROL_TRANSMIT_PAUSE); + if (flow_control) { + if (flow_control & LM_FLOW_CONTROL_RECEIVE_PAUSE) { + B57_INFO((", receive ")); + if (flow_control & LM_FLOW_CONTROL_TRANSMIT_PAUSE) + B57_INFO(("& transmit ")); + } + else { + B57_INFO((", transmit ")); + } + B57_INFO(("flow control ON")); + } + B57_INFO(("\n")); + } + return LM_STATUS_SUCCESS; +} + +void +MM_UnmapRxDma(LM_DEVICE_BLOCK *pDevice, LM_PACKET *pPacket) +{ +#if !defined(NO_PCI_UNMAP) + UM_DEVICE_BLOCK *pUmDevice = (UM_DEVICE_BLOCK *) pDevice; + UM_PACKET *pUmPacket = (UM_PACKET *) pPacket; + + if (!pUmPacket->skbuff) + return; + + pci_unmap_single(pUmDevice->pdev, + pci_unmap_addr(pUmPacket, map[0]), + pPacket->u.Rx.RxBufferSize, + PCI_DMA_FROMDEVICE); +#endif +} + +LM_STATUS +MM_FreeRxBuffer(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket) +{ + PUM_PACKET pUmPacket; + struct sk_buff *skb; + + if (pPacket == 0) + return LM_STATUS_SUCCESS; + pUmPacket = (PUM_PACKET) pPacket; + if ((skb = pUmPacket->skbuff)) { + /* DMA address already unmapped */ + dev_kfree_skb(skb); + } + pUmPacket->skbuff = 0; + return LM_STATUS_SUCCESS; +} + +LM_STATUS +MM_Sleep(LM_DEVICE_BLOCK *pDevice, LM_UINT32 msec) +{ + current->state = TASK_INTERRUPTIBLE; + if (schedule_timeout(HZ * msec / 1000) != 0) { + return LM_STATUS_FAILURE; + } + if (signal_pending(current)) + return LM_STATUS_FAILURE; + + return LM_STATUS_SUCCESS; +} + +void +bcm5700_shutdown(UM_DEVICE_BLOCK *pUmDevice) +{ + LM_DEVICE_BLOCK *pDevice = (LM_DEVICE_BLOCK *) pUmDevice; + + bcm5700_intr_off(pUmDevice); + netif_carrier_off(pUmDevice->dev); +#ifdef BCM_TASKLET + tasklet_kill(&pUmDevice->tasklet); +#endif + bcm5700_poll_wait(pUmDevice); + + LM_Halt(pDevice); + + pDevice->InitDone = 0; + bcm5700_free_remaining_rx_bufs(pUmDevice); +} + +void +bcm5700_free_remaining_rx_bufs(UM_DEVICE_BLOCK *pUmDevice) +{ + LM_DEVICE_BLOCK *pDevice = &pUmDevice->lm_dev; + UM_PACKET *pUmPacket; + int cnt, i; + + cnt = QQ_GetEntryCnt(&pUmDevice->rx_out_of_buf_q.Container); + for (i = 0; i < cnt; i++) { + if ((pUmPacket = + QQ_PopHead(&pUmDevice->rx_out_of_buf_q.Container)) + != 0) { + + MM_UnmapRxDma(pDevice, (LM_PACKET *) pUmPacket); + MM_FreeRxBuffer(pDevice, &pUmPacket->lm_packet); + QQ_PushTail(&pDevice->RxPacketFreeQ.Container, + pUmPacket); + } + } +} + +void +bcm5700_validate_param_range(UM_DEVICE_BLOCK *pUmDevice, int *param, + char *param_name, int min, int max, int deflt) +{ + if (((unsigned int) *param < (unsigned int) min) || + ((unsigned int) *param > (unsigned int) max)) { + + printk(KERN_WARNING "%s-%d: Invalid %s parameter (%u), using %u\n", bcm5700_driver, pUmDevice->index, param_name, (unsigned int) *param, (unsigned int) deflt); + *param = deflt; + } +} + +struct net_device * +bcm5700_find_peer(struct net_device *dev) +{ + struct net_device *tmp_dev; + UM_DEVICE_BLOCK *pUmDevice, *pUmTmp; + LM_DEVICE_BLOCK *pDevice; + + tmp_dev = 0; + pUmDevice = (UM_DEVICE_BLOCK *) dev->priv; + pDevice = &pUmDevice->lm_dev; + if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5704) { + tmp_dev = root_tigon3_dev; + while (tmp_dev) { + pUmTmp = (PUM_DEVICE_BLOCK) tmp_dev->priv; + if ((tmp_dev != dev) && + (pUmDevice->pdev->bus->number == + pUmTmp->pdev->bus->number) && + PCI_SLOT(pUmDevice->pdev->devfn) == + PCI_SLOT(pUmTmp->pdev->devfn)) { + + break; + } + tmp_dev = pUmTmp->next_module; + } + } + return tmp_dev; +} + +LM_DEVICE_BLOCK * +MM_FindPeerDev(LM_DEVICE_BLOCK *pDevice) +{ + UM_DEVICE_BLOCK *pUmDevice = (UM_DEVICE_BLOCK *) pDevice; + struct net_device *dev = pUmDevice->dev; + struct net_device *peer_dev; + + peer_dev = bcm5700_find_peer(dev); + if (!peer_dev) + return 0; + return ((LM_DEVICE_BLOCK *) peer_dev->priv); +} + +int MM_FindCapability(LM_DEVICE_BLOCK *pDevice, int capability) +{ + UM_DEVICE_BLOCK *pUmDevice = (UM_DEVICE_BLOCK *) pDevice; + return (pci_find_capability(pUmDevice->pdev, capability)); +} + +#if defined(HAVE_POLL_CONTROLLER)||defined(CONFIG_NET_POLL_CONTROLLER) +STATIC void +poll_bcm5700(struct net_device *dev) +{ + UM_DEVICE_BLOCK *pUmDevice = dev->priv; + +#if defined(RED_HAT_LINUX_KERNEL) && (LINUX_VERSION_CODE < 0x020605) + if (netdump_mode) { + bcm5700_interrupt(pUmDevice->pdev->irq, dev, NULL); +#ifdef BCM_NAPI_RXPOLL + if (dev->poll_list.prev) { + int budget = 64; + + bcm5700_poll(dev, &budget); + } +#endif + } + else +#endif + { + disable_irq(pUmDevice->pdev->irq); + bcm5700_interrupt(pUmDevice->pdev->irq, dev, NULL); + enable_irq(pUmDevice->pdev->irq); + } +} +#endif diff --git a/package/broadcom-57xx/src/bcmendian.h b/package/broadcom-57xx/src/bcmendian.h new file mode 100644 index 0000000000..dc26d51fff --- /dev/null +++ b/package/broadcom-57xx/src/bcmendian.h @@ -0,0 +1,198 @@ +/* + * local version of endian.h - byte order defines + * + * Copyright 2007, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * + * $Id: bcmendian.h,v 1.1.1.11 2007/05/31 08:00:41 michael Exp $ +*/ + +#ifndef _BCMENDIAN_H_ +#define _BCMENDIAN_H_ + +#include + +/* Byte swap a 16 bit value */ +#define BCMSWAP16(val) \ + ((uint16)(\ + (((uint16)(val) & (uint16)0x00ffU) << 8) | \ + (((uint16)(val) & (uint16)0xff00U) >> 8))) + +/* Byte swap a 32 bit value */ +#define BCMSWAP32(val) \ + ((uint32)(\ + (((uint32)(val) & (uint32)0x000000ffUL) << 24) | \ + (((uint32)(val) & (uint32)0x0000ff00UL) << 8) | \ + (((uint32)(val) & (uint32)0x00ff0000UL) >> 8) | \ + (((uint32)(val) & (uint32)0xff000000UL) >> 24))) + +/* 2 Byte swap a 32 bit value */ +#define BCMSWAP32BY16(val) \ + ((uint32)(\ + (((uint32)(val) & (uint32)0x0000ffffUL) << 16) | \ + (((uint32)(val) & (uint32)0xffff0000UL) >> 16))) + + +static INLINE uint16 +bcmswap16(uint16 val) +{ + return BCMSWAP16(val); +} + +static INLINE uint32 +bcmswap32(uint32 val) +{ + return BCMSWAP32(val); +} + +static INLINE uint32 +bcmswap32by16(uint32 val) +{ + return BCMSWAP32BY16(val); +} + +/* buf - start of buffer of shorts to swap */ +/* len - byte length of buffer */ +static INLINE void +bcmswap16_buf(uint16 *buf, uint len) +{ + len = len/2; + + while (len--) { + *buf = bcmswap16(*buf); + buf++; + } +} + +#ifndef hton16 +#ifndef IL_BIGENDIAN +#define HTON16(i) BCMSWAP16(i) +#define hton16(i) bcmswap16(i) +#define hton32(i) bcmswap32(i) +#define ntoh16(i) bcmswap16(i) +#define ntoh32(i) bcmswap32(i) +#define ltoh16(i) (i) +#define ltoh32(i) (i) +#define htol16(i) (i) +#define htol32(i) (i) +#else +#define HTON16(i) (i) +#define hton16(i) (i) +#define hton32(i) (i) +#define ntoh16(i) (i) +#define ntoh32(i) (i) +#define ltoh16(i) bcmswap16(i) +#define ltoh32(i) bcmswap32(i) +#define htol16(i) bcmswap16(i) +#define htol32(i) bcmswap32(i) +#endif /* IL_BIGENDIAN */ +#endif /* hton16 */ + +#ifndef IL_BIGENDIAN +#define ltoh16_buf(buf, i) +#define htol16_buf(buf, i) +#else +#define ltoh16_buf(buf, i) bcmswap16_buf((uint16*)buf, i) +#define htol16_buf(buf, i) bcmswap16_buf((uint16*)buf, i) +#endif /* IL_BIGENDIAN */ + +/* +* store 16-bit value to unaligned little endian byte array. +*/ +static INLINE void +htol16_ua_store(uint16 val, uint8 *bytes) +{ + bytes[0] = val&0xff; + bytes[1] = val>>8; +} + +/* +* store 32-bit value to unaligned little endian byte array. +*/ +static INLINE void +htol32_ua_store(uint32 val, uint8 *bytes) +{ + bytes[0] = val&0xff; + bytes[1] = (val>>8)&0xff; + bytes[2] = (val>>16)&0xff; + bytes[3] = val>>24; +} + +/* +* store 16-bit value to unaligned network(big) endian byte array. +*/ +static INLINE void +hton16_ua_store(uint16 val, uint8 *bytes) +{ + bytes[1] = val&0xff; + bytes[0] = val>>8; +} + +/* +* store 32-bit value to unaligned network(big) endian byte array. +*/ +static INLINE void +hton32_ua_store(uint32 val, uint8 *bytes) +{ + bytes[3] = val&0xff; + bytes[2] = (val>>8)&0xff; + bytes[1] = (val>>16)&0xff; + bytes[0] = val>>24; +} + +/* +* load 16-bit value from unaligned little endian byte array. +*/ +static INLINE uint16 +ltoh16_ua(void *bytes) +{ + return (((uint8*)bytes)[1]<<8)+((uint8 *)bytes)[0]; +} + +/* +* load 32-bit value from unaligned little endian byte array. +*/ +static INLINE uint32 +ltoh32_ua(void *bytes) +{ + return (((uint8*)bytes)[3]<<24)+(((uint8*)bytes)[2]<<16)+ + (((uint8*)bytes)[1]<<8)+((uint8*)bytes)[0]; +} + +/* +* load 16-bit value from unaligned big(network) endian byte array. +*/ +static INLINE uint16 +ntoh16_ua(void *bytes) +{ + return (((uint8*)bytes)[0]<<8)+((uint8*)bytes)[1]; +} + +/* +* load 32-bit value from unaligned big(network) endian byte array. +*/ +static INLINE uint32 +ntoh32_ua(void *bytes) +{ + return (((uint8*)bytes)[0]<<24)+(((uint8*)bytes)[1]<<16)+ + (((uint8*)bytes)[2]<<8)+((uint8*)bytes)[3]; +} + +#define ltoh_ua(ptr) (\ + sizeof(*(ptr)) == sizeof(uint8) ? *(uint8 *)ptr : \ + sizeof(*(ptr)) == sizeof(uint16) ? (((uint8 *)ptr)[1]<<8)+((uint8 *)ptr)[0] : \ + (((uint8 *)ptr)[3]<<24)+(((uint8 *)ptr)[2]<<16)+(((uint8 *)ptr)[1]<<8)+((uint8 *)ptr)[0] \ +) + +#define ntoh_ua(ptr) (\ + sizeof(*(ptr)) == sizeof(uint8) ? *(uint8 *)ptr : \ + sizeof(*(ptr)) == sizeof(uint16) ? (((uint8 *)ptr)[0]<<8)+((uint8 *)ptr)[1] : \ + (((uint8 *)ptr)[0]<<24)+(((uint8 *)ptr)[1]<<16)+(((uint8 *)ptr)[2]<<8)+((uint8 *)ptr)[3] \ +) + +#endif /* _BCMENDIAN_H_ */ diff --git a/package/broadcom-57xx/src/bcmparams.h b/package/broadcom-57xx/src/bcmparams.h new file mode 100644 index 0000000000..9445d1b0f3 --- /dev/null +++ b/package/broadcom-57xx/src/bcmparams.h @@ -0,0 +1,25 @@ +/* + * Misc system wide parameters. + * + * Copyright 2007, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * $Id: bcmparams.h,v 1.1.1.5 2007/05/31 08:00:41 michael Exp $ + */ + +#ifndef _bcmparams_h_ +#define _bcmparams_h_ + +#define VLAN_MAXVID 15 /* Max. VLAN ID supported/allowed */ + +#define VLAN_NUMPRIS 8 /* # of prio, start from 0 */ + +#define DEV_NUMIFS 16 /* Max. # of devices/interfaces supported */ + +#define WL_MAXBSSCFG 16 /* maximum number of BSS Configs we can configure */ + +#endif diff --git a/package/broadcom-57xx/src/bcmrobo.c b/package/broadcom-57xx/src/bcmrobo.c new file mode 100644 index 0000000000..72824f6f62 --- /dev/null +++ b/package/broadcom-57xx/src/bcmrobo.c @@ -0,0 +1,1329 @@ +/* + * Broadcom BCM5325E/536x switch configuration module + * + * Copyright (C) 2007 Felix Fietkau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Based on: + * Broadcom 53xx RoboSwitch device driver. + * + * Copyright 2007, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + */ + + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "bcmparams.h" +#include +#include +#include "bcmrobo.h" +#include "proto/ethernet.h" +#include + +#define DRIVER_NAME "bcm57xx" +#define DRIVER_VERSION "0.1" + +#ifndef GPIO_PIN_NOTDEFINED +#define GPIO_PIN_NOTDEFINED 0x20 +#endif + +#ifdef BCMDBG +#define ET_ERROR(args) printk args +#else /* BCMDBG */ +#define ET_ERROR(args) +#endif /* BCMDBG */ +#define ET_MSG(args) + +/* + * Switch can be programmed through SPI interface, which + * has a rreg and a wreg functions to read from and write to + * registers. + */ + +/* MII access registers */ +#define PSEUDO_PHYAD 0x1E /* MII Pseudo PHY address */ +#define REG_MII_PAGE 0x10 /* MII Page register */ +#define REG_MII_ADDR 0x11 /* MII Address register */ +#define REG_MII_DATA0 0x18 /* MII Data register 0 */ +#define REG_MII_DATA1 0x19 /* MII Data register 1 */ +#define REG_MII_DATA2 0x1a /* MII Data register 2 */ +#define REG_MII_DATA3 0x1b /* MII Data register 3 */ + +/* Page numbers */ +#define PAGE_CTRL 0x00 /* Control page */ +#define PAGE_MMR 0x02 /* 5397 Management/Mirroring page */ +#define PAGE_VTBL 0x05 /* ARL/VLAN Table access page */ +#define PAGE_VLAN 0x34 /* VLAN page */ + +/* Control page registers */ +#define REG_CTRL_PORT0 0x00 /* Port 0 traffic control register */ +#define REG_CTRL_PORT1 0x01 /* Port 1 traffic control register */ +#define REG_CTRL_PORT2 0x02 /* Port 2 traffic control register */ +#define REG_CTRL_PORT3 0x03 /* Port 3 traffic control register */ +#define REG_CTRL_PORT4 0x04 /* Port 4 traffic control register */ +#define REG_CTRL_PORT5 0x05 /* Port 5 traffic control register */ +#define REG_CTRL_PORT6 0x06 /* Port 6 traffic control register */ +#define REG_CTRL_PORT7 0x07 /* Port 7 traffic control register */ +#define REG_CTRL_MODE 0x0B /* Switch Mode register */ +#define REG_CTRL_MIIPO 0x0E /* 5325: MII Port Override register */ +#define REG_CTRL_SRST 0x79 /* Software reset control register */ + +#define REG_DEVICE_ID 0x30 /* 539x Device id: */ +#define DEVID5325 0x25 /* 5325 (Not really be we fake it) */ +#define DEVID5395 0x95 /* 5395 */ +#define DEVID5397 0x97 /* 5397 */ +#define DEVID5398 0x98 /* 5398 */ + +/* VLAN page registers */ +#define REG_VLAN_CTRL0 0x00 /* VLAN Control 0 register */ +#define REG_VLAN_CTRL1 0x01 /* VLAN Control 1 register */ +#define REG_VLAN_CTRL4 0x04 /* VLAN Control 4 register */ +#define REG_VLAN_CTRL5 0x05 /* VLAN Control 5 register */ +#define REG_VLAN_ACCESS 0x06 /* VLAN Table Access register */ +#define REG_VLAN_WRITE 0x08 /* VLAN Write register */ +#define REG_VLAN_READ 0x0C /* VLAN Read register */ +#define REG_VLAN_PTAG0 0x10 /* VLAN Default Port Tag register - port 0 */ +#define REG_VLAN_PTAG1 0x12 /* VLAN Default Port Tag register - port 1 */ +#define REG_VLAN_PTAG2 0x14 /* VLAN Default Port Tag register - port 2 */ +#define REG_VLAN_PTAG3 0x16 /* VLAN Default Port Tag register - port 3 */ +#define REG_VLAN_PTAG4 0x18 /* VLAN Default Port Tag register - port 4 */ +#define REG_VLAN_PTAG5 0x1a /* VLAN Default Port Tag register - port 5 */ +#define REG_VLAN_PTAG6 0x1c /* VLAN Default Port Tag register - port 6 */ +#define REG_VLAN_PTAG7 0x1e /* VLAN Default Port Tag register - port 7 */ +#define REG_VLAN_PTAG8 0x20 /* 539x: VLAN Default Port Tag register - IMP port */ +#define REG_VLAN_PMAP 0x20 /* 5325: VLAN Priority Re-map register */ + +#define VLAN_NUMVLANS 16 /* # of VLANs */ + + +/* ARL/VLAN Table Access page registers */ +#define REG_VTBL_CTRL 0x00 /* ARL Read/Write Control */ +#define REG_VTBL_MINDX 0x02 /* MAC Address Index */ +#define REG_VTBL_VINDX 0x08 /* VID Table Index */ +#define REG_VTBL_ARL_E0 0x10 /* ARL Entry 0 */ +#define REG_VTBL_ARL_E1 0x18 /* ARL Entry 1 */ +#define REG_VTBL_DAT_E0 0x18 /* ARL Table Data Entry 0 */ +#define REG_VTBL_SCTRL 0x20 /* ARL Search Control */ +#define REG_VTBL_SADDR 0x22 /* ARL Search Address */ +#define REG_VTBL_SRES 0x24 /* ARL Search Result */ +#define REG_VTBL_SREXT 0x2c /* ARL Search Result */ +#define REG_VTBL_VID_E0 0x30 /* VID Entry 0 */ +#define REG_VTBL_VID_E1 0x32 /* VID Entry 1 */ +#define REG_VTBL_PREG 0xFF /* Page Register */ +#define REG_VTBL_ACCESS 0x60 /* VLAN table access register */ +#define REG_VTBL_INDX 0x61 /* VLAN table address index register */ +#define REG_VTBL_ENTRY 0x63 /* VLAN table entry register */ +#define REG_VTBL_ACCESS_5395 0x80 /* VLAN table access register */ +#define REG_VTBL_INDX_5395 0x81 /* VLAN table address index register */ +#define REG_VTBL_ENTRY_5395 0x83 /* VLAN table entry register */ + +/* SPI registers */ +#define REG_SPI_PAGE 0xff /* SPI Page register */ + +/* Access switch registers through GPIO/SPI */ + +/* Minimum timing constants */ +#define SCK_EDGE_TIME 2 /* clock edge duration - 2us */ +#define MOSI_SETUP_TIME 1 /* input setup duration - 1us */ +#define SS_SETUP_TIME 1 /* select setup duration - 1us */ + +/* misc. constants */ +#define SPI_MAX_RETRY 100 + +static int config_attach(robo_info_t *robo); +static void config_detach(robo_info_t *robo); + +/* Enable GPIO access to the chip */ +static void +gpio_enable(robo_info_t *robo) +{ + /* Enable GPIO outputs with SCK and MOSI low, SS high */ + sb_gpioout(robo->sbh, robo->ss | robo->sck | robo->mosi, robo->ss, GPIO_DRV_PRIORITY); + sb_gpioouten(robo->sbh, robo->ss | robo->sck | robo->mosi, + robo->ss | robo->sck | robo->mosi, GPIO_DRV_PRIORITY); +} + +/* Disable GPIO access to the chip */ +static void +gpio_disable(robo_info_t *robo) +{ + /* Disable GPIO outputs with all their current values */ + sb_gpioouten(robo->sbh, robo->ss | robo->sck | robo->mosi, 0, GPIO_DRV_PRIORITY); +} + +/* Write a byte stream to the chip thru SPI */ +static int +spi_write(robo_info_t *robo, uint8 *buf, uint len) +{ + uint i; + uint8 mask; + + /* Byte bang from LSB to MSB */ + for (i = 0; i < len; i++) { + /* Bit bang from MSB to LSB */ + for (mask = 0x80; mask; mask >>= 1) { + /* Clock low */ + sb_gpioout(robo->sbh, robo->sck, 0, GPIO_DRV_PRIORITY); + OSL_DELAY(SCK_EDGE_TIME); + + /* Sample on rising edge */ + if (mask & buf[i]) + sb_gpioout(robo->sbh, robo->mosi, robo->mosi, GPIO_DRV_PRIORITY); + else + sb_gpioout(robo->sbh, robo->mosi, 0, GPIO_DRV_PRIORITY); + OSL_DELAY(MOSI_SETUP_TIME); + + /* Clock high */ + sb_gpioout(robo->sbh, robo->sck, robo->sck, GPIO_DRV_PRIORITY); + OSL_DELAY(SCK_EDGE_TIME); + } + } + + return 0; +} + +/* Read a byte stream from the chip thru SPI */ +static int +spi_read(robo_info_t *robo, uint8 *buf, uint len) +{ + uint i, timeout; + uint8 rack, mask, byte; + + /* Timeout after 100 tries without RACK */ + for (i = 0, rack = 0, timeout = SPI_MAX_RETRY; i < len && timeout;) { + /* Bit bang from MSB to LSB */ + for (mask = 0x80, byte = 0; mask; mask >>= 1) { + /* Clock low */ + sb_gpioout(robo->sbh, robo->sck, 0, GPIO_DRV_PRIORITY); + OSL_DELAY(SCK_EDGE_TIME); + + /* Sample on falling edge */ + if (sb_gpioin(robo->sbh) & robo->miso) + byte |= mask; + + /* Clock high */ + sb_gpioout(robo->sbh, robo->sck, robo->sck, GPIO_DRV_PRIORITY); + OSL_DELAY(SCK_EDGE_TIME); + } + /* RACK when bit 0 is high */ + if (!rack) { + rack = (byte & 1); + timeout--; + continue; + } + /* Byte bang from LSB to MSB */ + buf[i] = byte; + i++; + } + + if (timeout == 0) { + ET_ERROR(("spi_read: timeout")); + return -1; + } + + return 0; +} + +/* Enable/disable SPI access */ +static void +spi_select(robo_info_t *robo, uint8 spi) +{ + if (spi) { + /* Enable SPI access */ + sb_gpioout(robo->sbh, robo->ss, 0, GPIO_DRV_PRIORITY); + } else { + /* Disable SPI access */ + sb_gpioout(robo->sbh, robo->ss, robo->ss, GPIO_DRV_PRIORITY); + } + OSL_DELAY(SS_SETUP_TIME); +} + + +/* Select chip and page */ +static void +spi_goto(robo_info_t *robo, uint8 page) +{ + uint8 reg8 = REG_SPI_PAGE; /* page select register */ + uint8 cmd8; + + /* Issue the command only when we are on a different page */ + if (robo->page == page) + return; + + robo->page = page; + + /* Enable SPI access */ + spi_select(robo, 1); + + /* Select new page with CID 0 */ + cmd8 = ((6 << 4) | /* normal SPI */ + 1); /* write */ + spi_write(robo, &cmd8, 1); + spi_write(robo, ®8, 1); + spi_write(robo, &page, 1); + + /* Disable SPI access */ + spi_select(robo, 0); +} + +/* Write register thru SPI */ +static int +spi_wreg(robo_info_t *robo, uint8 page, uint8 addr, void *val, int len) +{ + int status = 0; + uint8 cmd8; + union { + uint8 val8; + uint16 val16; + uint32 val32; + } bytes; + + /* validate value length and buffer address */ + ASSERT(len == 1 || (len == 2 && !((int)val & 1)) || + (len == 4 && !((int)val & 3))); + + /* Select chip and page */ + spi_goto(robo, page); + + /* Enable SPI access */ + spi_select(robo, 1); + + /* Write with CID 0 */ + cmd8 = ((6 << 4) | /* normal SPI */ + 1); /* write */ + spi_write(robo, &cmd8, 1); + spi_write(robo, &addr, 1); + switch (len) { + case 1: + bytes.val8 = *(uint8 *)val; + break; + case 2: + bytes.val16 = htol16(*(uint16 *)val); + break; + case 4: + bytes.val32 = htol32(*(uint32 *)val); + break; + } + spi_write(robo, (uint8 *)val, len); + + ET_MSG(("%s: [0x%x-0x%x] := 0x%x (len %d)\n", __FUNCTION__, page, addr, + *(uint16 *)val, len)); + /* Disable SPI access */ + spi_select(robo, 0); + return status; +} + +/* Read register thru SPI in fast SPI mode */ +static int +spi_rreg(robo_info_t *robo, uint8 page, uint8 addr, void *val, int len) +{ + int status = 0; + uint8 cmd8; + union { + uint8 val8; + uint16 val16; + uint32 val32; + } bytes; + + /* validate value length and buffer address */ + ASSERT(len == 1 || (len == 2 && !((int)val & 1)) || + (len == 4 && !((int)val & 3))); + + /* Select chip and page */ + spi_goto(robo, page); + + /* Enable SPI access */ + spi_select(robo, 1); + + /* Fast SPI read with CID 0 and byte offset 0 */ + cmd8 = (1 << 4); /* fast SPI */ + spi_write(robo, &cmd8, 1); + spi_write(robo, &addr, 1); + status = spi_read(robo, (uint8 *)&bytes, len); + switch (len) { + case 1: + *(uint8 *)val = bytes.val8; + break; + case 2: + *(uint16 *)val = ltoh16(bytes.val16); + break; + case 4: + *(uint32 *)val = ltoh32(bytes.val32); + break; + } + + ET_MSG(("%s: [0x%x-0x%x] => 0x%x (len %d)\n", __FUNCTION__, page, addr, + *(uint16 *)val, len)); + + /* Disable SPI access */ + spi_select(robo, 0); + return status; +} + +/* SPI/gpio interface functions */ +static dev_ops_t spigpio = { + gpio_enable, + gpio_disable, + spi_wreg, + spi_rreg, + "SPI (GPIO)" +}; + + +/* Access switch registers through MII (MDC/MDIO) */ + +#define MII_MAX_RETRY 100 + +/* Write register thru MDC/MDIO */ +static int +mii_wreg(robo_info_t *robo, uint8 page, uint8 reg, void *val, int len) +{ + uint16 cmd16, val16,val48[3]; + void *h = robo->h; + uint32 val64[2]; + memset(val48,0,6); + memset(val64,0,8); + int i; + uint8 *ptr = (uint8 *)val; + + /* validate value length and buffer address */ + ASSERT(len == 1 || len == 6 || len == 8 || + ((len == 2) && !((int)val & 1)) || ((len == 4) && !((int)val & 3))); + + ET_MSG(("%s: [0x%x-0x%x] := 0x%x (len %d)\n", __FUNCTION__, page, reg, + *(uint16 *)val, len)); + + /* set page number - MII register 0x10 */ + if (robo->page != page) { + cmd16 = ((page << 8) | /* page number */ + 1); /* mdc/mdio access enable */ + robo->miiwr(h, PSEUDO_PHYAD, REG_MII_PAGE, cmd16); + robo->page = page; + } + + switch (len) { + case 8: + val16 = ptr[7]; + val16 = ((val16 << 8) | ptr[6]); + robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA3, val16); + /* FALLTHRU */ + + case 6: + val16 = ptr[5]; + val16 = ((val16 << 8) | ptr[4]); + robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA2, val16); + val16 = ptr[3]; + val16 = ((val16 << 8) | ptr[2]); + robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA1, val16); + val16 = ptr[1]; + val16 = ((val16 << 8) | ptr[0]); + robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA0, val16); + break; + + case 4: + val16 = (uint16)((*(uint32 *)val) >> 16); + robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA1, val16); + val16 = (uint16)(*(uint32 *)val); + robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA0, val16); + break; + + case 2: + val16 = *(uint16 *)val; + robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA0, val16); + break; + + case 1: + val16 = *(uint8 *)val; + robo->miiwr(h, PSEUDO_PHYAD, REG_MII_DATA0, val16); + break; + } + + /* set register address - MII register 0x11 */ + cmd16 = ((reg << 8) | /* register address */ + 1); /* opcode write */ + robo->miiwr(h, PSEUDO_PHYAD, REG_MII_ADDR, cmd16); + + /* is operation finished? */ + for (i = MII_MAX_RETRY; i > 0; i --) { + val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_ADDR); + if ((val16 & 3) == 0) + break; + } + + /* timed out */ + if (!i) { + ET_ERROR(("mii_wreg: timeout")); + return -1; + } + return 0; +} + +/* Read register thru MDC/MDIO */ +static int +mii_rreg(robo_info_t *robo, uint8 page, uint8 reg, void *val, int len) +{ + uint16 cmd16, val16; + void *h = robo->h; + int i; + uint8 *ptr = (uint8 *)val; + + /* validate value length and buffer address */ + ASSERT(len == 1 || len == 6 || len == 8 || + ((len == 2) && !((int)val & 1)) || ((len == 4) && !((int)val & 3))); + + /* set page number - MII register 0x10 */ + if (robo->page != page) { + cmd16 = ((page << 8) | /* page number */ + 1); /* mdc/mdio access enable */ + robo->miiwr(h, PSEUDO_PHYAD, REG_MII_PAGE, cmd16); + robo->page = page; + } + + /* set register address - MII register 0x11 */ + cmd16 = ((reg << 8) | /* register address */ + 2); /* opcode read */ + robo->miiwr(h, PSEUDO_PHYAD, REG_MII_ADDR, cmd16); + + /* is operation finished? */ + for (i = MII_MAX_RETRY; i > 0; i --) { + val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_ADDR); + if ((val16 & 3) == 0) + break; + } + /* timed out */ + if (!i) { + ET_ERROR(("mii_rreg: timeout")); + return -1; + } + + ET_MSG(("%s: [0x%x-0x%x] => 0x%x (len %d)\n", __FUNCTION__, page, reg, val16, len)); + + switch (len) { + case 8: + val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA3); + ptr[7] = (val16 >> 8); + ptr[6] = (val16 & 0xff); + /* FALLTHRU */ + + case 6: + val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA2); + ptr[5] = (val16 >> 8); + ptr[4] = (val16 & 0xff); + val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA1); + ptr[3] = (val16 >> 8); + ptr[2] = (val16 & 0xff); + val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA0); + ptr[1] = (val16 >> 8); + ptr[0] = (val16 & 0xff); + break; + + case 4: + val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA1); + *(uint32 *)val = (((uint32)val16) << 16); + val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA0); + *(uint32 *)val |= val16; + break; + + case 2: + val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA0); + *(uint16 *)val = val16; + break; + case 1: + val16 = robo->miird(h, PSEUDO_PHYAD, REG_MII_DATA0); + *(uint8 *)val = (uint8)(val16 & 0xff); + break; + } + + return 0; +} + +/* MII interface functions */ +static dev_ops_t mdcmdio = { + NULL, + NULL, + mii_wreg, + mii_rreg, + "MII (MDC/MDIO)" +}; + +/* High level switch configuration functions. */ + +static int +findmatch(char *string, char *name) +{ + uint len; + char *c; + + len = strlen(name); + /* CSTYLED */ + while ((c = strchr(string, ',')) != NULL) { + if (len == (uint)(c - string) && !strncmp(string, name, len)) + return 1; + string = c + 1; + } + + return (!strcmp(string, name)); +} + +static uint +getgpiopin(char *vars, char *pin_name, uint def_pin) +{ + char name[] = "gpioXXXX"; + char *val; + uint pin; + + /* Go thru all possibilities till a match in pin name */ + for (pin = 0; pin < GPIO_NUMPINS; pin ++) { + snprintf(name, sizeof(name), "gpio%d", pin); + val = getvar(vars, name); + if (val && findmatch(val, pin_name)) + return pin; + } + + if (def_pin != GPIO_PIN_NOTDEFINED) { + /* make sure the default pin is not used by someone else */ + snprintf(name, sizeof(name), "gpio%d", def_pin); + if (getvar(vars, name)) { + def_pin = GPIO_PIN_NOTDEFINED; + } + } + + return def_pin; +} + + +/* Port flags */ +#define FLAG_TAGGED 't' /* output tagged (external ports only) */ +#define FLAG_UNTAG 'u' /* input & output untagged (CPU port only, for OS (linux, ...) */ +#define FLAG_LAN '*' /* input & output untagged (CPU port only, for CFE */ + +/* port descriptor */ +typedef struct { + uint32 untag; /* untag enable bit (Page 0x05 Address 0x63-0x66 Bit[17:9]) */ + uint32 member; /* vlan member bit (Page 0x05 Address 0x63-0x66 Bit[7:0]) */ + uint8 ptagr; /* port tag register address (Page 0x34 Address 0x10-0x1F) */ + uint8 cpu; /* is this cpu port? */ +} pdesc_t; + +pdesc_t pdesc97[] = { + /* 5395/5397/5398 is 0 ~ 7. port 8 is IMP port. */ + /* port 0 */ {1 << 9, 1 << 0, REG_VLAN_PTAG0, 0}, + /* port 1 */ {1 << 10, 1 << 1, REG_VLAN_PTAG1, 0}, + /* port 2 */ {1 << 11, 1 << 2, REG_VLAN_PTAG2, 0}, + /* port 3 */ {1 << 12, 1 << 3, REG_VLAN_PTAG3, 0}, + /* port 4 */ {1 << 13, 1 << 4, REG_VLAN_PTAG4, 0}, + /* port 5 */ {1 << 14, 1 << 5, REG_VLAN_PTAG5, 0}, + /* port 6 */ {1 << 15, 1 << 6, REG_VLAN_PTAG6, 0}, + /* port 7 */ {1 << 16, 1 << 7, REG_VLAN_PTAG7, 0}, + /* mii port */ {1 << 17, 1 << 8, REG_VLAN_PTAG8, 1}, +}; + +pdesc_t pdesc25[] = { + /* port 0 */ {1 << 6, 1 << 0, REG_VLAN_PTAG0, 0}, + /* port 1 */ {1 << 7, 1 << 1, REG_VLAN_PTAG1, 0}, + /* port 2 */ {1 << 8, 1 << 2, REG_VLAN_PTAG2, 0}, + /* port 3 */ {1 << 9, 1 << 3, REG_VLAN_PTAG3, 0}, + /* port 4 */ {1 << 10, 1 << 4, REG_VLAN_PTAG4, 0}, + /* mii port */ {1 << 11, 1 << 5, REG_VLAN_PTAG5, 1}, +}; + + +#define to_robo(driver) ((robo_info_t *) ((switch_driver *) driver)->priv) +#define ROBO_START(driver) \ + do { \ + robo_info_t *robo = to_robo(driver); \ + if (robo->ops->enable_mgmtif) \ + robo->ops->enable_mgmtif(robo) + +#define ROBO_END(driver) \ + if (robo->ops->disable_mgmtif) \ + robo->ops->disable_mgmtif(robo); \ + } while (0) + +int +bcm_robo_reset(robo_info_t *robo) +{ + int i, max_port_ind; + uint8 val8; + uint16 val16; + uint32 val32; + pdesc_t *pdesc; + int pdescsz; + +/* printk(KERN_WARNING "bcmrobo.c: bcm_robo_reset\n"); */ + + if (robo->ops->enable_mgmtif) + robo->ops->enable_mgmtif(robo); + + /* setup global vlan configuration, FIXME: necessary? */ + /* VLAN Control 0 Register (Page 0x34, Address 0) */ + val8 = ((1 << 7) | /* enable 802.1Q VLAN */ + (3 << 5)); /* individual VLAN learning mode */ + robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL0, &val8, sizeof(val8)); + + /* VLAN Control 1 Register (Page 0x34, Address 1) */ + robo->ops->read_reg(robo, PAGE_VLAN, REG_VLAN_CTRL0, &val8, sizeof(val8)); + val8 |= ((1 << 2) | /* enable RSV multicast V Fwdmap */ + (1 << 3)); /* enable RSV multicast V Untagmap */ + if (robo->devid == DEVID5325) + val8 |= (1 << 1); /* enable RSV multicast V Tagging */ + robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL1, &val8, sizeof(val8)); + + bcm_robo_set_macaddr(robo, NULL); + + if (robo->devid == DEVID5325) { + /* VLAN Control 4 Register (Page 0x34, Address 4) */ + val8 = (1 << 6); /* drop frame with VID violation */ + robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL4, &val8, sizeof(val8)); + + /* VLAN Control 5 Register (Page 0x34, Address 5) */ + val8 = (1 << 3); /* drop frame when miss V table */ + robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL5, &val8, sizeof(val8)); + + pdesc = pdesc25; + pdescsz = sizeof(pdesc25) / sizeof(pdesc_t); + } else { + pdesc = pdesc97; + pdescsz = sizeof(pdesc97) / sizeof(pdesc_t); + } + + if (robo->devid == DEVID5325) { + /* setup priority mapping - applies to tagged ingress frames */ + /* Priority Re-map Register (Page 0x34, Address 0x20-0x23) */ + /* FIXME: un-hardcode */ + val32 = ((0 << 0) | /* 0 -> 0 */ + (1 << 3) | /* 1 -> 1 */ + (2 << 6) | /* 2 -> 2 */ + (3 << 9) | /* 3 -> 3 */ + (4 << 12) | /* 4 -> 4 */ + (5 << 15) | /* 5 -> 5 */ + (6 << 18) | /* 6 -> 6 */ + (7 << 21)); /* 7 -> 7 */ + robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_PMAP, &val32, sizeof(val32)); + } + + /* Set unmanaged mode */ + robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_MODE, &val8, sizeof(val8)); + val8 &= (~(1 << 0)); + robo->ops->write_reg(robo, PAGE_CTRL, REG_CTRL_MODE, &val8, sizeof(val8)); + + /* No spanning tree for unmanaged mode */ + val8 = 0; + max_port_ind = ((robo->devid == DEVID5398) ? REG_CTRL_PORT7 : REG_CTRL_PORT4); + for (i = REG_CTRL_PORT0; i <= max_port_ind; i++) { + robo->ops->write_reg(robo, PAGE_CTRL, i, &val8, sizeof(val8)); + } + + /* WAN port LED */ + val16 = 0x1f; + robo->ops->write_reg(robo, PAGE_CTRL, 0x16, &val16, 2); + + if (robo->ops->enable_mgmtif) + robo->ops->disable_mgmtif(robo); + + return 0; +} + +/* Get access to the RoboSwitch */ +robo_info_t * +bcm_robo_attach(sb_t *sbh, void *h, char *name, char *vars, miird_f miird, miiwr_f miiwr) +{ + robo_info_t *robo; + uint32 reset, idx; + uint8 val8; + uint16 val16; + + /* Allocate and init private state */ + if (!(robo = MALLOC(sb_osh(sbh), sizeof(robo_info_t)))) { + ET_ERROR(("robo_attach: out of memory, malloced %d bytes", MALLOCED(sb_osh(sbh)))); + return NULL; + } + bzero(robo, sizeof(robo_info_t)); + + robo->h = h; + robo->sbh = sbh; + robo->vars = vars; + robo->miird = miird; + robo->miiwr = miiwr; + robo->page = -1; + robo->name = name; + + /* Trigger external reset by nvram variable existance */ + if ((reset = getgpiopin(robo->vars, "robo_reset", GPIO_PIN_NOTDEFINED)) != + GPIO_PIN_NOTDEFINED) { + /* + * Reset sequence: RESET low(50ms)->high(20ms) + * + * We have to perform a full sequence for we don't know how long + * it has been from power on till now. + */ + ET_MSG(("%s: Using external reset in gpio pin %d\n", __FUNCTION__, reset)); + reset = 1 << reset; + + /* Keep RESET low for 50 ms */ + sb_gpioout(robo->sbh, reset, 0, GPIO_DRV_PRIORITY); + sb_gpioouten(robo->sbh, reset, reset, GPIO_DRV_PRIORITY); + bcm_mdelay(50); + + if (robo->devid == DEVID5395) + nvram_set("switch_type", "BCM5395"); + else if(robo->devid == DEVID5397) + nvram_set("switch_type", "BCM5397"); + else + nvram_set("switch_type", "unknown"); + + /* Keep RESET high for at least 20 ms */ + sb_gpioout(robo->sbh, reset, reset, GPIO_DRV_PRIORITY); + bcm_mdelay(20); + } else { + /* In case we need it */ + idx = sb_coreidx(robo->sbh); + + if (sb_setcore(robo->sbh, SB_ROBO, 0)) { + /* If we have an internal robo core, reset it using sb_core_reset */ + ET_MSG(("%s: Resetting internal robo core\n", __FUNCTION__)); + sb_core_reset(robo->sbh, 0, 0); + } + + sb_setcoreidx(robo->sbh, idx); + } + + if (miird && miiwr) { + uint16 tmp; + int rc, retry_count = 0; + + /* Read the PHY ID */ + tmp = miird(h, PSEUDO_PHYAD, 2); + if (tmp != 0xffff) { + do { + rc = mii_rreg(robo, PAGE_MMR, REG_DEVICE_ID, \ + &robo->devid, sizeof(uint16)); + if (rc != 0) + break; + retry_count++; + } while ((robo->devid == 0) && (retry_count < 10)); + + ET_MSG(("%s: devid read %ssuccesfully via mii: 0x%x\n", __FUNCTION__, \ + rc ? "un" : "", robo->devid)); + ET_MSG(("%s: mii access to switch works\n", __FUNCTION__)); + robo->ops = &mdcmdio; + if ((rc != 0) || (robo->devid == 0)) { + ET_MSG(("%s: error reading devid, assuming 5325e\n", __FUNCTION__)); + robo->devid = DEVID5325; + } + ET_MSG(("%s: devid: 0x%x\n", __FUNCTION__, robo->devid)); + } + } + + if ((robo->devid == DEVID5395) || + (robo->devid == DEVID5397) || + (robo->devid == DEVID5398)) { + uint8 srst_ctrl; + + /* If it is a 539x switch, use the soft reset register */ + ET_MSG(("%s: Resetting 539x robo switch\n", __FUNCTION__)); + + /* Reset the 539x switch core and register file */ + srst_ctrl = 0x83; + mii_wreg(robo, PAGE_CTRL, REG_CTRL_SRST, &srst_ctrl, sizeof(uint8)); + + bcm_mdelay(500); + + srst_ctrl = 0x00; + mii_wreg(robo, PAGE_CTRL, REG_CTRL_SRST, &srst_ctrl, sizeof(uint8)); + } + + if (!robo->ops) { + int mosi, miso, ss, sck; + + robo->ops = &spigpio; + robo->devid = DEVID5325; + + /* Init GPIO mapping. Default 2, 3, 4, 5 */ + ss = getgpiopin(vars, "robo_ss", 2); + if (ss == GPIO_PIN_NOTDEFINED) { + ET_ERROR(("robo_attach: robo_ss gpio fail: GPIO 2 in use")); + goto error; + } + robo->ss = 1 << ss; + sck = getgpiopin(vars, "robo_sck", 3); + if (sck == GPIO_PIN_NOTDEFINED) { + ET_ERROR(("robo_attach: robo_sck gpio fail: GPIO 3 in use")); + goto error; + } + robo->sck = 1 << sck; + mosi = getgpiopin(vars, "robo_mosi", 4); + if (mosi == GPIO_PIN_NOTDEFINED) { + ET_ERROR(("robo_attach: robo_mosi gpio fail: GPIO 4 in use")); + goto error; + } + robo->mosi = 1 << mosi; + miso = getgpiopin(vars, "robo_miso", 5); + if (miso == GPIO_PIN_NOTDEFINED) { + ET_ERROR(("robo_attach: robo_miso gpio fail: GPIO 5 in use")); + goto error; + } + robo->miso = 1 << miso; + ET_MSG(("%s: ss %d sck %d mosi %d miso %d\n", __FUNCTION__, + ss, sck, mosi, miso)); + } + + /* sanity check */ + ASSERT(robo->ops); + ASSERT(robo->ops->write_reg); + ASSERT(robo->ops->read_reg); + ASSERT((robo->devid == DEVID5325) || + (robo->devid == DEVID5395) || + (robo->devid == DEVID5397) || + (robo->devid == DEVID5398)); + + bcm_robo_reset(robo); + config_attach(robo); + + return robo; + +error: + MFREE(sb_osh(robo->sbh), robo, sizeof(robo_info_t)); + return NULL; +} + +/* Release access to the RoboSwitch */ +void +bcm_robo_detach(robo_info_t *robo) +{ + config_detach(robo); + MFREE(sb_osh(robo->sbh), robo, sizeof(robo_info_t)); +} + +/* Enable the device and set it to a known good state */ +int +bcm_robo_enable_device(robo_info_t *robo) +{ + uint8 reg_offset, reg_val; + int ret = 0; + + /* Enable management interface access */ + if (robo->ops->enable_mgmtif) + robo->ops->enable_mgmtif(robo); + + if (robo->devid == DEVID5398) { + /* Disable unused ports: port 6 and 7 */ + for (reg_offset = REG_CTRL_PORT6; reg_offset <= REG_CTRL_PORT7; reg_offset ++) { + /* Set bits [1:0] to disable RX and TX */ + reg_val = 0x03; + robo->ops->write_reg(robo, PAGE_CTRL, reg_offset, ®_val, + sizeof(reg_val)); + } + } + + if (robo->devid == DEVID5325) { + /* Must put the switch into Reverse MII mode! */ + + /* MII port state override (page 0 register 14) */ + robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_MIIPO, ®_val, sizeof(reg_val)); + + /* Bit 4 enables reverse MII mode */ + if (!(reg_val & (1 << 4))) { + /* Enable RvMII */ + reg_val |= (1 << 4); + robo->ops->write_reg(robo, PAGE_CTRL, REG_CTRL_MIIPO, ®_val, + sizeof(reg_val)); + + /* Read back */ + robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_MIIPO, ®_val, + sizeof(reg_val)); + if (!(reg_val & (1 << 4))) { + ET_ERROR(("robo_enable_device: enabling RvMII mode failed\n")); + ret = -1; + } + } + } + + /* Disable management interface access */ + if (robo->ops->disable_mgmtif) + robo->ops->disable_mgmtif(robo); + + return ret; +} + + +void bcm_robo_set_macaddr(robo_info_t *robo, char *mac_addr) +{ + uint8 arl_entry[8] = { 0 }, arl_entry1[8] = { 0 }; + + if (mac_addr != NULL) + memcpy(robo->macaddr, mac_addr, 6); + + mac_addr = robo->macaddr; + + /* setup mac address */ + arl_entry[0] = mac_addr[5]; + arl_entry[1] = mac_addr[4]; + arl_entry[2] = mac_addr[3]; + arl_entry[3] = mac_addr[2]; + arl_entry[4] = mac_addr[1]; + arl_entry[5] = mac_addr[0]; + + if (robo->devid == DEVID5325) { + /* Init the entry 1 of the bin */ + robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_ARL_E1, \ + arl_entry1, sizeof(arl_entry1)); + robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_VID_E1, \ + arl_entry1, 1); + + /* Init the entry 0 of the bin */ + arl_entry[6] = 0x8; /* Port Id: MII */ + arl_entry[7] = 0xc0; /* Static Entry, Valid */ + + robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_ARL_E0, \ + arl_entry, sizeof(arl_entry)); + robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_MINDX, \ + arl_entry, ETHER_ADDR_LEN); + + } else { + /* Initialize the MAC Addr Index Register */ + robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_MINDX, \ + arl_entry, ETHER_ADDR_LEN); + } +} + +static int handle_reset(void *driver, char *buf, int nr) +{ + ROBO_START(driver); + bcm_robo_reset(robo); + ROBO_END(driver); + + return 0; +} + + +static int handle_enable_read(void *driver, char *buf, int nr) +{ + int ret; + uint8 val8; + + ROBO_START(driver); + robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_MODE, &val8, sizeof(val8)); + ret = sprintf(buf, "%d\n", !!(val8 & (1 << 1))); + ROBO_END(driver); + + return ret; +} + +static int handle_enable_write(void *driver, char *buf, int nr) +{ + uint8 val8; + +/* printk(KERN_WARNING "bcmrobo.c: handle_enable_write\n"); */ + + ROBO_START(driver); + robo->ops->read_reg(robo, PAGE_CTRL, REG_CTRL_MODE, &val8, sizeof(val8)); + val8 &= ~(1 << 1); + val8 |= ((buf[0] == '1') << 1); + robo->ops->write_reg(robo, PAGE_CTRL, REG_CTRL_MODE, &val8, sizeof(val8)); + ROBO_END(driver); + + return 0; +} + +static int handle_enable_vlan_read(void *driver, char *buf, int nr) +{ + uint8 val8; + + ROBO_START(driver); + robo->ops->read_reg(robo, PAGE_VLAN, REG_VLAN_CTRL0, &val8, sizeof(val8)); + ROBO_END(driver); + + return sprintf(buf, "%d\n", (((val8 & (1 << 7)) == (1 << 7)) ? 1 : 0)); +} +static int handle_enable_vlan_write(void *driver, char *buf, int nr) +{ + int disable = ((buf[0] != '1') ? 1 : 0); + + uint8 val8; + uint16 val16; + pdesc_t *pdesc; + int pdescsz; + uint16 vid; + uint8 arl_entry[8] = { 0 }, arl_entry1[8] = { 0 }; + +/* printk(KERN_WARNING "bcmrobo.c: handle_enable_vlan_write\n"); */ + + ROBO_START(driver); + + /* setup global vlan configuration */ + /* VLAN Control 0 Register (Page 0x34, Address 0) */ + val8 = disable ? 0 : + ((1 << 7) | /* enable/disable 802.1Q VLAN */ + (3 << 5)); /* individual VLAN learning mode */ + robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL0, &val8, sizeof(val8)); + + /* VLAN Control 1 Register (Page 0x34, Address 1) */ + val8 = disable ? 0 : + ((1 << 2) | /* enable/disable RSV multicast V Fwdmap */ + (1 << 3)); /* enable/disable RSV multicast V Untagmap */ + if (robo->devid == DEVID5325) + val8 |= disable ? 0 : (1 << 1); /* enable/disable RSV multicast V Tagging */ + robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL1, &val8, sizeof(val8)); + + if ( disable == 0 ) { /* FIXME: ok to stop here when disabling? */ + arl_entry[0] = robo->macaddr[5]; + arl_entry[1] = robo->macaddr[4]; + arl_entry[2] = robo->macaddr[3]; + arl_entry[3] = robo->macaddr[2]; + arl_entry[4] = robo->macaddr[1]; + arl_entry[5] = robo->macaddr[0]; + + if (robo->devid == DEVID5325) { + /* Init the entry 1 of the bin */ + robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_ARL_E1, \ + arl_entry1, sizeof(arl_entry1)); + robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_VID_E1, \ + arl_entry1, 1); + + /* Init the entry 0 of the bin */ + arl_entry[6] = 0x8; /* Port Id: MII */ + arl_entry[7] = 0xc0; /* Static Entry, Valid */ + + robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_ARL_E0, \ + arl_entry, sizeof(arl_entry)); + robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_MINDX, \ + arl_entry, ETHER_ADDR_LEN); + + /* VLAN Control 4 Register (Page 0x34, Address 4) */ + val8 = (1 << 6); /* drop frame with VID violation */ + robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL4, &val8, sizeof(val8)); + + /* VLAN Control 5 Register (Page 0x34, Address 5) */ + val8 = (1 << 3); /* drop frame when miss V table */ + robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_CTRL5, &val8, sizeof(val8)); + + pdesc = pdesc25; + pdescsz = sizeof(pdesc25) / sizeof(pdesc_t); + } else { + /* Initialize the MAC Addr Index Register */ + robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_MINDX, \ + arl_entry, ETHER_ADDR_LEN); + + pdesc = pdesc97; + pdescsz = sizeof(pdesc97) / sizeof(pdesc_t); + } + + /* setup each vlan. max. 16 vlans. */ + /* force vlan id to be equal to vlan number */ + for (vid = 0; vid < VLAN_NUMVLANS; vid ++) { + + /* Add static ARL entries */ + if (robo->devid == DEVID5325) { + val8 = vid; + robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_VID_E0, \ + &val8, sizeof(val8)); + robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_VINDX, \ + &val8, sizeof(val8)); + + /* Write the entry */ + val8 = 0x80; + robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_CTRL, \ + &val8, sizeof(val8)); + /* Wait for write to complete */ + SPINWAIT((robo->ops->read_reg(robo, PAGE_VTBL, REG_VTBL_CTRL, \ + &val8, sizeof(val8)), ((val8 & 0x80) != 0)), + 100 /* usec */); + } else { + /* Set the VLAN Id in VLAN ID Index Register */ + val8 = vid; + robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_VINDX, \ + &val8, sizeof(val8)); + + /* Set the MAC addr and VLAN Id in ARL Table MAC/VID Entry 0 + * Register. + */ + arl_entry[6] = vid; + arl_entry[7] = 0x0; + robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_ARL_E0, \ + arl_entry, sizeof(arl_entry)); + + /* Set the Static bit , Valid bit and Port ID fields in + * ARL Table Data Entry 0 Register + */ + val16 = 0xc008; + robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_DAT_E0, \ + &val16, sizeof(val16)); + + /* Clear the ARL_R/W bit and set the START/DONE bit in + * the ARL Read/Write Control Register. + */ + val8 = 0x80; + robo->ops->write_reg(robo, PAGE_VTBL, REG_VTBL_CTRL, \ + &val8, sizeof(val8)); + /* Wait for write to complete */ + SPINWAIT((robo->ops->read_reg(robo, PAGE_VTBL, REG_VTBL_CTRL, \ + &val8, sizeof(val8)), ((val8 & 0x80) != 0)), + 100 /* usec */); + } + } + } + + ROBO_END(driver); + return 0; +} + +static int handle_vlan_port_read(void *driver, char *buf, int nr) +{ + /* FIXME: yeah, some work is missing here */ + return sprintf(buf, "bcmrobo.c: handle_vlan_port_read unimplimented\n"); +} + +static int handle_vlan_port_write(void *driver, char *buf, int nr) +{ + + switch_driver *d = (switch_driver *) driver; + switch_vlan_config *c = switch_parse_vlan(d, buf); + + uint8 val8; + uint16 val16; + uint32 val32; + int j; + pdesc_t *pdesc; + int pdescsz; + +/* printk(KERN_WARNING "bcmrobo.c: handle_vlan_port_write, nr %d\n", nr); */ + + if (c == NULL) + return -EINVAL; + + ROBO_START(driver); + + if (robo->devid == DEVID5325) { + pdesc = pdesc25; + pdescsz = sizeof(pdesc25) / sizeof(pdesc_t); + } else { + pdesc = pdesc97; + pdescsz = sizeof(pdesc97) / sizeof(pdesc_t); + } + + + for (j = 0; j < d->ports; j++) { + if ((c->untag | c->pvid) & (1 << j)) + if ((j != d->cpuport) || (c->untag & (1 << j))) { + + /* change default vlan tag */ + +/* printk(KERN_WARNING "bcmrobo.c: set default vlan tag, port %d -> vlan %d\n", j, nr); */ + + val16 = ((0 << 13) | /* priority - always 0 */ + nr); /* vlan id */ + robo->ops->write_reg(robo, PAGE_VLAN, pdesc[j].ptagr, &val16, sizeof(val16)); + } + } + + + if (robo->devid == DEVID5325) { + val32 = ((c->untag << 6) | /* untag enable */ + c->port); /* vlan members */ + val32 |= ((1 << 20) | /* valid write */ + ((nr >> 4) << 12)); /* vlan id bit[11:4] */ + /* VLAN Write Register (Page 0x34, Address 0x08-0x0B) */ + robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_WRITE, &val32, + sizeof(val32)); + /* VLAN Table Access Register (Page 0x34, Address 0x06-0x07) */ + val16 = ((1 << 13) | /* start command */ + (1 << 12) | /* write state */ + nr); /* vlan id */ + robo->ops->write_reg(robo, PAGE_VLAN, REG_VLAN_ACCESS, &val16, + sizeof(val16)); + } else { + uint8 vtble, vtbli, vtbla; + val32 = ((c->untag << 9) | /* untag enable */ + c->port); /* vlan members */ + + if (robo->devid == DEVID5395) { + vtble = REG_VTBL_ENTRY_5395; + vtbli = REG_VTBL_INDX_5395; + vtbla = REG_VTBL_ACCESS_5395; + } else { + vtble = REG_VTBL_ENTRY; + vtbli = REG_VTBL_INDX; + vtbla = REG_VTBL_ACCESS; + } + + /* VLAN Table Entry Register (Page 0x05, Address 0x63-0x66/0x83-0x86) */ + robo->ops->write_reg(robo, PAGE_VTBL, vtble, &val32, + sizeof(val32)); + /* VLAN Table Address Index Reg (Page 0x05, Address 0x61-0x62/0x81-0x82) */ + val16 = nr; /* vlan id */ + robo->ops->write_reg(robo, PAGE_VTBL, vtbli, &val16, + sizeof(val16)); + + /* VLAN Table Access Register (Page 0x34, Address 0x60/0x80) */ + val8 = ((1 << 7) | /* start command */ + 0); /* write */ + robo->ops->write_reg(robo, PAGE_VTBL, vtbla, &val8, + sizeof(val8)); + } + + ROBO_END(driver); + return 0; +} + +static int __init config_attach(robo_info_t *robo) +{ + switch_config cfg[] = { + {"enable", handle_enable_read, handle_enable_write}, + {"reset", NULL, handle_reset}, + {"enable_vlan", handle_enable_vlan_read, handle_enable_vlan_write}, + {NULL, NULL, NULL} + }; + switch_config vlan[] = { + {"ports", handle_vlan_port_read, handle_vlan_port_write}, + {NULL, NULL, NULL} + }; + switch_driver driver = { + name: DRIVER_NAME, + version: DRIVER_VERSION, + interface: robo->name, + cpuport: 8, + ports: 9, + vlans: 16, + driver_handlers: cfg, + port_handlers: NULL, + vlan_handlers: vlan, + }; + if (robo->devid == DEVID5325) { + driver.ports = 6; + driver.cpuport = 5; + } + driver.priv = (void *) robo; + + return switch_register_driver(&driver); +} + +static void __exit config_detach(robo_info_t *robo) +{ + switch_unregister_driver(DRIVER_NAME); +} + + diff --git a/package/broadcom-57xx/src/bcmrobo.h b/package/broadcom-57xx/src/bcmrobo.h new file mode 100644 index 0000000000..ce9659bba0 --- /dev/null +++ b/package/broadcom-57xx/src/bcmrobo.h @@ -0,0 +1,70 @@ +/* + * RoboSwitch setup functions + * + * Copyright 2007, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * + * $Id: bcmrobo.h,v 1.1.1.6 2007/05/31 08:00:41 michael Exp $ + */ + +#ifndef _bcm_robo_h_ +#define _bcm_robo_h_ +#include + +#define DEVID5325 0x25 /* 5325 (Not really be we fake it) */ + +/* Forward declaration */ +typedef struct robo_info_s robo_info_t; + +/* Device access/config oprands */ +typedef struct { + /* low level routines */ + void (*enable_mgmtif)(robo_info_t *robo); /* enable mgmt i/f, optional */ + void (*disable_mgmtif)(robo_info_t *robo); /* disable mgmt i/f, optional */ + int (*write_reg)(robo_info_t *robo, uint8 page, uint8 reg, void *val, int len); + int (*read_reg)(robo_info_t *robo, uint8 page, uint8 reg, void *val, int len); + /* description */ + char *desc; +} dev_ops_t; + + +typedef uint16 (*miird_f)(void *h, int add, int off); +typedef void (*miiwr_f)(void *h, int add, int off, uint16 val); + +/* Private state per RoboSwitch */ +struct robo_info_s { + sb_t *sbh; /* SiliconBackplane handle */ + char *vars; /* nvram variables handle */ + void *h; /* dev handle */ + uint16 devid; /* Device id for the switch */ + char *name; /* Linux device name */ + char macaddr[6]; + + dev_ops_t *ops; /* device ops */ + uint8 page; /* current page */ + + /* SPI */ + uint32 ss, sck, mosi, miso; /* GPIO mapping */ + + /* MII */ + miird_f miird; + miiwr_f miiwr; +}; + +extern robo_info_t *bcm_robo_attach(sb_t *sbh, void *h, char *name, char *vars, miird_f miird, miiwr_f miiwr); +extern void bcm_robo_detach(robo_info_t *robo); +extern int bcm_robo_enable_device(robo_info_t *robo); +extern int bcm_robo_config_vlan(robo_info_t *robo, uint8 *mac_addr); +extern int bcm_robo_enable_switch(robo_info_t *robo); +extern void bcm_robo_set_macaddr(robo_info_t *robo, char *macaddr); + +#ifdef BCMDBG +extern void robo_dump_regs(robo_info_t *robo, struct bcmstrbuf *b); +#endif /* BCMDBG */ + +#endif /* _bcm_robo_h_ */ diff --git a/package/broadcom-57xx/src/bits.h b/package/broadcom-57xx/src/bits.h new file mode 100644 index 0000000000..cd97e84862 --- /dev/null +++ b/package/broadcom-57xx/src/bits.h @@ -0,0 +1,61 @@ +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 - 2004 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* History: */ +/* 02/25/00 Hav Khauv Initial version. */ +/******************************************************************************/ + +#ifndef BITS_H +#define BITS_H + + + +/******************************************************************************/ +/* Bit Mask definitions */ +/******************************************************************************/ + +#define BIT_NONE 0x00 +#define BIT_0 0x01 +#define BIT_1 0x02 +#define BIT_2 0x04 +#define BIT_3 0x08 +#define BIT_4 0x10 +#define BIT_5 0x20 +#define BIT_6 0x40 +#define BIT_7 0x80 +#define BIT_8 0x0100 +#define BIT_9 0x0200 +#define BIT_10 0x0400 +#define BIT_11 0x0800 +#define BIT_12 0x1000 +#define BIT_13 0x2000 +#define BIT_14 0x4000 +#define BIT_15 0x8000 +#define BIT_16 0x010000 +#define BIT_17 0x020000 +#define BIT_18 0x040000 +#define BIT_19 0x080000 +#define BIT_20 0x100000 +#define BIT_21 0x200000 +#define BIT_22 0x400000 +#define BIT_23 0x800000 +#define BIT_24 0x01000000 +#define BIT_25 0x02000000 +#define BIT_26 0x04000000 +#define BIT_27 0x08000000 +#define BIT_28 0x10000000 +#define BIT_29 0x20000000 +#define BIT_30 0x40000000 +#define BIT_31 0x80000000 + + + +#endif /* BITS_H */ + diff --git a/package/broadcom-57xx/src/fw_lso05.h b/package/broadcom-57xx/src/fw_lso05.h new file mode 100644 index 0000000000..cfe6a9cf2f --- /dev/null +++ b/package/broadcom-57xx/src/fw_lso05.h @@ -0,0 +1,289 @@ +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 - 2004 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* (c) COPYRIGHT 2001-2004 Broadcom Corporation, ALL RIGHTS RESERVED. */ +/* */ +/* Name: F W _ L S O 0 5. H */ +/* Author : Kevin Tran */ +/* Version: 1.2 */ +/* */ +/* Module Description: This file contains firmware binary code of TCP */ +/* Segmentation firmware (BCM5705). */ +/* */ +/* History: */ +/* 08/10/02 Kevin Tran Incarnation. */ +/* 02/02/04 Kevin Tran Added Support for BCM5788. */ +/******************************************************************************/ + +#ifndef __FW_LSO05_H__ +#define __FW_LSO05_H__ + +int t3StkOffLd05FwReleaseMajor = 0x1; +int t3StkOffLd05FwReleaseMinor = 0x2; +int t3StkOffLd05FwReleaseFix = 0x0; +U32 t3StkOffLd05FwStartAddr = 0x00010000; +U32 t3StkOffLd05FwTextAddr = 0x00010000; +int t3StkOffLd05FwTextLen = 0xe90; +U32 t3StkOffLd05FwRodataAddr = 0x00010e90; +int t3StkOffLd05FwRodataLen = 0x50; +U32 t3StkOffLd05FwDataAddr = 0x00010f00; +int t3StkOffLd05FwDataLen = 0x20; +U32 t3StkOffLd05FwSbssAddr = 0x00010f20; +int t3StkOffLd05FwSbssLen = 0x28; +U32 t3StkOffLd05FwBssAddr = 0x00010f50; +int t3StkOffLd05FwBssLen = 0x88; +U32 t3StkOffLd05FwText[(0xe90/4) + 1] = { +0xc004003, 0x0, 0x10f04, +0x0, 0x10000003, 0x0, 0xd, +0xd, 0x3c1d0001, 0x37bde000, 0x3a0f021, +0x3c100001, 0x26100000, 0xc004010, 0x0, +0xd, 0x27bdffe0, 0x3c04fefe, 0xafbf0018, +0xc0042e8, 0x34840002, 0xc004364, 0x0, +0x3c030001, 0x90630f34, 0x24020002, 0x3c040001, +0x24840e9c, 0x14620003, 0x24050001, 0x3c040001, +0x24840e90, 0x24060002, 0x3821, 0xafa00010, +0xc004378, 0xafa00014, 0xc00402c, 0x0, +0x8fbf0018, 0x3e00008, 0x27bd0020, 0x0, +0x0, 0x27bdffe0, 0xafbf001c, 0xafb20018, +0xafb10014, 0xc0042d4, 0xafb00010, 0x3c128000, +0x24110001, 0x8f706810, 0x32020400, 0x10400007, +0x0, 0x8f641008, 0x921024, 0x14400003, +0x0, 0xc004064, 0x0, 0x3c020001, +0x90420f56, 0x10510003, 0x32020200, 0x1040fff1, +0x0, 0xc0041b4, 0x0, 0x8004034, +0x0, 0x8fbf001c, 0x8fb20018, 0x8fb10014, +0x8fb00010, 0x3e00008, 0x27bd0020, 0x27bdffe0, +0x3c040001, 0x24840eb0, 0x2821, 0x3021, +0x3821, 0xafbf0018, 0xafa00010, 0xc004378, +0xafa00014, 0xd021, 0x24020130, 0xaf625000, +0x3c010001, 0xa4200f50, 0x3c010001, 0xa0200f57, +0x8fbf0018, 0x3e00008, 0x27bd0020, 0x0, +0x0, 0x3c030001, 0x24630f60, 0x90620000, +0x27bdfff0, 0x14400003, 0x80c021, 0x8004073, +0x4821, 0x3c022000, 0x3021024, 0x10400003, +0x24090002, 0x8004073, 0xa0600000, 0x24090001, +0x181040, 0x30431f80, 0x346f8008, 0x1520004b, +0x25eb0028, 0x3c040001, 0x832021, 0x8c848010, +0x3c050001, 0x24a50f7a, 0x41402, 0xa0a20000, +0x3c010001, 0xa0240f7b, 0x3c020001, 0x431021, +0x94428014, 0x3c010001, 0xa0220f7c, 0x3c0c0001, +0x1836021, 0x8d8c8018, 0x304200ff, 0x24420008, +0x220c3, 0x24020001, 0x3c010001, 0xa0220f60, +0x124102b, 0x1040000c, 0x3821, 0x24a6000e, +0x1602821, 0x8ca20000, 0x8ca30004, 0x24a50008, +0x24e70001, 0xacc20000, 0xacc30004, 0xe4102b, +0x1440fff8, 0x24c60008, 0x3821, 0x3c080001, +0x25080f7b, 0x91060000, 0x3c020001, 0x90420f7c, +0x2503000d, 0xc32821, 0x461023, 0x21fc2, +0x431021, 0x21043, 0x1840000c, 0x2021, +0x91020001, 0x461023, 0x21fc2, 0x431021, +0x21843, 0x94a20000, 0x24e70001, 0x822021, +0xe3102a, 0x1440fffb, 0x24a50002, 0x41c02, +0x3082ffff, 0x622021, 0x41402, 0x822021, +0x3c02ffff, 0x1821024, 0x3083ffff, 0x431025, +0x3c010001, 0x80040fa, 0xac220f80, 0x3c050001, +0x24a50f7c, 0x90a20000, 0x3c0c0001, 0x1836021, +0x8d8c8018, 0x220c2, 0x1080000e, 0x3821, +0x1603021, 0x24a5000c, 0x8ca20000, 0x8ca30004, +0x24a50008, 0x24e70001, 0xacc20000, 0xacc30004, +0xe4102b, 0x1440fff8, 0x24c60008, 0x3c050001, +0x24a50f7c, 0x90a20000, 0x30430007, 0x24020004, +0x10620011, 0x28620005, 0x10400005, 0x24020002, +0x10620008, 0x710c0, 0x80040fa, 0x0, +0x24020006, 0x1062000e, 0x710c0, 0x80040fa, +0x0, 0xa21821, 0x9463000c, 0x4b1021, +0x80040fa, 0xa4430000, 0x710c0, 0xa21821, +0x8c63000c, 0x4b1021, 0x80040fa, 0xac430000, +0xa21821, 0x8c63000c, 0x4b2021, 0xa21021, +0xac830000, 0x94420010, 0xa4820004, 0x95e70006, +0x3c020001, 0x90420f7c, 0x3c030001, 0x90630f7a, +0xe2c823, 0x3c020001, 0x90420f7b, 0x24630028, +0x1e34021, 0x24420028, 0x15200012, 0x1e23021, +0x94c2000c, 0x3c010001, 0xa4220f78, 0x94c20004, +0x94c30006, 0x3c010001, 0xa4200f76, 0x3c010001, +0xa4200f72, 0x21400, 0x431025, 0x3c010001, +0xac220f6c, 0x95020004, 0x3c010001, 0x8004124, +0xa4220f70, 0x3c020001, 0x94420f70, 0x3c030001, +0x94630f72, 0x431021, 0xa5020004, 0x3c020001, +0x94420f6c, 0xa4c20004, 0x3c020001, 0x8c420f6c, +0xa4c20006, 0x3c040001, 0x94840f72, 0x3c020001, +0x94420f70, 0x3c0a0001, 0x954a0f76, 0x441821, +0x3063ffff, 0x62182a, 0x24020002, 0x1122000b, +0x832023, 0x3c030001, 0x94630f78, 0x30620009, +0x10400006, 0x3062fff6, 0xa4c2000c, 0x3c020001, +0x94420f78, 0x30420009, 0x1425023, 0x24020001, +0x1122001b, 0x29220002, 0x50400005, 0x24020002, +0x11200007, 0x31a2ffff, 0x8004197, 0x0, +0x1122001d, 0x24020016, 0x8004197, 0x31a2ffff, +0x3c0e0001, 0x95ce0f80, 0x10800005, 0x1806821, +0x1c42021, 0x41c02, 0x3082ffff, 0x627021, +0xe1027, 0xa502000a, 0x3c030001, 0x90630f7b, +0x31a2ffff, 0xe21021, 0x800418d, 0x432023, +0x3c020001, 0x94420f80, 0x442021, 0x41c02, +0x3082ffff, 0x622021, 0x807021, 0x41027, +0x8004185, 0xa502000a, 0x3c050001, 0x24a50f7a, +0x90a30000, 0x14620002, 0x24e2fff2, 0xa5e20034, +0x90a20000, 0xe21023, 0xa5020002, 0x3c030001, +0x94630f80, 0x3c020001, 0x94420f5a, 0x30e5ffff, +0x641821, 0x451023, 0x622023, 0x41c02, +0x3082ffff, 0x622021, 0x41027, 0xa502000a, +0x3c030001, 0x90630f7c, 0x24620001, 0x14a20005, +0x807021, 0x1631021, 0x90420000, 0x8004185, +0x26200, 0x24620002, 0x14a20003, 0x306200fe, +0x4b1021, 0x944c0000, 0x3c020001, 0x94420f82, +0x3183ffff, 0x3c040001, 0x90840f7b, 0x431021, +0xe21021, 0x442023, 0x8a2021, 0x41c02, +0x3082ffff, 0x622021, 0x41402, 0x822021, +0x806821, 0x41027, 0xa4c20010, 0x31a2ffff, +0xe1c00, 0x431025, 0x3c040001, 0x24840f72, +0xade20010, 0x94820000, 0x3c050001, 0x94a50f76, +0x3c030001, 0x8c630f6c, 0x24420001, 0xb92821, +0xa4820000, 0x3322ffff, 0x622021, 0x83182b, +0x3c010001, 0xa4250f76, 0x10600003, 0x24a2ffff, +0x3c010001, 0xa4220f76, 0x3c024000, 0x3021025, +0x3c010001, 0xac240f6c, 0xaf621008, 0x3e00008, +0x27bd0010, 0x3c030001, 0x90630f56, 0x27bdffe8, +0x24020001, 0xafbf0014, 0x10620026, 0xafb00010, +0x8f620cf4, 0x2442ffff, 0x3042007f, 0x21100, +0x8c434000, 0x3c010001, 0xac230f64, 0x8c434008, +0x24444000, 0x8c5c4004, 0x30620040, 0x14400002, +0x24020088, 0x24020008, 0x3c010001, 0xa4220f68, +0x30620004, 0x10400005, 0x24020001, 0x3c010001, +0xa0220f57, 0x80041d5, 0x31402, 0x3c010001, +0xa0200f57, 0x31402, 0x3c010001, 0xa4220f54, +0x9483000c, 0x24020001, 0x3c010001, 0xa4200f50, +0x3c010001, 0xa0220f56, 0x3c010001, 0xa4230f62, +0x24020001, 0x1342001e, 0x0, 0x13400005, +0x24020003, 0x13420067, 0x0, 0x80042cf, +0x0, 0x3c020001, 0x94420f62, 0x241a0001, +0x3c010001, 0xa4200f5e, 0x3c010001, 0xa4200f52, +0x304407ff, 0x21bc2, 0x31823, 0x3063003e, +0x34630036, 0x21242, 0x3042003c, 0x621821, +0x3c010001, 0xa4240f58, 0x832021, 0x24630030, +0x3c010001, 0xa4240f5a, 0x3c010001, 0xa4230f5c, +0x3c060001, 0x24c60f52, 0x94c50000, 0x94c30002, +0x3c040001, 0x94840f5a, 0x651021, 0x44102a, +0x10400013, 0x3c108000, 0xa31021, 0xa4c20000, +0x3c02a000, 0xaf620cf4, 0x3c010001, 0xa0200f56, +0x8f641008, 0x901024, 0x14400003, 0x0, +0xc004064, 0x0, 0x8f620cf4, 0x501024, +0x104000b7, 0x0, 0x800420f, 0x0, +0x3c030001, 0x94630f50, 0x851023, 0xa4c40000, +0x621821, 0x3042ffff, 0x3c010001, 0xa4230f50, +0xaf620ce8, 0x3c020001, 0x94420f68, 0x34420024, +0xaf620cec, 0x94c30002, 0x3c020001, 0x94420f50, +0x14620012, 0x3c028000, 0x3c108000, 0x3c02a000, +0xaf620cf4, 0x3c010001, 0xa0200f56, 0x8f641008, +0x901024, 0x14400003, 0x0, 0xc004064, +0x0, 0x8f620cf4, 0x501024, 0x1440fff7, +0x0, 0x80042cf, 0x241a0003, 0xaf620cf4, +0x3c108000, 0x8f641008, 0x901024, 0x14400003, +0x0, 0xc004064, 0x0, 0x8f620cf4, +0x501024, 0x1440fff7, 0x0, 0x80042cf, +0x241a0003, 0x3c070001, 0x24e70f50, 0x94e20000, +0x3821021, 0xaf620ce0, 0x3c020001, 0x8c420f64, +0xaf620ce4, 0x3c050001, 0x94a50f54, 0x94e30000, +0x3c040001, 0x94840f58, 0x3c020001, 0x94420f5e, +0xa32823, 0x822023, 0x30a6ffff, 0x3083ffff, +0xc3102b, 0x14400043, 0x0, 0x3c020001, +0x94420f5c, 0x21400, 0x621025, 0xaf620ce8, +0x94e20000, 0x3c030001, 0x94630f54, 0x441021, +0xa4e20000, 0x3042ffff, 0x14430021, 0x3c020008, +0x3c020001, 0x90420f57, 0x10400006, 0x3c03000c, +0x3c020001, 0x94420f68, 0x34630624, 0x800427c, +0xd021, 0x3c020001, 0x94420f68, 0x3c030008, +0x34630624, 0x431025, 0xaf620cec, 0x3c108000, +0x3c02a000, 0xaf620cf4, 0x3c010001, 0xa0200f56, +0x8f641008, 0x901024, 0x14400003, 0x0, +0xc004064, 0x0, 0x8f620cf4, 0x501024, +0x10400015, 0x0, 0x8004283, 0x0, +0x3c030001, 0x94630f68, 0x34420624, 0x3c108000, +0x621825, 0x3c028000, 0xaf630cec, 0xaf620cf4, +0x8f641008, 0x901024, 0x14400003, 0x0, +0xc004064, 0x0, 0x8f620cf4, 0x501024, +0x1440fff7, 0x0, 0x3c010001, 0x80042cf, +0xa4200f5e, 0x3c020001, 0x94420f5c, 0x21400, +0xc21025, 0xaf620ce8, 0x3c020001, 0x90420f57, +0x10400009, 0x3c03000c, 0x3c020001, 0x94420f68, +0x34630624, 0xd021, 0x431025, 0xaf620cec, +0x80042c1, 0x3c108000, 0x3c020001, 0x94420f68, +0x3c030008, 0x34630604, 0x431025, 0xaf620cec, +0x3c020001, 0x94420f5e, 0x451021, 0x3c010001, +0xa4220f5e, 0x3c108000, 0x3c02a000, 0xaf620cf4, +0x3c010001, 0xa0200f56, 0x8f641008, 0x901024, +0x14400003, 0x0, 0xc004064, 0x0, +0x8f620cf4, 0x501024, 0x1440fff7, 0x0, +0x8fbf0014, 0x8fb00010, 0x3e00008, 0x27bd0018, +0x0, 0x27bdffe0, 0x3c040001, 0x24840ec0, +0x2821, 0x3021, 0x3821, 0xafbf0018, +0xafa00010, 0xc004378, 0xafa00014, 0xd021, +0x24020130, 0xaf625000, 0x3c010001, 0xa4200f50, +0x3c010001, 0xa0200f57, 0x8fbf0018, 0x3e00008, +0x27bd0020, 0x27bdffe8, 0x3c1bc000, 0xafbf0014, +0xafb00010, 0xaf60680c, 0x8f626804, 0x34420082, +0xaf626804, 0x8f634000, 0x24020b50, 0x3c010001, +0xac220f20, 0x24020b78, 0x3c010001, 0xac220f30, +0x34630002, 0xaf634000, 0xc004315, 0x808021, +0x3c010001, 0xa0220f34, 0x304200ff, 0x24030002, +0x14430005, 0x0, 0x3c020001, 0x8c420f20, +0x8004308, 0xac5000c0, 0x3c020001, 0x8c420f20, +0xac5000bc, 0x8f624434, 0x8f634438, 0x8f644410, +0x3c010001, 0xac220f28, 0x3c010001, 0xac230f38, +0x3c010001, 0xac240f24, 0x8fbf0014, 0x8fb00010, +0x3e00008, 0x27bd0018, 0x3e00008, 0x24020001, +0x27bdfff8, 0x18800009, 0x2821, 0x8f63680c, +0x8f62680c, 0x1043fffe, 0x0, 0x24a50001, +0xa4102a, 0x1440fff9, 0x0, 0x3e00008, +0x27bd0008, 0x8f634450, 0x3c020001, 0x8c420f28, +0x31c02, 0x43102b, 0x14400008, 0x3c038000, +0x3c040001, 0x8c840f38, 0x8f624450, 0x21c02, +0x83102b, 0x1040fffc, 0x3c038000, 0xaf634444, +0x8f624444, 0x431024, 0x1440fffd, 0x0, +0x8f624448, 0x3e00008, 0x3042ffff, 0x3082ffff, +0x2442e000, 0x2c422001, 0x14400003, 0x3c024000, +0x8004347, 0x2402ffff, 0x822025, 0xaf645c38, +0x8f625c30, 0x30420002, 0x1440fffc, 0x1021, +0x3e00008, 0x0, 0x8f624450, 0x3c030001, +0x8c630f24, 0x8004350, 0x3042ffff, 0x8f624450, +0x3042ffff, 0x43102b, 0x1440fffc, 0x0, +0x3e00008, 0x0, 0x27bdffe0, 0x802821, +0x3c040001, 0x24840ed0, 0x3021, 0x3821, +0xafbf0018, 0xafa00010, 0xc004378, 0xafa00014, +0x800435f, 0x0, 0x8fbf0018, 0x3e00008, +0x27bd0020, 0x3c020001, 0x3442d600, 0x3c030001, +0x3463d600, 0x3c040001, 0x3484ddff, 0x3c010001, +0xac220f40, 0x24020040, 0x3c010001, 0xac220f44, +0x3c010001, 0xac200f3c, 0xac600000, 0x24630004, +0x83102b, 0x5040fffd, 0xac600000, 0x3e00008, +0x0, 0x804821, 0x8faa0010, 0x3c020001, +0x8c420f3c, 0x3c040001, 0x8c840f44, 0x8fab0014, +0x24430001, 0x44102b, 0x3c010001, 0xac230f3c, +0x14400003, 0x4021, 0x3c010001, 0xac200f3c, +0x3c020001, 0x8c420f3c, 0x3c030001, 0x8c630f40, +0x91240000, 0x21140, 0x431021, 0x481021, +0x25080001, 0xa0440000, 0x29020008, 0x1440fff4, +0x25290001, 0x3c020001, 0x8c420f3c, 0x3c030001, +0x8c630f40, 0x8f64680c, 0x21140, 0x431021, +0xac440008, 0xac45000c, 0xac460010, 0xac470014, +0xac4a0018, 0x3e00008, 0xac4b001c, 0x0, +0x0, 0x0 }; +U32 t3StkOffLd05FwRodata[(0x50/4) + 1] = { +0x4d61696e, +0x43707542, 0x0, 0x4d61696e, 0x43707541, +0x0, 0x0, 0x0, 0x73746b6f, +0x66666c64, 0x0, 0x0, 0x73746b6f, +0x66666c64, 0x0, 0x0, 0x66617461, +0x6c457272, 0x0, 0x0, 0x0 }; +U32 t3StkOffLd05FwData[(0x20/4) + 1] = { +0x0, +0x73746b6f, 0x66666c64, 0x5f76312e, 0x322e3000, +0x0, 0x0, 0x0, 0x0 }; + +#endif /* __FW_LSO05_H__ */ diff --git a/package/broadcom-57xx/src/fw_stkoffld.h b/package/broadcom-57xx/src/fw_stkoffld.h new file mode 100644 index 0000000000..119a17b341 --- /dev/null +++ b/package/broadcom-57xx/src/fw_stkoffld.h @@ -0,0 +1,519 @@ +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 - 2004 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* (c) COPYRIGHT 2000-2003 Broadcom Corporation, ALL RIGHTS RESERVED. */ +/* */ +/* Name: F W _ S T K O F F L D . H */ +/* Author : Kevin Tran */ +/* Version : 1.6 */ +/* */ +/* Module Description: This file contains firmware binary code of for TCP/IP */ +/* stack offload support. Currently, this firmware supports the following */ +/* features: */ +/* 1. TCP segmentation (aka Large Send Offload -- LSO) */ +/* 2. UDP Checksum offload support for IP fragmented UDP frames. */ +/* */ +/* History: */ +/* 07/17/01 Kevin Tran Incarnation. */ +/* 10/10/01 Kevin Tran Added UDP checksum offload support. */ +/* 10/20/01 Kevin Tran Fixed a problem where pseudo checksum is not */ +/* calculated correctly in case of IP */ +/* fragmentation case. */ +/* 10/30/01 Kevin Tran Fixed a problem where checksum is incorrectly */ +/* computed if bit BD_FLAG_TCP_UDP_CKSUM is set */ +/* in Send BDs. */ +/* 05/30/02 Kevin Tran Fixed a problem where UDP checksum is */ +/* incorrectly computed if the length of data is */ +/* less than 6 bytes in the last packetst of */ +/* of a chain of fragmented IP/UDP packets. */ +/* 12/01/02 Kevin Tran Fixed a problem where firmware might lockup */ +/* in a certain test scenario with BCM5704. */ +/* 12/10/02 Kevin Tran Fixed a problem where IP checksum might be */ +/* incorrectly calculated in some corner cases. */ +/* This problem should ONLY happen with BCM5702/ */ +/* BCM5703/BCM5704 ASICs. */ +/* 06/20/03 Kevin Tran Optimized performance so that pre-DMA code */ +/* doesn't have to wait until the first packet */ +/* is completely DMAed before it can setup DMAs */ +/* for subsequent packets. This requires host */ +/* driver to pass IP/TCP option lengths if any */ +/* to F/W via bit 15..12 of Send BD flag. */ +/* 08/12/03 Kevin Tran Fixed a problem where UDP checksum doesn't */ +/* work when the host driver seeds pseudo */ +/* checksum. */ +/* 12/24/03 Kevin Tran Fixed a problem where VLAN tag is not */ +/* inserted correctly in LSO mode. */ +/* 01/16/04 Kevin Tran Fixed a problem where Ethernet Type is not */ +/* set to 0x8870 when the outgoing LSO packet is */ +/* jumbo frame with SNAP encapsulation. */ +/******************************************************************************/ + +#ifndef __FW_STKOFFLD_H__ +#define __FW_STKOFFLD_H__ + +typedef LM_UINT32 U32; + +int t3StkOffLdFwReleaseMajor = 0x1; +int t3StkOffLdFwReleaseMinor = 0x6; +int t3StkOffLdFwReleaseFix = 0x0; +U32 t3StkOffLdFwStartAddr = 0x08000000; +U32 t3StkOffLdFwTextAddr = 0x08000000; +int t3StkOffLdFwTextLen = 0x1aa0; +U32 t3StkOffLdFwRodataAddr = 0x08001aa0; +int t3StkOffLdFwRodataLen = 0x60; +U32 t3StkOffLdFwDataAddr = 0x08001b20; +int t3StkOffLdFwDataLen = 0x30; +U32 t3StkOffLdFwSbssAddr = 0x08001b50; +int t3StkOffLdFwSbssLen = 0x2c; +U32 t3StkOffLdFwBssAddr = 0x08001b80; +int t3StkOffLdFwBssLen = 0x894; +U32 t3StkOffLdFwText[(0x1aa0/4) + 1] = { +0xe000003, 0x0, 0x8001b24, +0x0, 0x10000003, 0x0, 0xd, +0xd, 0x3c1d0800, 0x37bd4000, 0x3a0f021, +0x3c100800, 0x26100000, 0xe000010, 0x0, +0xd, 0x27bdffe0, 0x3c04fefe, 0xafbf0018, +0xe0005d8, 0x34840002, 0xe000668, 0x0, +0x3c030800, 0x90631b68, 0x24020002, 0x3c040800, +0x24841aac, 0x14620003, 0x24050001, 0x3c040800, +0x24841aa0, 0x24060006, 0x3821, 0xafa00010, +0xe00067c, 0xafa00014, 0x8f625c50, 0x34420001, +0xaf625c50, 0x8f625c90, 0x34420001, 0xaf625c90, +0x2402ffff, 0xe000034, 0xaf625404, 0x8fbf0018, +0x3e00008, 0x27bd0020, 0x0, 0x0, +0x0, 0x27bdffe0, 0xafbf001c, 0xafb20018, +0xafb10014, 0xe00005b, 0xafb00010, 0x24120002, +0x24110001, 0x8f706820, 0x32020100, 0x10400003, +0x0, 0xe0000bb, 0x0, 0x8f706820, +0x32022000, 0x10400004, 0x32020001, 0xe0001f0, +0x24040001, 0x32020001, 0x10400003, 0x0, +0xe0000a3, 0x0, 0x3c020800, 0x90421b98, +0x14520003, 0x0, 0xe0004c0, 0x0, +0xa00003c, 0xaf715028, 0x8fbf001c, 0x8fb20018, +0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0020, +0x27bdffe0, 0x3c040800, 0x24841ac0, 0x2821, +0x3021, 0x3821, 0xafbf0018, 0xafa00010, +0xe00067c, 0xafa00014, 0x3c040800, 0x248423d8, +0xa4800000, 0x3c010800, 0xa0201b98, 0x3c010800, +0xac201b9c, 0x3c010800, 0xac201ba0, 0x3c010800, +0xac201ba4, 0x3c010800, 0xac201bac, 0x3c010800, +0xac201bb8, 0x3c010800, 0xac201bbc, 0x8f624434, +0x3c010800, 0xac221b88, 0x8f624438, 0x3c010800, +0xac221b8c, 0x8f624410, 0xac80f7a8, 0x3c010800, +0xac201b84, 0x3c010800, 0xac2023e0, 0x3c010800, +0xac2023c8, 0x3c010800, 0xac2023cc, 0x3c010800, +0xac202400, 0x3c010800, 0xac221b90, 0x8f620068, +0x24030007, 0x21702, 0x10430005, 0x0, +0x8f620068, 0x21702, 0x14400004, 0x24020001, +0x3c010800, 0xa000097, 0xac20240c, 0xac820034, +0x3c040800, 0x24841acc, 0x3c050800, 0x8ca5240c, +0x3021, 0x3821, 0xafa00010, 0xe00067c, +0xafa00014, 0x8fbf0018, 0x3e00008, 0x27bd0020, +0x27bdffe0, 0x3c040800, 0x24841ad8, 0x2821, +0x3021, 0x3821, 0xafbf0018, 0xafa00010, +0xe00067c, 0xafa00014, 0xe00005b, 0x0, +0xe0000b4, 0x2021, 0x8fbf0018, 0x3e00008, +0x27bd0020, 0x24020001, 0x8f636820, 0x821004, +0x21027, 0x621824, 0x3e00008, 0xaf636820, +0x27bdffd0, 0xafbf002c, 0xafb60028, 0xafb50024, +0xafb40020, 0xafb3001c, 0xafb20018, 0xafb10014, +0xafb00010, 0x8f675c5c, 0x3c030800, 0x24631bbc, +0x8c620000, 0x14470005, 0x3c0200ff, 0x3c020800, +0x90421b98, 0x14400119, 0x3c0200ff, 0x3442fff8, +0xe28824, 0xac670000, 0x111902, 0x306300ff, +0x30e20003, 0x211c0, 0x622825, 0xa04021, +0x71602, 0x3c030800, 0x90631b98, 0x3044000f, +0x14600036, 0x804821, 0x24020001, 0x3c010800, +0xa0221b98, 0x51100, 0x821025, 0x3c010800, +0xac201b9c, 0x3c010800, 0xac201ba0, 0x3c010800, +0xac201ba4, 0x3c010800, 0xac201bac, 0x3c010800, +0xac201bb8, 0x3c010800, 0xac201bb0, 0x3c010800, +0xac201bb4, 0x3c010800, 0xa42223d8, 0x9622000c, +0x30437fff, 0x3c010800, 0xa4222410, 0x30428000, +0x3c010800, 0xa4231bc6, 0x10400005, 0x24020001, +0x3c010800, 0xac2223f4, 0xa000102, 0x2406003e, +0x24060036, 0x3c010800, 0xac2023f4, 0x9622000a, +0x3c030800, 0x94631bc6, 0x3c010800, 0xac2023f0, +0x3c010800, 0xac2023f8, 0x21302, 0x21080, +0xc21021, 0x621821, 0x3c010800, 0xa42223d0, +0x3c010800, 0xa000115, 0xa4231b96, 0x9622000c, +0x3c010800, 0xa42223ec, 0x3c040800, 0x24841b9c, +0x8c820000, 0x21100, 0x3c010800, 0x220821, +0xac311bc8, 0x8c820000, 0x21100, 0x3c010800, +0x220821, 0xac271bcc, 0x8c820000, 0x25030001, +0x306601ff, 0x21100, 0x3c010800, 0x220821, +0xac261bd0, 0x8c820000, 0x21100, 0x3c010800, +0x220821, 0xac291bd4, 0x96230008, 0x3c020800, +0x8c421bac, 0x432821, 0x3c010800, 0xac251bac, +0x9622000a, 0x30420004, 0x14400018, 0x61100, +0x8f630c14, 0x3063000f, 0x2c620002, 0x1440000b, +0x3c02c000, 0x8f630c14, 0x3c020800, 0x8c421b40, +0x3063000f, 0x24420001, 0x3c010800, 0xac221b40, +0x2c620002, 0x1040fff7, 0x3c02c000, 0xe21825, +0xaf635c5c, 0x8f625c50, 0x30420002, 0x10400014, +0x0, 0xa000147, 0x0, 0x3c030800, +0x8c631b80, 0x3c040800, 0x94841b94, 0x1221025, +0x3c010800, 0xa42223da, 0x24020001, 0x3c010800, +0xac221bb8, 0x24630001, 0x85202a, 0x3c010800, +0x10800003, 0xac231b80, 0x3c010800, 0xa4251b94, +0x3c060800, 0x24c61b9c, 0x8cc20000, 0x24420001, +0xacc20000, 0x28420080, 0x14400005, 0x0, +0xe000656, 0x24040002, 0xa0001e6, 0x0, +0x3c020800, 0x8c421bb8, 0x10400078, 0x24020001, +0x3c050800, 0x90a51b98, 0x14a20072, 0x0, +0x3c150800, 0x96b51b96, 0x3c040800, 0x8c841bac, +0x32a3ffff, 0x83102a, 0x1440006c, 0x0, +0x14830003, 0x0, 0x3c010800, 0xac2523f0, +0x1060005c, 0x9021, 0x24d60004, 0x60a021, +0x24d30014, 0x8ec20000, 0x28100, 0x3c110800, +0x2308821, 0xe000625, 0x8e311bc8, 0x402821, +0x10a00054, 0x0, 0x9628000a, 0x31020040, +0x10400005, 0x2407180c, 0x8e22000c, 0x2407188c, +0x21400, 0xaca20018, 0x3c030800, 0x701821, +0x8c631bd0, 0x3c020800, 0x501021, 0x8c421bd4, +0x31d00, 0x21400, 0x621825, 0xaca30014, +0x8ec30004, 0x96220008, 0x432023, 0x3242ffff, +0x3083ffff, 0x431021, 0x282102a, 0x14400002, +0x2b23023, 0x803021, 0x8e620000, 0x30c4ffff, +0x441021, 0xae620000, 0x8e220000, 0xaca20000, +0x8e220004, 0x8e63fff4, 0x431021, 0xaca20004, +0xa4a6000e, 0x8e62fff4, 0x441021, 0xae62fff4, +0x96230008, 0x43102a, 0x14400005, 0x2469021, +0x8e62fff0, 0xae60fff4, 0x24420001, 0xae62fff0, +0xaca00008, 0x3242ffff, 0x14540008, 0x24020305, +0x31020080, 0x54400001, 0x34e70010, 0x24020905, +0xa4a2000c, 0xa0001cb, 0x34e70020, 0xa4a2000c, +0x3c020800, 0x8c4223f0, 0x10400003, 0x3c024b65, +0xa0001d3, 0x34427654, 0x3c02b49a, 0x344289ab, +0xaca2001c, 0x30e2ffff, 0xaca20010, 0xe0005a2, +0xa02021, 0x3242ffff, 0x54102b, 0x1440ffa9, +0x0, 0x24020002, 0x3c010800, 0xa0001e6, +0xa0221b98, 0x8ec2083c, 0x24420001, 0xa0001e6, +0xaec2083c, 0xe0004c0, 0x0, 0x8fbf002c, +0x8fb60028, 0x8fb50024, 0x8fb40020, 0x8fb3001c, +0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, +0x27bd0030, 0x27bdffd0, 0xafbf0028, 0xafb30024, +0xafb20020, 0xafb1001c, 0xafb00018, 0x8f725c9c, +0x3c0200ff, 0x3442fff8, 0x3c070800, 0x24e71bb4, +0x2428824, 0x9623000e, 0x8ce20000, 0x431021, +0xace20000, 0x8e220010, 0x30420020, 0x14400011, +0x809821, 0xe00063b, 0x2202021, 0x3c02c000, +0x2421825, 0xaf635c9c, 0x8f625c90, 0x30420002, +0x1040011e, 0x0, 0xaf635c9c, 0x8f625c90, +0x30420002, 0x10400119, 0x0, 0xa00020d, +0x0, 0x8e240008, 0x8e230014, 0x41402, +0x231c0, 0x31502, 0x304201ff, 0x2442ffff, +0x3042007f, 0x31942, 0x30637800, 0x21100, +0x24424000, 0x624821, 0x9522000a, 0x3084ffff, +0x30420008, 0x104000b0, 0x429c0, 0x3c020800, +0x8c422400, 0x14400024, 0x24c50008, 0x94c20014, +0x3c010800, 0xa42223d0, 0x8cc40010, 0x41402, +0x3c010800, 0xa42223d2, 0x3c010800, 0xa42423d4, +0x94c2000e, 0x3083ffff, 0x431023, 0x3c010800, +0xac222408, 0x94c2001a, 0x3c010800, 0xac262400, +0x3c010800, 0xac322404, 0x3c010800, 0xac2223fc, +0x3c02c000, 0x2421825, 0xaf635c9c, 0x8f625c90, +0x30420002, 0x104000e5, 0x0, 0xaf635c9c, +0x8f625c90, 0x30420002, 0x104000e0, 0x0, +0xa000246, 0x0, 0x94c2000e, 0x3c030800, +0x946323d4, 0x434023, 0x3103ffff, 0x2c620008, +0x1040001c, 0x0, 0x94c20014, 0x24420028, +0xa22821, 0x31042, 0x1840000b, 0x2021, +0x24e60848, 0x403821, 0x94a30000, 0x8cc20000, +0x24840001, 0x431021, 0xacc20000, 0x87102a, +0x1440fff9, 0x24a50002, 0x31020001, 0x1040001f, +0x3c024000, 0x3c040800, 0x248423fc, 0xa0a00001, +0x94a30000, 0x8c820000, 0x431021, 0xa000285, +0xac820000, 0x8f626800, 0x3c030010, 0x431024, +0x10400009, 0x0, 0x94c2001a, 0x3c030800, +0x8c6323fc, 0x431021, 0x3c010800, 0xac2223fc, +0xa000286, 0x3c024000, 0x94c2001a, 0x94c4001c, +0x3c030800, 0x8c6323fc, 0x441023, 0x621821, +0x3c010800, 0xac2323fc, 0x3c024000, 0x2421825, +0xaf635c9c, 0x8f625c90, 0x30420002, 0x1440fffc, +0x0, 0x9522000a, 0x30420010, 0x1040009b, +0x0, 0x3c030800, 0x946323d4, 0x3c070800, +0x24e72400, 0x8ce40000, 0x8f626800, 0x24630030, +0x832821, 0x3c030010, 0x431024, 0x1440000a, +0x0, 0x94a20004, 0x3c040800, 0x8c842408, +0x3c030800, 0x8c6323fc, 0x441023, 0x621821, +0x3c010800, 0xac2323fc, 0x3c040800, 0x8c8423fc, +0x41c02, 0x3082ffff, 0x622021, 0x41402, +0x822021, 0x41027, 0xa4a20006, 0x3c030800, +0x8c632404, 0x3c0200ff, 0x3442fff8, 0x628824, +0x96220008, 0x24050001, 0x24034000, 0x231c0, +0x801021, 0xa4c2001a, 0xa4c0001c, 0xace00000, +0x3c010800, 0xac251b60, 0xaf635cb8, 0x8f625cb0, +0x30420002, 0x10400003, 0x0, 0x3c010800, +0xac201b60, 0x8e220008, 0xaf625cb8, 0x8f625cb0, +0x30420002, 0x10400003, 0x0, 0x3c010800, +0xac201b60, 0x3c020800, 0x8c421b60, 0x1040ffec, +0x0, 0x3c040800, 0xe00063b, 0x8c842404, +0xa00032a, 0x0, 0x3c030800, 0x90631b98, +0x24020002, 0x14620003, 0x3c034b65, 0xa0002e1, +0x8021, 0x8e22001c, 0x34637654, 0x10430002, +0x24100002, 0x24100001, 0xc02021, 0xe000350, +0x2003021, 0x24020003, 0x3c010800, 0xa0221b98, +0x24020002, 0x1202000a, 0x24020001, 0x3c030800, +0x8c6323f0, 0x10620006, 0x0, 0x3c020800, +0x944223d8, 0x21400, 0xa00031f, 0xae220014, +0x3c040800, 0x248423da, 0x94820000, 0x21400, +0xae220014, 0x3c020800, 0x8c421bbc, 0x3c03c000, +0x3c010800, 0xa0201b98, 0x431025, 0xaf625c5c, +0x8f625c50, 0x30420002, 0x10400009, 0x0, +0x2484f7e2, 0x8c820000, 0x431025, 0xaf625c5c, +0x8f625c50, 0x30420002, 0x1440fffa, 0x0, +0x3c020800, 0x24421b84, 0x8c430000, 0x24630001, +0xac430000, 0x8f630c14, 0x3063000f, 0x2c620002, +0x1440000c, 0x3c024000, 0x8f630c14, 0x3c020800, +0x8c421b40, 0x3063000f, 0x24420001, 0x3c010800, +0xac221b40, 0x2c620002, 0x1040fff7, 0x0, +0x3c024000, 0x2421825, 0xaf635c9c, 0x8f625c90, +0x30420002, 0x1440fffc, 0x0, 0x12600003, +0x0, 0xe0004c0, 0x0, 0x8fbf0028, +0x8fb30024, 0x8fb20020, 0x8fb1001c, 0x8fb00018, +0x3e00008, 0x27bd0030, 0x8f634450, 0x3c040800, +0x24841b88, 0x8c820000, 0x31c02, 0x43102b, +0x14400007, 0x3c038000, 0x8c840004, 0x8f624450, +0x21c02, 0x83102b, 0x1040fffc, 0x3c038000, +0xaf634444, 0x8f624444, 0x431024, 0x1440fffd, +0x0, 0x8f624448, 0x3e00008, 0x3042ffff, +0x3c024000, 0x822025, 0xaf645c38, 0x8f625c30, +0x30420002, 0x1440fffc, 0x0, 0x3e00008, +0x0, 0x27bdffe0, 0x805821, 0x14c00011, +0x256e0008, 0x3c020800, 0x8c4223f4, 0x10400007, +0x24020016, 0x3c010800, 0xa42223d2, 0x2402002a, +0x3c010800, 0xa000364, 0xa42223d4, 0x8d670010, +0x71402, 0x3c010800, 0xa42223d2, 0x3c010800, +0xa42723d4, 0x3c040800, 0x948423d4, 0x3c030800, +0x946323d2, 0x95cf0006, 0x3c020800, 0x944223d0, +0x832023, 0x1e2c023, 0x3065ffff, 0x24a20028, +0x1c24821, 0x3082ffff, 0x14c0001a, 0x1226021, +0x9582000c, 0x3042003f, 0x3c010800, 0xa42223d6, +0x95820004, 0x95830006, 0x3c010800, 0xac2023e4, +0x3c010800, 0xac2023e8, 0x21400, 0x431025, +0x3c010800, 0xac221bc0, 0x95220004, 0x3c010800, +0xa4221bc4, 0x95230002, 0x1e51023, 0x43102a, +0x10400010, 0x24020001, 0x3c010800, 0xa000398, +0xac2223f8, 0x3c030800, 0x8c6323e8, 0x3c020800, +0x94421bc4, 0x431021, 0xa5220004, 0x3c020800, +0x94421bc0, 0xa5820004, 0x3c020800, 0x8c421bc0, +0xa5820006, 0x3c020800, 0x8c4223f0, 0x3c0d0800, +0x8dad23e4, 0x3c0a0800, 0x144000e5, 0x8d4a23e8, +0x3c020800, 0x94421bc4, 0x4a1821, 0x3063ffff, +0x62182b, 0x24020002, 0x10c2000d, 0x1435023, +0x3c020800, 0x944223d6, 0x30420009, 0x10400008, +0x0, 0x9582000c, 0x3042fff6, 0xa582000c, +0x3c020800, 0x944223d6, 0x30420009, 0x1a26823, +0x3c020800, 0x8c4223f8, 0x1040004a, 0x1203821, +0x3c020800, 0x944223d2, 0x4021, 0xa520000a, +0x1e21023, 0xa5220002, 0x3082ffff, 0x21042, +0x18400008, 0x3021, 0x401821, 0x94e20000, +0x25080001, 0xc23021, 0x103102a, 0x1440fffb, +0x24e70002, 0x61c02, 0x30c2ffff, 0x623021, +0x61402, 0xc23021, 0xc02821, 0x61027, +0xa522000a, 0x3021, 0x2527000c, 0x4021, +0x94e20000, 0x25080001, 0xc23021, 0x2d020004, +0x1440fffb, 0x24e70002, 0x95220002, 0x4021, +0x91230009, 0x442023, 0x1803821, 0x3082ffff, +0xa4e00010, 0x621821, 0x21042, 0x18400010, +0xc33021, 0x404821, 0x94e20000, 0x24e70002, +0xc23021, 0x30e2007f, 0x14400006, 0x25080001, +0x8d630000, 0x3c02007f, 0x3442ff80, 0x625824, +0x25670008, 0x109102a, 0x1440fff3, 0x0, +0x30820001, 0x10400005, 0x61c02, 0xa0e00001, +0x94e20000, 0xc23021, 0x61c02, 0x30c2ffff, +0x623021, 0x61402, 0xc23021, 0xa00047d, +0x30c6ffff, 0x24020002, 0x14c20081, 0x0, +0x3c020800, 0x8c42240c, 0x14400007, 0x0, +0x3c020800, 0x944223d2, 0x95230002, 0x1e21023, +0x10620077, 0x0, 0x3c020800, 0x944223d2, +0x1e21023, 0xa5220002, 0x3c020800, 0x8c42240c, +0x1040001a, 0x31e3ffff, 0x8dc70010, 0x3c020800, +0x94421b96, 0xe04021, 0x72c02, 0xaa2021, +0x431023, 0x823823, 0x72402, 0x30e2ffff, +0x823821, 0x71027, 0xa522000a, 0x3102ffff, +0x3c040800, 0x948423d4, 0x453023, 0xe02821, +0x641823, 0x6d1821, 0xc33021, 0x61c02, +0x30c2ffff, 0xa00047d, 0x623021, 0x1203821, +0x4021, 0x3082ffff, 0x21042, 0x18400008, +0x3021, 0x401821, 0x94e20000, 0x25080001, +0xc23021, 0x103102a, 0x1440fffb, 0x24e70002, +0x61c02, 0x30c2ffff, 0x623021, 0x61402, +0xc23021, 0xc02821, 0x61027, 0xa522000a, +0x3021, 0x2527000c, 0x4021, 0x94e20000, +0x25080001, 0xc23021, 0x2d020004, 0x1440fffb, +0x24e70002, 0x95220002, 0x4021, 0x91230009, +0x442023, 0x1803821, 0x3082ffff, 0xa4e00010, +0x3c040800, 0x948423d4, 0x621821, 0xc33021, +0x61c02, 0x30c2ffff, 0x623021, 0x61c02, +0x3c020800, 0x944223d0, 0xc34821, 0x441023, +0x21fc2, 0x431021, 0x21043, 0x18400010, +0x3021, 0x402021, 0x94e20000, 0x24e70002, +0xc23021, 0x30e2007f, 0x14400006, 0x25080001, +0x8d630000, 0x3c02007f, 0x3442ff80, 0x625824, +0x25670008, 0x104102a, 0x1440fff3, 0x0, +0x3c020800, 0x944223ec, 0xc23021, 0x3122ffff, +0xc23021, 0x61c02, 0x30c2ffff, 0x623021, +0x61402, 0xc23021, 0xc04021, 0x61027, +0xa5820010, 0xadc00014, 0xa00049d, 0xadc00000, +0x8dc70010, 0xe04021, 0x11400007, 0x72c02, +0xaa3021, 0x61402, 0x30c3ffff, 0x433021, +0x61402, 0xc22821, 0x51027, 0xa522000a, +0x3c030800, 0x946323d4, 0x3102ffff, 0x1e21021, +0x433023, 0xcd3021, 0x61c02, 0x30c2ffff, +0x623021, 0x61402, 0xc23021, 0xc04021, +0x61027, 0xa5820010, 0x3102ffff, 0x51c00, +0x431025, 0xadc20010, 0x3c020800, 0x8c4223f4, +0x10400005, 0x2de205eb, 0x14400002, 0x25e2fff2, +0x34028870, 0xa5c20034, 0x3c030800, 0x246323e8, +0x8c620000, 0x24420001, 0xac620000, 0x3c040800, +0x8c8423e4, 0x3c020800, 0x8c421bc0, 0x3303ffff, +0x832021, 0x431821, 0x62102b, 0x3c010800, +0xac2423e4, 0x10400003, 0x2482ffff, 0x3c010800, +0xac2223e4, 0x3c010800, 0xac231bc0, 0x3e00008, +0x27bd0020, 0x27bdffb8, 0x3c050800, 0x24a51b96, +0xafbf0044, 0xafbe0040, 0xafb7003c, 0xafb60038, +0xafb50034, 0xafb40030, 0xafb3002c, 0xafb20028, +0xafb10024, 0xafb00020, 0x94a90000, 0x3c020800, +0x944223d0, 0x3c030800, 0x8c631bb0, 0x3c040800, +0x8c841bac, 0x1221023, 0x64182a, 0xa7a9001e, +0x106000be, 0xa7a20016, 0x24be0022, 0x97b6001e, +0x24b3001a, 0x24b70016, 0x8fc20000, 0x14400008, +0x0, 0x8fc2fff8, 0x97a30016, 0x8fc4fff4, +0x431021, 0x82202a, 0x148000b0, 0x0, +0x97d50818, 0x32a2ffff, 0x104000a3, 0x9021, +0x40a021, 0x8821, 0xe000625, 0x0, +0x403021, 0x14c00007, 0x0, 0x3c020800, +0x8c4223dc, 0x24420001, 0x3c010800, 0xa000596, +0xac2223dc, 0x3c100800, 0x2118021, 0x8e101bc8, +0x9608000a, 0x31020040, 0x10400005, 0x2407180c, +0x8e02000c, 0x2407188c, 0x21400, 0xacc20018, +0x31020080, 0x54400001, 0x34e70010, 0x3c020800, +0x511021, 0x8c421bd0, 0x3c030800, 0x711821, +0x8c631bd4, 0x21500, 0x31c00, 0x431025, +0xacc20014, 0x96040008, 0x3242ffff, 0x821021, +0x282102a, 0x14400002, 0x2b22823, 0x802821, +0x8e020000, 0x2459021, 0xacc20000, 0x8e020004, +0xc02021, 0x26310010, 0xac820004, 0x30e2ffff, +0xac800008, 0xa485000e, 0xac820010, 0x24020305, +0xe0005a2, 0xa482000c, 0x3242ffff, 0x54102b, +0x1440ffc5, 0x3242ffff, 0xa00058e, 0x0, +0x8e620000, 0x8e63fffc, 0x43102a, 0x10400067, +0x0, 0x8e62fff0, 0x28900, 0x3c100800, +0x2118021, 0xe000625, 0x8e101bc8, 0x403021, +0x14c00005, 0x0, 0x8e62082c, 0x24420001, +0xa000596, 0xae62082c, 0x9608000a, 0x31020040, +0x10400005, 0x2407180c, 0x8e02000c, 0x2407188c, +0x21400, 0xacc20018, 0x3c020800, 0x511021, +0x8c421bd0, 0x3c030800, 0x711821, 0x8c631bd4, +0x21500, 0x31c00, 0x431025, 0xacc20014, +0x8e63fff4, 0x96020008, 0x432023, 0x3242ffff, +0x3083ffff, 0x431021, 0x2c2102a, 0x10400003, +0x802821, 0x97a9001e, 0x1322823, 0x8e620000, +0x30a4ffff, 0x441021, 0xae620000, 0xa4c5000e, +0x8e020000, 0xacc20000, 0x8e020004, 0x8e63fff4, +0x431021, 0xacc20004, 0x8e63fff4, 0x96020008, +0x641821, 0x62102a, 0x14400006, 0x2459021, +0x8e62fff0, 0xae60fff4, 0x24420001, 0xa000571, +0xae62fff0, 0xae63fff4, 0xacc00008, 0x3242ffff, +0x10560003, 0x31020004, 0x10400006, 0x24020305, +0x31020080, 0x54400001, 0x34e70010, 0x34e70020, +0x24020905, 0xa4c2000c, 0x8ee30000, 0x8ee20004, +0x14620007, 0x3c02b49a, 0x8ee20860, 0x54400001, +0x34e70400, 0x3c024b65, 0xa000588, 0x34427654, +0x344289ab, 0xacc2001c, 0x30e2ffff, 0xacc20010, +0xe0005a2, 0xc02021, 0x3242ffff, 0x56102b, +0x1440ff9b, 0x0, 0x8e620000, 0x8e63fffc, +0x43102a, 0x1440ff48, 0x0, 0x8fbf0044, +0x8fbe0040, 0x8fb7003c, 0x8fb60038, 0x8fb50034, +0x8fb40030, 0x8fb3002c, 0x8fb20028, 0x8fb10024, +0x8fb00020, 0x3e00008, 0x27bd0048, 0x27bdffe8, +0xafbf0014, 0xafb00010, 0x8f624450, 0x8f634410, +0xa0005b1, 0x808021, 0x8f626820, 0x30422000, +0x10400003, 0x0, 0xe0001f0, 0x2021, +0x8f624450, 0x8f634410, 0x3042ffff, 0x43102b, +0x1440fff5, 0x0, 0x8f630c14, 0x3063000f, +0x2c620002, 0x1440000b, 0x0, 0x8f630c14, +0x3c020800, 0x8c421b40, 0x3063000f, 0x24420001, +0x3c010800, 0xac221b40, 0x2c620002, 0x1040fff7, +0x0, 0xaf705c18, 0x8f625c10, 0x30420002, +0x10400009, 0x0, 0x8f626820, 0x30422000, +0x1040fff8, 0x0, 0xe0001f0, 0x2021, +0xa0005c4, 0x0, 0x8fbf0014, 0x8fb00010, +0x3e00008, 0x27bd0018, 0x0, 0x0, +0x0, 0x27bdffe8, 0x3c1bc000, 0xafbf0014, +0xafb00010, 0xaf60680c, 0x8f626804, 0x34420082, +0xaf626804, 0x8f634000, 0x24020b50, 0x3c010800, +0xac221b54, 0x24020b78, 0x3c010800, 0xac221b64, +0x34630002, 0xaf634000, 0xe000605, 0x808021, +0x3c010800, 0xa0221b68, 0x304200ff, 0x24030002, +0x14430005, 0x0, 0x3c020800, 0x8c421b54, +0xa0005f8, 0xac5000c0, 0x3c020800, 0x8c421b54, +0xac5000bc, 0x8f624434, 0x8f634438, 0x8f644410, +0x3c010800, 0xac221b5c, 0x3c010800, 0xac231b6c, +0x3c010800, 0xac241b58, 0x8fbf0014, 0x8fb00010, +0x3e00008, 0x27bd0018, 0x3c040800, 0x8c870000, +0x3c03aa55, 0x3463aa55, 0x3c06c003, 0xac830000, +0x8cc20000, 0x14430007, 0x24050002, 0x3c0355aa, +0x346355aa, 0xac830000, 0x8cc20000, 0x50430001, +0x24050001, 0x3c020800, 0xac470000, 0x3e00008, +0xa01021, 0x27bdfff8, 0x18800009, 0x2821, +0x8f63680c, 0x8f62680c, 0x1043fffe, 0x0, +0x24a50001, 0xa4102a, 0x1440fff9, 0x0, +0x3e00008, 0x27bd0008, 0x8f634450, 0x3c020800, +0x8c421b5c, 0x31c02, 0x43102b, 0x14400008, +0x3c038000, 0x3c040800, 0x8c841b6c, 0x8f624450, +0x21c02, 0x83102b, 0x1040fffc, 0x3c038000, +0xaf634444, 0x8f624444, 0x431024, 0x1440fffd, +0x0, 0x8f624448, 0x3e00008, 0x3042ffff, +0x3082ffff, 0x2442e000, 0x2c422001, 0x14400003, +0x3c024000, 0xa000648, 0x2402ffff, 0x822025, +0xaf645c38, 0x8f625c30, 0x30420002, 0x1440fffc, +0x1021, 0x3e00008, 0x0, 0x8f624450, +0x3c030800, 0x8c631b58, 0xa000651, 0x3042ffff, +0x8f624450, 0x3042ffff, 0x43102b, 0x1440fffc, +0x0, 0x3e00008, 0x0, 0x27bdffe0, +0x802821, 0x3c040800, 0x24841af0, 0x3021, +0x3821, 0xafbf0018, 0xafa00010, 0xe00067c, +0xafa00014, 0xa000660, 0x0, 0x8fbf0018, +0x3e00008, 0x27bd0020, 0x0, 0x0, +0x0, 0x3c020800, 0x34423000, 0x3c030800, +0x34633000, 0x3c040800, 0x348437ff, 0x3c010800, +0xac221b74, 0x24020040, 0x3c010800, 0xac221b78, +0x3c010800, 0xac201b70, 0xac600000, 0x24630004, +0x83102b, 0x5040fffd, 0xac600000, 0x3e00008, +0x0, 0x804821, 0x8faa0010, 0x3c020800, +0x8c421b70, 0x3c040800, 0x8c841b78, 0x8fab0014, +0x24430001, 0x44102b, 0x3c010800, 0xac231b70, +0x14400003, 0x4021, 0x3c010800, 0xac201b70, +0x3c020800, 0x8c421b70, 0x3c030800, 0x8c631b74, +0x91240000, 0x21140, 0x431021, 0x481021, +0x25080001, 0xa0440000, 0x29020008, 0x1440fff4, +0x25290001, 0x3c020800, 0x8c421b70, 0x3c030800, +0x8c631b74, 0x8f64680c, 0x21140, 0x431021, +0xac440008, 0xac45000c, 0xac460010, 0xac470014, +0xac4a0018, 0x3e00008, 0xac4b001c, 0x0, +0x0, 0x0 }; +U32 t3StkOffLdFwRodata[(0x60/4) + 1] = { +0x4d61696e, +0x43707542, 0x0, 0x4d61696e, 0x43707541, +0x0, 0x0, 0x0, 0x73746b6f, +0x66666c64, 0x496e0000, 0x73746b6f, 0x66662a2a, +0x0, 0x53774576, 0x656e7430, 0x0, +0x0, 0x0, 0x0, 0x66617461, +0x6c457272, 0x0, 0x0, 0x0 }; +U32 t3StkOffLdFwData[(0x30/4) + 1] = { +0x0, 0x73746b6f, 0x66666c64, +0x5f76312e, 0x362e3000, 0x0, 0x0, +0x0, 0x0, 0x0, 0x0, +0x0, 0x0 }; + +#endif /* __FW_STKOFFLD_H__ */ diff --git a/package/broadcom-57xx/src/hndgige.c b/package/broadcom-57xx/src/hndgige.c new file mode 100644 index 0000000000..19774934a3 --- /dev/null +++ b/package/broadcom-57xx/src/hndgige.c @@ -0,0 +1,146 @@ +/* + * HND SiliconBackplane Gigabit Ethernet core software interface + * + * Copyright 2007, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * + * $Id: hndgige.c,v 1.6 2007/06/01 05:59:06 michael Exp $ + */ + +#include +#include +#include +#include +#include +#include "sbgige.h" +#include +#include "hndgige.h" + +uint32 +sb_base(uint32 admatch) +{ + uint32 base; + uint type; + + type = admatch & SBAM_TYPE_MASK; + ASSERT(type < 3); + + base = 0; + + if (type == 0) { + base = admatch & SBAM_BASE0_MASK; + } else if (type == 1) { + ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ + base = admatch & SBAM_BASE1_MASK; + } else if (type == 2) { + ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */ + base = admatch & SBAM_BASE2_MASK; + } + + return (base); +} + +/* + * Setup the gige core. + * Resetting the core will lose all settings. + */ +void +sb_gige_init(sb_t *sbh, uint32 unit, bool *rgmii) +{ + volatile pci_config_regs *pci; + sbgige_pcishim_t *ocp; + sbconfig_t *sb; + osl_t *osh; + uint32 statelow; + uint32 statehigh; + uint32 base; + uint32 idx; + void *regs; + + /* Sanity checks */ + ASSERT(sbh); + ASSERT(rgmii); + + idx = sb_coreidx(sbh); + + /* point to the gige core registers */ + regs = sb_setcore(sbh, SB_GIGETH, unit); + ASSERT(regs); + + osh = sb_osh(sbh); + + pci = &((sbgige_t *)regs)->pcicfg; + ocp = &((sbgige_t *)regs)->pcishim; + sb = &((sbgige_t *)regs)->sbconfig; + + /* Enable the core clock and memory access */ + if (!sb_iscoreup(sbh)) + sb_core_reset(sbh, 0, 0); + + /* + * Setup the 64K memory-mapped region base address through BAR0. + * Leave the other BAR values alone. + */ + base = sb_base(R_REG(osh, &sb->sbadmatch1)); + W_REG(osh, &pci->base[0], base); + W_REG(osh, &pci->base[1], 0); + + /* + * Enable the PCI memory access anyway. Any PCI config commands + * issued before the core is enabled will go to the emulation + * only and will not go to the real PCI config registers. + */ + OR_REG(osh, &pci->command, 2); + + /* + * Enable the posted write flush scheme as follows: + * + * - Enable flush on any core register read + * - Enable timeout on the flush + * - Disable the interrupt mask when flushing + * + * This differs from the default setting only in that interrupts are + * not masked. Since posted writes are not flushed on interrupt, the + * driver must explicitly request a flush in its interrupt handling + * by reading a core register. + */ + W_REG(osh, &ocp->FlushStatusControl, 0x68); + + /* + * Determine whether the GbE is in GMII or RGMII mode. This is + * indicated in bit 16 of the SBTMStateHigh register, which is + * part of the core-specific flags field. + * + * For GMII, bypass the Rx/Tx DLLs, i.e. add no delay to RXC/GTXC + * within the core. For RGMII, do not bypass the DLLs, resulting + * in added delay for RXC/GTXC. The SBTMStateLow register contains + * the controls for doing this in the core-specific flags field: + * + * bit 24 - Enable DLL controls + * bit 20 - Bypass Rx DLL + * bit 19 - Bypass Tx DLL + */ + statelow = R_REG(osh, &sb->sbtmstatelow); /* DLL controls */ + statehigh = R_REG(osh, &sb->sbtmstatehigh); /* GMII/RGMII mode */ + if ((statehigh & (1 << 16)) != 0) /* RGMII */ + { + statelow &= ~(1 << 20); /* no Rx bypass (delay) */ + statelow &= ~(1 << 19); /* no Tx bypass (delay) */ + *rgmii = TRUE; + } + else /* GMII */ + { + statelow |= (1 << 20); /* Rx bypass (no delay) */ + statelow |= (1 << 19); /* Tx bypass (no delay) */ + *rgmii = FALSE; + } + statelow |= (1 << 24); /* enable DLL controls */ + W_REG(osh, &sb->sbtmstatelow, statelow); + + sb_setcoreidx(sbh, idx); +} diff --git a/package/broadcom-57xx/src/hndgige.h b/package/broadcom-57xx/src/hndgige.h new file mode 100644 index 0000000000..cdda406cf5 --- /dev/null +++ b/package/broadcom-57xx/src/hndgige.h @@ -0,0 +1,20 @@ +/* + * HND SiliconBackplane Gigabit Ethernet core software interface. + * + * Copyright 2007, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * + * $Id: hndgige.h,v 1.5 2007/06/01 05:58:20 michael Exp $ + */ + +#ifndef _hndgige_h_ +#define _hndgige_h_ + +extern void sb_gige_init(sb_t *sbh, uint32 unit, bool *rgmii); + +#endif /* _hndgige_h_ */ diff --git a/package/broadcom-57xx/src/lm.h b/package/broadcom-57xx/src/lm.h new file mode 100644 index 0000000000..81d40f1382 --- /dev/null +++ b/package/broadcom-57xx/src/lm.h @@ -0,0 +1,483 @@ +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 - 2004 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* History: */ +/* 02/25/00 Hav Khauv Initial version. */ +/******************************************************************************/ + +#ifndef LM_H +#define LM_H + +#include "queue.h" +#include "bits.h" + + + +/******************************************************************************/ +/* Basic types. */ +/******************************************************************************/ + +typedef char LM_CHAR, *PLM_CHAR; +typedef unsigned int LM_UINT, *PLM_UINT; +typedef unsigned char LM_UINT8, *PLM_UINT8; +typedef unsigned short LM_UINT16, *PLM_UINT16; +typedef unsigned int LM_UINT32, *PLM_UINT32; +typedef unsigned int LM_COUNTER, *PLM_COUNTER; +typedef void LM_VOID, *PLM_VOID; +typedef char LM_BOOL, *PLM_BOOL; + +/* 64bit value. */ +typedef struct { +#ifdef BIG_ENDIAN_HOST + LM_UINT32 High; + LM_UINT32 Low; +#else /* BIG_ENDIAN_HOST */ + LM_UINT32 Low; + LM_UINT32 High; +#endif /* !BIG_ENDIAN_HOST */ +} LM_UINT64, *PLM_UINT64; + +typedef LM_UINT64 LM_PHYSICAL_ADDRESS, *PLM_PHYSICAL_ADDRESS; + +/* void LM_INC_PHYSICAL_ADDRESS(PLM_PHYSICAL_ADDRESS pAddr,LM_UINT32 IncSize) */ +#define LM_INC_PHYSICAL_ADDRESS(pAddr, IncSize) \ + { \ + LM_UINT32 OrgLow; \ + \ + OrgLow = (pAddr)->Low; \ + (pAddr)->Low += IncSize; \ + if((pAddr)->Low < OrgLow) { \ + (pAddr)->High++; /* Wrap around. */ \ + } \ + } + + +#ifndef TRUE +#define TRUE 1 +#endif /* TRUE */ + +#ifndef FALSE +#define FALSE 0 +#endif /* FALSE */ + +#ifndef NULL +#define NULL ((void *) 0) +#endif /* NULL */ + +#ifndef OFFSETOF +#define OFFSETOF(_s, _m) (MM_UINT_PTR(&(((_s *) 0)->_m))) +#endif /* OFFSETOF */ + + + +/******************************************************************************/ +/* Simple macros. */ +/******************************************************************************/ + +#define IS_ETH_BROADCAST(_pEthAddr) \ + (((unsigned char *) (_pEthAddr))[0] == ((unsigned char) 0xff)) + +#define IS_ETH_MULTICAST(_pEthAddr) \ + (((unsigned char *) (_pEthAddr))[0] & ((unsigned char) 0x01)) + +#define IS_ETH_ADDRESS_EQUAL(_pEtherAddr1, _pEtherAddr2) \ + ((((unsigned char *) (_pEtherAddr1))[0] == \ + ((unsigned char *) (_pEtherAddr2))[0]) && \ + (((unsigned char *) (_pEtherAddr1))[1] == \ + ((unsigned char *) (_pEtherAddr2))[1]) && \ + (((unsigned char *) (_pEtherAddr1))[2] == \ + ((unsigned char *) (_pEtherAddr2))[2]) && \ + (((unsigned char *) (_pEtherAddr1))[3] == \ + ((unsigned char *) (_pEtherAddr2))[3]) && \ + (((unsigned char *) (_pEtherAddr1))[4] == \ + ((unsigned char *) (_pEtherAddr2))[4]) && \ + (((unsigned char *) (_pEtherAddr1))[5] == \ + ((unsigned char *) (_pEtherAddr2))[5])) + +#define COPY_ETH_ADDRESS(_Src, _Dst) \ + ((unsigned char *) (_Dst))[0] = ((unsigned char *) (_Src))[0]; \ + ((unsigned char *) (_Dst))[1] = ((unsigned char *) (_Src))[1]; \ + ((unsigned char *) (_Dst))[2] = ((unsigned char *) (_Src))[2]; \ + ((unsigned char *) (_Dst))[3] = ((unsigned char *) (_Src))[3]; \ + ((unsigned char *) (_Dst))[4] = ((unsigned char *) (_Src))[4]; \ + ((unsigned char *) (_Dst))[5] = ((unsigned char *) (_Src))[5]; + + + +/******************************************************************************/ +/* Constants. */ +/******************************************************************************/ + +#define ETHERNET_ADDRESS_SIZE 6 +#define ETHERNET_PACKET_HEADER_SIZE 14 +#define MIN_ETHERNET_PACKET_SIZE 64 /* with 4 byte crc. */ +#define MAX_ETHERNET_PACKET_SIZE 1518 /* with 4 byte crc. */ +#define MIN_ETHERNET_PACKET_SIZE_NO_CRC 60 +#define MAX_ETHERNET_PACKET_SIZE_NO_CRC 1514 +#define MAX_ETHERNET_PACKET_BUFFER_SIZE 1536 /* A nice even number. */ +#define MAX_ETHERNET_JUMBO_PACKET_SIZE_NO_CRC 9014 + +#ifndef LM_MAX_MC_TABLE_SIZE +#define LM_MAX_MC_TABLE_SIZE 32 +#endif /* LM_MAX_MC_TABLE_SIZE */ +#define LM_MC_ENTRY_SIZE (ETHERNET_ADDRESS_SIZE+1) +#define LM_MC_INSTANCE_COUNT_INDEX (LM_MC_ENTRY_SIZE-1) + + +/* Receive filter masks. */ +#define LM_ACCEPT_UNICAST 0x0001 +#define LM_ACCEPT_MULTICAST 0x0002 +#define LM_ACCEPT_ALL_MULTICAST 0x0004 +#define LM_ACCEPT_BROADCAST 0x0008 +#define LM_ACCEPT_ERROR_PACKET 0x0010 +#define LM_KEEP_VLAN_TAG 0x0020 + +#define LM_PROMISCUOUS_MODE 0x10000 + + + +/******************************************************************************/ +/* PCI registers. */ +/******************************************************************************/ + +#define PCI_VENDOR_ID_REG 0x00 +#define PCI_DEVICE_ID_REG 0x02 + +#define PCI_COMMAND_REG 0x04 +#define PCI_IO_SPACE_ENABLE 0x0001 +#define PCI_MEM_SPACE_ENABLE 0x0002 +#define PCI_BUSMASTER_ENABLE 0x0004 +#define PCI_MEMORY_WRITE_INVALIDATE 0x0010 +#define PCI_PARITY_ERROR_ENABLE 0x0040 +#define PCI_SYSTEM_ERROR_ENABLE 0x0100 +#define PCI_FAST_BACK_TO_BACK_ENABLE 0x0200 + +#define PCI_STATUS_REG 0x06 +#define PCI_REV_ID_REG 0x08 + +#define PCI_CACHE_LINE_SIZE_REG 0x0c + +#define PCI_IO_BASE_ADDR_REG 0x10 +#define PCI_IO_BASE_ADDR_MASK 0xfffffff0 + +#define PCI_MEM_BASE_ADDR_LOW 0x10 +#define PCI_MEM_BASE_ADDR_HIGH 0x14 + +#define PCI_SUBSYSTEM_VENDOR_ID_REG 0x2c +#define PCI_SUBSYSTEM_ID_REG 0x2e +#define PCI_INT_LINE_REG 0x3c + +#define PCIX_CAP_REG 0x40 +#define PCIX_ENABLE_RELAXED_ORDERING BIT_17 + +/******************************************************************************/ +/* Fragment structure. */ +/******************************************************************************/ + +typedef struct { + LM_UINT32 FragSize; + LM_PHYSICAL_ADDRESS FragBuf; +} LM_FRAG, *PLM_FRAG; + +typedef struct { + /* FragCount is initialized for the caller to the maximum array size, on */ + /* return FragCount is the number of the actual fragments in the array. */ + LM_UINT32 FragCount; + + /* Total buffer size. */ + LM_UINT32 TotalSize; + + /* Fragment array buffer. */ + LM_FRAG Fragments[1]; +} LM_FRAG_LIST, *PLM_FRAG_LIST; + +#define DECLARE_FRAG_LIST_BUFFER_TYPE(_FRAG_LIST_TYPE_NAME, _MAX_FRAG_COUNT) \ + typedef struct { \ + LM_FRAG_LIST FragList; \ + LM_FRAG FragListBuffer[_MAX_FRAG_COUNT-1]; \ + } _FRAG_LIST_TYPE_NAME, *P##_FRAG_LIST_TYPE_NAME + + + +/******************************************************************************/ +/* Status codes. */ +/******************************************************************************/ + +#define LM_STATUS_SUCCESS 0 +#define LM_STATUS_FAILURE 1 + +#define LM_STATUS_INTERRUPT_ACTIVE 2 +#define LM_STATUS_INTERRUPT_NOT_ACTIVE 3 + +#define LM_STATUS_LINK_ACTIVE 4 +#define LM_STATUS_LINK_DOWN 5 +#define LM_STATUS_LINK_SETTING_MISMATCH 6 + +#define LM_STATUS_TOO_MANY_FRAGMENTS 7 +#define LM_STATUS_TRANSMIT_ABORTED 8 +#define LM_STATUS_TRANSMIT_ERROR 9 +#define LM_STATUS_RECEIVE_ABORTED 10 +#define LM_STATUS_RECEIVE_ERROR 11 +#define LM_STATUS_INVALID_PACKET_SIZE 12 +#define LM_STATUS_OUT_OF_MAP_REGISTERS 13 +#define LM_STATUS_UNKNOWN_ADAPTER 14 + +typedef LM_UINT LM_STATUS, *PLM_STATUS; + + +/******************************************************************************/ +/* Line speed. */ +/******************************************************************************/ + +#define LM_LINE_SPEED_UNKNOWN 0 +#define LM_LINE_SPEED_AUTO LM_LINE_SPEED_UNKNOWN +#define LM_LINE_SPEED_10MBPS 10 +#define LM_LINE_SPEED_100MBPS 100 +#define LM_LINE_SPEED_1000MBPS 1000 + +typedef LM_UINT32 LM_LINE_SPEED, *PLM_LINE_SPEED; + + + +/******************************************************************************/ +/* Duplex mode. */ +/******************************************************************************/ + +#define LM_DUPLEX_MODE_UNKNOWN 0 +#define LM_DUPLEX_MODE_HALF 1 +#define LM_DUPLEX_MODE_FULL 2 + +typedef LM_UINT32 LM_DUPLEX_MODE, *PLM_DUPLEX_MODE; + + + +/******************************************************************************/ +/* Power state. */ +/******************************************************************************/ + +#define LM_POWER_STATE_D0 0 +#define LM_POWER_STATE_D1 1 +#define LM_POWER_STATE_D2 2 +#define LM_POWER_STATE_D3 3 + +typedef LM_UINT32 LM_POWER_STATE, *PLM_POWER_STATE; + + + +/******************************************************************************/ +/* Task offloading. */ +/******************************************************************************/ + +#define LM_TASK_OFFLOAD_NONE 0x0000 +#define LM_TASK_OFFLOAD_TX_IP_CHECKSUM 0x0001 +#define LM_TASK_OFFLOAD_RX_IP_CHECKSUM 0x0002 +#define LM_TASK_OFFLOAD_TX_TCP_CHECKSUM 0x0004 +#define LM_TASK_OFFLOAD_RX_TCP_CHECKSUM 0x0008 +#define LM_TASK_OFFLOAD_TX_UDP_CHECKSUM 0x0010 +#define LM_TASK_OFFLOAD_RX_UDP_CHECKSUM 0x0020 +#define LM_TASK_OFFLOAD_TCP_SEGMENTATION 0x0040 + +typedef LM_UINT32 LM_TASK_OFFLOAD, *PLM_TASK_OFFLOAD; + + + +/******************************************************************************/ +/* Flow control. */ +/******************************************************************************/ + +#define LM_FLOW_CONTROL_NONE 0x00 +#define LM_FLOW_CONTROL_RECEIVE_PAUSE 0x01 +#define LM_FLOW_CONTROL_TRANSMIT_PAUSE 0x02 +#define LM_FLOW_CONTROL_RX_TX_PAUSE (LM_FLOW_CONTROL_RECEIVE_PAUSE | \ + LM_FLOW_CONTROL_TRANSMIT_PAUSE) + +/* This value can be or-ed with RECEIVE_PAUSE and TRANSMIT_PAUSE. If the */ +/* auto-negotiation is disabled and the RECEIVE_PAUSE and TRANSMIT_PAUSE */ +/* bits are set, then flow control is enabled regardless of link partner's */ +/* flow control capability. */ +#define LM_FLOW_CONTROL_AUTO_PAUSE 0x80000000 + +typedef LM_UINT32 LM_FLOW_CONTROL, *PLM_FLOW_CONTROL; + + + +/******************************************************************************/ +/* Wake up mode. */ +/******************************************************************************/ + +#define LM_WAKE_UP_MODE_NONE 0 +#define LM_WAKE_UP_MODE_MAGIC_PACKET 1 +#define LM_WAKE_UP_MODE_NWUF 2 +#define LM_WAKE_UP_MODE_LINK_CHANGE 4 + +typedef LM_UINT32 LM_WAKE_UP_MODE, *PLM_WAKE_UP_MODE; + + + +/******************************************************************************/ +/* Counters. */ +/******************************************************************************/ + +#define LM_COUNTER_FRAMES_XMITTED_OK 0 +#define LM_COUNTER_FRAMES_RECEIVED_OK 1 +#define LM_COUNTER_ERRORED_TRANSMIT_COUNT 2 +#define LM_COUNTER_ERRORED_RECEIVE_COUNT 3 +#define LM_COUNTER_RCV_CRC_ERROR 4 +#define LM_COUNTER_ALIGNMENT_ERROR 5 +#define LM_COUNTER_SINGLE_COLLISION_FRAMES 6 +#define LM_COUNTER_MULTIPLE_COLLISION_FRAMES 7 +#define LM_COUNTER_FRAMES_DEFERRED 8 +#define LM_COUNTER_MAX_COLLISIONS 9 +#define LM_COUNTER_RCV_OVERRUN 10 +#define LM_COUNTER_XMIT_UNDERRUN 11 +#define LM_COUNTER_UNICAST_FRAMES_XMIT 12 +#define LM_COUNTER_MULTICAST_FRAMES_XMIT 13 +#define LM_COUNTER_BROADCAST_FRAMES_XMIT 14 +#define LM_COUNTER_UNICAST_FRAMES_RCV 15 +#define LM_COUNTER_MULTICAST_FRAMES_RCV 16 +#define LM_COUNTER_BROADCAST_FRAMES_RCV 17 + +typedef LM_UINT32 LM_COUNTER_TYPE, *PLM_COUNTER_TYPE; + + +typedef LM_UINT32 LM_RESET_TYPE; +#define LM_SHUTDOWN_RESET 0 +#define LM_INIT_RESET 1 +#define LM_SUSPEND_RESET 2 + +/******************************************************************************/ +/* Forward definition. */ +/******************************************************************************/ + +typedef struct _LM_DEVICE_BLOCK *PLM_DEVICE_BLOCK; +typedef struct _LM_PACKET *PLM_PACKET; + + + +/******************************************************************************/ +/* Function prototypes. */ +/******************************************************************************/ + +LM_STATUS LM_GetAdapterInfo(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_InitializeAdapter(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_ResetAdapter(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_DisableInterrupt(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_EnableInterrupt(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_SendPacket(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket); +LM_STATUS LM_ServiceInterrupts(PLM_DEVICE_BLOCK pDevice); +#ifdef BCM_NAPI_RXPOLL +int LM_ServiceRxPoll(PLM_DEVICE_BLOCK pDevice, int limit); +#endif +LM_STATUS LM_QueueRxPackets(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_SetReceiveMask(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Mask); +LM_STATUS LM_Halt(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_Abort(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_MulticastAdd(PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pMcAddress); +LM_STATUS LM_MulticastDel(PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pMcAddress); +LM_STATUS LM_MulticastClear(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_SetMacAddress(PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pMacAddress); +LM_STATUS LM_LoopbackAddress(PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pAddress); + +LM_UINT32 LM_GetCrcCounter(PLM_DEVICE_BLOCK pDevice); + +LM_WAKE_UP_MODE LM_PMCapabilities(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_NwufAdd(PLM_DEVICE_BLOCK pDevice, LM_UINT32 ByteMaskSize, + LM_UINT8 *pByteMask, LM_UINT8 *pPattern); +LM_STATUS LM_NwufRemove(PLM_DEVICE_BLOCK pDevice, LM_UINT32 ByteMaskSize, + LM_UINT8 *pByteMask, LM_UINT8 *pPattern); +LM_STATUS LM_SetPowerState(PLM_DEVICE_BLOCK pDevice, LM_POWER_STATE PowerLevel); + +LM_VOID LM_ReadPhy(PLM_DEVICE_BLOCK pDevice, LM_UINT32 PhyReg, + PLM_UINT32 pData32); +LM_VOID LM_WritePhy(PLM_DEVICE_BLOCK pDevice, LM_UINT32 PhyReg, + LM_UINT32 Data32); + +/* MII read/write functions to export to the robo support code */ +LM_UINT16 robo_miird(void *h, int phyadd, int regoff); +void robo_miiwr(void *h, int phyadd, int regoff, LM_UINT16 value); + + +LM_STATUS LM_EnableMacLoopBack(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_DisableMacLoopBack(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_EnablePhyLoopBack(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_DisablePhyLoopBack(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_EnableExtLoopBack(PLM_DEVICE_BLOCK pDevice, LM_LINE_SPEED Speed); +LM_STATUS LM_DisableExtLoopBack(PLM_DEVICE_BLOCK pDevice); + +LM_STATUS LM_SetupPhy(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_BlinkLED(PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlinkDuration); +LM_STATUS LM_GetStats(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_NvramRead(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, + LM_UINT32 *pData); +LM_STATUS LM_NvramWriteBlock(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, + LM_UINT32 *pData, LM_UINT32 Size); +LM_VOID LM_ResetPhy(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_ShutdownChip(PLM_DEVICE_BLOCK pDevice, LM_RESET_TYPE Mode); +LM_STATUS LM_HaltCpu(PLM_DEVICE_BLOCK pDevice,LM_UINT32 cpu_number); +LM_UINT32 ComputeCrc32(LM_UINT8 *pBuffer, LM_UINT32 BufferSize); +LM_STATUS LM_SwitchClocks(PLM_DEVICE_BLOCK pDevice); + +void LM_5714_FamForceFiber( PLM_DEVICE_BLOCK pDevice); +void LM_5714_FamGoFiberAutoNeg( PLM_DEVICE_BLOCK pDevice); +void LM_5714_FamFiberCheckLink( PLM_DEVICE_BLOCK pDevice); + +/******************************************************************************/ +/* These are the OS specific functions called by LMAC. */ +/******************************************************************************/ + +LM_STATUS MM_ReadConfig16(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, + LM_UINT16 *pValue16); +LM_STATUS MM_WriteConfig16(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, + LM_UINT16 Value16); +LM_STATUS MM_ReadConfig32(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, + LM_UINT32 *pValue32); +LM_STATUS MM_WriteConfig32(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Offset, + LM_UINT32 Value32); +LM_STATUS MM_MapMemBase(PLM_DEVICE_BLOCK pDevice); +LM_STATUS MM_MapIoBase(PLM_DEVICE_BLOCK pDevice); +LM_STATUS MM_IndicateRxPackets(PLM_DEVICE_BLOCK pDevice); +LM_STATUS MM_IndicateTxPackets(PLM_DEVICE_BLOCK pDevice); +LM_STATUS MM_StartTxDma(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket); +LM_STATUS MM_CompleteTxDma(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket); +LM_STATUS MM_AllocateMemory(PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize, + PLM_VOID *pMemoryBlockVirt); +LM_STATUS MM_AllocateSharedMemory(PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlockSize, + PLM_VOID *pMemoryBlockVirt, PLM_PHYSICAL_ADDRESS pMemoryBlockPhy, + LM_BOOL Cached); +LM_STATUS MM_GetConfig(PLM_DEVICE_BLOCK pDevice); +LM_STATUS MM_IndicateStatus(PLM_DEVICE_BLOCK pDevice, LM_STATUS Status); +LM_STATUS MM_InitializeUmPackets(PLM_DEVICE_BLOCK pDevice); +LM_STATUS MM_FreeRxBuffer(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket); +LM_STATUS MM_CoalesceTxBuffer(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket); +PLM_DEVICE_BLOCK MM_FindPeerDev(PLM_DEVICE_BLOCK pDevice); +int MM_FindCapability(PLM_DEVICE_BLOCK pDevice, int capability); +LM_VOID MM_UnmapRxDma(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket); +#ifdef BCM_NAPI_RXPOLL +LM_STATUS MM_ScheduleRxPoll(PLM_DEVICE_BLOCK pDevice); +#endif +LM_STATUS MM_Sleep(PLM_DEVICE_BLOCK pDevice, LM_UINT32 msec); +LM_STATUS LM_MbufWorkAround(PLM_DEVICE_BLOCK pDevice); + +#ifdef INCLUDE_5703_A0_FIX +LM_STATUS LM_Load5703DmaWFirmware(PLM_DEVICE_BLOCK pDevice); +#endif + +/* Debugging support */ + +extern int b57_msg_level; + +#define B57_ERR_VAL 1 +#define B57_INFO_VAL 2 + +#define B57_ERR(args) do {if (b57_msg_level & B57_ERR_VAL) printf args;} while (0) +#define B57_INFO(args) do {if (b57_msg_level & B57_INFO_VAL) printf args;} while (0) + +#endif /* LM_H */ + diff --git a/package/broadcom-57xx/src/mm.h b/package/broadcom-57xx/src/mm.h new file mode 100644 index 0000000000..35286831f2 --- /dev/null +++ b/package/broadcom-57xx/src/mm.h @@ -0,0 +1,609 @@ +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 - 2004 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/******************************************************************************/ + +/* $Id: mm.h,v 1.6 2006/09/26 05:22:21 michael Exp $ */ + +#ifndef MM_H +#define MM_H + +#include + +#if defined(CONFIG_SMP) && !defined(__SMP__) +#define __SMP__ +#endif + +#if defined(CONFIG_MODVERSIONS) && defined(MODULE) && !defined(MODVERSIONS) +#ifndef BCM_SMALL_DRV +#define MODVERSIONS +#endif +#endif + +#ifndef B57UM +#define __NO_VERSION__ +#endif +#include + +#ifdef MODULE + +#if defined(MODVERSIONS) && (LINUX_VERSION_CODE < 0x020500) +#ifndef BCM_SMALL_DRV +#include +#endif +#endif + +#if (LINUX_VERSION_CODE < 0x020605) +#include +#else +#include +#endif + +#else + +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#define SET_MODULE_OWNER(dev) +#define MODULE_DEVICE_TABLE(pci, pci_tbl) +#endif + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include +#include +#include +#include +#include +#include +#if (LINUX_VERSION_CODE >= 0x020400) +#if (LINUX_VERSION_CODE < 0x020500) +#include +#endif +#include +#endif +#ifdef CONFIG_PROC_FS +#include +#include +#define BCM_PROC_FS 1 +#endif +#ifdef NETIF_F_HW_VLAN_TX +#include +#define BCM_VLAN 1 +#endif +#ifdef NETIF_F_TSO +#define BCM_TSO 1 +#define INCLUDE_TCP_SEG_SUPPORT 1 +#include +#include +#include +#endif + +#ifndef LINUX_KERNEL_VERSION +#define LINUX_KERNEL_VERSION 0 +#endif + +#ifndef MAX_SKB_FRAGS +#define MAX_SKB_FRAGS 0 +#endif + +#if (LINUX_VERSION_CODE >= 0x020400) +#ifndef ETHTOOL_GEEPROM + +#define ETHTOOL_GEEPROM 0x0000000b /* Get EEPROM data */ +#define ETHTOOL_SEEPROM 0x0000000c /* Set EEPROM data */ + +/* for passing EEPROM chunks */ +struct ethtool_eeprom { + u32 cmd; + u32 magic; + u32 offset; /* in bytes */ + u32 len; /* in bytes */ + u8 data[0]; +}; +#define BCM_EEDUMP_LEN(info_p, size) *((u32 *) &((info_p)->reserved1[24]))=size + +#else + +#define BCM_EEDUMP_LEN(info_p, size) (info_p)->eedump_len=size + +#endif +#endif + +#define BCM_INT_COAL 1 +#define BCM_NIC_SEND_BD 1 +#define BCM_ASF 1 +#define BCM_WOL 1 +#define BCM_TASKLET 1 + +#if HAVE_NETIF_RECEIVE_SKB +#define BCM_NAPI_RXPOLL 1 +#undef BCM_TASKLET +#endif + +#if defined(CONFIG_PPC64) +#define BCM_DISCONNECT_AT_CACHELINE 1 +#endif + +#ifdef BCM_SMALL_DRV +#undef BCM_PROC_FS +#undef ETHTOOL_GEEPROM +#undef ETHTOOL_SEEPROM +#undef ETHTOOL_GREGS +#undef ETHTOOL_GPAUSEPARAM +#undef ETHTOOL_GRXCSUM +#undef ETHTOOL_TEST +#undef BCM_INT_COAL +#undef BCM_NIC_SEND_BD +#undef BCM_WOL +#undef BCM_TASKLET +#undef BCM_TSO +#endif + +#ifdef __BIG_ENDIAN +#define BIG_ENDIAN_HOST 1 +#endif + +#define MM_SWAP_LE32(x) cpu_to_le32(x) +#define MM_SWAP_BE32(x) cpu_to_be32(x) + +#if (LINUX_VERSION_CODE < 0x020327) +#define __raw_readl readl +#define __raw_writel writel +#endif + +#define MM_MEMWRITEL(ptr, val) __raw_writel(val, ptr) +#define MM_MEMREADL(ptr) __raw_readl(ptr) + +typedef atomic_t MM_ATOMIC_T; + +#define MM_ATOMIC_SET(ptr, val) atomic_set(ptr, val) +#define MM_ATOMIC_READ(ptr) atomic_read(ptr) +#define MM_ATOMIC_INC(ptr) atomic_inc(ptr) +#define MM_ATOMIC_ADD(ptr, val) atomic_add(val, ptr) +#define MM_ATOMIC_DEC(ptr) atomic_dec(ptr) +#define MM_ATOMIC_SUB(ptr, val) atomic_sub(val, ptr) + + +#ifndef mmiowb +#define mmiowb() +#endif + + +#define MM_MB() mb() +#define MM_WMB() wmb() +#define MM_RMB() rmb() +#define MM_MMIOWB() mmiowb() + +#include "lm.h" +#include "queue.h" +#include "tigon3.h" + +#if DBG +#define STATIC +#else +#define STATIC static +#endif + +extern int MM_Packet_Desc_Size; + +#define MM_PACKET_DESC_SIZE MM_Packet_Desc_Size + +DECLARE_QUEUE_TYPE(UM_RX_PACKET_Q, MAX_RX_PACKET_DESC_COUNT+1); + +#define MAX_MEM 16 +#define MAX_MEM2 4 + +#if (LINUX_VERSION_CODE < 0x020211) +typedef u32 dma_addr_t; +#endif + +#if (LINUX_VERSION_CODE < 0x02032a) +#define pci_map_single(dev, address, size, dir) virt_to_bus(address) +#define pci_unmap_single(dev, dma_addr, size, dir) +#endif + +#if MAX_SKB_FRAGS +#if (LINUX_VERSION_CODE >= 0x02040d) + +typedef dma_addr_t dmaaddr_high_t; + +#else + +#if defined(CONFIG_HIGHMEM) && defined(CONFIG_X86) && !defined(CONFIG_X86_64) + +#if defined(CONFIG_HIGHMEM64G) +typedef unsigned long long dmaaddr_high_t; +#else +typedef dma_addr_t dmaaddr_high_t; +#endif + +#ifndef pci_map_page +#define pci_map_page bcm_pci_map_page +#endif + +static inline dmaaddr_high_t +bcm_pci_map_page(struct pci_dev *dev, struct page *page, + int offset, size_t size, int dir) +{ + dmaaddr_high_t phys; + + phys = (page-mem_map) * (dmaaddr_high_t) PAGE_SIZE + offset; + + return phys; +} + +#ifndef pci_unmap_page +#define pci_unmap_page(dev, map, size, dir) +#endif + +#else /* #if defined(CONFIG_HIGHMEM) && defined(CONFIG_X86) && ! defined(CONFIG_X86_64)*/ + +typedef dma_addr_t dmaaddr_high_t; + +/* Warning - This may not work for all architectures if HIGHMEM is defined */ + +#ifndef pci_map_page +#define pci_map_page(dev, page, offset, size, dir) \ + pci_map_single(dev, page_address(page) + (offset), size, dir) +#endif +#ifndef pci_unmap_page +#define pci_unmap_page(dev, map, size, dir) \ + pci_unmap_single(dev, map, size, dir) +#endif + +#endif /* #if defined(CONFIG_HIGHMEM) && defined(CONFIG_X86) && ! defined(CONFIG_X86_64)*/ + +#endif /* #if (LINUX_VERSION_CODE >= 0x02040d)*/ +#endif /* #if MAX_SKB_FRAGS*/ + +#if defined(CONFIG_X86) && !defined(CONFIG_X86_64) +#define NO_PCI_UNMAP 1 +#endif + +#if (LINUX_VERSION_CODE < 0x020412) +#if !defined(NO_PCI_UNMAP) +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) dma_addr_t ADDR_NAME; +#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) __u32 LEN_NAME; + +#define pci_unmap_addr(PTR, ADDR_NAME) \ + ((PTR)->ADDR_NAME) + +#define pci_unmap_len(PTR, LEN_NAME) \ + ((PTR)->LEN_NAME) + +#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) \ + (((PTR)->ADDR_NAME) = (VAL)) + +#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \ + (((PTR)->LEN_NAME) = (VAL)) +#else +#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) +#define DECLARE_PCI_UNMAP_LEN(ADDR_NAME) + +#define pci_unmap_addr(PTR, ADDR_NAME) 0 +#define pci_unmap_len(PTR, LEN_NAME) 0 +#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) do { } while (0) +#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0) +#endif +#endif + +#if (LINUX_VERSION_CODE < 0x02030e) +#define net_device device +#define netif_carrier_on(dev) +#define netif_carrier_off(dev) +#endif + +#if (LINUX_VERSION_CODE < 0x02032b) +#define tasklet_struct tq_struct +#endif + +typedef struct _UM_DEVICE_BLOCK { + LM_DEVICE_BLOCK lm_dev; + struct net_device *dev; + struct pci_dev *pdev; + struct net_device *next_module; + char *name; +#ifdef BCM_PROC_FS + struct proc_dir_entry *pfs_entry; + char pfs_name[32]; +#endif + void *mem_list[MAX_MEM]; + dma_addr_t dma_list[MAX_MEM]; + int mem_size_list[MAX_MEM]; + int mem_list_num; + + int index; + int opened; + int suspended; + int using_dac; /* dual address cycle */ + int delayed_link_ind; /* Delay link status during initial load */ + int adapter_just_inited; /* the first few seconds after init. */ + int timer_interval; + int statstimer_interval; + int adaptive_expiry; + int crc_counter_expiry; + int poll_tbi_interval; + int poll_tbi_expiry; + int asf_heartbeat; + int tx_full; + int tx_queued; + int line_speed; /* in Mbps, 0 if link is down */ + UM_RX_PACKET_Q rx_out_of_buf_q; + int rx_out_of_buf; + int rx_buf_repl_thresh; + int rx_buf_repl_panic_thresh; + int rx_buf_repl_isr_limit; + int rx_buf_align; + struct timer_list timer; + struct timer_list statstimer; + int do_global_lock; + spinlock_t global_lock; + spinlock_t undi_lock; + spinlock_t phy_lock; + unsigned long undi_flags; + volatile unsigned long interrupt; + atomic_t intr_sem; + int tasklet_pending; + volatile unsigned long tasklet_busy; + struct tasklet_struct tasklet; + struct net_device_stats stats; + int intr_test; + int intr_test_result; +#ifdef NETIF_F_HW_VLAN_TX + struct vlan_group *vlgrp; +#endif + int vlan_tag_mode; /* Setting to allow ASF to work properly with */ + /* VLANs */ + #define VLAN_TAG_MODE_AUTO_STRIP 0 + #define VLAN_TAG_MODE_NORMAL_STRIP 1 + #define VLAN_TAG_MODE_FORCED_STRIP 2 + + /* Auto mode - VLAN TAGs are always stripped if ASF is enabled, */ + /* If ASF is not enabled, it will be in normal mode. */ + /* Normal mode - VLAN TAGs are stripped when VLANs are registered */ + /* Forced mode - VLAN TAGs are always stripped. */ + + int adaptive_coalesce; + uint rx_last_cnt; + uint tx_last_cnt; + uint rx_curr_coalesce_frames; + uint rx_curr_coalesce_frames_intr; + uint rx_curr_coalesce_ticks; + uint tx_curr_coalesce_frames; +#if TIGON3_DEBUG + unsigned long tx_zc_count; + unsigned long tx_chksum_count; + unsigned long tx_himem_count; + unsigned long rx_good_chksum_count; +#endif + unsigned long rx_bad_chksum_count; +#ifdef BCM_TSO + unsigned long tso_pkt_count; +#endif + unsigned long rx_misc_errors; + uint64_t phy_crc_count; + unsigned int spurious_int; + + void *sbh; + unsigned long boardflags; + void *robo; + int qos; +} UM_DEVICE_BLOCK, *PUM_DEVICE_BLOCK; + +typedef struct _UM_PACKET { + LM_PACKET lm_packet; + struct sk_buff *skbuff; +#if MAX_SKB_FRAGS + DECLARE_PCI_UNMAP_ADDR(map[MAX_SKB_FRAGS + 1]) + DECLARE_PCI_UNMAP_LEN(map_len[MAX_SKB_FRAGS + 1]) +#else + DECLARE_PCI_UNMAP_ADDR(map[1]) + DECLARE_PCI_UNMAP_LEN(map_len[1]) +#endif +} UM_PACKET, *PUM_PACKET; + +static inline void MM_SetAddr(LM_PHYSICAL_ADDRESS *paddr, dma_addr_t addr) +{ +#if BITS_PER_LONG == 64 + paddr->High = ((unsigned long) addr) >> 32; + paddr->Low = ((unsigned long) addr) & 0xffffffff; +#else + paddr->High = 0; + paddr->Low = (unsigned long) addr; +#endif +} + +static inline void MM_SetT3Addr(T3_64BIT_HOST_ADDR *paddr, dma_addr_t addr) +{ +#if BITS_PER_LONG == 64 + paddr->High = ((unsigned long) addr) >> 32; + paddr->Low = ((unsigned long) addr) & 0xffffffff; +#else + paddr->High = 0; + paddr->Low = (unsigned long) addr; +#endif +} + +#if MAX_SKB_FRAGS +static inline void MM_SetT3AddrHigh(T3_64BIT_HOST_ADDR *paddr, + dmaaddr_high_t addr) +{ +#if defined(CONFIG_HIGHMEM64G) && defined(CONFIG_X86) && !defined(CONFIG_X86_64) + paddr->High = (unsigned long) (addr >> 32); + paddr->Low = (unsigned long) (addr & 0xffffffff); +#else + MM_SetT3Addr(paddr, (dma_addr_t) addr); +#endif +} +#endif + +static inline void MM_MapRxDma(PLM_DEVICE_BLOCK pDevice, + struct _LM_PACKET *pPacket, + T3_64BIT_HOST_ADDR *paddr) +{ + dma_addr_t map; + struct sk_buff *skb = ((struct _UM_PACKET *) pPacket)->skbuff; + + map = pci_map_single(((struct _UM_DEVICE_BLOCK *)pDevice)->pdev, + skb->tail, + pPacket->u.Rx.RxBufferSize, + PCI_DMA_FROMDEVICE); + pci_unmap_addr_set(((struct _UM_PACKET *) pPacket), map[0], map); + MM_SetT3Addr(paddr, map); +} + +static inline void MM_MapTxDma(PLM_DEVICE_BLOCK pDevice, + struct _LM_PACKET *pPacket, + T3_64BIT_HOST_ADDR *paddr, + LM_UINT32 *len, + int frag) +{ + dma_addr_t map; + struct sk_buff *skb = ((struct _UM_PACKET *) pPacket)->skbuff; + unsigned int length; + + if (frag == 0) { +#if MAX_SKB_FRAGS + if (skb_shinfo(skb)->nr_frags) + length = skb->len - skb->data_len; + else +#endif + length = skb->len; + map = pci_map_single(((struct _UM_DEVICE_BLOCK *)pDevice)->pdev, + skb->data, length, PCI_DMA_TODEVICE); + MM_SetT3Addr(paddr, map); + pci_unmap_addr_set(((struct _UM_PACKET *)pPacket), map[0], map); + pci_unmap_len_set(((struct _UM_PACKET *) pPacket), map_len[0], + length); + *len = length; + } +#if MAX_SKB_FRAGS + else { + skb_frag_t *sk_frag; + dmaaddr_high_t hi_map; + + sk_frag = &skb_shinfo(skb)->frags[frag - 1]; + + hi_map = pci_map_page( + ((struct _UM_DEVICE_BLOCK *)pDevice)->pdev, + sk_frag->page, + sk_frag->page_offset, + sk_frag->size, PCI_DMA_TODEVICE); + + MM_SetT3AddrHigh(paddr, hi_map); + pci_unmap_addr_set(((struct _UM_PACKET *) pPacket), map[frag], + hi_map); + pci_unmap_len_set(((struct _UM_PACKET *) pPacket), + map_len[frag], sk_frag->size); + *len = sk_frag->size; + } +#endif +} + +#define BCM5700_PHY_LOCK(pUmDevice, flags) { \ + spinlock_t *lock; \ + if ((pUmDevice)->do_global_lock) { \ + lock = &(pUmDevice)->global_lock; \ + } \ + else { \ + lock = &(pUmDevice)->phy_lock; \ + } \ + spin_lock_irqsave(lock, flags); \ +} + +#define BCM5700_PHY_UNLOCK(pUmDevice, flags) { \ + spinlock_t *lock; \ + if ((pUmDevice)->do_global_lock) { \ + lock = &(pUmDevice)->global_lock; \ + } \ + else { \ + lock = &(pUmDevice)->phy_lock; \ + } \ + spin_unlock_irqrestore(lock, flags); \ +} + + +#define MM_ACQUIRE_UNDI_LOCK(_pDevice) \ + if (!(((PUM_DEVICE_BLOCK)(_pDevice))->do_global_lock)) { \ + unsigned long flags; \ + spin_lock_irqsave(&((PUM_DEVICE_BLOCK)(_pDevice))->undi_lock, flags); \ + ((PUM_DEVICE_BLOCK)(_pDevice))->undi_flags = flags; \ + } + +#define MM_RELEASE_UNDI_LOCK(_pDevice) \ + if (!(((PUM_DEVICE_BLOCK)(_pDevice))->do_global_lock)) { \ + unsigned long flags = ((PUM_DEVICE_BLOCK) (_pDevice))->undi_flags; \ + spin_unlock_irqrestore(&((PUM_DEVICE_BLOCK)(_pDevice))->undi_lock, flags); \ + } + +#define MM_ACQUIRE_PHY_LOCK_IN_IRQ(_pDevice) \ + if (!(((PUM_DEVICE_BLOCK)(_pDevice))->do_global_lock)) { \ + spin_lock(&((PUM_DEVICE_BLOCK)(_pDevice))->phy_lock); \ + } + +#define MM_RELEASE_PHY_LOCK_IN_IRQ(_pDevice) \ + if (!(((PUM_DEVICE_BLOCK)(_pDevice))->do_global_lock)) { \ + spin_unlock(&((PUM_DEVICE_BLOCK)(_pDevice))->phy_lock); \ + } + +#define MM_UINT_PTR(_ptr) ((unsigned long) (_ptr)) + +#define MM_GETSTATS64(_Ctr) \ + (uint64_t) (_Ctr).Low + ((uint64_t) (_Ctr).High << 32) + +#define MM_GETSTATS32(_Ctr) \ + (uint32_t) (_Ctr).Low + +#if BITS_PER_LONG == 64 +#define MM_GETSTATS(_Ctr) (unsigned long) MM_GETSTATS64(_Ctr) +#else +#define MM_GETSTATS(_Ctr) (unsigned long) MM_GETSTATS32(_Ctr) +#endif + +#if (LINUX_VERSION_CODE >= 0x020600) +#define mm_copy_to_user( to, from, size ) \ + (in_atomic() ? (memcpy((to),(from),(size)), 0) : copy_to_user((to),(from),(size))) +#define mm_copy_from_user( to, from, size ) \ + (in_atomic() ? (memcpy((to),(from),(size)), 0) : copy_from_user((to),(from),(size))) +#else +#define mm_copy_to_user( to, from, size ) \ + copy_to_user((to),(from),(size) ) +#define mm_copy_from_user( to, from, size ) \ + copy_from_user((to),(from),(size)) +#endif + +#ifndef printf +#define printf(fmt, args...) printk(KERN_WARNING fmt, ##args) +#endif + +#define DbgPrint(fmt, arg...) printk(KERN_DEBUG fmt, ##arg) +#if defined(CONFIG_X86) +#define DbgBreakPoint() __asm__("int $129") +#else +#define DbgBreakPoint() +#endif +#define MM_Wait(time) udelay(time) + +#endif diff --git a/package/broadcom-57xx/src/proto/802.11.h b/package/broadcom-57xx/src/proto/802.11.h new file mode 100644 index 0000000000..ebabf730a3 --- /dev/null +++ b/package/broadcom-57xx/src/proto/802.11.h @@ -0,0 +1,1387 @@ +/* + * Copyright 2007, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * + * Fundamental types and constants relating to 802.11 + * + * $Id: 802.11.h,v 1.1.1.25 2007/05/31 08:00:41 michael Exp $ + */ + +#ifndef _802_11_H_ +#define _802_11_H_ + +#ifndef _TYPEDEFS_H_ +#include +#endif + +#ifndef _NET_ETHERNET_H_ +#include +#endif + +#include + +/* enable structure packing */ +#if defined(__GNUC__) +#define PACKED __attribute__((packed)) +#else +#pragma pack(1) +#define PACKED +#endif + +#define DOT11_TU_TO_US 1024 /* 802.11 Time Unit is 1024 microseconds */ + +/* Generic 802.11 frame constants */ +#define DOT11_A3_HDR_LEN 24 /* d11 header length with A3 */ +#define DOT11_A4_HDR_LEN 30 /* d11 header length with A4 */ +#define DOT11_MAC_HDR_LEN DOT11_A3_HDR_LEN /* MAC header length */ +#define DOT11_FCS_LEN 4 /* d11 FCS length */ +#define DOT11_ICV_LEN 4 /* d11 ICV length */ +#define DOT11_ICV_AES_LEN 8 /* d11 ICV/AES length */ +#define DOT11_QOS_LEN 2 /* d11 QoS length */ +#define DOT11_HTC_LEN 4 /* d11 HT Control field length */ + +#define DOT11_KEY_INDEX_SHIFT 6 /* d11 key index shift */ +#define DOT11_IV_LEN 4 /* d11 IV length */ +#define DOT11_IV_TKIP_LEN 8 /* d11 IV TKIP length */ +#define DOT11_IV_AES_OCB_LEN 4 /* d11 IV/AES/OCB length */ +#define DOT11_IV_AES_CCM_LEN 8 /* d11 IV/AES/CCM length */ +#define DOT11_IV_MAX_LEN 8 /* maximum iv len for any encryption */ + +/* Includes MIC */ +#define DOT11_MAX_MPDU_BODY_LEN 2304 /* max MPDU body length */ +/* A4 header + QoS + CCMP + PDU + ICV + FCS = 2352 */ +#define DOT11_MAX_MPDU_LEN (DOT11_A4_HDR_LEN + \ + DOT11_QOS_LEN + \ + DOT11_IV_AES_CCM_LEN + \ + DOT11_MAX_MPDU_BODY_LEN + \ + DOT11_ICV_LEN + \ + DOT11_FCS_LEN) /* d11 max MPDU length */ + +#define DOT11_MAX_SSID_LEN 32 /* d11 max ssid length */ + +/* dot11RTSThreshold */ +#define DOT11_DEFAULT_RTS_LEN 2347 /* d11 default RTS length */ +#define DOT11_MAX_RTS_LEN 2347 /* d11 max RTS length */ + +/* dot11FragmentationThreshold */ +#define DOT11_MIN_FRAG_LEN 256 /* d11 min fragmentation length */ +#define DOT11_MAX_FRAG_LEN 2346 /* Max frag is also limited by aMPDUMaxLength + * of the attached PHY + */ +#define DOT11_DEFAULT_FRAG_LEN 2346 /* d11 default fragmentation length */ + +/* dot11BeaconPeriod */ +#define DOT11_MIN_BEACON_PERIOD 1 /* d11 min beacon period */ +#define DOT11_MAX_BEACON_PERIOD 0xFFFF /* d11 max beacon period */ + +/* dot11DTIMPeriod */ +#define DOT11_MIN_DTIM_PERIOD 1 /* d11 min DTIM period */ +#define DOT11_MAX_DTIM_PERIOD 0xFF /* d11 max DTIM period */ + +/* 802.2 LLC/SNAP header used by 802.11 per 802.1H */ +#define DOT11_LLC_SNAP_HDR_LEN 8 /* d11 LLC/SNAP header length */ +#define DOT11_OUI_LEN 3 /* d11 OUI length */ +struct dot11_llc_snap_header { + uint8 dsap; /* always 0xAA */ + uint8 ssap; /* always 0xAA */ + uint8 ctl; /* always 0x03 */ + uint8 oui[DOT11_OUI_LEN]; /* RFC1042: 0x00 0x00 0x00 + * Bridge-Tunnel: 0x00 0x00 0xF8 + */ + uint16 type; /* ethertype */ +} PACKED; + +/* RFC1042 header used by 802.11 per 802.1H */ +#define RFC1042_HDR_LEN (ETHER_HDR_LEN + DOT11_LLC_SNAP_HDR_LEN) /* RCF1042 header length */ + +/* Generic 802.11 MAC header */ +/* + * N.B.: This struct reflects the full 4 address 802.11 MAC header. + * The fields are defined such that the shorter 1, 2, and 3 + * address headers just use the first k fields. + */ +struct dot11_header { + uint16 fc; /* frame control */ + uint16 durid; /* duration/ID */ + struct ether_addr a1; /* address 1 */ + struct ether_addr a2; /* address 2 */ + struct ether_addr a3; /* address 3 */ + uint16 seq; /* sequence control */ + struct ether_addr a4; /* address 4 */ +} PACKED; + +/* Control frames */ + +struct dot11_rts_frame { + uint16 fc; /* frame control */ + uint16 durid; /* duration/ID */ + struct ether_addr ra; /* receiver address */ + struct ether_addr ta; /* transmitter address */ +} PACKED; +#define DOT11_RTS_LEN 16 /* d11 RTS frame length */ + +struct dot11_cts_frame { + uint16 fc; /* frame control */ + uint16 durid; /* duration/ID */ + struct ether_addr ra; /* receiver address */ +} PACKED; +#define DOT11_CTS_LEN 10 /* d11 CTS frame length */ + +struct dot11_ack_frame { + uint16 fc; /* frame control */ + uint16 durid; /* duration/ID */ + struct ether_addr ra; /* receiver address */ +} PACKED; +#define DOT11_ACK_LEN 10 /* d11 ACK frame length */ + +struct dot11_ps_poll_frame { + uint16 fc; /* frame control */ + uint16 durid; /* AID */ + struct ether_addr bssid; /* receiver address, STA in AP */ + struct ether_addr ta; /* transmitter address */ +} PACKED; +#define DOT11_PS_POLL_LEN 16 /* d11 PS poll frame length */ + +struct dot11_cf_end_frame { + uint16 fc; /* frame control */ + uint16 durid; /* duration/ID */ + struct ether_addr ra; /* receiver address */ + struct ether_addr bssid; /* transmitter address, STA in AP */ +} PACKED; +#define DOT11_CS_END_LEN 16 /* d11 CF-END frame length */ + +/* BA/BAR Control parameters */ +#define DOT11_BA_CTL_POLICY_NORMAL 0x0000 /* normal ack */ +#define DOT11_BA_CTL_POLICY_NOACK 0x0001 /* no ack */ +#define DOT11_BA_CTL_POLICY_MASK 0x0001 /* ack policy mask */ + +#define DOT11_BA_CTL_MTID 0x0002 /* multi tid BA */ +#define DOT11_BA_CTL_COMPRESSED 0x0004 /* compressed bitmap */ + +#define DOT11_BA_CTL_NUMMSDU_MASK 0x0FC0 /* num msdu in bitmap mask */ +#define DOT11_BA_CTL_NUMMSDU_SHIFT 6 /* num msdu in bitmap shift */ + +#define DOT11_BA_CTL_TID_MASK 0xF000 /* tid mask */ +#define DOT11_BA_CTL_TID_SHIFT 12 /* tid shift */ + +/* control frame header (BA/BAR) */ +struct dot11_ctl_header { + uint16 fc; /* frame control */ + uint16 durid; /* duration/ID */ + struct ether_addr ra; /* receiver address */ + struct ether_addr ta; /* transmitter address */ +} PACKED; +#define DOT11_CTL_HDR_LEN 16 /* control frame hdr len */ + +/* BAR frame payload */ +struct dot11_bar { + uint16 bar_control; /* BAR Control */ + uint16 seqnum; /* Starting Sequence control */ +} PACKED; +#define DOT11_BAR_LEN 4 /* BAR frame payload length */ + +#define DOT11_BA_BITMAP_LEN 128 /* bitmap length */ +#define DOT11_BA_CMP_BITMAP_LEN 8 /* compressed bitmap length */ +/* BA frame payload */ +struct dot11_ba { + uint16 ba_control; /* BA Control */ + uint16 seqnum; /* Starting Sequence control */ + uint8 bitmap[DOT11_BA_BITMAP_LEN]; /* Block Ack Bitmap */ +} PACKED; +#define DOT11_BA_LEN 4 /* BA frame payload len (wo bitmap) */ + +/* Management frame header */ +struct dot11_management_header { + uint16 fc; /* frame control */ + uint16 durid; /* duration/ID */ + struct ether_addr da; /* receiver address */ + struct ether_addr sa; /* transmitter address */ + struct ether_addr bssid; /* BSS ID */ + uint16 seq; /* sequence control */ +} PACKED; +#define DOT11_MGMT_HDR_LEN 24 /* d11 management header length */ + +/* Management frame payloads */ + +struct dot11_bcn_prb { + uint32 timestamp[2]; + uint16 beacon_interval; + uint16 capability; +} PACKED; +#define DOT11_BCN_PRB_LEN 12 /* 802.11 beacon/probe frame fixed length */ + +struct dot11_auth { + uint16 alg; /* algorithm */ + uint16 seq; /* sequence control */ + uint16 status; /* status code */ +} PACKED; +#define DOT11_AUTH_FIXED_LEN 6 /* length of auth frame without challenge info + * elt + */ + +struct dot11_assoc_req { + uint16 capability; /* capability information */ + uint16 listen; /* listen interval */ +} PACKED; +#define DOT11_ASSOC_REQ_FIXED_LEN 4 /* length of assoc frame without info elts */ + +struct dot11_reassoc_req { + uint16 capability; /* capability information */ + uint16 listen; /* listen interval */ + struct ether_addr ap; /* Current AP address */ +} PACKED; +#define DOT11_REASSOC_REQ_FIXED_LEN 10 /* length of assoc frame without info elts */ + +struct dot11_assoc_resp { + uint16 capability; /* capability information */ + uint16 status; /* status code */ + uint16 aid; /* association ID */ +} PACKED; + +struct dot11_action_measure { + uint8 category; + uint8 action; + uint8 token; + uint8 data[1]; +} PACKED; +#define DOT11_ACTION_MEASURE_LEN 3 /* d11 action measurement header length */ + +struct dot11_action_ht_ch_width { + uint8 category; + uint8 action; + uint8 ch_width; +} PACKED; + +struct dot11_action_ht_mimops { + uint8 category; + uint8 action; + uint8 control; +} PACKED; + +#define SM_PWRSAVE_ENABLE 1 +#define SM_PWRSAVE_MODE 2 + +struct dot11_action_ht_info_xchg { + uint8 category; + uint8 action; + uint8 info; +} PACKED; + +#define DOT11_HT_INFO_XCHG_INFO_REQ 0x01 +#define DOT11_HT_INFO_XCHG_40MHZ_INTOLERANT 0x02 +#define DOT11_HT_INFO_XCHG_STA_CHAN_WIDTH 0x04 + + +/* ************* 802.11h related definitions. ************* */ +struct dot11_power_cnst { + uint8 id; + uint8 len; + uint8 power; +} PACKED; +typedef struct dot11_power_cnst dot11_power_cnst_t; + +struct dot11_power_cap { + uint8 min; + uint8 max; +} PACKED; +typedef struct dot11_power_cap dot11_power_cap_t; + +struct dot11_tpc_rep { + uint8 id; + uint8 len; + uint8 tx_pwr; + uint8 margin; +} PACKED; +typedef struct dot11_tpc_rep dot11_tpc_rep_t; +#define DOT11_MNG_IE_TPC_REPORT_LEN 2 /* length of IE data, not including 2 byte header */ + +struct dot11_supp_channels { + uint8 id; + uint8 len; + uint8 first_channel; + uint8 num_channels; +} PACKED; +typedef struct dot11_supp_channels dot11_supp_channels_t; + +/* Extension Channel Offset IE: 802.11n-D1.0 spec. added sideband + * offset for 40MHz operation. The possible 3 values are: + * 1 = above control channel + * 3 = below control channel + * 0 = no extension channel + */ +struct dot11_extch { + uint8 id; /* IE ID, 62, DOT11_MNG_EXT_CHANNEL_OFFSET */ + uint8 len; /* IE length */ + uint8 extch; +} PACKED; +typedef struct dot11_extch dot11_extch_ie_t; + +struct dot11_brcm_extch { + uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ + uint8 len; /* IE length */ + uint8 oui[3]; /* Proprietary OUI, BRCM_OUI */ + uint8 type; /* type inidicates what follows */ + uint8 extch; +} PACKED; +typedef struct dot11_brcm_extch dot11_brcm_extch_ie_t; + +#define BRCM_EXTCH_IE_LEN 5 +#define BRCM_EXTCH_IE_TYPE 53 /* 802.11n ID not yet assigned */ +#define DOT11_EXTCH_IE_LEN 1 +#define DOT11_EXT_CH_MASK 0x03 /* extension channel mask */ +#define DOT11_EXT_CH_UPPER 0x01 /* ext. ch. on upper sb */ +#define DOT11_EXT_CH_LOWER 0x03 /* ext. ch. on lower sb */ +#define DOT11_EXT_CH_NONE 0x00 /* no extension ch. */ + +struct dot11_action_frmhdr { + uint8 category; + uint8 action; + uint8 data[1]; +} PACKED; + +/* CSA IE data structure */ +struct dot11_channel_switch { + uint8 id; /* id DOT11_MNG_CHANNEL_SWITCH_ID */ + uint8 len; /* length of IE */ + uint8 mode; /* mode 0 or 1 */ + uint8 channel; /* channel switch to */ + uint8 count; /* number of beacons before switching */ +} PACKED; +typedef struct dot11_channel_switch dot11_chan_switch_ie_t; + +#define DOT11_SWITCH_IE_LEN 3 /* length of IE data, not including 2 byte header */ +/* CSA mode - 802.11h-2003 $7.3.2.20 */ +#define DOT11_CSA_MODE_ADVISORY 0 /* no DOT11_CSA_MODE_NO_TX restriction imposed */ +#define DOT11_CSA_MODE_NO_TX 1 /* no transmission upon receiving CSA frame. */ + +struct dot11_action_switch_channel { + uint8 category; + uint8 action; + dot11_chan_switch_ie_t chan_switch_ie; /* for switch IE */ + dot11_brcm_extch_ie_t extch_ie; /* extension channel offset */ +} PACKED; + +/* 11n Extended Channel Switch IE data structure */ +struct dot11_ext_csa { + uint8 id; /* id DOT11_MNG_EXT_CHANNEL_SWITCH_ID */ + uint8 len; /* length of IE */ + uint8 mode; /* mode 0 or 1 */ + uint8 reg; /* regulatory class */ + uint8 channel; /* channel switch to */ + uint8 count; /* number of beacons before switching */ +} PACKED; +typedef struct dot11_ext_csa dot11_ext_csa_ie_t; +#define DOT11_EXT_CSA_IE_LEN 4 /* length of extended channel switch IE body */ + +struct dot11_action_ext_csa { + uint8 category; + uint8 action; + dot11_ext_csa_ie_t chan_switch_ie; /* for switch IE */ +} PACKED; + +/* 802.11h Measurement Request/Report IEs */ +/* Measurement Type field */ +#define DOT11_MEASURE_TYPE_BASIC 0 /* d11 measurement basic type */ +#define DOT11_MEASURE_TYPE_CCA 1 /* d11 measurement CCA type */ +#define DOT11_MEASURE_TYPE_RPI 2 /* d11 measurement PRI type */ + +/* Measurement Request Modes */ +#define DOT11_MEASURE_MODE_ENABLE (1<<1) /* d11 measurement enable */ +#define DOT11_MEASURE_MODE_REQUEST (1<<2) /* d11 measurement request */ +#define DOT11_MEASURE_MODE_REPORT (1<<3) /* d11 measurement report */ +/* Measurement Report Modes */ +#define DOT11_MEASURE_MODE_LATE (1<<0) /* d11 measurement late */ +#define DOT11_MEASURE_MODE_INCAPABLE (1<<1) /* d11 measurement incapable */ +#define DOT11_MEASURE_MODE_REFUSED (1<<2) /* d11 measurement refuse */ +/* Basic Measurement Map bits */ +#define DOT11_MEASURE_BASIC_MAP_BSS ((uint8)(1<<0)) /* d11 measurement basic map BSS */ +#define DOT11_MEASURE_BASIC_MAP_OFDM ((uint8)(1<<1)) /* d11 measurement map OFDM */ +#define DOT11_MEASURE_BASIC_MAP_UKNOWN ((uint8)(1<<2)) /* d11 measurement map unknown */ +#define DOT11_MEASURE_BASIC_MAP_RADAR ((uint8)(1<<3)) /* d11 measurement map radar */ +#define DOT11_MEASURE_BASIC_MAP_UNMEAS ((uint8)(1<<4)) /* d11 measurement map unmeasuremnt */ + +struct dot11_meas_req { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + uint8 channel; + uint8 start_time[8]; + uint16 duration; +} PACKED; +typedef struct dot11_meas_req dot11_meas_req_t; +#define DOT11_MNG_IE_MREQ_LEN 14 /* d11 measurement request IE length */ +/* length of Measure Request IE data not including variable len */ +#define DOT11_MNG_IE_MREQ_FIXED_LEN 3 /* d11 measurement request IE fixed length */ + +struct dot11_meas_rep { + uint8 id; + uint8 len; + uint8 token; + uint8 mode; + uint8 type; + union + { + struct { + uint8 channel; + uint8 start_time[8]; + uint16 duration; + uint8 map; + } PACKED basic; + uint8 data[1]; + } PACKED rep; +} PACKED; +typedef struct dot11_meas_rep dot11_meas_rep_t; + +/* length of Measure Report IE data not including variable len */ +#define DOT11_MNG_IE_MREP_FIXED_LEN 3 /* d11 measurement response IE fixed length */ + +struct dot11_meas_rep_basic { + uint8 channel; + uint8 start_time[8]; + uint16 duration; + uint8 map; +} PACKED; +typedef struct dot11_meas_rep_basic dot11_meas_rep_basic_t; +#define DOT11_MEASURE_BASIC_REP_LEN 12 /* d11 measurement basic report length */ + +struct dot11_quiet { + uint8 id; + uint8 len; + uint8 count; /* TBTTs until beacon interval in quiet starts */ + uint8 period; /* Beacon intervals between periodic quiet periods ? */ + uint16 duration; /* Length of quiet period, in TU's */ + uint16 offset; /* TU's offset from TBTT in Count field */ +} PACKED; +typedef struct dot11_quiet dot11_quiet_t; + +struct chan_map_tuple { + uint8 channel; + uint8 map; +} PACKED; +typedef struct chan_map_tuple chan_map_tuple_t; + +struct dot11_ibss_dfs { + uint8 id; + uint8 len; + uint8 eaddr[ETHER_ADDR_LEN]; + uint8 interval; + chan_map_tuple_t map[1]; +} PACKED; +typedef struct dot11_ibss_dfs dot11_ibss_dfs_t; + +/* WME Elements */ +#define WME_OUI "\x00\x50\xf2" /* WME OUI */ +#define WME_VER 1 /* WME version */ +#define WME_TYPE 2 /* WME type */ +#define WME_SUBTYPE_IE 0 /* Information Element */ +#define WME_SUBTYPE_PARAM_IE 1 /* Parameter Element */ +#define WME_SUBTYPE_TSPEC 2 /* Traffic Specification */ + +/* WME Access Category Indices (ACIs) */ +#define AC_BE 0 /* Best Effort */ +#define AC_BK 1 /* Background */ +#define AC_VI 2 /* Video */ +#define AC_VO 3 /* Voice */ +#define AC_COUNT 4 /* number of ACs */ + +typedef uint8 ac_bitmap_t; /* AC bitmap of (1 << AC_xx) */ + +#define AC_BITMAP_NONE 0x0 /* No ACs */ +#define AC_BITMAP_ALL 0xf /* All ACs */ +#define AC_BITMAP_TST(ab, ac) (((ab) & (1 << (ac))) != 0) + +/* WME Information Element (IE) */ +struct wme_ie { + uint8 oui[3]; + uint8 type; + uint8 subtype; + uint8 version; + uint8 qosinfo; +} PACKED; +typedef struct wme_ie wme_ie_t; +#define WME_IE_LEN 7 /* WME IE length */ + +struct edcf_acparam { + uint8 ACI; + uint8 ECW; + uint16 TXOP; /* stored in network order (ls octet first) */ +} PACKED; +typedef struct edcf_acparam edcf_acparam_t; + +/* WME Parameter Element (PE) */ +struct wme_param_ie { + uint8 oui[3]; + uint8 type; + uint8 subtype; + uint8 version; + uint8 qosinfo; + uint8 rsvd; + edcf_acparam_t acparam[AC_COUNT]; +} PACKED; +typedef struct wme_param_ie wme_param_ie_t; +#define WME_PARAM_IE_LEN 24 /* WME Parameter IE length */ + +/* QoS Info field for IE as sent from AP */ +#define WME_QI_AP_APSD_MASK 0x80 /* U-APSD Supported mask */ +#define WME_QI_AP_APSD_SHIFT 7 /* U-APSD Supported shift */ +#define WME_QI_AP_COUNT_MASK 0x0f /* Parameter set count mask */ +#define WME_QI_AP_COUNT_SHIFT 0 /* Parameter set count shift */ + +/* QoS Info field for IE as sent from STA */ +#define WME_QI_STA_MAXSPLEN_MASK 0x60 /* Max Service Period Length mask */ +#define WME_QI_STA_MAXSPLEN_SHIFT 5 /* Max Service Period Length shift */ +#define WME_QI_STA_APSD_ALL_MASK 0xf /* APSD all AC bits mask */ +#define WME_QI_STA_APSD_ALL_SHIFT 0 /* APSD all AC bits shift */ +#define WME_QI_STA_APSD_BE_MASK 0x8 /* APSD AC_BE mask */ +#define WME_QI_STA_APSD_BE_SHIFT 3 /* APSD AC_BE shift */ +#define WME_QI_STA_APSD_BK_MASK 0x4 /* APSD AC_BK mask */ +#define WME_QI_STA_APSD_BK_SHIFT 2 /* APSD AC_BK shift */ +#define WME_QI_STA_APSD_VI_MASK 0x2 /* APSD AC_VI mask */ +#define WME_QI_STA_APSD_VI_SHIFT 1 /* APSD AC_VI shift */ +#define WME_QI_STA_APSD_VO_MASK 0x1 /* APSD AC_VO mask */ +#define WME_QI_STA_APSD_VO_SHIFT 0 /* APSD AC_VO shift */ + +/* ACI */ +#define EDCF_AIFSN_MIN 1 /* AIFSN minimum value */ +#define EDCF_AIFSN_MAX 15 /* AIFSN maximum value */ +#define EDCF_AIFSN_MASK 0x0f /* AIFSN mask */ +#define EDCF_ACM_MASK 0x10 /* ACM mask */ +#define EDCF_ACI_MASK 0x60 /* ACI mask */ +#define EDCF_ACI_SHIFT 5 /* ACI shift */ + +/* ECW */ +#define EDCF_ECW_MIN 0 /* cwmin/cwmax exponent minimum value */ +#define EDCF_ECW_MAX 15 /* cwmin/cwmax exponent maximum value */ +#define EDCF_ECW2CW(exp) ((1 << (exp)) - 1) +#define EDCF_ECWMIN_MASK 0x0f /* cwmin exponent form mask */ +#define EDCF_ECWMAX_MASK 0xf0 /* cwmax exponent form mask */ +#define EDCF_ECWMAX_SHIFT 4 /* cwmax exponent form shift */ + +/* TXOP */ +#define EDCF_TXOP_MIN 0 /* TXOP minimum value */ +#define EDCF_TXOP_MAX 65535 /* TXOP maximum value */ +#define EDCF_TXOP2USEC(txop) ((txop) << 5) + +/* Default EDCF parameters that AP advertises for STA to use; WMM draft Table 12 */ +#define EDCF_AC_BE_ACI_STA 0x03 /* STA ACI value for best effort AC */ +#define EDCF_AC_BE_ECW_STA 0xA4 /* STA ECW value for best effort AC */ +#define EDCF_AC_BE_TXOP_STA 0x0000 /* STA TXOP value for best effort AC */ +#define EDCF_AC_BK_ACI_STA 0x27 /* STA ACI value for background AC */ +#define EDCF_AC_BK_ECW_STA 0xA4 /* STA ECW value for background AC */ +#define EDCF_AC_BK_TXOP_STA 0x0000 /* STA TXOP value for background AC */ +#define EDCF_AC_VI_ACI_STA 0x42 /* STA ACI value for video AC */ +#define EDCF_AC_VI_ECW_STA 0x43 /* STA ECW value for video AC */ +#define EDCF_AC_VI_TXOP_STA 0x005e /* STA TXOP value for video AC */ +#define EDCF_AC_VO_ACI_STA 0x62 /* STA ACI value for audio AC */ +#define EDCF_AC_VO_ECW_STA 0x32 /* STA ECW value for audio AC */ +#define EDCF_AC_VO_TXOP_STA 0x002f /* STA TXOP value for audio AC */ + +/* Default EDCF parameters that AP uses; WMM draft Table 14 */ +#define EDCF_AC_BE_ACI_AP 0x03 /* AP ACI value for best effort AC */ +#define EDCF_AC_BE_ECW_AP 0x64 /* AP ECW value for best effort AC */ +#define EDCF_AC_BE_TXOP_AP 0x0000 /* AP TXOP value for best effort AC */ +#define EDCF_AC_BK_ACI_AP 0x27 /* AP ACI value for background AC */ +#define EDCF_AC_BK_ECW_AP 0xA4 /* AP ECW value for background AC */ +#define EDCF_AC_BK_TXOP_AP 0x0000 /* AP TXOP value for background AC */ +#define EDCF_AC_VI_ACI_AP 0x41 /* AP ACI value for video AC */ +#define EDCF_AC_VI_ECW_AP 0x43 /* AP ECW value for video AC */ +#define EDCF_AC_VI_TXOP_AP 0x005e /* AP TXOP value for video AC */ +#define EDCF_AC_VO_ACI_AP 0x61 /* AP ACI value for audio AC */ +#define EDCF_AC_VO_ECW_AP 0x32 /* AP ECW value for audio AC */ +#define EDCF_AC_VO_TXOP_AP 0x002f /* AP TXOP value for audio AC */ + +struct dot11_qbss_load_ie { + uint8 id; /* 11, DOT11_MNG_QBSS_LOAD_ID */ + uint8 length; + uint16 station_count; /* total number of STAs associated */ + uint8 channel_utilization; /* % of time, normalized to 255, QAP sensed medium busy */ + uint16 aac; /* available admission capacity */ +} PACKED; +typedef struct dot11_qbss_load_ie dot11_qbss_load_ie_t; + +/* nom_msdu_size */ +#define FIXED_MSDU_SIZE 0x8000 /* MSDU size is fixed */ +#define MSDU_SIZE_MASK 0x7fff /* (Nominal or fixed) MSDU size */ + +/* surplus_bandwidth */ +/* Represented as 3 bits of integer, binary point, 13 bits fraction */ +#define INTEGER_SHIFT 13 /* integer shift */ +#define FRACTION_MASK 0x1FFF /* fraction mask */ + +/* Management Notification Frame */ +struct dot11_management_notification { + uint8 category; /* DOT11_ACTION_NOTIFICATION */ + uint8 action; + uint8 token; + uint8 status; + uint8 data[1]; /* Elements */ +} PACKED; +#define DOT11_MGMT_NOTIFICATION_LEN 4 /* Fixed length */ + +/* WME Action Codes */ +#define WME_ADDTS_REQUEST 0 /* WME ADDTS request */ +#define WME_ADDTS_RESPONSE 1 /* WME ADDTS response */ +#define WME_DELTS_REQUEST 2 /* WME DELTS request */ + +/* WME Setup Response Status Codes */ +#define WME_ADMISSION_ACCEPTED 0 /* WME admission accepted */ +#define WME_INVALID_PARAMETERS 1 /* WME invalide parameters */ +#define WME_ADMISSION_REFUSED 3 /* WME admission refused */ + +/* Macro to take a pointer to a beacon or probe response + * body and return the char* pointer to the SSID info element + */ +#define BCN_PRB_SSID(body) ((char*)(body) + DOT11_BCN_PRB_LEN) + +/* Authentication frame payload constants */ +#define DOT11_OPEN_SYSTEM 0 /* d11 open authentication */ +#define DOT11_SHARED_KEY 1 /* d11 shared authentication */ +#define DOT11_CHALLENGE_LEN 128 /* d11 challenge text length */ + +/* Frame control macros */ +#define FC_PVER_MASK 0x3 /* PVER mask */ +#define FC_PVER_SHIFT 0 /* PVER shift */ +#define FC_TYPE_MASK 0xC /* type mask */ +#define FC_TYPE_SHIFT 2 /* type shift */ +#define FC_SUBTYPE_MASK 0xF0 /* subtype mask */ +#define FC_SUBTYPE_SHIFT 4 /* subtype shift */ +#define FC_TODS 0x100 /* to DS */ +#define FC_TODS_SHIFT 8 /* to DS shift */ +#define FC_FROMDS 0x200 /* from DS */ +#define FC_FROMDS_SHIFT 9 /* from DS shift */ +#define FC_MOREFRAG 0x400 /* more frag. */ +#define FC_MOREFRAG_SHIFT 10 /* more frag. shift */ +#define FC_RETRY 0x800 /* retry */ +#define FC_RETRY_SHIFT 11 /* retry shift */ +#define FC_PM 0x1000 /* PM */ +#define FC_PM_SHIFT 12 /* PM shift */ +#define FC_MOREDATA 0x2000 /* more data */ +#define FC_MOREDATA_SHIFT 13 /* more data shift */ +#define FC_WEP 0x4000 /* WEP */ +#define FC_WEP_SHIFT 14 /* WEP shift */ +#define FC_ORDER 0x8000 /* order */ +#define FC_ORDER_SHIFT 15 /* order shift */ + +/* sequence control macros */ +#define SEQNUM_SHIFT 4 /* seq. number shift */ +#define SEQNUM_MAX 0x1000 /* max seqnum + 1 */ +#define FRAGNUM_MASK 0xF /* frag. number mask */ + +/* Frame Control type/subtype defs */ + +/* FC Types */ +#define FC_TYPE_MNG 0 /* management type */ +#define FC_TYPE_CTL 1 /* control type */ +#define FC_TYPE_DATA 2 /* data type */ + +/* Management Subtypes */ +#define FC_SUBTYPE_ASSOC_REQ 0 /* assoc. request */ +#define FC_SUBTYPE_ASSOC_RESP 1 /* assoc. response */ +#define FC_SUBTYPE_REASSOC_REQ 2 /* reassoc. request */ +#define FC_SUBTYPE_REASSOC_RESP 3 /* reassoc. response */ +#define FC_SUBTYPE_PROBE_REQ 4 /* probe request */ +#define FC_SUBTYPE_PROBE_RESP 5 /* probe response */ +#define FC_SUBTYPE_BEACON 8 /* beacon */ +#define FC_SUBTYPE_ATIM 9 /* ATIM */ +#define FC_SUBTYPE_DISASSOC 10 /* disassoc. */ +#define FC_SUBTYPE_AUTH 11 /* authentication */ +#define FC_SUBTYPE_DEAUTH 12 /* de-authentication */ +#define FC_SUBTYPE_ACTION 13 /* action */ +#define FC_SUBTYPE_ACTION_NOACK 14 /* action no-ack */ + +/* Control Subtypes */ +#define FC_SUBTYPE_CTL_WRAPPER 7 /* Control Wrapper */ +#define FC_SUBTYPE_BLOCKACK_REQ 8 /* Block Ack Req */ +#define FC_SUBTYPE_BLOCKACK 9 /* Block Ack */ +#define FC_SUBTYPE_PS_POLL 10 /* PS poll */ +#define FC_SUBTYPE_RTS 11 /* RTS */ +#define FC_SUBTYPE_CTS 12 /* CTS */ +#define FC_SUBTYPE_ACK 13 /* ACK */ +#define FC_SUBTYPE_CF_END 14 /* CF-END */ +#define FC_SUBTYPE_CF_END_ACK 15 /* CF-END ACK */ + +/* Data Subtypes */ +#define FC_SUBTYPE_DATA 0 /* Data */ +#define FC_SUBTYPE_DATA_CF_ACK 1 /* Data + CF-ACK */ +#define FC_SUBTYPE_DATA_CF_POLL 2 /* Data + CF-Poll */ +#define FC_SUBTYPE_DATA_CF_ACK_POLL 3 /* Data + CF-Ack + CF-Poll */ +#define FC_SUBTYPE_NULL 4 /* Null */ +#define FC_SUBTYPE_CF_ACK 5 /* CF-Ack */ +#define FC_SUBTYPE_CF_POLL 6 /* CF-Poll */ +#define FC_SUBTYPE_CF_ACK_POLL 7 /* CF-Ack + CF-Poll */ +#define FC_SUBTYPE_QOS_DATA 8 /* QoS Data */ +#define FC_SUBTYPE_QOS_DATA_CF_ACK 9 /* QoS Data + CF-Ack */ +#define FC_SUBTYPE_QOS_DATA_CF_POLL 10 /* QoS Data + CF-Poll */ +#define FC_SUBTYPE_QOS_DATA_CF_ACK_POLL 11 /* QoS Data + CF-Ack + CF-Poll */ +#define FC_SUBTYPE_QOS_NULL 12 /* QoS Null */ +#define FC_SUBTYPE_QOS_CF_POLL 14 /* QoS CF-Poll */ +#define FC_SUBTYPE_QOS_CF_ACK_POLL 15 /* QoS CF-Ack + CF-Poll */ + +/* Data Subtype Groups */ +#define FC_SUBTYPE_ANY_QOS(s) (((s) & 8) != 0) +#define FC_SUBTYPE_ANY_NULL(s) (((s) & 4) != 0) +#define FC_SUBTYPE_ANY_CF_POLL(s) (((s) & 2) != 0) +#define FC_SUBTYPE_ANY_CF_ACK(s) (((s) & 1) != 0) + +/* Type/Subtype Combos */ +#define FC_KIND_MASK (FC_TYPE_MASK | FC_SUBTYPE_MASK) /* FC kind mask */ + +#define FC_KIND(t, s) (((t) << FC_TYPE_SHIFT) | ((s) << FC_SUBTYPE_SHIFT)) /* FC kind */ + +#define FC_SUBTYPE(fc) (((fc) & FC_SUBTYPE_MASK) >> FC_SUBTYPE_SHIFT) /* Subtype from FC */ +#define FC_TYPE(fc) (((fc) & FC_TYPE_MASK) >> FC_TYPE_SHIFT) /* Type from FC */ + +#define FC_ASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_REQ) /* assoc. request */ +#define FC_ASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_RESP) /* assoc. response */ +#define FC_REASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_REQ) /* reassoc. request */ +#define FC_REASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_RESP) /* reassoc. response */ +#define FC_PROBE_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_REQ) /* probe request */ +#define FC_PROBE_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_RESP) /* probe response */ +#define FC_BEACON FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_BEACON) /* beacon */ +#define FC_DISASSOC FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DISASSOC) /* disassoc */ +#define FC_AUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_AUTH) /* authentication */ +#define FC_DEAUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DEAUTH) /* deauthentication */ +#define FC_ACTION FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION) /* action */ +#define FC_ACTION_NOACK FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION_NOACK) /* action no-ack */ + +#define FC_CTL_WRAPPER FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTL_WRAPPER) /* Control Wrapper */ +#define FC_BLOCKACK_REQ FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK_REQ) /* Block Ack Req */ +#define FC_BLOCKACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK) /* Block Ack */ +#define FC_PS_POLL FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_PS_POLL) /* PS poll */ +#define FC_RTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_RTS) /* RTS */ +#define FC_CTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTS) /* CTS */ +#define FC_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_ACK) /* ACK */ +#define FC_CF_END FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END) /* CF-END */ +#define FC_CF_END_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END_ACK) /* CF-END ACK */ + +#define FC_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA) /* data */ +#define FC_NULL_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_NULL) /* null data */ +#define FC_DATA_CF_ACK FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA_CF_ACK) /* data CF ACK */ +#define FC_QOS_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_DATA) /* QoS data */ +#define FC_QOS_NULL FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_NULL) /* QoS null */ + +/* QoS Control Field */ + +/* 802.1D Priority */ +#define QOS_PRIO_SHIFT 0 /* QoS priority shift */ +#define QOS_PRIO_MASK 0x0007 /* QoS priority mask */ +#define QOS_PRIO(qos) (((qos) & QOS_PRIO_MASK) >> QOS_PRIO_SHIFT) /* QoS priority */ + +/* Traffic Identifier */ +#define QOS_TID_SHIFT 0 /* QoS TID shift */ +#define QOS_TID_MASK 0x000f /* QoS TID mask */ +#define QOS_TID(qos) (((qos) & QOS_TID_MASK) >> QOS_TID_SHIFT) /* QoS TID */ + +/* End of Service Period (U-APSD) */ +#define QOS_EOSP_SHIFT 4 /* QoS End of Service Period shift */ +#define QOS_EOSP_MASK 0x0010 /* QoS End of Service Period mask */ +#define QOS_EOSP(qos) (((qos) & QOS_EOSP_MASK) >> QOS_EOSP_SHIFT) /* Qos EOSP */ + +/* Ack Policy */ +#define QOS_ACK_NORMAL_ACK 0 /* Normal Ack */ +#define QOS_ACK_NO_ACK 1 /* No Ack (eg mcast) */ +#define QOS_ACK_NO_EXP_ACK 2 /* No Explicit Ack */ +#define QOS_ACK_BLOCK_ACK 3 /* Block Ack */ +#define QOS_ACK_SHIFT 5 /* QoS ACK shift */ +#define QOS_ACK_MASK 0x0060 /* QoS ACK mask */ +#define QOS_ACK(qos) (((qos) & QOS_ACK_MASK) >> QOS_ACK_SHIFT) /* QoS ACK */ + +/* A-MSDU flag */ +#define QOS_AMSDU_SHIFT 7 /* AMSDU shift */ +#define QOS_AMSDU_MASK 0x0080 /* AMSDU mask */ + +/* Management Frames */ + +/* Management Frame Constants */ + +/* Fixed fields */ +#define DOT11_MNG_AUTH_ALGO_LEN 2 /* d11 management auth. algo. length */ +#define DOT11_MNG_AUTH_SEQ_LEN 2 /* d11 management auth. seq. length */ +#define DOT11_MNG_BEACON_INT_LEN 2 /* d11 management beacon interval length */ +#define DOT11_MNG_CAP_LEN 2 /* d11 management cap. length */ +#define DOT11_MNG_AP_ADDR_LEN 6 /* d11 management AP address length */ +#define DOT11_MNG_LISTEN_INT_LEN 2 /* d11 management listen interval length */ +#define DOT11_MNG_REASON_LEN 2 /* d11 management reason length */ +#define DOT11_MNG_AID_LEN 2 /* d11 management AID length */ +#define DOT11_MNG_STATUS_LEN 2 /* d11 management status length */ +#define DOT11_MNG_TIMESTAMP_LEN 8 /* d11 management timestamp length */ + +/* DUR/ID field in assoc resp is 0xc000 | AID */ +#define DOT11_AID_MASK 0x3fff /* d11 AID mask */ + +/* Reason Codes */ +#define DOT11_RC_RESERVED 0 /* d11 RC reserved */ +#define DOT11_RC_UNSPECIFIED 1 /* Unspecified reason */ +#define DOT11_RC_AUTH_INVAL 2 /* Previous authentication no longer valid */ +#define DOT11_RC_DEAUTH_LEAVING 3 /* Deauthenticated because sending station + * is leaving (or has left) IBSS or ESS + */ +#define DOT11_RC_INACTIVITY 4 /* Disassociated due to inactivity */ +#define DOT11_RC_BUSY 5 /* Disassociated because AP is unable to handle + * all currently associated stations + */ +#define DOT11_RC_INVAL_CLASS_2 6 /* Class 2 frame received from + * nonauthenticated station + */ +#define DOT11_RC_INVAL_CLASS_3 7 /* Class 3 frame received from + * nonassociated station + */ +#define DOT11_RC_DISASSOC_LEAVING 8 /* Disassociated because sending station is + * leaving (or has left) BSS + */ +#define DOT11_RC_NOT_AUTH 9 /* Station requesting (re)association is not + * authenticated with responding station + */ +#define DOT11_RC_BAD_PC 10 /* Unacceptable power capability element */ +#define DOT11_RC_BAD_CHANNELS 11 /* Unacceptable supported channels element */ +/* 12 is unused */ + +/* 32-39 are QSTA specific reasons added in 11e */ +#define DOT11_RC_UNSPECIFIED_QOS 32 /* unspecified QoS-related reason */ +#define DOT11_RC_INSUFFCIENT_BW 33 /* QAP lacks sufficient bandwidth */ +#define DOT11_RC_EXCESSIVE_FRAMES 34 /* excessive number of frames need ack */ +#define DOT11_RC_TX_OUTSIDE_TXOP 35 /* transmitting outside the limits of txop */ +#define DOT11_RC_LEAVING_QBSS 36 /* QSTA is leaving the QBSS (or restting) */ +#define DOT11_RC_BAD_MECHANISM 37 /* does not want to use the mechanism */ +#define DOT11_RC_SETUP_NEEDED 38 /* mechanism needs a setup */ +#define DOT11_RC_TIMEOUT 39 /* timeout */ + +#define DOT11_RC_MAX 23 /* Reason codes > 23 are reserved */ + +/* Status Codes */ +#define DOT11_SC_SUCCESS 0 /* Successful */ +#define DOT11_SC_FAILURE 1 /* Unspecified failure */ +#define DOT11_SC_CAP_MISMATCH 10 /* Cannot support all requested + * capabilities in the Capability + * Information field + */ +#define DOT11_SC_REASSOC_FAIL 11 /* Reassociation denied due to inability + * to confirm that association exists + */ +#define DOT11_SC_ASSOC_FAIL 12 /* Association denied due to reason + * outside the scope of this standard + */ +#define DOT11_SC_AUTH_MISMATCH 13 /* Responding station does not support + * the specified authentication + * algorithm + */ +#define DOT11_SC_AUTH_SEQ 14 /* Received an Authentication frame + * with authentication transaction + * sequence number out of expected + * sequence + */ +#define DOT11_SC_AUTH_CHALLENGE_FAIL 15 /* Authentication rejected because of + * challenge failure + */ +#define DOT11_SC_AUTH_TIMEOUT 16 /* Authentication rejected due to timeout + * waiting for next frame in sequence + */ +#define DOT11_SC_ASSOC_BUSY_FAIL 17 /* Association denied because AP is + * unable to handle additional + * associated stations + */ +#define DOT11_SC_ASSOC_RATE_MISMATCH 18 /* Association denied due to requesting + * station not supporting all of the + * data rates in the BSSBasicRateSet + * parameter + */ +#define DOT11_SC_ASSOC_SHORT_REQUIRED 19 /* Association denied due to requesting + * station not supporting the Short + * Preamble option + */ +#define DOT11_SC_ASSOC_PBCC_REQUIRED 20 /* Association denied due to requesting + * station not supporting the PBCC + * Modulation option + */ +#define DOT11_SC_ASSOC_AGILITY_REQUIRED 21 /* Association denied due to requesting + * station not supporting the Channel + * Agility option + */ +#define DOT11_SC_ASSOC_SPECTRUM_REQUIRED 22 /* Association denied because Spectrum + * Management capability is required. + */ +#define DOT11_SC_ASSOC_BAD_POWER_CAP 23 /* Association denied because the info + * in the Power Cap element is + * unacceptable. + */ +#define DOT11_SC_ASSOC_BAD_SUP_CHANNELS 24 /* Association denied because the info + * in the Supported Channel element is + * unacceptable + */ +#define DOT11_SC_ASSOC_SHORTSLOT_REQUIRED 25 /* Association denied due to requesting + * station not supporting the Short Slot + * Time option + */ +#define DOT11_SC_ASSOC_ERPBCC_REQUIRED 26 /* Association denied due to requesting + * station not supporting the ER-PBCC + * Modulation option + */ +#define DOT11_SC_ASSOC_DSSOFDM_REQUIRED 27 /* Association denied due to requesting + * station not supporting the DSS-OFDM + * option + */ + +#define DOT11_SC_DECLINED 37 /* request declined */ +#define DOT11_SC_INVALID_PARAMS 38 /* One or more params have invalid values */ + +/* Info Elts, length of INFORMATION portion of Info Elts */ +#define DOT11_MNG_DS_PARAM_LEN 1 /* d11 management DS parameter length */ +#define DOT11_MNG_IBSS_PARAM_LEN 2 /* d11 management IBSS parameter length */ + +/* TIM Info element has 3 bytes fixed info in INFORMATION field, + * followed by 1 to 251 bytes of Partial Virtual Bitmap + */ +#define DOT11_MNG_TIM_FIXED_LEN 3 /* d11 management TIM fixed length */ +#define DOT11_MNG_TIM_DTIM_COUNT 0 /* d11 management DTIM count */ +#define DOT11_MNG_TIM_DTIM_PERIOD 1 /* d11 management DTIM period */ +#define DOT11_MNG_TIM_BITMAP_CTL 2 /* d11 management TIM BITMAP control */ +#define DOT11_MNG_TIM_PVB 3 /* d11 management TIM PVB */ + +/* TLV defines */ +#define TLV_TAG_OFF 0 /* tag offset */ +#define TLV_LEN_OFF 1 /* length offset */ +#define TLV_HDR_LEN 2 /* header length */ +#define TLV_BODY_OFF 2 /* body offset */ + +/* Management Frame Information Element IDs */ +#define DOT11_MNG_SSID_ID 0 /* d11 management SSID id */ +#define DOT11_MNG_RATES_ID 1 /* d11 management rates id */ +#define DOT11_MNG_FH_PARMS_ID 2 /* d11 management FH parameter id */ +#define DOT11_MNG_DS_PARMS_ID 3 /* d11 management DS parameter id */ +#define DOT11_MNG_CF_PARMS_ID 4 /* d11 management CF parameter id */ +#define DOT11_MNG_TIM_ID 5 /* d11 management TIM id */ +#define DOT11_MNG_IBSS_PARMS_ID 6 /* d11 management IBSS parameter id */ +#define DOT11_MNG_COUNTRY_ID 7 /* d11 management country id */ +#define DOT11_MNG_HOPPING_PARMS_ID 8 /* d11 management hopping parameter id */ +#define DOT11_MNG_HOPPING_TABLE_ID 9 /* d11 management hopping table id */ +#define DOT11_MNG_REQUEST_ID 10 /* d11 management request id */ +#define DOT11_MNG_QBSS_LOAD_ID 11 /* d11 management QBSS Load id */ +#define DOT11_MNG_CHALLENGE_ID 16 /* d11 management chanllenge id */ +#define DOT11_MNG_PWR_CONSTRAINT_ID 32 /* 11H PowerConstraint */ +#define DOT11_MNG_PWR_CAP_ID 33 /* 11H PowerCapability */ +#define DOT11_MNG_TPC_REQUEST_ID 34 /* 11H TPC Request */ +#define DOT11_MNG_TPC_REPORT_ID 35 /* 11H TPC Report */ +#define DOT11_MNG_SUPP_CHANNELS_ID 36 /* 11H Supported Channels */ +#define DOT11_MNG_CHANNEL_SWITCH_ID 37 /* 11H ChannelSwitch Announcement */ +#define DOT11_MNG_MEASURE_REQUEST_ID 38 /* 11H MeasurementRequest */ +#define DOT11_MNG_MEASURE_REPORT_ID 39 /* 11H MeasurementReport */ +#define DOT11_MNG_QUIET_ID 40 /* 11H Quiet */ +#define DOT11_MNG_IBSS_DFS_ID 41 /* 11H IBSS_DFS */ +#define DOT11_MNG_ERP_ID 42 /* d11 management ERP id */ +#define DOT11_MNG_TS_DELAY_ID 43 /* d11 management TS Delay id */ +#define DOT11_MNG_HT_CAP 45 /* d11 mgmt HT cap id */ +#define DOT11_MNG_NONERP_ID 47 /* d11 management NON-ERP id */ +#define DOT11_MNG_RSN_ID 48 /* d11 management RSN id */ +#define DOT11_MNG_EXT_RATES_ID 50 /* d11 management ext. rates id */ +#define DOT11_MNG_EXT_CSA_ID 60 /* d11 Extended CSA */ +#define DOT11_MNG_HT_ADD 61 /* d11 mgmt additional HT info */ +#define DOT11_MNG_EXT_CHANNEL_OFFSET 62 /* d11 mgmt ext channel offset */ +#define DOT11_MNG_EXT_CAP 127 /* d11 mgmt ext capability */ +#define DOT11_MNG_WPA_ID 221 /* d11 management WPA id */ +#define DOT11_MNG_PROPR_ID 221 /* d11 management proprietary id */ + +/* Rate element Basic flag and rate mask */ +#define DOT11_RATE_BASIC 0x80 /* flag for a Basic Rate */ +#define DOT11_RATE_MASK 0x7F /* mask for numeric part of rate */ + +/* ERP info element bit values */ +#define DOT11_MNG_ERP_LEN 1 /* ERP is currently 1 byte long */ +#define DOT11_MNG_NONERP_PRESENT 0x01 /* NonERP (802.11b) STAs are present + *in the BSS + */ +#define DOT11_MNG_USE_PROTECTION 0x02 /* Use protection mechanisms for + *ERP-OFDM frames + */ +#define DOT11_MNG_BARKER_PREAMBLE 0x04 /* Short Preambles: 0 == allowed, + * 1 == not allowed + */ +/* TS Delay element offset & size */ +#define DOT11_MGN_TS_DELAY_LEN 4 /* length of TS DELAY IE */ +#define TS_DELAY_FIELD_SIZE 4 /* TS DELAY field size */ + +/* Capability Information Field */ +#define DOT11_CAP_ESS 0x0001 /* d11 cap. ESS */ +#define DOT11_CAP_IBSS 0x0002 /* d11 cap. IBSS */ +#define DOT11_CAP_POLLABLE 0x0004 /* d11 cap. pollable */ +#define DOT11_CAP_POLL_RQ 0x0008 /* d11 cap. poll request */ +#define DOT11_CAP_PRIVACY 0x0010 /* d11 cap. privacy */ +#define DOT11_CAP_SHORT 0x0020 /* d11 cap. short */ +#define DOT11_CAP_PBCC 0x0040 /* d11 cap. PBCC */ +#define DOT11_CAP_AGILITY 0x0080 /* d11 cap. agility */ +#define DOT11_CAP_SPECTRUM 0x0100 /* d11 cap. spectrum */ +#define DOT11_CAP_SHORTSLOT 0x0400 /* d11 cap. shortslot */ +#define DOT11_CAP_CCK_OFDM 0x2000 /* d11 cap. CCK/OFDM */ + +/* Extended Capability Information Field */ +#define DOT11_EXT_CAP_HT_IE_SUPPORT 0x01 /* support for info xchg action frame */ + +/* Action Frame Constants */ +#define DOT11_ACTION_HDR_LEN 2 /* action frame header length */ +#define DOT11_ACTION_CAT_ERR_MASK 0x80 /* d11 action category error mask */ +#define DOT11_ACTION_CAT_MASK 0x7F /* d11 action category mask */ +#define DOT11_ACTION_CAT_SPECT_MNG 0x00 /* d11 action category spectrum management */ +#define DOT11_ACTION_CAT_BLOCKACK 0x03 /* d11 action category block ack */ +#define DOT11_ACTION_CAT_HT 0x07 /* d11 action category for HT */ +#define DOT11_ACTION_NOTIFICATION 0x11 /* 17 */ + +#define DOT11_ACTION_ID_M_REQ 0 /* d11 action measurement request */ +#define DOT11_ACTION_ID_M_REP 1 /* d11 action measurement response */ +#define DOT11_ACTION_ID_TPC_REQ 2 /* d11 action TPC request */ +#define DOT11_ACTION_ID_TPC_REP 3 /* d11 action TPC response */ +#define DOT11_ACTION_ID_CHANNEL_SWITCH 4 /* d11 action channel switch */ +#define DOT11_ACTION_ID_EXT_CSA 5 /* d11 extened CSA for 11n */ + +/* HT action ids */ +#define DOT11_ACTION_ID_HT_CH_WIDTH 0 /* notify channel width action id */ +#define DOT11_ACTION_ID_HT_MIMO_PS 1 /* mimo ps action id */ +#define DOT11_ACTION_ID_HT_INFO_XCHG 8 /* HT Information Exchange action id */ + +/* Block Ack action types */ +#define DOT11_BA_ACTION_ADDBA_REQ 0 /* ADDBA Req action frame type */ +#define DOT11_BA_ACTION_ADDBA_RESP 1 /* ADDBA Resp action frame type */ +#define DOT11_BA_ACTION_DELBA 2 /* DELBA action frame type */ + +/* ADDBA action parameters */ +#define DOT11_ADDBA_PARAM_AMSDU_SUP 0x0001 /* AMSDU supported under BA */ +#define DOT11_ADDBA_PARAM_POLICY_MASK 0x0002 /* policy mask(ack vs delayed) */ +#define DOT11_ADDBA_PARAM_POLICY_SHIFT 1 /* policy shift */ +#define DOT11_ADDBA_PARAM_TID_MASK 0x003c /* tid mask */ +#define DOT11_ADDBA_PARAM_TID_SHIFT 2 /* tid shift */ +#define DOT11_ADDBA_PARAM_BSIZE_MASK 0xffc0 /* buffer size mask */ +#define DOT11_ADDBA_PARAM_BSIZE_SHIFT 6 /* buffer size shift */ + +#define DOT11_ADDBA_POLICY_DELAYED 0 /* delayed BA policy */ +#define DOT11_ADDBA_POLICY_IMMEDIATE 1 /* immediate BA policy */ + +struct dot11_addba_req { + uint8 category; /* category of action frame (3) */ + uint8 action; /* action: addba req */ + uint8 token; /* identifier */ + uint16 addba_param_set; /* parameter set */ + uint16 timeout; /* timeout in seconds */ + uint16 start_seqnum; /* starting sequence number */ +}PACKED; +typedef struct dot11_addba_req dot11_addba_req_t; +#define DOT11_ADDBA_REQ_LEN 9 /* length of addba req frame */ + +struct dot11_addba_resp { + uint8 category; /* category of action frame (3) */ + uint8 action; /* action: addba resp */ + uint8 token; /* identifier */ + uint16 status; /* status of add request */ + uint16 addba_param_set; /* negotiated parameter set */ + uint16 timeout; /* negotiated timeout in seconds */ +}PACKED; +typedef struct dot11_addba_resp dot11_addba_resp_t; +#define DOT11_ADDBA_RESP_LEN 9 /* length of addba resp frame */ + +/* DELBA action parameters */ +#define DOT11_DELBA_PARAM_INIT_MASK 0x0800 /* initiator mask */ +#define DOT11_DELBA_PARAM_INIT_SHIFT 11 /* initiator shift */ +#define DOT11_DELBA_PARAM_TID_MASK 0xf000 /* tid mask */ +#define DOT11_DELBA_PARAM_TID_SHIFT 12 /* tid shift */ + +struct dot11_delba { + uint8 category; /* category of action frame (3) */ + uint8 action; /* action: addba req */ + uint16 delba_param_set; /* paarmeter set */ + uint16 reason; /* reason for dellba */ +}PACKED; +typedef struct dot11_delba dot11_delba_t; +#define DOT11_DELBA_LEN 6 /* length of delba frame */ + +/* MLME Enumerations */ +#define DOT11_BSSTYPE_INFRASTRUCTURE 0 /* d11 infrastructure */ +#define DOT11_BSSTYPE_INDEPENDENT 1 /* d11 independent */ +#define DOT11_BSSTYPE_ANY 2 /* d11 any BSS type */ +#define DOT11_SCANTYPE_ACTIVE 0 /* d11 scan active */ +#define DOT11_SCANTYPE_PASSIVE 1 /* d11 scan passive */ + +/* 802.11 BRCM "Compromise" Pre N constants */ +#define PREN_PREAMBLE 24 /* green field preamble time */ +#define PREN_MM_EXT 8 /* extra mixed mode preamble time */ +#define PREN_PREAMBLE_EXT 4 /* extra preamble (multiply by unique_streams-1) */ + +/* 802.11 N PHY constants */ +#define NPHY_RIFS_TIME 2 /* NPHY RIFS time */ + +/* 802.11 A PHY constants */ +#define APHY_SLOT_TIME 9 /* APHY slot time */ +#define APHY_SIFS_TIME 16 /* APHY SIFS time */ +#define APHY_DIFS_TIME (APHY_SIFS_TIME + (2 * APHY_SLOT_TIME)) /* APHY DIFS time */ +#define APHY_PREAMBLE_TIME 16 /* APHY preamble time */ +#define APHY_SIGNAL_TIME 4 /* APHY signal time */ +#define APHY_SYMBOL_TIME 4 /* APHY symbol time */ +#define APHY_SERVICE_NBITS 16 /* APHY service nbits */ +#define APHY_TAIL_NBITS 6 /* APHY tail nbits */ +#define APHY_CWMIN 15 /* APHY cwmin */ + +/* 802.11 B PHY constants */ +#define BPHY_SLOT_TIME 20 /* BPHY slot time */ +#define BPHY_SIFS_TIME 10 /* BPHY SIFS time */ +#define BPHY_DIFS_TIME 50 /* BPHY DIFS time */ +#define BPHY_PLCP_TIME 192 /* BPHY PLCP time */ +#define BPHY_PLCP_SHORT_TIME 96 /* BPHY PLCP short time */ +#define BPHY_CWMIN 31 /* BPHY cwmin */ + +/* 802.11 G constants */ +#define DOT11_OFDM_SIGNAL_EXTENSION 6 /* d11 OFDM signal extension */ + +#define PHY_CWMAX 1023 /* PHY cwmax */ + +#define DOT11_MAXNUMFRAGS 16 /* max # fragments per MSDU */ + +/* dot11Counters Table - 802.11 spec., Annex D */ +typedef struct d11cnt { + uint32 txfrag; /* dot11TransmittedFragmentCount */ + uint32 txmulti; /* dot11MulticastTransmittedFrameCount */ + uint32 txfail; /* dot11FailedCount */ + uint32 txretry; /* dot11RetryCount */ + uint32 txretrie; /* dot11MultipleRetryCount */ + uint32 rxdup; /* dot11FrameduplicateCount */ + uint32 txrts; /* dot11RTSSuccessCount */ + uint32 txnocts; /* dot11RTSFailureCount */ + uint32 txnoack; /* dot11ACKFailureCount */ + uint32 rxfrag; /* dot11ReceivedFragmentCount */ + uint32 rxmulti; /* dot11MulticastReceivedFrameCount */ + uint32 rxcrc; /* dot11FCSErrorCount */ + uint32 txfrmsnt; /* dot11TransmittedFrameCount */ + uint32 rxundec; /* dot11WEPUndecryptableCount */ +} d11cnt_t; + +/* BRCM OUI */ +#define BRCM_OUI "\x00\x10\x18" /* Broadcom OUI */ + +/* OUI for BRCM proprietary IE */ +#define BRCM_PROP_OUI "\x00\x90\x4C" /* Broadcom proprietary OUI */ + +/* BRCM info element */ +struct brcm_ie { + uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ + uint8 len; /* IE length */ + uint8 oui[3]; /* Proprietary OUI, BRCM_OUI */ + uint8 ver; /* type/ver of this IE */ + uint8 assoc; /* # of assoc STAs */ + uint8 flags; /* misc flags */ + uint8 flags1; /* misc flags */ + uint16 amsdu_mtu_pref; /* preferred A-MSDU MTU */ +} PACKED; +typedef struct brcm_ie brcm_ie_t; +#define BRCM_IE_LEN 11 /* BRCM IE length */ +#define BRCM_IE_VER 2 /* BRCM IE version */ +#define BRCM_IE_LEGACY_AES_VER 1 /* BRCM IE legacy AES version */ + +/* brcm_ie flags */ +#define BRF_ABCAP 0x1 /* afterburner capable */ +#define BRF_ABRQRD 0x2 /* afterburner requested */ +#define BRF_LZWDS 0x4 /* lazy wds enabled */ +#define BRF_BLOCKACK 0x8 /* BlockACK capable */ +#define BRF_ABCOUNTER_MASK 0xf0 /* afterburner wds "state" counter */ +#define BRF_ABCOUNTER_SHIFT 4 /* offset of afterburner wds "state" counter */ + +/* brcm_ie flags1 */ +#define BRF1_AMSDU 0x1 /* A-MSDU capable */ +#define BRF1_DPT 0x2 /* DPT capable */ + +#define AB_WDS_TIMEOUT_MAX 15 /* afterburner wds Max count indicating not + * locally capable + */ +#define AB_WDS_TIMEOUT_MIN 1 /* afterburner wds, use zero count as indicating + * "downrev" + */ + +/* EWC definitions */ +#define MCSSET_LEN 16 /* 16-bits per 8-bit set to give 128-bits bitmap of MCS Index */ +#define MAX_MCS_NUM (128) /* max mcs number = 128 */ + +struct ewc_cap_ie { + uint16 cap; + uint8 params; + uint8 supp_mcs[MCSSET_LEN]; + uint16 ext_htcap; + uint32 txbf_cap; + uint8 as_cap; +} PACKED; +typedef struct ewc_cap_ie ewc_cap_ie_t; + +/* CAP IE: EWC 1.0 spec. simply stole a 802.11 IE, we use our prop. IE until this is resolved */ +/* the capability IE is primarily used to convey this nodes abilities */ +struct ewc_prop_cap_ie { + uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ + uint8 len; /* IE length */ + uint8 oui[3]; /* Proprietary OUI, BRCM_PROP_OUI */ + uint8 type; /* type inidicates what follows */ + ewc_cap_ie_t cap_ie; +} PACKED; +typedef struct ewc_prop_cap_ie ewc_prop_cap_ie_t; +#define EWC_PROP_IE_OVERHEAD 4 /* overhead bytes for prop oui ie */ +#define EWC_CAP_IE_LEN 26 +#define EWC_CAP_IE_TYPE 51 + +#define EWC_CAP_LDPC_CODING 0x0001 /* Support for rx of LDPC coded pkts */ +#define EWC_CAP_40MHZ 0x0002 /* FALSE:20Mhz, TRUE:20/40MHZ supported */ +#define EWC_CAP_MIMO_PS_MASK 0x000C /* Mimo PS mask */ +#define EWC_CAP_MIMO_PS_SHIFT 0x0002 /* Mimo PS shift */ +#define EWC_CAP_MIMO_PS_OFF 0x0003 /* Mimo PS, no restriction */ +#define EWC_CAP_MIMO_PS_RTS 0x0001 /* Mimo PS, send RTS/CTS around MIMO frames */ +#define EWC_CAP_MIMO_PS_ON 0x0000 /* Mimo PS, MIMO disallowed */ +#define EWC_CAP_GF 0x0010 /* Greenfield preamble support */ +#define EWC_CAP_SHORT_GI_20 0x0020 /* 20MHZ short guard interval support */ +#define EWC_CAP_SHORT_GI_40 0x0040 /* 40Mhz short guard interval support */ +#define EWC_CAP_TX_STBC 0x0080 /* Tx STBC support */ +#define EWC_CAP_RX_STBC_MASK 0x0300 /* Rx STBC mask */ +#define EWC_CAP_RX_STBC_SHIFT 8 /* Rx STBC shift */ +#define EWC_CAP_DELAYED_BA 0x0400 /* delayed BA support */ +#define EWC_CAP_MAX_AMSDU 0x0800 /* Max AMSDU size in bytes , 0=3839, 1=7935 */ +#define EWC_CAP_DSSS_CCK 0x1000 /* DSSS/CCK supported by the BSS */ +#define EWC_CAP_PSMP 0x2000 /* Power Save Multi Poll support */ +#define EWC_CAP_40MHZ_INTOLERANT 0x4000 /* 40MHz Intolerant */ +#define EWC_CAP_LSIG_TXOP 0x8000 /* L-SIG TXOP protection support */ + +#define EWC_CAP_RX_STBC_NO 0x0 /* no rx STBC support */ +#define EWC_CAP_RX_STBC_ONE_STREAM 0x1 /* rx STBC support of 1 spatial stream */ +#define EWC_CAP_RX_STBC_TWO_STREAM 0x2 /* rx STBC support of 1-2 spatial streams */ +#define EWC_CAP_RX_STBC_THREE_STREAM 0x3 /* rx STBC support of 1-3 spatial streams */ + +#define EWC_MAX_AMSDU 7935 /* max amsdu size (bytes) per the EWC spec */ +#define EWC_MIN_AMSDU 3835 /* min amsdu size (bytes) per the EWC spec */ + +#define EWC_PARAMS_RX_FACTOR_MASK 0x03 /* ampdu rcv factor mask */ +#define EWC_PARAMS_DENSITY_MASK 0x1C /* ampdu density mask */ +#define EWC_PARAMS_DENSITY_SHIFT 2 /* ampdu density shift */ + +/* EWC/AMPDU specific define */ +#define AMPDU_MAX_MPDU_DENSITY 7 /* max mpdu density; in 1/8 usec units */ +#define AMPDU_MAX_RX_FACTOR 3 /* max rcv ampdu len (64kb) */ +#define AMPDU_RX_FACTOR_BASE 8*1024 /* ampdu factor base for rx len */ +#define AMPDU_DELIMITER_LEN 4 /* length of ampdu delimiter */ + +struct ewc_add_ie { + uint8 ctl_ch; /* control channel number */ + uint8 byte1; /* ext ch,rec. ch. width, RIFS support */ + uint16 opmode; /* operation mode */ + uint16 misc_bits; /* misc bits */ + uint8 basic_mcs[MCSSET_LEN]; /* required MCS set */ +} PACKED; +typedef struct ewc_add_ie ewc_add_ie_t; + +/* ADD IE: EWC 1.0 spec. simply stole a 802.11 IE, we use our prop. IE until this is resolved */ +/* the additional IE is primarily used to convey the current BSS configuration */ +struct ewc_prop_add_ie { + uint8 id; /* IE ID, 221, DOT11_MNG_PROPR_ID */ + uint8 len; /* IE length */ + uint8 oui[3]; /* Proprietary OUI, BRCM_PROP_OUI */ + uint8 type; /* indicates what follows */ + ewc_add_ie_t add_ie; +} PACKED; +typedef struct ewc_prop_add_ie ewc_prop_add_ie_t; + +#define EWC_ADD_IE_LEN 22 +#define EWC_ADD_IE_TYPE 52 + +/* byte1 defn's */ +#define EWC_BW_ANY 0x04 /* set, STA can use 20 or 40MHz */ +#define EWC_RIFS_PERMITTED 0x08 /* RIFS allowed */ + +/* opmode defn's */ +#define EWC_OPMODE_MASK 0x0003 /* protection mode mask */ +#define EWC_OPMODE_SHIFT 0 /* protection mode shift */ +#define EWC_OPMODE_PURE 0x0000 /* protection mode PURE */ +#define EWC_OPMODE_OPTIONAL 0x0001 /* protection mode optional */ +#define EWC_OPMODE_HT20IN40 0x0002 /* protection mode 20MHz HT in 40MHz BSS */ +#define EWC_OPMODE_MIXED 0x0003 /* protection mode Mixed Mode */ +#define EWC_OPMODE_NONGF 0x0004 /* protection mode non-GF */ +#define DOT11N_TXBURST 0x0008 /* Tx burst limit */ +#define DOT11N_OBSS_NONHT 0x0010 /* OBSS Non-HT STA present */ + +/* misc_bites defn's */ +#define EWC_BASIC_STBC_MCS 0x007f /* basic STBC MCS */ +#define EWC_DUAL_STBC_PROT 0x0080 /* Dual STBC Protection */ +#define EWC_SECOND_BCN 0x0100 /* Secondary beacon support */ +#define EWC_LSIG_TXOP 0x0200 /* L-SIG TXOP Protection full support */ +#define EWC_PCO_ACTIVE 0x0400 /* PCO active */ +#define EWC_PCO_PHASE 0x0800 /* PCO phase */ + +/* Tx Burst Limits */ +#define DOT11N_2G_TXBURST_LIMIT 6160 /* 2G band Tx burst limit per 802.11n Draft 1.10 (usec) */ +#define DOT11N_5G_TXBURST_LIMIT 3080 /* 5G band Tx burst limit per 802.11n Draft 1.10 (usec) */ + +/* Macros for opmode */ +#define GET_EWC_OPMODE(add_ie) ((ltoh16_ua(&add_ie->opmode) & EWC_OPMODE_MASK) \ + >> EWC_OPMODE_SHIFT) +#define EWC_MIXEDMODE_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & EWC_OPMODE_MASK) \ + == EWC_OPMODE_MIXED) /* mixed mode present */ +#define EWC_HT20_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & EWC_OPMODE_MASK) \ + == EWC_OPMODE_HT20IN40) /* 20MHz HT present */ +#define EWC_OPTIONAL_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & EWC_OPMODE_MASK) \ + == EWC_OPMODE_OPTIONAL) /* Optional protection present */ +#define EWC_USE_PROTECTION(add_ie) (EWC_HT20_PRESENT((add_ie)) || \ + EWC_MIXEDMODE_PRESENT((add_ie))) /* use protection */ +#define EWC_NONGF_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & EWC_OPMODE_NONGF) \ + == EWC_OPMODE_NONGF) /* non-GF present */ +#define DOT11N_TXBURST_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_TXBURST) \ + == DOT11N_TXBURST) /* Tx Burst present */ +#define DOT11N_OBSS_NONHT_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_OBSS_NONHT) \ + == DOT11N_OBSS_NONHT) /* OBSS Non-HT present */ + +/* Vendor IE structure */ +struct vndr_ie { + uchar id; + uchar len; + uchar oui [3]; + uchar data [1]; /* Variable size data */ +} PACKED; +typedef struct vndr_ie vndr_ie_t; + +#define VNDR_IE_HDR_LEN 2 /* id + len field */ +#define VNDR_IE_MIN_LEN 3 /* size of the oui field */ +#define VNDR_IE_MAX_LEN 256 /* verdor IE max length */ + +/* WPA definitions */ +#define WPA_VERSION 1 /* WPA version */ +#define WPA_OUI "\x00\x50\xF2" /* WPA OUI */ + +#define WPA2_VERSION 1 /* WPA2 version */ +#define WPA2_VERSION_LEN 2 /* WAP2 version length */ +#define WPA2_OUI "\x00\x0F\xAC" /* WPA2 OUI */ + +#define WPA_OUI_LEN 3 /* WPA OUI length */ + +/* RSN authenticated key managment suite */ +#define RSN_AKM_NONE 0 /* None (IBSS) */ +#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */ +#define RSN_AKM_PSK 2 /* Pre-shared Key */ + +/* Key related defines */ +#define DOT11_MAX_DEFAULT_KEYS 4 /* number of default keys */ +#define DOT11_MAX_KEY_SIZE 32 /* max size of any key */ +#define DOT11_MAX_IV_SIZE 16 /* max size of any IV */ +#define DOT11_EXT_IV_FLAG (1<<5) /* flag to indicate IV is > 4 bytes */ + +#define WEP1_KEY_SIZE 5 /* max size of any WEP key */ +#define WEP1_KEY_HEX_SIZE 10 /* size of WEP key in hex. */ +#define WEP128_KEY_SIZE 13 /* max size of any WEP key */ +#define WEP128_KEY_HEX_SIZE 26 /* size of WEP key in hex. */ +#define TKIP_MIC_SIZE 8 /* size of TKIP MIC */ +#define TKIP_EOM_SIZE 7 /* max size of TKIP EOM */ +#define TKIP_EOM_FLAG 0x5a /* TKIP EOM flag byte */ +#define TKIP_KEY_SIZE 32 /* size of any TKIP key */ +#define TKIP_MIC_AUTH_TX 16 /* offset to Authenticator MIC TX key */ +#define TKIP_MIC_AUTH_RX 24 /* offset to Authenticator MIC RX key */ +#define TKIP_MIC_SUP_RX TKIP_MIC_AUTH_TX /* offset to Supplicant MIC RX key */ +#define TKIP_MIC_SUP_TX TKIP_MIC_AUTH_RX /* offset to Supplicant MIC TX key */ +#define AES_KEY_SIZE 16 /* size of AES key */ + +#undef PACKED +#if !defined(__GNUC__) +#pragma pack() +#endif + +#endif /* _802_11_H_ */ diff --git a/package/broadcom-57xx/src/proto/802.11e.h b/package/broadcom-57xx/src/proto/802.11e.h new file mode 100644 index 0000000000..278ab9c8c5 --- /dev/null +++ b/package/broadcom-57xx/src/proto/802.11e.h @@ -0,0 +1,123 @@ +/* + * 802.11e protocol header file + * + * Copyright 2007, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * + * $Id: 802.11e.h,v 1.1.1.2 2007/05/31 08:00:41 michael Exp $ + */ + +#ifndef _802_11e_H_ +#define _802_11e_H_ + +/* enable structure packing */ +#if defined(__GNUC__) +#define PACKED __attribute__((packed)) +#else +#pragma pack(1) +#define PACKED +#endif + +#ifdef BCMDBG +extern const char *aci_names[]; +#endif /* BCMDBG */ + +/* WME Traffic Specification (TSPEC) element */ +#define WME_TSPEC_HDR_LEN 2 /* WME TSPEC header length */ +#define WME_TSPEC_BODY_OFF 2 /* WME TSPEC body offset */ + +#define WME_CATEGORY_CODE_OFFSET 0 /* WME Category code offset */ +#define WME_ACTION_CODE_OFFSET 1 /* WME Action code offset */ +#define WME_TOKEN_CODE_OFFSET 2 /* WME Token code offset */ +#define WME_STATUS_CODE_OFFSET 3 /* WME Status code offset */ + +struct tsinfo { + uint8 octets[3]; +} PACKED; + +typedef struct tsinfo tsinfo_t; + +/* 802.11e TSPEC IE */ +typedef struct tspec { + uint8 oui[DOT11_OUI_LEN]; /* WME_OUI */ + uint8 type; /* WME_TYPE */ + uint8 subtype; /* WME_SUBTYPE_TSPEC */ + uint8 version; /* WME_VERSION */ + tsinfo_t tsinfo; /* TS Info bit field */ + uint16 nom_msdu_size; /* (Nominal or fixed) MSDU Size (bytes) */ + uint16 max_msdu_size; /* Maximum MSDU Size (bytes) */ + uint32 min_srv_interval; /* Minimum Service Interval (us) */ + uint32 max_srv_interval; /* Maximum Service Interval (us) */ + uint32 inactivity_interval; /* Inactivity Interval (us) */ + uint32 suspension_interval; /* Suspension Interval (us) */ + uint32 srv_start_time; /* Service Start Time (us) */ + uint32 min_data_rate; /* Minimum Data Rate (bps) */ + uint32 mean_data_rate; /* Mean Data Rate (bps) */ + uint32 peak_data_rate; /* Peak Data Rate (bps) */ + uint32 max_burst_size; /* Maximum Burst Size (bytes) */ + uint32 delay_bound; /* Delay Bound (us) */ + uint32 min_phy_rate; /* Minimum PHY Rate (bps) */ + uint16 surplus_bw; /* Surplus Bandwidth Allowance Factor */ + uint16 medium_time; /* Medium Time (32 us/s periods) */ +} PACKED tspec_t; + +#define WME_TSPEC_LEN (sizeof(tspec_t)) /* not including 2-bytes of header */ + +/* ts_info */ +/* 802.1D priority is duplicated - bits 13-11 AND bits 3-1 */ +#define TS_INFO_TID_SHIFT 1 /* TS info. TID shift */ +#define TS_INFO_TID_MASK (0xf << TS_INFO_TID_SHIFT) /* TS info. TID mask */ +#define TS_INFO_CONTENTION_SHIFT 7 /* TS info. contention shift */ +#define TS_INFO_CONTENTION_MASK (0x1 << TS_INFO_CONTENTION_SHIFT) /* TS info. contention mask */ +#define TS_INFO_DIRECTION_SHIFT 5 /* TS info. direction shift */ +#define TS_INFO_DIRECTION_MASK (0x3 << TS_INFO_DIRECTION_SHIFT) /* TS info. direction mask */ +#define TS_INFO_PSB_SHIFT 2 /* TS info. PSB bit Shift */ +#define TS_INFO_PSB_MASK (1 << TS_INFO_PSB_SHIFT) /* TS info. PSB mask */ +#define TS_INFO_UPLINK (0 << TS_INFO_DIRECTION_SHIFT) /* TS info. uplink */ +#define TS_INFO_DOWNLINK (1 << TS_INFO_DIRECTION_SHIFT) /* TS info. downlink */ +#define TS_INFO_BIDIRECTIONAL (3 << TS_INFO_DIRECTION_SHIFT) /* TS info. bidirectional */ +#define TS_INFO_USER_PRIO_SHIFT 3 /* TS info. user priority shift */ +/* TS info. user priority mask */ +#define TS_INFO_USER_PRIO_MASK (0x7 << TS_INFO_USER_PRIO_SHIFT) + +/* Macro to get/set bit(s) field in TSINFO */ +#define WLC_CAC_GET_TID(pt) ((((pt).octets[0]) & TS_INFO_TID_MASK) >> TS_INFO_TID_SHIFT) +#define WLC_CAC_GET_DIR(pt) ((((pt).octets[0]) & \ + TS_INFO_DIRECTION_MASK) >> TS_INFO_DIRECTION_SHIFT) +#define WLC_CAC_GET_PSB(pt) ((((pt).octets[1]) & WLC_CAC_PSB_MASK) >> WLC_CAC_PSB_SHIFT) +#define WLC_CAC_GET_USER_PRIO(pt) ((((pt).octets[1]) & \ + TS_INFO_USER_PRIO_MASK) >> TS_INFO_USER_PRIO_SHIFT) + +#define WLC_CAC_SET_TID(pt, id) ((((pt).octets[0]) & (~TS_INFO_TID_MASK)) | \ + ((id) << TS_INFO_TID_SHIFT)) +#define WLC_CAC_SET_USER_PRIO(pt, prio) ((((pt).octets[0]) & (~TS_INFO_USER_PRIO_MASK)) | \ + ((prio) << TS_INFO_USER_PRIO_SHIFT)) + +/* 802.11e QBSS Load IE */ +#define QBSS_LOAD_IE_LEN 5 /* QBSS Load IE length */ +#define QBSS_LOAD_AAC_OFF 3 /* AAC offset in IE */ + +#define CAC_ADDTS_RESP_TIMEOUT 300 /* default ADDTS response timeout in ms */ + +/* 802.11e ADDTS status code */ +#define DOT11E_STATUS_ADMISSION_ACCEPTED 0 /* TSPEC Admission accepted status */ +#define DOT11E_STATUS_ADDTS_INVALID_PARAM 1 /* TSPEC invalid parameter status */ +#define DOT11E_STATUS_ADDTS_REFUSED_NSBW 3 /* ADDTS refused (non-sufficient BW) */ + +/* 802.11e DELTS status code */ +#define DOT11E_STATUS_QSTA_LEAVE_QBSS 36 /* STA leave QBSS */ +#define DOT11E_STATUS_END_TS 37 /* END TS */ +#define DOT11E_STATUS_UNKNOWN_TS 38 /* UNKNOWN TS */ +#define DOT11E_STATUS_QSTA_REQ_TIMEOUT 39 /* STA ADDTS request timeout */ + +#undef PACKED +#if !defined(__GNUC__) +#pragma pack() +#endif + +#endif /* _802_11e_CAC_H_ */ diff --git a/package/broadcom-57xx/src/proto/802.1d.h b/package/broadcom-57xx/src/proto/802.1d.h new file mode 100644 index 0000000000..831c43bf80 --- /dev/null +++ b/package/broadcom-57xx/src/proto/802.1d.h @@ -0,0 +1,38 @@ +/* + * Copyright 2007, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * + * Fundamental types and constants relating to 802.1D + * + * $Id: 802.1d.h,v 1.1.1.2 2007/05/31 08:00:41 michael Exp $ + */ + +#ifndef _802_1_D_ +#define _802_1_D_ + +/* 802.1D priority defines */ +#define PRIO_8021D_NONE 2 /* None = - */ +#define PRIO_8021D_BK 1 /* BK - Background */ +#define PRIO_8021D_BE 0 /* BE - Best-effort */ +#define PRIO_8021D_EE 3 /* EE - Excellent-effort */ +#define PRIO_8021D_CL 4 /* CL - Controlled Load */ +#define PRIO_8021D_VI 5 /* Vi - Video */ +#define PRIO_8021D_VO 6 /* Vo - Voice */ +#define PRIO_8021D_NC 7 /* NC - Network Control */ +#define MAXPRIO 7 /* 0-7 */ +#define NUMPRIO (MAXPRIO + 1) + +#define ALLPRIO -1 /* All prioirty */ + +/* Converts prio to precedence since the numerical value of + * PRIO_8021D_BE and PRIO_8021D_NONE are swapped. + */ +#define PRIO2PREC(prio) \ + (((prio) == PRIO_8021D_NONE || (prio) == PRIO_8021D_BE) ? ((prio^2)) : (prio)) + +#endif /* _802_1_D__ */ diff --git a/package/broadcom-57xx/src/proto/802.3.h b/package/broadcom-57xx/src/proto/802.3.h new file mode 100644 index 0000000000..493b60e3f8 --- /dev/null +++ b/package/broadcom-57xx/src/proto/802.3.h @@ -0,0 +1,20 @@ +/* + * Copyright 2007, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * Fundamental constants relating to 802.3 + * + * $Id: 802.3.h,v 1.1.1.1 2007/05/31 08:00:41 michael Exp $ + */ + +#ifndef _802_3_h_ +#define _802_3_h_ + +#define SNAP_HDR_LEN 6 /* 802.3 LLC/SNAP header length */ + +#endif /* #ifndef _802_3_h_ */ diff --git a/package/broadcom-57xx/src/proto/bcmarp.h b/package/broadcom-57xx/src/proto/bcmarp.h new file mode 100644 index 0000000000..2e27ac1669 --- /dev/null +++ b/package/broadcom-57xx/src/proto/bcmarp.h @@ -0,0 +1,60 @@ +/* + * Copyright 2007, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * Fundamental constants relating to ARP Protocol + * + * $Id: bcmarp.h,v 1.1.1.1 2007/05/31 08:00:41 michael Exp $ + */ + +#ifndef _bcmarp_h_ +#define _bcmarp_h_ + +/* enable structure packing */ +#if defined(__GNUC__) +#define PACKED __attribute__((packed)) +#else +#pragma pack(1) +#define PACKED +#endif + +#define ARP_OPC_OFFSET 6 /* option code offset */ +#define ARP_SRC_ETH_OFFSET 8 /* src h/w address offset */ +#define ARP_SRC_IP_OFFSET 14 /* src IP address offset */ +#define ARP_TGT_ETH_OFFSET 18 /* target h/w address offset */ +#define ARP_TGT_IP_OFFSET 24 /* target IP address offset */ + +#define ARP_OPC_REQUEST 1 /* ARP request */ +#define ARP_OPC_REPLY 2 /* ARP reply */ + +#define ARP_DATA_LEN 28 /* ARP data length */ + +struct bcmarp { + uint16 htype; /* Header type (1 = ethernet) */ + uint16 ptype; /* Protocol type (0x800 = IP) */ + uint8 hlen; /* Hardware address length (Eth = 6) */ + uint8 plen; /* Protocol address length (IP = 4) */ + uint16 oper; /* ARP_OPC_... */ + uint8 src_eth[ETHER_ADDR_LEN]; /* Source hardware address */ + uint8 src_ip[IPV4_ADDR_LEN]; /* Source protocol address (not aligned) */ + uint8 dst_eth[ETHER_ADDR_LEN]; /* Destination hardware address */ + uint8 dst_ip[IPV4_ADDR_LEN]; /* Destination protocol address */ +} PACKED; + +/* Ethernet header + Arp message */ +struct bcmetharp { + struct ether_header eh; + struct bcmarp arp; +} PACKED; + +#undef PACKED +#if !defined(__GNUC__) +#pragma pack() +#endif + +#endif /* !defined(_bcmarp_h_) */ diff --git a/package/broadcom-57xx/src/proto/bcmdhcp.h b/package/broadcom-57xx/src/proto/bcmdhcp.h new file mode 100644 index 0000000000..f92a69b362 --- /dev/null +++ b/package/broadcom-57xx/src/proto/bcmdhcp.h @@ -0,0 +1,36 @@ +/* + * Copyright 2007, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * Fundamental constants relating to DHCP Protocol + * + * $Id: bcmdhcp.h,v 1.1.1.1 2007/05/31 08:00:41 michael Exp $ + */ + +#ifndef _bcmdhcp_h_ +#define _bcmdhcp_h_ + +/* DHCP params */ +#define DHCP_TYPE_OFFSET 0 /* DHCP type (request|reply) offset */ +#define DHCP_FLAGS_OFFSET 10 /* DHCP flags offset */ +#define DHCP_CIADDR_OFFSET 12 /* DHCP client IP address offset */ +#define DHCP_YIADDR_OFFSET 16 /* DHCP your IP address offset */ +#define DHCP_GIADDR_OFFSET 24 /* DHCP relay agent IP address offset */ +#define DHCP_CHADDR_OFFSET 28 /* DHCP client h/w address offset */ + +#define DHCP_TYPE_REQUEST 1 /* DHCP request (discover|request) */ +#define DHCP_TYPE_REPLY 2 /* DHCP reply (offset|ack) */ + +#define DHCP_PORT_SERVER 67 /* DHCP server UDP port */ +#define DHCP_PORT_CLIENT 68 /* DHCP client UDP port */ + +#define DHCP_FLAG_BCAST 0x8000 /* DHCP broadcast flag */ + +#define DHCP_FLAGS_LEN 2 /* DHCP flags field length */ + +#endif /* #ifndef _bcmdhcp_h_ */ diff --git a/package/broadcom-57xx/src/proto/bcmeth.h b/package/broadcom-57xx/src/proto/bcmeth.h new file mode 100644 index 0000000000..fffce6e7b5 --- /dev/null +++ b/package/broadcom-57xx/src/proto/bcmeth.h @@ -0,0 +1,101 @@ +/* + * Broadcom Ethernettype protocol definitions + * + * Copyright 2007, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * + * $Id: bcmeth.h,v 1.1.1.5 2007/05/31 08:00:41 michael Exp $ + */ + +/* + * Broadcom Ethernet protocol defines + */ + +#ifndef _BCMETH_H_ +#define _BCMETH_H_ + +/* enable structure packing */ +#if defined(__GNUC__) +#define PACKED __attribute__((packed)) +#else +#pragma pack(1) +#define PACKED +#endif + +/* ETHER_TYPE_BRCM is defined in ethernet.h */ + +/* + * Following the 2byte BRCM ether_type is a 16bit BRCM subtype field + * in one of two formats: (only subtypes 32768-65535 are in use now) + * + * subtypes 0-32767: + * 8 bit subtype (0-127) + * 8 bit length in bytes (0-255) + * + * subtypes 32768-65535: + * 16 bit big-endian subtype + * 16 bit big-endian length in bytes (0-65535) + * + * length is the number of additional bytes beyond the 4 or 6 byte header + * + * Reserved values: + * 0 reserved + * 5-15 reserved for iLine protocol assignments + * 17-126 reserved, assignable + * 127 reserved + * 32768 reserved + * 32769-65534 reserved, assignable + * 65535 reserved + */ + +/* + * While adding the subtypes and their specific processing code make sure + * bcmeth_bcm_hdr_t is the first data structure in the user specific data structure definition + */ + +#define BCMILCP_SUBTYPE_RATE 1 +#define BCMILCP_SUBTYPE_LINK 2 +#define BCMILCP_SUBTYPE_CSA 3 +#define BCMILCP_SUBTYPE_LARQ 4 +#define BCMILCP_SUBTYPE_VENDOR 5 +#define BCMILCP_SUBTYPE_FLH 17 + +#define BCMILCP_SUBTYPE_VENDOR_LONG 32769 +#define BCMILCP_SUBTYPE_CERT 32770 +#define BCMILCP_SUBTYPE_SES 32771 + + +#define BCMILCP_BCM_SUBTYPE_RESERVED 0 +#define BCMILCP_BCM_SUBTYPE_EVENT 1 +#define BCMILCP_BCM_SUBTYPE_SES 2 +/* + * The EAPOL type is not used anymore. Instead EAPOL messages are now embedded + * within BCMILCP_BCM_SUBTYPE_EVENT type messages + */ +/* #define BCMILCP_BCM_SUBTYPE_EAPOL 3 */ + +#define BCMILCP_BCM_SUBTYPEHDR_MINLENGTH 8 +#define BCMILCP_BCM_SUBTYPEHDR_VERSION 0 + +/* These fields are stored in network order */ +typedef struct bcmeth_hdr +{ + uint16 subtype; /* Vendor specific..32769 */ + uint16 length; + uint8 version; /* Version is 0 */ + uint8 oui[3]; /* Broadcom OUI */ + /* user specific Data */ + uint16 usr_subtype; +} PACKED bcmeth_hdr_t; + +#undef PACKED +#if !defined(__GNUC__) +#pragma pack() +#endif + +#endif /* _BCMETH_H_ */ diff --git a/package/broadcom-57xx/src/proto/bcmevent.h b/package/broadcom-57xx/src/proto/bcmevent.h new file mode 100644 index 0000000000..e862763762 --- /dev/null +++ b/package/broadcom-57xx/src/proto/bcmevent.h @@ -0,0 +1,166 @@ +/* + * Broadcom Event protocol definitions + * + * Copyright 2007, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * + * + * Dependencies: proto/bcmeth.h + * + * $Id: bcmevent.h,v 1.1.1.11 2007/05/31 08:00:41 michael Exp $ + * + */ + +/* + * Broadcom Ethernet Events protocol defines + * + */ + +#ifndef _BCMEVENT_H_ +#define _BCMEVENT_H_ + +/* enable structure packing */ +#if defined(__GNUC__) +#define PACKED __attribute__((packed)) +#else +#pragma pack(1) +#define PACKED +#endif /* defined(__GNUC__) */ + +#define BCM_EVENT_MSG_VERSION 1 /* wl_event_msg_t struct version */ +#define BCM_MSG_IFNAME_MAX 16 /* max length of interface name */ + +/* flags */ +#define WLC_EVENT_MSG_LINK 0x01 /* link is up */ +#define WLC_EVENT_MSG_FLUSHTXQ 0x02 /* flush tx queue on MIC error */ +#define WLC_EVENT_MSG_GROUP 0x04 /* group MIC error */ + +/* these fields are stored in network order */ +typedef struct +{ + uint16 version; + uint16 flags; /* see flags below */ + uint32 event_type; /* Message (see below) */ + uint32 status; /* Status code (see below) */ + uint32 reason; /* Reason code (if applicable) */ + uint32 auth_type; /* WLC_E_AUTH */ + uint32 datalen; /* data buf */ + struct ether_addr addr; /* Station address (if applicable) */ + char ifname[BCM_MSG_IFNAME_MAX]; /* name of the packet incoming interface */ +} PACKED wl_event_msg_t; + +/* used by driver msgs */ +typedef struct bcm_event { + struct ether_header eth; + bcmeth_hdr_t bcm_hdr; + wl_event_msg_t event; + /* data portion follows */ +} PACKED bcm_event_t; + +#define BCM_MSG_LEN (sizeof(bcm_event_t) - sizeof(bcmeth_hdr_t) - sizeof(struct ether_header)) + +/* Event messages */ +#define WLC_E_SET_SSID 0 /* indicates status of set SSID */ +#define WLC_E_JOIN 1 /* differentiates join IBSS from found (WLC_E_START) IBSS */ +#define WLC_E_START 2 /* STA founded an IBSS or AP started a BSS */ +#define WLC_E_AUTH 3 /* 802.11 AUTH request */ +#define WLC_E_AUTH_IND 4 /* 802.11 AUTH indication */ +#define WLC_E_DEAUTH 5 /* 802.11 DEAUTH request */ +#define WLC_E_DEAUTH_IND 6 /* 802.11 DEAUTH indication */ +#define WLC_E_ASSOC 7 /* 802.11 ASSOC request */ +#define WLC_E_ASSOC_IND 8 /* 802.11 ASSOC indication */ +#define WLC_E_REASSOC 9 /* 802.11 REASSOC request */ +#define WLC_E_REASSOC_IND 10 /* 802.11 REASSOC indication */ +#define WLC_E_DISASSOC 11 /* 802.11 DISASSOC request */ +#define WLC_E_DISASSOC_IND 12 /* 802.11 DISASSOC indication */ +#define WLC_E_QUIET_START 13 /* 802.11h Quiet period started */ +#define WLC_E_QUIET_END 14 /* 802.11h Quiet period ended */ +#define WLC_E_BEACON_RX 15 /* BEACONS received/lost indication */ +#define WLC_E_LINK 16 /* generic link indication */ +#define WLC_E_MIC_ERROR 17 /* TKIP MIC error occurred */ +#define WLC_E_NDIS_LINK 18 /* NDIS style link indication */ +#define WLC_E_ROAM 19 /* roam attempt occurred: indicate status & reason */ +#define WLC_E_TXFAIL 20 /* change in dot11FailedCount (txfail) */ +#define WLC_E_PMKID_CACHE 21 /* WPA2 pmkid cache indication */ +#define WLC_E_RETROGRADE_TSF 22 /* current AP's TSF value went backward */ +#define WLC_E_PRUNE 23 /* AP was pruned from join list for reason */ +#define WLC_E_AUTOAUTH 24 /* report AutoAuth table entry match for join attempt */ +#define WLC_E_EAPOL_MSG 25 /* Event encapsulating an EAPOL message */ +#define WLC_E_SCAN_COMPLETE 26 /* Scan results are ready or scan was aborted */ +#define WLC_E_ADDTS_IND 27 /* indicate to host addts fail/success */ +#define WLC_E_DELTS_IND 28 /* indicate to host delts fail/success */ +#define WLC_E_BCNSENT_IND 29 /* indicate to host of beacon transmit */ +#define WLC_E_BCNRX_MSG 30 /* Send the received beacon up to the host */ +#define WLC_E_BCNLOST_MSG 31 /* indicate to host loss of beacon */ +#define WLC_E_ROAM_PREP 32 /* before attempting to roam */ +#define WLC_E_PFN_NET_FOUND 33 /* PFN network found event */ +#define WLC_E_PFN_NET_LOST 34 /* PFN network lost event */ + +#ifdef EXT_STA +#define WLC_E_RESET_COMPLETE 35 +#define WLC_E_JOIN_START 36 +#define WLC_E_ROAM_START 37 +#define WLC_E_ASSOC_START 38 +#define WLC_E_IBSS_ASSOC 39 +#define WLC_E_RADIO 40 +#define WLC_E_LAST 41 /* highest val + 1 for range checking */ +#else /* EXT_STA */ +#define WLC_E_LAST 35 /* highest val + 1 for range checking */ +#endif /* EXT_STA */ + +/* Event status codes */ +#define WLC_E_STATUS_SUCCESS 0 /* operation was successful */ +#define WLC_E_STATUS_FAIL 1 /* operation failed */ +#define WLC_E_STATUS_TIMEOUT 2 /* operation timed out */ +#define WLC_E_STATUS_NO_NETWORKS 3 /* failed due to no matching network found */ +#define WLC_E_STATUS_ABORT 4 /* operation was aborted */ +#define WLC_E_STATUS_NO_ACK 5 /* protocol failure: packet not ack'd */ +#define WLC_E_STATUS_UNSOLICITED 6 /* AUTH or ASSOC packet was unsolicited */ +#define WLC_E_STATUS_ATTEMPT 7 /* attempt to assoc to an auto auth configuration */ +#define WLC_E_STATUS_PARTIAL 8 /* scan results are incomplete */ +#define WLC_E_STATUS_NEWSCAN 9 /* scan aborted by another scan */ +#define WLC_E_STATUS_NEWASSOC 10 /* scan aborted due to assoc in progress */ +#define WLC_E_STATUS_11HQUIET 11 /* 802.11h quiet period started */ +#define WLC_E_STATUS_SUPPRESS 12 /* user disabled scanning (WLC_SET_SCANSUPPRESS) */ +#define WLC_E_STATUS_NOCHANS 13 /* no allowable channels to scan */ +#define WLC_E_STATUS_CCXFASTRM 14 /* scan aborted due to CCX fast roam */ + +/* roam reason codes */ +#define WLC_E_REASON_INITIAL_ASSOC 0 /* initial assoc */ +#define WLC_E_REASON_LOW_RSSI 1 /* roamed due to low RSSI */ +#define WLC_E_REASON_DEAUTH 2 /* roamed due to DEAUTH indication */ +#define WLC_E_REASON_DISASSOC 3 /* roamed due to DISASSOC indication */ +#define WLC_E_REASON_BCNS_LOST 4 /* roamed due to lost beacons */ +#define WLC_E_REASON_FAST_ROAM_FAILED 5 /* roamed due to fast roam failure */ +#define WLC_E_REASON_DIRECTED_ROAM 6 /* roamed due to request by AP */ +#define WLC_E_REASON_TSPEC_REJECTED 7 /* roamed due to TSPEC rejection */ +#define WLC_E_REASON_BETTER_AP 8 /* roamed due to finding better AP */ + +/* prune reason codes */ +#define WLC_E_PRUNE_ENCR_MISMATCH 1 /* encryption mismatch */ +#define WLC_E_PRUNE_BCAST_BSSID 2 /* AP uses a broadcast BSSID */ +#define WLC_E_PRUNE_MAC_DENY 3 /* STA's MAC addr is in AP's MAC deny list */ +#define WLC_E_PRUNE_MAC_NA 4 /* STA's MAC addr is not in AP's MAC allow list */ +#define WLC_E_PRUNE_REG_PASSV 5 /* AP not allowed due to regulatory restriction */ +#define WLC_E_PRUNE_SPCT_MGMT 6 /* AP does not support STA locale spectrum mgmt */ +#define WLC_E_PRUNE_RADAR 7 /* AP is on a radar channel of STA locale */ +#define WLC_E_RSN_MISMATCH 8 /* STA does not support AP's RSN */ +#define WLC_E_PRUNE_NO_COMMON_RATES 9 /* No rates in common with AP */ +#define WLC_E_PRUNE_BASIC_RATES 10 /* STA does not support all basic rates of BSS */ +#define WLC_E_PRUNE_CIPHER_NA 12 /* BSS's cipher not supported */ +#define WLC_E_PRUNE_KNOWN_STA 13 /* AP is already known to us as a STA */ +#define WLC_E_PRUNE_WDS_PEER 15 /* AP is already known to us as a WDS peer */ +#define WLC_E_PRUNE_QBSS_LOAD 16 /* QBSS LOAD - AAC is too low */ +#define WLC_E_PRUNE_HOME_AP 17 /* prune home AP */ + +#undef PACKED +#if !defined(__GNUC__) +#pragma pack() +#endif /* PACKED */ + +#endif /* _BCMEVENT_H_ */ diff --git a/package/broadcom-57xx/src/proto/bcmip.h b/package/broadcom-57xx/src/proto/bcmip.h new file mode 100644 index 0000000000..11f63f3208 --- /dev/null +++ b/package/broadcom-57xx/src/proto/bcmip.h @@ -0,0 +1,152 @@ +/* + * Copyright 2007, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * + * Fundamental constants relating to IP Protocol + * + * $Id: bcmip.h,v 1.1.1.4 2007/05/31 08:00:41 michael Exp $ + */ + +#ifndef _bcmip_h_ +#define _bcmip_h_ + +/* enable structure packing */ +#if defined(__GNUC__) +#define PACKED __attribute__((packed)) +#else +#pragma pack(1) +#define PACKED +#endif + + +/* IPV4 and IPV6 common */ +#define IP_VER_OFFSET 0x0 /* offset to version field */ +#define IP_VER_MASK 0xf0 /* version mask */ +#define IP_VER_SHIFT 4 /* version shift */ +#define IP_VER_4 4 /* version number for IPV4 */ +#define IP_VER_6 6 /* version number for IPV6 */ + +#define IP_VER(ip_body) \ + ((((uint8 *)(ip_body))[IP_VER_OFFSET] & IP_VER_MASK) >> IP_VER_SHIFT) + +#define IP_PROT_ICMP 0x1 /* ICMP protocol */ +#define IP_PROT_TCP 0x6 /* TCP protocol */ +#define IP_PROT_UDP 0x11 /* UDP protocol type */ + +/* IPV4 field offsets */ +#define IPV4_VER_HL_OFFSET 0 /* version and ihl byte offset */ +#define IPV4_TOS_OFFSET 1 /* type of service offset */ +#define IPV4_PKTLEN_OFFSET 2 /* packet length offset */ +#define IPV4_PKTFLAG_OFFSET 6 /* more-frag,dont-frag flag offset */ +#define IPV4_PROT_OFFSET 9 /* protocol type offset */ +#define IPV4_CHKSUM_OFFSET 10 /* IP header checksum offset */ +#define IPV4_SRC_IP_OFFSET 12 /* src IP addr offset */ +#define IPV4_DEST_IP_OFFSET 16 /* dest IP addr offset */ +#define IPV4_OPTIONS_OFFSET 20 /* IP options offset */ + +/* IPV4 field decodes */ +#define IPV4_VER_MASK 0xf0 /* IPV4 version mask */ +#define IPV4_VER_SHIFT 4 /* IPV4 version shift */ + +#define IPV4_HLEN_MASK 0x0f /* IPV4 header length mask */ +#define IPV4_HLEN(ipv4_body) (4 * (((uint8 *)(ipv4_body))[IPV4_VER_HL_OFFSET] & IPV4_HLEN_MASK)) + +#define IPV4_ADDR_LEN 4 /* IPV4 address length */ + +#define IPV4_ADDR_NULL(a) ((((uint8 *)(a))[0] | ((uint8 *)(a))[1] | \ + ((uint8 *)(a))[2] | ((uint8 *)(a))[3]) == 0) + +#define IPV4_ADDR_BCAST(a) ((((uint8 *)(a))[0] & ((uint8 *)(a))[1] & \ + ((uint8 *)(a))[2] & ((uint8 *)(a))[3]) == 0xff) + +#define IPV4_TOS_DSCP_MASK 0xfc /* DiffServ codepoint mask */ +#define IPV4_TOS_DSCP_SHIFT 2 /* DiffServ codepoint shift */ + +#define IPV4_TOS(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_TOS_OFFSET]) + +#define IPV4_TOS_PREC_MASK 0xe0 /* Historical precedence mask */ +#define IPV4_TOS_PREC_SHIFT 5 /* Historical precedence shift */ + +#define IPV4_TOS_LOWDELAY 0x10 /* Lowest delay requested */ +#define IPV4_TOS_THROUGHPUT 0x8 /* Best throughput requested */ +#define IPV4_TOS_RELIABILITY 0x4 /* Most reliable delivery requested */ + +#define IPV4_PROT(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_PROT_OFFSET]) + +#define IPV4_FRAG_RESV 0x8000 /* Reserved */ +#define IPV4_FRAG_DONT 0x4000 /* Don't fragment */ +#define IPV4_FRAG_MORE 0x2000 /* More fragments */ +#define IPV4_FRAG_OFFSET_MASK 0x1fff /* Fragment offset */ + +#define IPV4_ADDR_STR_LEN 16 /* Max IP address length in string format */ + +/* IPv4, no options only. */ +#define IPV4_NO_OPTIONS_HDR_LEN 20 +#define IPV4_NO_OPTIONS_PAYLOAD(ip_hdr) (&(((uint8 *)(ip_hdr))[IPV4_NO_OPTIONS_HDR_LEN])) + +#define IPV4_PAYLOAD_LEN(ip_body) \ + (((int)(((uint8 *)(ip_body))[IPV4_PKTLEN_OFFSET + 0]) << 8) | \ + ((uint8 *)(ip_body))[IPV4_PKTLEN_OFFSET + 1]) + +/* IPV4 packet formats */ +struct ipv4_addr { + uint8 addr[IPV4_ADDR_LEN]; +} PACKED; + +struct ipv4_hdr { + uint8 version_ihl; /* Version and Internet Header Length */ + uint8 tos; /* Type Of Service */ + uint16 tot_len; /* Number of bytes in packet (max 65535) */ + uint16 id; + uint16 frag; /* 3 flag bits and fragment offset */ + uint8 ttl; /* Time To Live */ + uint8 prot; /* Protocol */ + uint16 hdr_chksum; /* IP header checksum */ + uint8 src_ip[IPV4_ADDR_LEN]; /* Source IP Address */ + uint8 dst_ip[IPV4_ADDR_LEN]; /* Destination IP Address */ +} PACKED; + +/* IPV6 field offsets */ +#define IPV6_PAYLOAD_LEN_OFFSET 4 /* payload length offset */ +#define IPV6_NEXT_HDR_OFFSET 6 /* next header/protocol offset */ +#define IPV6_HOP_LIMIT_OFFSET 7 /* hop limit offset */ +#define IPV6_SRC_IP_OFFSET 8 /* src IP addr offset */ +#define IPV6_DEST_IP_OFFSET 24 /* dst IP addr offset */ + +/* IPV6 field decodes */ +#define IPV6_TRAFFIC_CLASS(ipv6_body) \ + (((((uint8 *)(ipv6_body))[0] & 0x0f) << 4) | \ + ((((uint8 *)(ipv6_body))[1] & 0xf0) >> 4)) + +#define IPV6_FLOW_LABEL(ipv6_body) \ + (((((uint8 *)(ipv6_body))[1] & 0x0f) << 16) | \ + (((uint8 *)(ipv6_body))[2] << 8) | \ + (((uint8 *)(ipv6_body))[3])) + +#define IPV6_PAYLOAD_LEN(ipv6_body) \ + ((((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 0] << 8) | \ + ((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 1]) + +#define IPV6_NEXT_HDR(ipv6_body) \ + (((uint8 *)(ipv6_body))[IPV6_NEXT_HDR_OFFSET]) + +#define IPV6_PROT(ipv6_body) IPV6_NEXT_HDR(ipv6_body) + +#define IPV6_ADDR_LEN 16 /* IPV6 address length */ + +/* IPV4 TOS or IPV6 Traffic Classifier or 0 */ +#define IP_TOS(ip_body) \ + (IP_VER(ip_body) == IP_VER_4 ? IPV4_TOS(ip_body) : \ + IP_VER(ip_body) == IP_VER_6 ? IPV6_TRAFFIC_CLASS(ip_body) : 0) + +#undef PACKED +#if !defined(__GNUC__) +#pragma pack() +#endif + +#endif /* _bcmip_h_ */ diff --git a/package/broadcom-57xx/src/proto/bcmtcp.h b/package/broadcom-57xx/src/proto/bcmtcp.h new file mode 100644 index 0000000000..7e834a77b9 --- /dev/null +++ b/package/broadcom-57xx/src/proto/bcmtcp.h @@ -0,0 +1,68 @@ +/* + * Copyright 2007, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * + * Fundamental constants relating to TCP Protocol + * + * $Id: bcmtcp.h,v 1.1.1.1 2007/05/31 08:00:41 michael Exp $ + */ + +#ifndef _bcmtcp_h_ +#define _bcmtcp_h_ + +/* enable structure packing */ +#if defined(__GNUC__) +#define PACKED __attribute__((packed)) +#else +#pragma pack(1) +#define PACKED +#endif + +#define TCP_SRC_PORT_OFFSET 0 /* TCP source port offset */ +#define TCP_DEST_PORT_OFFSET 2 /* TCP dest port offset */ +#define TCP_CHKSUM_OFFSET 16 /* TCP body checksum offset */ + +/* These fields are stored in network order */ +struct bcmtcp_hdr +{ + uint16 src_port; /* Source Port Address */ + uint16 dst_port; /* Destination Port Address */ + uint32 seq_num; /* TCP Sequence Number */ + uint32 ack_num; /* TCP Sequence Number */ + uint16 hdrlen_rsvd_flags; /* Header length, reserved bits and flags */ + uint16 tcpwin; /* TCP window */ + uint16 chksum; /* Segment checksum with pseudoheader */ + uint16 urg_ptr; /* Points to seq-num of byte following urg data */ +} PACKED; + +#undef PACKED +#if !defined(__GNUC__) +#pragma pack() +#endif + +/* Byte offset of flags in TCP header */ +#define TCP_FLAGS_OFFSET 13 + +#define TCP_FLAGS_FIN 0x01 +#define TCP_FLAGS_SYN 0x02 +#define TCP_FLAGS_RST 0x03 +#define TCP_FLAGS_PSH 0x04 +#define TCP_FLAGS_ACK 0x10 +#define TCP_FLAGS_URG 0x20 +#define TCP_FLAGS_ECN 0x40 +#define TCP_FLAGS_CWR 0x80 + +#define TCP_FLAGS(tcp_hdr) (((uint8 *)(tcp_hdr))[TCP_FLAGS_OFFSET]) +#define TCP_IS_ACK(tcp_hdr) (TCP_FLAGS(tcp_hdr) & TCP_FLAGS_ACK) + +#define TCP_SRC_PORT(tcp_hdr) (ntoh16(((struct bcmtcp_hdr*)(tcp_hdr))->src_port)) +#define TCP_DST_PORT(tcp_hdr) (ntoh16(((struct bcmtcp_hdr*)(tcp_hdr))->dst_port)) +#define TCP_SEQ_NUM(tcp_hdr) (ntoh32(((struct bcmtcp_hdr*)(tcp_hdr))->seq_num)) +#define TCP_ACK_NUM(tcp_hdr) (ntoh32(((struct bcmtcp_hdr*)(tcp_hdr))->ack_num)) + +#endif /* #ifndef _bcmtcp_h_ */ diff --git a/package/broadcom-57xx/src/proto/bcmudp.h b/package/broadcom-57xx/src/proto/bcmudp.h new file mode 100644 index 0000000000..782f12e219 --- /dev/null +++ b/package/broadcom-57xx/src/proto/bcmudp.h @@ -0,0 +1,48 @@ +/* + * Copyright 2007, Broadcom Corporation + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation; + * the contents of this file may not be disclosed to third parties, copied + * or duplicated in any form, in whole or in part, without the prior + * written permission of Broadcom Corporation. + * + * Fundamental constants relating to UDP Protocol + * + * $Id: bcmudp.h,v 1.1.1.1 2007/05/31 08:00:41 michael Exp $ + */ + +#ifndef _bcmudp_h_ +#define _bcmudp_h_ + +/* enable structure packing */ +#if defined(__GNUC__) +#define PACKED __attribute__((packed)) +#else +#pragma pack(1) +#define PACKED +#endif + +/* UDP header */ +#define UDP_DEST_PORT_OFFSET 2 /* UDP dest port offset */ +#define UDP_LEN_OFFSET 4 /* UDP length offset */ +#define UDP_CHKSUM_OFFSET 6 /* UDP body checksum offset */ + +#define UDP_HDR_LEN 8 /* UDP header length */ +#define UDP_PORT_LEN 2 /* UDP port length */ + +/* These fields are stored in network order */ +struct bcmudp_hdr +{ + uint16 src_port; /* Source Port Address */ + uint16 dst_port; /* Destination Port Address */ + uint16 len; /* Number of bytes in datagram including header */ + uint16 chksum; /* entire datagram checksum with pseudoheader */ +} PACKED; + +#undef PACKED +#if !defined(__GNUC__) +#pragma pack() +#endif + +#endif /* #ifndef _bcmudp_h_ */ diff --git a/package/broadcom-57xx/src/proto/eap.h b/package/broadcom-57xx/src/proto/eap.h new file mode 100644 index 0000000000..36ed138769 --- /dev/null +++ b/package/broadcom-57xx/src/proto/eap.h @@ -0,0 +1,45 @@ +/* + * Extensible Authentication Protocol (EAP) definitions + * + * See + * RFC 2284: PPP Extensible Authentication Protocol (EAP) + * + * Copyright (C) 2002 Broadcom Corporation + * + * $Id: eap.h,v 1.2 2007/04/17 08:52:47 yogo Exp $ + */ + +#ifndef _eap_h_ +#define _eap_h_ + +/* EAP packet format */ +typedef struct { + unsigned char code; /* EAP code */ + unsigned char id; /* Current request ID */ + unsigned short length; /* Length including header */ + unsigned char type; /* EAP type (optional) */ + unsigned char data[1]; /* Type data (optional) */ +} eap_header_t; + +#define EAP_HEADER_LEN 4 + +/* EAP codes */ +#define EAP_REQUEST 1 +#define EAP_RESPONSE 2 +#define EAP_SUCCESS 3 +#define EAP_FAILURE 4 + +/* EAP types */ +#define EAP_IDENTITY 1 +#define EAP_NOTIFICATION 2 +#define EAP_NAK 3 +#define EAP_MD5 4 +#define EAP_OTP 5 +#define EAP_GTC 6 +#define EAP_TLS 13 +#define EAP_EXPANDED 254 +#define BCM_EAP_SES 10 +#define BCM_EAP_EXP_LEN 12 /* EAP_LEN 5 + 3 bytes for SMI ID + 4 bytes for ven type */ +#define BCM_SMI_ID 0x113d + +#endif /* _eap_h_ */ diff --git a/package/broadcom-57xx/src/proto/eapol.h b/package/broadcom-57xx/src/proto/eapol.h new file mode 100644 index 0000000000..36bbe8155c --- /dev/null +++ b/package/broadcom-57xx/src/proto/eapol.h @@ -0,0 +1,179 @@ +/* + * 802.1x EAPOL definitions + * + * See + * IEEE Std 802.1X-2001 + * IEEE 802.1X RADIUS Usage Guidelines + * + * Copyright (C) 2002 Broadcom Corporation + * + * eapol.h,v 9.17 2004/12/13 22:36:09 davidm Exp + */ + +#ifndef _eapol_h_ +#define _eapol_h_ + +/* enable structure packing */ +#if defined(__GNUC__) +#define PACKED __attribute__((packed)) +#else +#pragma pack(1) +#define PACKED +#endif + +#include + +/* EAPOL for 802.3/Ethernet */ +typedef struct { + struct ether_header eth; /* 802.3/Ethernet header */ + unsigned char version; /* EAPOL protocol version */ + unsigned char type; /* EAPOL type */ + unsigned short length; /* Length of body */ + unsigned char body[1]; /* Body (optional) */ +} eapol_header_t; + +#define EAPOL_HEADER_LEN 18 + +/* EAPOL version */ +#define WPA2_EAPOL_VERSION 2 +#define WPA_EAPOL_VERSION 1 +#define LEAP_EAPOL_VERSION 1 +#define SES_EAPOL_VERSION 1 + +/* EAPOL types */ +#define EAP_PACKET 0 +#define EAPOL_START 1 +#define EAPOL_LOGOFF 2 +#define EAPOL_KEY 3 +#define EAPOL_ASF 4 + +/* EAPOL-Key types */ +#define EAPOL_RC4_KEY 1 +#ifdef BCMWPA2 +#define EAPOL_WPA2_KEY 2 /* 802.11i/WPA2 */ +#endif +#define EAPOL_WPA_KEY 254 /* WPA */ + +/* RC4 EAPOL-Key header field sizes */ +#define EAPOL_KEY_REPLAY_LEN 8 +#define EAPOL_KEY_IV_LEN 16 +#define EAPOL_KEY_SIG_LEN 16 + +/* RC4 EAPOL-Key */ +typedef struct { + unsigned char type; /* Key Descriptor Type */ + unsigned short length; /* Key Length (unaligned) */ + unsigned char replay[EAPOL_KEY_REPLAY_LEN]; /* Replay Counter */ + unsigned char iv[EAPOL_KEY_IV_LEN]; /* Key IV */ + unsigned char index; /* Key Flags & Index */ + unsigned char signature[EAPOL_KEY_SIG_LEN]; /* Key Signature */ + unsigned char key[1]; /* Key (optional) */ +} PACKED eapol_key_header_t; + +#define EAPOL_KEY_HEADER_LEN 44 + +/* RC4 EAPOL-Key flags */ +#define EAPOL_KEY_FLAGS_MASK 0x80 +#define EAPOL_KEY_BROADCAST 0 +#define EAPOL_KEY_UNICAST 0x80 + +/* RC4 EAPOL-Key index */ +#define EAPOL_KEY_INDEX_MASK 0x7f + +/* WPA/802.11i/WPA2 EAPOL-Key header field sizes */ +#define EAPOL_WPA_KEY_REPLAY_LEN 8 +#define EAPOL_WPA_KEY_NONCE_LEN 32 +#define EAPOL_WPA_KEY_IV_LEN 16 +#define EAPOL_WPA_KEY_RSC_LEN 8 +#define EAPOL_WPA_KEY_ID_LEN 8 +#define EAPOL_WPA_KEY_MIC_LEN 16 +#define EAPOL_WPA_KEY_DATA_LEN (EAPOL_WPA_MAX_KEY_SIZE + AKW_BLOCK_LEN) +#define EAPOL_WPA_MAX_KEY_SIZE 32 + +/* WPA EAPOL-Key */ +typedef struct { + unsigned char type; /* Key Descriptor Type */ + unsigned short key_info; /* Key Information (unaligned) */ + unsigned short key_len; /* Key Length (unaligned) */ + unsigned char replay[EAPOL_WPA_KEY_REPLAY_LEN]; /* Replay Counter */ + unsigned char nonce[EAPOL_WPA_KEY_NONCE_LEN]; /* Nonce */ + unsigned char iv[EAPOL_WPA_KEY_IV_LEN]; /* Key IV */ + unsigned char rsc[EAPOL_WPA_KEY_RSC_LEN]; /* Key RSC */ + unsigned char id[EAPOL_WPA_KEY_ID_LEN]; /* WPA:Key ID, 802.11i/WPA2: Reserved */ + unsigned char mic[EAPOL_WPA_KEY_MIC_LEN]; /* Key MIC */ + unsigned short data_len; /* Key Data Length */ + unsigned char data[EAPOL_WPA_KEY_DATA_LEN]; /* Key data */ +} PACKED eapol_wpa_key_header_t; + +#define EAPOL_WPA_KEY_LEN 95 + +/* WPA/802.11i/WPA2 KEY KEY_INFO bits */ +#define WPA_KEY_DESC_V1 0x01 +#define WPA_KEY_DESC_V2 0x02 +#define WPA_KEY_PAIRWISE 0x08 +#define WPA_KEY_INSTALL 0x40 +#define WPA_KEY_ACK 0x80 +#define WPA_KEY_MIC 0x100 +#define WPA_KEY_SECURE 0x200 +#define WPA_KEY_ERROR 0x400 +#define WPA_KEY_REQ 0x800 + +/* WPA-only KEY KEY_INFO bits */ +#define WPA_KEY_INDEX_0 0x00 +#define WPA_KEY_INDEX_1 0x10 +#define WPA_KEY_INDEX_2 0x20 +#define WPA_KEY_INDEX_3 0x30 +#define WPA_KEY_INDEX_MASK 0x30 +#define WPA_KEY_INDEX_SHIFT 0x04 + +#ifdef BCMWPA2 +/* 802.11i/WPA2-only KEY KEY_INFO bits */ +#define WPA_KEY_ENCRYPTED_DATA 0x1000 + +/* Key Data encapsulation */ +typedef struct { + uint8 type; + uint8 length; + uint8 oui[3]; + uint8 subtype; + uint8 data[1]; +} PACKED eapol_wpa2_encap_data_t; + +#define EAPOL_WPA2_ENCAP_DATA_HDR_LEN 6 + +#define WPA2_KEY_DATA_SUBTYPE_GTK 1 +#define WPA2_KEY_DATA_SUBTYPE_STAKEY 2 +#define WPA2_KEY_DATA_SUBTYPE_MAC 3 +#define WPA2_KEY_DATA_SUBTYPE_PMKID 4 + +/* GTK encapsulation */ +typedef struct { + uint8 flags; + uint8 reserved; + uint8 gtk[EAPOL_WPA_MAX_KEY_SIZE]; +} PACKED eapol_wpa2_key_gtk_encap_t; + +#define EAPOL_WPA2_KEY_GTK_ENCAP_HDR_LEN 2 + +#define WPA2_GTK_INDEX_MASK 0x03 +#define WPA2_GTK_INDEX_SHIFT 0x00 + +#define WPA2_GTK_TRANSMIT 0x04 + +/* STAKey encapsulation */ +typedef struct { + uint8 reserved[2]; + uint8 mac[ETHER_ADDR_LEN]; + uint8 stakey[EAPOL_WPA_MAX_KEY_SIZE]; +} PACKED eapol_wpa2_key_stakey_encap_t; + +#define WPA2_KEY_DATA_PAD 0xdd + +#endif /* BCMWPA2 */ + +#undef PACKED +#if !defined(__GNUC__) +#pragma pack() +#endif + +#endif /* _eapol_h_ */ diff --git a/package/broadcom-57xx/src/proto/ethernet.h b/package/broadcom-57xx/src/proto/ethernet.h new file mode 100644 index 0000000000..63430be5e2 --- /dev/null +++ b/package/broadcom-57xx/src/proto/ethernet.h @@ -0,0 +1,173 @@ +/* + * From FreeBSD 2.2.7: Fundamental constants relating to ethernet. + * + * Copyright 2007, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * + * $Id: ethernet.h,v 1.1.1.16 2007/05/31 08:00:41 michael Exp $ + */ + +#ifndef _NET_ETHERNET_H_ /* use native BSD ethernet.h when available */ +#define _NET_ETHERNET_H_ + +#ifndef _TYPEDEFS_H_ +#include "typedefs.h" +#endif + +/* enable structure packing */ +#if defined(__GNUC__) +#define PACKED __attribute__((packed)) +#else +#pragma pack(1) +#define PACKED +#endif + +/* + * The number of bytes in an ethernet (MAC) address. + */ +#define ETHER_ADDR_LEN 6 + +/* + * The number of bytes in the type field. + */ +#define ETHER_TYPE_LEN 2 + +/* + * The number of bytes in the trailing CRC field. + */ +#define ETHER_CRC_LEN 4 + +/* + * The length of the combined header. + */ +#define ETHER_HDR_LEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN) + +/* + * The minimum packet length. + */ +#define ETHER_MIN_LEN 64 + +/* + * The minimum packet user data length. + */ +#define ETHER_MIN_DATA 46 + +/* + * The maximum packet length. + */ +#define ETHER_MAX_LEN 1518 + +/* + * The maximum packet user data length. + */ +#define ETHER_MAX_DATA 1500 + +/* ether types */ +#define ETHER_TYPE_MIN 0x0600 /* Anything less than MIN is a length */ +#define ETHER_TYPE_IP 0x0800 /* IP */ +#define ETHER_TYPE_ARP 0x0806 /* ARP */ +#define ETHER_TYPE_8021Q 0x8100 /* 802.1Q */ +#define ETHER_TYPE_BRCM 0x886c /* Broadcom Corp. */ +#define ETHER_TYPE_802_1X 0x888e /* 802.1x */ +#ifdef BCMWPA2 +#define ETHER_TYPE_802_1X_PREAUTH 0x88c7 /* 802.1x preauthentication */ +#endif + +/* Broadcom subtype follows ethertype; First 2 bytes are reserved; Next 2 are subtype; */ +#define ETHER_BRCM_SUBTYPE_LEN 4 /* Broadcom 4 byte subtype */ +#define ETHER_BRCM_CRAM 0x1 /* Broadcom subtype cram protocol */ + +/* ether header */ +#define ETHER_DEST_OFFSET (0 * ETHER_ADDR_LEN) /* dest address offset */ +#define ETHER_SRC_OFFSET (1 * ETHER_ADDR_LEN) /* src address offset */ +#define ETHER_TYPE_OFFSET (2 * ETHER_ADDR_LEN) /* ether type offset */ + +/* + * A macro to validate a length with + */ +#define ETHER_IS_VALID_LEN(foo) \ + ((foo) >= ETHER_MIN_LEN && (foo) <= ETHER_MAX_LEN) + + +#ifndef __INCif_etherh /* Quick and ugly hack for VxWorks */ +/* + * Structure of a 10Mb/s Ethernet header. + */ +struct ether_header { + uint8 ether_dhost[ETHER_ADDR_LEN]; + uint8 ether_shost[ETHER_ADDR_LEN]; + uint16 ether_type; +} PACKED; + +/* + * Structure of a 48-bit Ethernet address. + */ +struct ether_addr { + uint8 octet[ETHER_ADDR_LEN]; +} PACKED; +#endif /* !__INCif_etherh Quick and ugly hack for VxWorks */ + +/* + * Takes a pointer, set, test, clear, toggle locally admininistered + * address bit in the 48-bit Ethernet address. + */ +#define ETHER_SET_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] | 2)) +#define ETHER_IS_LOCALADDR(ea) (((uint8 *)(ea))[0] & 2) +#define ETHER_CLR_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & 0xd)) +#define ETHER_TOGGLE_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] ^ 2)) + +/* Takes a pointer, marks unicast address bit in the MAC address */ +#define ETHER_SET_UNICAST(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & ~1)) + +/* + * Takes a pointer, returns true if a 48-bit multicast address + * (including broadcast, since it is all ones) + */ +#define ETHER_ISMULTI(ea) (((const uint8 *)(ea))[0] & 1) + + +/* compare two ethernet addresses - assumes the pointers can be referenced as shorts */ +#define ether_cmp(a, b) (!(((short*)a)[0] == ((short*)b)[0]) | \ + !(((short*)a)[1] == ((short*)b)[1]) | \ + !(((short*)a)[2] == ((short*)b)[2])) + +/* copy an ethernet address - assumes the pointers can be referenced as shorts */ +#define ether_copy(s, d) { \ + ((short*)d)[0] = ((short*)s)[0]; \ + ((short*)d)[1] = ((short*)s)[1]; \ + ((short*)d)[2] = ((short*)s)[2]; } + +/* + * Takes a pointer, returns true if a 48-bit broadcast (all ones) + */ +#define ETHER_ISBCAST(ea) ((((uint8 *)(ea))[0] & \ + ((uint8 *)(ea))[1] & \ + ((uint8 *)(ea))[2] & \ + ((uint8 *)(ea))[3] & \ + ((uint8 *)(ea))[4] & \ + ((uint8 *)(ea))[5]) == 0xff) + +static const struct ether_addr ether_bcast = {{255, 255, 255, 255, 255, 255}}; +static const struct ether_addr ether_null = {{0, 0, 0, 0, 0, 0}}; + +/* + * Takes a pointer, returns true if a 48-bit null address (all zeros) + */ +#define ETHER_ISNULLADDR(ea) ((((uint8 *)(ea))[0] | \ + ((uint8 *)(ea))[1] | \ + ((uint8 *)(ea))[2] | \ + ((uint8 *)(ea))[3] | \ + ((uint8 *)(ea))[4] | \ + ((uint8 *)(ea))[5]) == 0) + +#undef PACKED +#if !defined(__GNUC__) +#pragma pack() +#endif + +#endif /* _NET_ETHERNET_H_ */ diff --git a/package/broadcom-57xx/src/proto/vlan.h b/package/broadcom-57xx/src/proto/vlan.h new file mode 100644 index 0000000000..79cd5891e1 --- /dev/null +++ b/package/broadcom-57xx/src/proto/vlan.h @@ -0,0 +1,52 @@ +/* + * 802.1Q VLAN protocol definitions + * + * Copyright 2007, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * + * $Id: vlan.h,v 1.1.1.4 2007/05/31 08:00:41 michael Exp $ + */ + +#ifndef _vlan_h_ +#define _vlan_h_ + +/* enable structure packing */ +#if defined(__GNUC__) +#define PACKED __attribute__((packed)) +#else +#pragma pack(1) +#define PACKED +#endif + +#define VLAN_VID_MASK 0xfff /* low 12 bits are vlan id */ +#define VLAN_CFI_SHIFT 12 /* canonical format indicator bit */ +#define VLAN_PRI_SHIFT 13 /* user priority */ + +#define VLAN_PRI_MASK 7 /* 3 bits of priority */ + +#define VLAN_TAG_LEN 4 +#define VLAN_TAG_OFFSET (2 * ETHER_ADDR_LEN) /* offset in Ethernet II packet only */ + +#define VLAN_TPID 0x8100 /* VLAN ethertype/Tag Protocol ID */ + +struct ethervlan_header { + uint8 ether_dhost[ETHER_ADDR_LEN]; + uint8 ether_shost[ETHER_ADDR_LEN]; + uint16 vlan_type; /* 0x8100 */ + uint16 vlan_tag; /* priority, cfi and vid */ + uint16 ether_type; +}; + +#define ETHERVLAN_HDR_LEN (ETHER_HDR_LEN + VLAN_TAG_LEN) + +#undef PACKED +#if !defined(__GNUC__) +#pragma pack() +#endif + +#endif /* _vlan_h_ */ diff --git a/package/broadcom-57xx/src/proto/wpa.h b/package/broadcom-57xx/src/proto/wpa.h new file mode 100644 index 0000000000..9bb6752b8f --- /dev/null +++ b/package/broadcom-57xx/src/proto/wpa.h @@ -0,0 +1,158 @@ +/* + * Fundamental types and constants relating to WPA + * + * Copyright 2007, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * + * $Id: wpa.h,v 1.1.1.6 2007/05/31 08:00:41 michael Exp $ + */ + +#ifndef _proto_wpa_h_ +#define _proto_wpa_h_ + +#include +#include + +/* enable structure packing */ +#if defined(__GNUC__) +#define PACKED __attribute__((packed)) +#else +#pragma pack(1) +#define PACKED +#endif + +/* Reason Codes */ + +/* 13 through 23 taken from IEEE Std 802.11i-2004 */ +#define DOT11_RC_INVALID_WPA_IE 13 /* Invalid info. element */ +#define DOT11_RC_MIC_FAILURE 14 /* Michael failure */ +#define DOT11_RC_4WH_TIMEOUT 15 /* 4-way handshake timeout */ +#define DOT11_RC_GTK_UPDATE_TIMEOUT 16 /* Group key update timeout */ +#define DOT11_RC_WPA_IE_MISMATCH 17 /* WPA IE in 4-way handshake differs from + * (re-)assoc. request/probe response + */ +#define DOT11_RC_INVALID_MC_CIPHER 18 /* Invalid multicast cipher */ +#define DOT11_RC_INVALID_UC_CIPHER 19 /* Invalid unicast cipher */ +#define DOT11_RC_INVALID_AKMP 20 /* Invalid authenticated key management protocol */ +#define DOT11_RC_BAD_WPA_VERSION 21 /* Unsupported WPA version */ +#define DOT11_RC_INVALID_WPA_CAP 22 /* Invalid WPA IE capabilities */ +#define DOT11_RC_8021X_AUTH_FAIL 23 /* 802.1X authentication failure */ + +#define WPA2_PMKID_LEN 16 + +/* WPA IE fixed portion */ +typedef struct +{ + uint8 tag; /* TAG */ + uint8 length; /* TAG length */ + uint8 oui[3]; /* IE OUI */ + uint8 oui_type; /* OUI type */ + struct { + uint8 low; + uint8 high; + } PACKED version; /* IE version */ +} PACKED wpa_ie_fixed_t; +#define WPA_IE_OUITYPE_LEN 4 +#define WPA_IE_FIXED_LEN 8 +#define WPA_IE_TAG_FIXED_LEN 6 + +#ifdef BCMWPA2 +typedef struct { + uint8 tag; /* TAG */ + uint8 length; /* TAG length */ + struct { + uint8 low; + uint8 high; + } PACKED version; /* IE version */ +} PACKED wpa_rsn_ie_fixed_t; +#define WPA_RSN_IE_FIXED_LEN 4 +#define WPA_RSN_IE_TAG_FIXED_LEN 2 +typedef uint8 wpa_pmkid_t[WPA2_PMKID_LEN]; +#endif + +/* WPA suite/multicast suite */ +typedef struct +{ + uint8 oui[3]; + uint8 type; +} PACKED wpa_suite_t, wpa_suite_mcast_t; +#define WPA_SUITE_LEN 4 + +/* WPA unicast suite list/key management suite list */ +typedef struct +{ + struct { + uint8 low; + uint8 high; + } PACKED count; + wpa_suite_t list[1]; +} PACKED wpa_suite_ucast_t, wpa_suite_auth_key_mgmt_t; +#define WPA_IE_SUITE_COUNT_LEN 2 +#ifdef BCMWPA2 +typedef struct +{ + struct { + uint8 low; + uint8 high; + } PACKED count; + wpa_pmkid_t list[1]; +} PACKED wpa_pmkid_list_t; +#endif + +/* WPA cipher suites */ +#define WPA_CIPHER_NONE 0 /* None */ +#define WPA_CIPHER_WEP_40 1 /* WEP (40-bit) */ +#define WPA_CIPHER_TKIP 2 /* TKIP: default for WPA */ +#define WPA_CIPHER_AES_OCB 3 /* AES (OCB) */ +#define WPA_CIPHER_AES_CCM 4 /* AES (CCM) */ +#define WPA_CIPHER_WEP_104 5 /* WEP (104-bit) */ + +#define IS_WPA_CIPHER(cipher) ((cipher) == WPA_CIPHER_NONE || \ + (cipher) == WPA_CIPHER_WEP_40 || \ + (cipher) == WPA_CIPHER_WEP_104 || \ + (cipher) == WPA_CIPHER_TKIP || \ + (cipher) == WPA_CIPHER_AES_OCB || \ + (cipher) == WPA_CIPHER_AES_CCM) + +/* WPA TKIP countermeasures parameters */ +#define WPA_TKIP_CM_DETECT 60 /* multiple MIC failure window (seconds) */ +#define WPA_TKIP_CM_BLOCK 60 /* countermeasures active window (seconds) */ + +/* RSN IE defines */ +#define RSN_CAP_LEN 2 /* Length of RSN capabilities field (2 octets) */ + +/* RSN Capabilities defined in 802.11i */ +#define RSN_CAP_PREAUTH 0x0001 +#define RSN_CAP_NOPAIRWISE 0x0002 +#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C +#define RSN_CAP_PTK_REPLAY_CNTR_SHIFT 2 +#define RSN_CAP_GTK_REPLAY_CNTR_MASK 0x0030 +#define RSN_CAP_GTK_REPLAY_CNTR_SHIFT 4 +#define RSN_CAP_1_REPLAY_CNTR 0 +#define RSN_CAP_2_REPLAY_CNTRS 1 +#define RSN_CAP_4_REPLAY_CNTRS 2 +#define RSN_CAP_16_REPLAY_CNTRS 3 + +/* WPA capabilities defined in 802.11i */ +#define WPA_CAP_4_REPLAY_CNTRS RSN_CAP_4_REPLAY_CNTRS +#define WPA_CAP_16_REPLAY_CNTRS RSN_CAP_16_REPLAY_CNTRS +#define WPA_CAP_REPLAY_CNTR_SHIFT RSN_CAP_PTK_REPLAY_CNTR_SHIFT +#define WPA_CAP_REPLAY_CNTR_MASK RSN_CAP_PTK_REPLAY_CNTR_MASK + +/* WPA Specific defines */ +#define WPA_CAP_LEN RSN_CAP_LEN /* Length of RSN capabilities in RSN IE (2 octets) */ + +#define WPA_CAP_WPA2_PREAUTH RSN_CAP_PREAUTH + + +#undef PACKED +#if !defined(__GNUC__) +#pragma pack() +#endif + +#endif /* _proto_wpa_h_ */ diff --git a/package/broadcom-57xx/src/queue.h b/package/broadcom-57xx/src/queue.h new file mode 100644 index 0000000000..c73be5e881 --- /dev/null +++ b/package/broadcom-57xx/src/queue.h @@ -0,0 +1,347 @@ +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 - 2004 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* Queue functions. */ +/* void QQ_InitQueue(PQQ_CONTAINER pQueue) */ +/* char QQ_Full(PQQ_CONTAINER pQueue) */ +/* char QQ_Empty(PQQ_CONTAINER pQueue) */ +/* unsigned int QQ_GetSize(PQQ_CONTAINER pQueue) */ +/* unsigned int QQ_GetEntryCnt(PQQ_CONTAINER pQueue) */ +/* char QQ_PushHead(PQQ_CONTAINER pQueue, PQQ_ENTRY pEntry) */ +/* char QQ_PushTail(PQQ_CONTAINER pQueue, PQQ_ENTRY pEntry) */ +/* PQQ_ENTRY QQ_PopHead(PQQ_CONTAINER pQueue) */ +/* PQQ_ENTRY QQ_PopTail(PQQ_CONTAINER pQueue) */ +/* PQQ_ENTRY QQ_GetHead(PQQ_CONTAINER pQueue, unsigned int Idx) */ +/* PQQ_ENTRY QQ_GetTail(PQQ_CONTAINER pQueue, unsigned int Idx) */ +/* */ +/* */ +/* History: */ +/* 02/25/00 Hav Khauv Initial version. */ +/******************************************************************************/ + +#ifndef BCM_QUEUE_H +#define BCM_QUEUE_H + + + +/******************************************************************************/ +/* Queue definitions. */ +/******************************************************************************/ + +/* Entry for queueing. */ +typedef void *PQQ_ENTRY; + + +/* Queue header -- base type. */ +typedef struct { + unsigned int Head; + unsigned int Tail; + unsigned int Size; + MM_ATOMIC_T EntryCnt; + PQQ_ENTRY Array[1]; +} QQ_CONTAINER, *PQQ_CONTAINER; + + +/* Declare queue type macro. */ +#define DECLARE_QUEUE_TYPE(_QUEUE_TYPE, _QUEUE_SIZE) \ + \ + typedef struct { \ + QQ_CONTAINER Container; \ + PQQ_ENTRY EntryBuffer[_QUEUE_SIZE]; \ + } _QUEUE_TYPE, *P##_QUEUE_TYPE + + + +/******************************************************************************/ +/* Compilation switches. */ +/******************************************************************************/ + +#if DBG +#undef QQ_NO_OVERFLOW_CHECK +#undef QQ_NO_UNDERFLOW_CHECK +#endif /* DBG */ + +#ifdef QQ_USE_MACROS +/* notdone */ +#else + +#ifdef QQ_NO_INLINE +#define __inline +#endif /* QQ_NO_INLINE */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +__inline static void +QQ_InitQueue( +PQQ_CONTAINER pQueue, +unsigned int QueueSize) { + pQueue->Head = 0; + pQueue->Tail = 0; + pQueue->Size = QueueSize+1; + MM_ATOMIC_SET(&pQueue->EntryCnt, 0); +} /* QQ_InitQueue */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +__inline static char +QQ_Full( +PQQ_CONTAINER pQueue) { + unsigned int NewHead; + + NewHead = (pQueue->Head + 1) % pQueue->Size; + + return(NewHead == pQueue->Tail); +} /* QQ_Full */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +__inline static char +QQ_Empty( +PQQ_CONTAINER pQueue) { + return(pQueue->Head == pQueue->Tail); +} /* QQ_Empty */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +__inline static unsigned int +QQ_GetSize( +PQQ_CONTAINER pQueue) { + return pQueue->Size; +} /* QQ_GetSize */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +__inline static unsigned int +QQ_GetEntryCnt( +PQQ_CONTAINER pQueue) { + return MM_ATOMIC_READ(&pQueue->EntryCnt); +} /* QQ_GetEntryCnt */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/* TRUE entry was added successfully. */ +/* FALSE queue is full. */ +/******************************************************************************/ +__inline static char +QQ_PushHead( +PQQ_CONTAINER pQueue, +PQQ_ENTRY pEntry) { + unsigned int Head; + + Head = (pQueue->Head + 1) % pQueue->Size; + +#if !defined(QQ_NO_OVERFLOW_CHECK) + if(Head == pQueue->Tail) { + return 0; + } /* if */ +#endif /* QQ_NO_OVERFLOW_CHECK */ + + pQueue->Array[pQueue->Head] = pEntry; + MM_WMB(); + pQueue->Head = Head; + MM_ATOMIC_INC(&pQueue->EntryCnt); + + return -1; +} /* QQ_PushHead */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/* TRUE entry was added successfully. */ +/* FALSE queue is full. */ +/******************************************************************************/ +__inline static char +QQ_PushTail( +PQQ_CONTAINER pQueue, +PQQ_ENTRY pEntry) { + unsigned int Tail; + + Tail = pQueue->Tail; + if(Tail == 0) { + Tail = pQueue->Size; + } /* if */ + Tail--; + +#if !defined(QQ_NO_OVERFLOW_CHECK) + if(Tail == pQueue->Head) { + return 0; + } /* if */ +#endif /* QQ_NO_OVERFLOW_CHECK */ + + pQueue->Array[Tail] = pEntry; + MM_WMB(); + pQueue->Tail = Tail; + MM_ATOMIC_INC(&pQueue->EntryCnt); + + return -1; +} /* QQ_PushTail */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +__inline static PQQ_ENTRY +QQ_PopHead( +PQQ_CONTAINER pQueue) { + unsigned int Head; + unsigned int Tail; + PQQ_ENTRY Entry; + + Head = pQueue->Head; + Tail = pQueue->Tail; + + MM_MB(); +#if !defined(QQ_NO_UNDERFLOW_CHECK) + if(Head == Tail) { + return (PQQ_ENTRY) 0; + } /* if */ +#endif /* QQ_NO_UNDERFLOW_CHECK */ + + if(Head == 0) { + Head = pQueue->Size; + } /* if */ + Head--; + + Entry = pQueue->Array[Head]; + MM_MB(); + pQueue->Head = Head; + MM_ATOMIC_DEC(&pQueue->EntryCnt); + + return Entry; +} /* QQ_PopHead */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +__inline static PQQ_ENTRY +QQ_PopTail( +PQQ_CONTAINER pQueue) { + unsigned int Head; + unsigned int Tail; + PQQ_ENTRY Entry; + + Head = pQueue->Head; + Tail = pQueue->Tail; + + MM_MB(); +#if !defined(QQ_NO_UNDERFLOW_CHECK) + if(Tail == Head) { + return (PQQ_ENTRY) 0; + } /* if */ +#endif /* QQ_NO_UNDERFLOW_CHECK */ + + Entry = pQueue->Array[Tail]; + MM_MB(); + pQueue->Tail = (Tail + 1) % pQueue->Size; + MM_ATOMIC_DEC(&pQueue->EntryCnt); + + return Entry; +} /* QQ_PopTail */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +__inline static PQQ_ENTRY +QQ_GetHead( + PQQ_CONTAINER pQueue, + unsigned int Idx) +{ + if(Idx >= (unsigned int) MM_ATOMIC_READ(&pQueue->EntryCnt)) + { + return (PQQ_ENTRY) 0; + } + + if(pQueue->Head > Idx) + { + Idx = pQueue->Head - Idx; + } + else + { + Idx = pQueue->Size - (Idx - pQueue->Head); + } + Idx--; + + return pQueue->Array[Idx]; +} + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +__inline static PQQ_ENTRY +QQ_GetTail( + PQQ_CONTAINER pQueue, + unsigned int Idx) +{ + if(Idx >= (unsigned int) MM_ATOMIC_READ(&pQueue->EntryCnt)) + { + return (PQQ_ENTRY) 0; + } + + Idx += pQueue->Tail; + if(Idx >= pQueue->Size) + { + Idx = Idx - pQueue->Size; + } + + return pQueue->Array[Idx]; +} + +#endif /* QQ_USE_MACROS */ + + + +#endif /* QUEUE_H */ diff --git a/package/broadcom-57xx/src/robo_register.c b/package/broadcom-57xx/src/robo_register.c new file mode 100644 index 0000000000..acd385e0bf --- /dev/null +++ b/package/broadcom-57xx/src/robo_register.c @@ -0,0 +1,111 @@ + +#if 1 +#define DEBUG_REG printk +#else +#define DEBUG_REG +#endif + +void ReadDataFromRegister(robo_info_t *robo, uint16 page_num,uint16 addr_num, uint16 len, void* data) +{ + + uint32 val32 = 0,val64[2]; + uint16 val16 =0,val48[3];//,val32[2],val64[4]; + memset(val48,0,6); + memset(val64,0,8); + //memset(val32,0,4); + DEBUG_REG("Read ioctl Page[0x%02x] Addr[0x%02x] len[%d].\n", page_num, addr_num, len); + switch (len) + { + case 1: + case 2: + { + robo->ops->read_reg(robo, page_num, addr_num, &val16, len); + DEBUG_REG("IRead 8/16 bit Page[0x%02x]addr[0x%02x]len[%d]val[0x%04x].\n", + page_num, addr_num, len, val16); + memcpy(data,&val16,2); + break; + } + case 4: + { + robo->ops->read_reg(robo, page_num, addr_num, &val32, len); + DEBUG_REG("IRead 32bit Page[0x%02x]addr[0x%02x]len[%d]val[0x%08x].\n", + page_num, addr_num, len, val32); + memcpy(data,&val32,4); + break; + } + case 6: + { + robo->ops->read_reg(robo, page_num,addr_num, &val48, len); + DEBUG_REG("IRead 48bit Page[0x%02x]addr[0x%02x]len[%d]val[0x%04x-0x%04x-0x%04x].\n", + page_num, addr_num, len, val48[0], val48[1], val48[2]); + memcpy(data,&val48,6); + break; + } + case 8: + { + robo->ops->read_reg(robo, page_num, addr_num, &val64, len); + DEBUG_REG("IRead 64bit Page[0x%02x]addr[0x%02x]len[%d]val[0x%08x-0x%08x].\n", + page_num, addr_num, len, val64[0], val64[1]); + memcpy(data,&val64,8); + break; + } + } +} + + + +void WriteDataToRegister(robo_info_t *robo,uint16 page_num,uint16 addr_num, uint16 len, void* data) +{ + DEBUG_REG("Write ioctl Page[0x%02x]Addr[0x%02x]len[%d].\n",page_num,addr_num,len); + switch (len) + { + case 1: + case 2: + { + DEBUG_REG("Write 2byte Page[0x%02x]addr[0x%02x]len[%d]val[0x%04x].\n", + page_num, addr_num, len, *((uint16 *)data)); + robo->ops->write_reg(robo, page_num, addr_num, data, len); + if (page_num < 0x10 || page_num > 0x17) { + robo->ops->read_reg(robo, page_num, addr_num, data, len); + DEBUG_REG("Reload Page[0x%02x]addr[0x%02x]len[%d]val[0x%04x].\n", + page_num, addr_num, len, *((uint16 *)data)); + } + break; + } + case 4: + { + DEBUG_REG("Write 4byte Page[0x%02x]addr[0x%02x]len[%d]val[0x%08x].\n", + page_num, addr_num, len, *((uint32 *)data)); + robo->ops->write_reg(robo, page_num, addr_num, data, len); + if (page_num < 0x10 || page_num > 0x17) { + robo->ops->read_reg(robo, page_num, addr_num, data, len); + DEBUG_REG("Reload Page[0x%02x]addr[0x%02x]len[%d]val[0x%08x].\n", + page_num, addr_num, len, *((uint32 *)data)); + } + break; + } + case 6: + { + DEBUG_REG("Write 6byte Page[0x%02x]addr[0x%02x]len[%d]val[0x%04x-0x%04x-0x%04x].\n", + page_num, addr_num, len, *((uint16 *)data),*((((uint16 *)data)+1)), + *(((uint16 *)data)+2)); + robo->ops->write_reg(robo, page_num, addr_num, data, len); + robo->ops->read_reg(robo, page_num, addr_num, data, len); + DEBUG_REG("Reload Page[0x%02x]addr[0x%02x]len[%d]val[0x%04x-0x%04x-0x%04x].\n", + page_num, addr_num, len,*((uint16 *)data),*((((uint16 *)data)+1)), + *(((uint16 *)data)+2)); + break; + } + case 8: + { + DEBUG_REG("Write 8byte Page[0x%02x]addr[0x%02x]len[%d]val[0x%08x-0x%08x].\n", + page_num, addr_num, len, *((uint32*)data),*(((uint32 *)data)+1)); + robo->ops->write_reg(robo, page_num, addr_num, data, len); + robo->ops->read_reg(robo, page_num, addr_num, data, len); + DEBUG_REG("Reload Page[0x%x]addr[0x%x]len[%d]val[0x%08x-0x%08x].\n", + page_num, addr_num, len,*((uint32 *)data), *(((uint32 *)data)+1)); + break; + } + } +} + diff --git a/package/broadcom-57xx/src/sbgige.h b/package/broadcom-57xx/src/sbgige.h new file mode 100644 index 0000000000..7975a7ac7e --- /dev/null +++ b/package/broadcom-57xx/src/sbgige.h @@ -0,0 +1,59 @@ +/* + * HND SiliconBackplane Gigabit Ethernet core registers + * + * Copyright 2007, Broadcom Corporation + * All Rights Reserved. + * + * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. + * + * $Id: sbgige.h,v 1.5 2007/06/01 05:58:20 michael Exp $ + */ + +#ifndef _sbgige_h_ +#define _sbgige_h_ + +#include +#include +#include + +/* cpp contortions to concatenate w/arg prescan */ +#ifndef PAD +#define _PADLINE(line) pad ## line +#define _XSTR(line) _PADLINE(line) +#define PAD _XSTR(__LINE__) +#endif /* PAD */ + +/* PCI to OCP shim registers */ +typedef volatile struct { + uint32 FlushStatusControl; + uint32 FlushReadAddr; + uint32 FlushTimeoutCntr; + uint32 BarrierReg; + uint32 MaocpSIControl; + uint32 SiocpMaControl; + uint8 PAD[0x02E8]; +} sbgige_pcishim_t; + +/* SB core registers */ +typedef volatile struct { + /* PCI I/O Read/Write registers */ + uint8 pciio[0x0400]; + + /* Reserved */ + uint8 reserved[0x0400]; + + /* PCI configuration registers */ + pci_config_regs pcicfg; + uint8 PAD[0x0300]; + + /* PCI to OCP shim registers */ + sbgige_pcishim_t pcishim; + + /* Sonics SiliconBackplane registers */ + sbconfig_t sbconfig; +} sbgige_t; + +#endif /* _sbgige_h_ */ diff --git a/package/broadcom-57xx/src/tcp_seg.c b/package/broadcom-57xx/src/tcp_seg.c new file mode 100644 index 0000000000..5a7c8f14a4 --- /dev/null +++ b/package/broadcom-57xx/src/tcp_seg.c @@ -0,0 +1,106 @@ +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2002 - 2004 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* History: */ +/* */ +/******************************************************************************/ + +#include "mm.h" + +#ifdef INCLUDE_TCP_SEG_SUPPORT +#include "fw_stkoffld.h" +#include "fw_lso05.h" + +LM_UINT32 LM_GetStkOffLdFirmwareSize(PLM_DEVICE_BLOCK pDevice) +{ + LM_UINT32 FwSize; + + if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5750) + { + return 0; + } + if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5705) + { + FwSize = (LM_UINT32)(t3StkOffLd05FwTextLen + + t3StkOffLd05FwRodataLen + + t3StkOffLd05FwDataLen + + t3StkOffLd05FwSbssLen + + t3StkOffLd05FwBssLen); + } + else + { + FwSize = (LM_UINT32)(t3StkOffLdFwTextLen + + t3StkOffLdFwRodataLen + + t3StkOffLdFwDataLen + + t3StkOffLdFwSbssLen + + t3StkOffLdFwBssLen); + } + + return FwSize; +} + +LM_STATUS LM_LoadStkOffLdFirmware(PLM_DEVICE_BLOCK pDevice) +{ + T3_FWIMG_INFO FwImgInfo; + LM_UINT32 Cpu; + + if (T3_ASIC_IS_575X_PLUS(pDevice->ChipRevId)) + { + return LM_STATUS_SUCCESS; + } + if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5705) + { + FwImgInfo.StartAddress = t3StkOffLd05FwStartAddr; + FwImgInfo.Text.Buffer = (PLM_UINT8)t3StkOffLd05FwText; + FwImgInfo.Text.Offset = t3StkOffLd05FwTextAddr; + FwImgInfo.Text.Length = t3StkOffLd05FwTextLen; + FwImgInfo.ROnlyData.Buffer = (PLM_UINT8)t3StkOffLd05FwRodata; + FwImgInfo.ROnlyData.Offset = t3StkOffLd05FwRodataAddr; + FwImgInfo.ROnlyData.Length = t3StkOffLd05FwRodataLen; + FwImgInfo.Data.Buffer = (PLM_UINT8)t3StkOffLd05FwData; + FwImgInfo.Data.Offset = t3StkOffLd05FwDataAddr; + FwImgInfo.Data.Length = t3StkOffLd05FwDataLen; + FwImgInfo.Sbss.Offset = t3StkOffLd05FwSbssAddr; + FwImgInfo.Sbss.Length = t3StkOffLd05FwSbssLen; + FwImgInfo.Bss.Offset = t3StkOffLd05FwBssAddr; + FwImgInfo.Bss.Length = t3StkOffLd05FwBssLen; + Cpu = T3_RX_CPU_ID; + } + else + { + FwImgInfo.StartAddress = t3StkOffLdFwStartAddr; + FwImgInfo.Text.Buffer = (PLM_UINT8)t3StkOffLdFwText; + FwImgInfo.Text.Offset = t3StkOffLdFwTextAddr; + FwImgInfo.Text.Length = t3StkOffLdFwTextLen; + FwImgInfo.ROnlyData.Buffer = (PLM_UINT8)t3StkOffLdFwRodata; + FwImgInfo.ROnlyData.Offset = t3StkOffLdFwRodataAddr; + FwImgInfo.ROnlyData.Length = t3StkOffLdFwRodataLen; + FwImgInfo.Data.Buffer = (PLM_UINT8)t3StkOffLdFwData; + FwImgInfo.Data.Offset = t3StkOffLdFwDataAddr; + FwImgInfo.Data.Length = t3StkOffLdFwDataLen; + FwImgInfo.Sbss.Offset = t3StkOffLdFwSbssAddr; + FwImgInfo.Sbss.Length = t3StkOffLdFwSbssLen; + FwImgInfo.Bss.Offset = t3StkOffLdFwBssAddr; + FwImgInfo.Bss.Length = t3StkOffLdFwBssLen; + Cpu = T3_TX_CPU_ID; + } + + if (LM_LoadFirmware(pDevice, + &FwImgInfo, + Cpu, + Cpu) != LM_STATUS_SUCCESS) + { + return LM_STATUS_FAILURE; + } + + return LM_STATUS_SUCCESS; +} + +#endif /* INCLUDE_TCP_SEG_SUPPORT */ diff --git a/package/broadcom-57xx/src/tigon3.c b/package/broadcom-57xx/src/tigon3.c new file mode 100644 index 0000000000..159a0a7f56 --- /dev/null +++ b/package/broadcom-57xx/src/tigon3.c @@ -0,0 +1,9736 @@ +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 - 2005 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* History: */ +/******************************************************************************/ + +/* $Id: tigon3.c,v 1.10 2007/06/01 05:58:19 michael Exp $ */ + +#include "mm.h" +#include "typedefs.h" +#include "osl.h" +#include "bcmdefs.h" +#include "bcmdevs.h" +#include "sbutils.h" +#include "bcmrobo.h" +#include "proto/ethernet.h" + +/******************************************************************************/ +/* Local functions. */ +/******************************************************************************/ + +LM_STATUS LM_Abort(PLM_DEVICE_BLOCK pDevice); +LM_STATUS LM_QueueRxPackets(PLM_DEVICE_BLOCK pDevice); + +static LM_STATUS LM_InitBcm540xPhy(PLM_DEVICE_BLOCK pDevice); +static LM_VOID LM_PhyTapPowerMgmt(LM_DEVICE_BLOCK *pDevice); + +LM_VOID LM_ServiceRxInterrupt(PLM_DEVICE_BLOCK pDevice); +LM_VOID LM_ServiceTxInterrupt(PLM_DEVICE_BLOCK pDevice); + +static LM_STATUS LM_ForceAutoNeg(PLM_DEVICE_BLOCK pDevice); +static LM_UINT32 GetPhyAdFlowCntrlSettings(PLM_DEVICE_BLOCK pDevice); +STATIC LM_STATUS LM_SetFlowControl(PLM_DEVICE_BLOCK pDevice, + LM_UINT32 LocalPhyAd, LM_UINT32 RemotePhyAd); +#ifdef INCLUDE_TBI_SUPPORT +STATIC LM_STATUS LM_SetupFiberPhy(PLM_DEVICE_BLOCK pDevice); +STATIC LM_STATUS LM_InitBcm800xPhy(PLM_DEVICE_BLOCK pDevice); +#endif +STATIC LM_STATUS LM_SetupCopperPhy(PLM_DEVICE_BLOCK pDevice); +STATIC LM_VOID LM_SetEthWireSpeed(LM_DEVICE_BLOCK *pDevice); +STATIC LM_STATUS LM_PhyAdvertiseAll(LM_DEVICE_BLOCK *pDevice); +STATIC PLM_ADAPTER_INFO LM_GetAdapterInfoBySsid(LM_UINT16 Svid, LM_UINT16 Ssid); +LM_VOID LM_SwitchVaux(PLM_DEVICE_BLOCK pDevice, PLM_DEVICE_BLOCK pDevice2); +STATIC LM_STATUS LM_DmaTest(PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pBufferVirt, + LM_PHYSICAL_ADDRESS BufferPhy, LM_UINT32 BufferSize); +STATIC LM_STATUS LM_DisableChip(PLM_DEVICE_BLOCK pDevice); +STATIC LM_STATUS LM_ResetChip(PLM_DEVICE_BLOCK pDevice); +STATIC LM_STATUS LM_DisableFW(PLM_DEVICE_BLOCK pDevice); +STATIC LM_STATUS LM_Test4GBoundary(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket, + PT3_SND_BD pSendBd); +STATIC LM_VOID LM_WritePreResetSignatures(LM_DEVICE_BLOCK *pDevice, + LM_RESET_TYPE Mode); +STATIC LM_VOID LM_WritePostResetSignatures(LM_DEVICE_BLOCK *pDevice, + LM_RESET_TYPE Mode); +STATIC LM_VOID LM_WriteLegacySignatures(LM_DEVICE_BLOCK *pDevice, + LM_RESET_TYPE Mode); +STATIC void LM_GetPhyId(LM_DEVICE_BLOCK *pDevice); + +/******************************************************************************/ +/* External functions. */ +/******************************************************************************/ + +LM_STATUS LM_LoadRlsFirmware(PLM_DEVICE_BLOCK pDevice); +#ifdef INCLUDE_TCP_SEG_SUPPORT +LM_STATUS LM_LoadStkOffLdFirmware(PLM_DEVICE_BLOCK pDevice); +LM_UINT32 LM_GetStkOffLdFirmwareSize(PLM_DEVICE_BLOCK pDevice); +#endif + +LM_UINT32 +LM_RegRd(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Register) +{ +#ifdef PCIX_TARGET_WORKAROUND + if (pDevice->Flags & UNDI_FIX_FLAG) + { + return (LM_RegRdInd(pDevice, Register)); + } + else +#endif + { + return (REG_RD_OFFSET(pDevice, Register)); + } +} + +/* Mainly used to flush posted write before delaying */ +LM_VOID +LM_RegRdBack(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Register) +{ + LM_UINT32 dummy; + +#ifdef PCIX_TARGET_WORKAROUND + if (pDevice->Flags & ENABLE_PCIX_FIX_FLAG) + { + return; + } + else +#endif + { + if (pDevice->Flags & REG_RD_BACK_FLAG) + return; + + dummy = REG_RD_OFFSET(pDevice, Register); + } +} + +LM_VOID +LM_RegWr(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Register, LM_UINT32 Value32, + LM_UINT32 ReadBack) +{ +#ifdef PCIX_TARGET_WORKAROUND + if (pDevice->Flags & ENABLE_PCIX_FIX_FLAG) + { + LM_RegWrInd(pDevice, Register, Value32); + } + else +#endif + { + LM_UINT32 dummy; + + REG_WR_OFFSET(pDevice, Register, Value32); + if (ReadBack && (pDevice->Flags & REG_RD_BACK_FLAG)) + { + dummy = REG_RD_OFFSET(pDevice, Register); + } + } +} + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_UINT32 +LM_RegRdInd( +PLM_DEVICE_BLOCK pDevice, +LM_UINT32 Register) { + LM_UINT32 Value32; + + MM_ACQUIRE_UNDI_LOCK(pDevice); + MM_WriteConfig32(pDevice, T3_PCI_REG_ADDR_REG, Register); + MM_ReadConfig32(pDevice, T3_PCI_REG_DATA_REG, &Value32); + MM_RELEASE_UNDI_LOCK(pDevice); + + return MM_SWAP_LE32(Value32); +} /* LM_RegRdInd */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_VOID +LM_RegWrInd( +PLM_DEVICE_BLOCK pDevice, +LM_UINT32 Register, +LM_UINT32 Value32) { + + MM_ACQUIRE_UNDI_LOCK(pDevice); + MM_WriteConfig32(pDevice, T3_PCI_REG_ADDR_REG, Register); + MM_WriteConfig32(pDevice, T3_PCI_REG_DATA_REG, MM_SWAP_LE32(Value32)); + MM_RELEASE_UNDI_LOCK(pDevice); +} /* LM_RegWrInd */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_UINT32 +LM_MemRdInd( +PLM_DEVICE_BLOCK pDevice, +LM_UINT32 MemAddr) { + LM_UINT32 Value32; + + MM_ACQUIRE_UNDI_LOCK(pDevice); + MM_WriteConfig32(pDevice, T3_PCI_MEM_WIN_ADDR_REG, MemAddr); + MM_ReadConfig32(pDevice, T3_PCI_MEM_WIN_DATA_REG, &Value32); + MM_RELEASE_UNDI_LOCK(pDevice); + + return MM_SWAP_LE32(Value32); +} /* LM_MemRdInd */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_VOID +LM_MemWrInd( +PLM_DEVICE_BLOCK pDevice, +LM_UINT32 MemAddr, +LM_UINT32 Value32) { + MM_ACQUIRE_UNDI_LOCK(pDevice); + MM_WriteConfig32(pDevice, T3_PCI_MEM_WIN_ADDR_REG, MemAddr); + MM_WriteConfig32(pDevice, T3_PCI_MEM_WIN_DATA_REG, MM_SWAP_LE32(Value32)); + MM_RELEASE_UNDI_LOCK(pDevice); +} /* LM_MemWrInd */ + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_STATUS +LM_QueueRxPackets( +PLM_DEVICE_BLOCK pDevice) { + LM_STATUS Lmstatus; + PLM_PACKET pPacket; + PT3_RCV_BD pRcvBd = 0; + LM_UINT32 StdBdAdded = 0; +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + LM_UINT32 JumboBdAdded = 0; +#endif /* T3_JUMBO_RCV_RCB_ENTRY_COUNT */ + LM_UINT32 ConIdx, Idx; + LM_UINT32 Diff = 0; + + Lmstatus = LM_STATUS_SUCCESS; + + if (pDevice->Flags & RX_BD_LIMIT_64_FLAG) + { + ConIdx = pDevice->pStatusBlkVirt->RcvStdConIdx; + Diff = (pDevice->RxStdProdIdx - ConIdx) & + T3_STD_RCV_RCB_ENTRY_COUNT_MASK; + if (Diff >= 56) + { + if (QQ_GetEntryCnt(&pDevice->RxPacketFreeQ.Container)) + { + pDevice->QueueAgain = TRUE; + } + return LM_STATUS_SUCCESS; + } + } + + pDevice->QueueAgain = FALSE; + + pPacket = (PLM_PACKET) QQ_PopHead(&pDevice->RxPacketFreeQ.Container); + while(pPacket) { + switch(pPacket->u.Rx.RcvProdRing) { +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + case T3_JUMBO_RCV_PROD_RING: /* Jumbo Receive Ring. */ + /* Initialize the buffer descriptor. */ + Idx = pDevice->RxJumboProdIdx; + pRcvBd = &pDevice->pRxJumboBdVirt[Idx]; + + pPacket->u.Rx.RcvRingProdIdx = Idx; + pDevice->RxJumboRing[Idx] = pPacket; + /* Update the producer index. */ + pDevice->RxJumboProdIdx = (Idx + 1) & + T3_JUMBO_RCV_RCB_ENTRY_COUNT_MASK; + + JumboBdAdded++; + break; +#endif /* T3_JUMBO_RCV_RCB_ENTRY_COUNT */ + + case T3_STD_RCV_PROD_RING: /* Standard Receive Ring. */ + /* Initialize the buffer descriptor. */ + Idx = pDevice->RxStdProdIdx; + pRcvBd = &pDevice->pRxStdBdVirt[Idx]; + + pPacket->u.Rx.RcvRingProdIdx = Idx; + pDevice->RxStdRing[Idx] = pPacket; + /* Update the producer index. */ + pDevice->RxStdProdIdx = (Idx + 1) & + T3_STD_RCV_RCB_ENTRY_COUNT_MASK; + + StdBdAdded++; + break; + + case T3_UNKNOWN_RCV_PROD_RING: + default: + Lmstatus = LM_STATUS_FAILURE; + break; + } /* switch */ + + /* Bail out if there is any error. */ + if(Lmstatus != LM_STATUS_SUCCESS) + { + break; + } + + /* Initialize the receive buffer pointer */ + MM_MapRxDma(pDevice, pPacket, &pRcvBd->HostAddr); + + /* The opaque field may point to an offset from a fix addr. */ + pRcvBd->Opaque = (LM_UINT32) (MM_UINT_PTR(pPacket) - + MM_UINT_PTR(pDevice->pPacketDescBase)); + + if ((pDevice->Flags & RX_BD_LIMIT_64_FLAG) && + ((Diff + StdBdAdded) >= 63)) + { + if (QQ_GetEntryCnt(&pDevice->RxPacketFreeQ.Container)) + { + pDevice->QueueAgain = TRUE; + } + break; + } + pPacket = (PLM_PACKET) QQ_PopHead(&pDevice->RxPacketFreeQ.Container); + } /* while */ + + MM_WMB(); + /* Update the procedure index. */ + if(StdBdAdded) + { + MB_REG_WR(pDevice, Mailbox.RcvStdProdIdx.Low, + pDevice->RxStdProdIdx); + if (pDevice->Flags & FLUSH_POSTED_WRITE_FLAG) + { + MB_REG_RD(pDevice, Mailbox.RcvStdProdIdx.Low); + } + } +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + if(JumboBdAdded) + { + MB_REG_WR(pDevice, Mailbox.RcvJumboProdIdx.Low, + pDevice->RxJumboProdIdx); + if (pDevice->Flags & FLUSH_POSTED_WRITE_FLAG) + { + MB_REG_RD(pDevice, Mailbox.RcvJumboProdIdx.Low); + } + } +#endif /* T3_JUMBO_RCV_RCB_ENTRY_COUNT */ + + return Lmstatus; +} /* LM_QueueRxPackets */ + + + + +#define EEPROM_CMD_TIMEOUT 100000 +#define NVRAM_CMD_TIMEOUT 100000 + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +STATIC LM_STATUS LM_NVRAM_AcquireLock( PLM_DEVICE_BLOCK pDevice ) +{ + LM_UINT i; + LM_UINT32 value32; + LM_STATUS status; + + status = LM_STATUS_SUCCESS; + + /* BCM4785: Avoid all access to NVRAM & EEPROM. */ + if (pDevice->Flags & SB_CORE_FLAG) + return status; + + /* Request access to the flash interface. */ + REG_WR( pDevice, Nvram.SwArb, SW_ARB_REQ_SET1 ); + + /* + * The worst case wait time for Nvram arbitration + * using serial eprom is about 45 msec on a 5704 + * with the other channel loading boot code. + */ + for( i = 0; i < NVRAM_CMD_TIMEOUT; i++ ) + { + value32 = REG_RD( pDevice, Nvram.SwArb ); + if( value32 & SW_ARB_GNT1 ) + { + break; + } + MM_Wait(20); + } + + + return status; +} /* LM_NVRAM_AcquireLock */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +STATIC LM_STATUS LM_NVRAM_ReleaseLock( PLM_DEVICE_BLOCK pDevice ) +{ + /* BCM4785: Avoid all access to NVRAM & EEPROM. */ + if (pDevice->Flags & SB_CORE_FLAG) + return LM_STATUS_SUCCESS; + + /* Relinquish nvram interface. */ + REG_WR( pDevice, Nvram.SwArb, SW_ARB_REQ_CLR1 ); + REG_RD_BACK( pDevice, Nvram.SwArb ); + + return LM_STATUS_SUCCESS; +} /* LM_NVRAM_ReleaseLock */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +STATIC LM_STATUS +LM_EEPROM_ExecuteCommand( PLM_DEVICE_BLOCK pDevice, LM_UINT32 cmd ) +{ + LM_UINT32 i; + LM_UINT32 value32; + LM_STATUS status; + + status = LM_STATUS_SUCCESS; + + REG_WR( pDevice, Grc.EepromAddr, cmd ); + + for( i = 0; i < EEPROM_CMD_TIMEOUT; i++ ) + { + value32 = REG_RD( pDevice, Grc.EepromAddr ); + if( value32 & SEEPROM_ADDR_COMPLETE ) + { + break; + } + MM_Wait(20); + } + + if( i == EEPROM_CMD_TIMEOUT ) + { + B57_ERR(("EEPROM command (0x%x) timed out!\n", cmd)); + status = LM_STATUS_FAILURE; + } + + return status; +} /* LM_EEPROM_ExecuteCommand */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +STATIC LM_STATUS +LM_NVRAM_ExecuteCommand( PLM_DEVICE_BLOCK pDevice, LM_UINT32 cmd ) +{ + LM_UINT32 i; + LM_UINT32 value32; + LM_STATUS status; + + status = LM_STATUS_SUCCESS; + + REG_WR( pDevice, Nvram.Cmd, cmd ); + REG_RD_BACK( pDevice, Nvram.Cmd ); + MM_Wait(10); + + /* Wait for the command to complete. */ + for( i = 0; i < NVRAM_CMD_TIMEOUT; i++ ) + { + value32 = REG_RD( pDevice, Nvram.Cmd ); + if( value32 & NVRAM_CMD_DONE ) + { + break; + } + MM_Wait(1); + } + + if( i == NVRAM_CMD_TIMEOUT ) + { + B57_ERR(("NVRAM command (0x%x) timed out!\n", cmd)); + status = LM_STATUS_FAILURE; + } + + return status; +} /* LM_NVRAM_ExecuteCommand */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +STATIC LM_STATUS +LM_EEPROM_Read_UINT32( PLM_DEVICE_BLOCK pDevice, LM_UINT32 offset, + LM_UINT32 * data ) +{ + LM_UINT32 value32; + LM_UINT32 Addr; + LM_UINT32 Dev; + LM_STATUS status; + + Dev = offset / pDevice->flashinfo.chipsize; + Addr = offset % pDevice->flashinfo.chipsize; + + value32 = REG_RD( pDevice, Grc.EepromAddr ); + value32 &= ~(SEEPROM_ADDR_DEV_ID_MASK | SEEPROM_ADDR_ADDRESS_MASK | + SEEPROM_ADDR_RW_MASK); + value32 |= SEEPROM_ADDR_DEV_ID(Dev) | SEEPROM_ADDR_ADDRESS(Addr) | + SEEPROM_ADDR_START | SEEPROM_ADDR_READ; + + status = LM_EEPROM_ExecuteCommand( pDevice, value32 ); + if( status == LM_STATUS_SUCCESS ) + { + value32 = REG_RD( pDevice, Grc.EepromData ); + + /* The endianess of the eeprom and flash interface is different */ + *data = MM_SWAP_LE32( value32 ); + } + + return status; +} /* LM_EEPROM_Read_UINT32 */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +STATIC LM_STATUS +LM_NVRAM_Read_UINT32( PLM_DEVICE_BLOCK pDevice, LM_UINT32 offset, + LM_UINT32 * data ) +{ + LM_UINT32 physaddr; + LM_UINT32 ctrlreg; + LM_UINT32 value32; + LM_STATUS status; + + if( pDevice->flashinfo.jedecnum == JEDEC_ATMEL && + pDevice->flashinfo.buffered == TRUE ) + { + /* + * One supported flash part has 9 address bits to address a + * particular page and another 9 address bits to address a + * particular byte within that page. + */ + LM_UINT32 pagenmbr; + + pagenmbr = offset / pDevice->flashinfo.pagesize; + pagenmbr = pagenmbr << ATMEL_AT45DB0X1B_PAGE_POS; + + physaddr = pagenmbr + (offset % pDevice->flashinfo.pagesize); + } + else + { + physaddr = offset; + } + + REG_WR( pDevice, Nvram.Addr, physaddr ); + + ctrlreg = NVRAM_CMD_DONE | NVRAM_CMD_DO_IT | + NVRAM_CMD_LAST | NVRAM_CMD_FIRST | NVRAM_CMD_RD; + + status = LM_NVRAM_ExecuteCommand( pDevice, ctrlreg ); + if( status == LM_STATUS_SUCCESS ) + { + value32 = REG_RD( pDevice, Nvram.ReadData ); + + /* + * Data is swapped so that the byte stream is the same + * in big and little endian systems. Caller will do + * additional swapping depending on how it wants to + * look at the data. + */ + *data = MM_SWAP_BE32( value32 ); + } + + return status; +} /* LM_NVRAM_Read_UINT32 */ + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +STATIC LM_VOID +LM_EEPROM_ReadSize( PLM_DEVICE_BLOCK pDevice, LM_UINT32 * size ) +{ + LM_UINT32 cursize; + LM_UINT32 value32; + LM_STATUS status; + + /* + * Initialize the chipsize to the largest EEPROM size we support. + * This will intentionally restrict our sizing operations to the + * first EEPROM chip. + */ + pDevice->flashinfo.chipsize = ATMEL_AT24C512_CHIP_SIZE; + + value32 = 0; + + /* If anything fails, use the smallest chip as the default chip size. */ + cursize = ATMEL_AT24C64_CHIP_SIZE; + + status = LM_NvramRead(pDevice, 0, &value32); + if( status != LM_STATUS_SUCCESS ) + { + goto done; + } + + value32 = MM_SWAP_BE32(value32); + if( value32 != 0x669955aa ) + { + goto done; + } + + /* + * Size the chip by reading offsets at increasing powers of two. + * When we encounter our validation signature, we know the addressing + * has wrapped around, and thus have our chip size. + */ + while( cursize < ATMEL_AT24C64_CHIP_SIZE ) + { + status = LM_NvramRead(pDevice, cursize, &value32); + if( status != LM_STATUS_SUCCESS ) + { + cursize = ATMEL_AT24C64_CHIP_SIZE; + break; + } + + value32 = MM_SWAP_BE32(value32); + if( value32 == 0x669955aa ) + { + break; + } + cursize <<= 1; + } + +done: + + *size = cursize; + pDevice->flashinfo.pagesize = cursize; + + +} /* LM_EEPROM_ReadSize */ + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +STATIC LM_STATUS +LM_FLASH_Atmel_Buffered_ReadSize( PLM_DEVICE_BLOCK pDevice, LM_UINT32 * size ) +{ + LM_UINT32 config3; + LM_UINT32 value32; + LM_STATUS status; + + /* Temporarily replace the read command with a "read ID" command. */ + config3 = REG_RD( pDevice, Nvram.Config3 ); + value32 = config3 & ~NVRAM_READ_COMMAND(NVRAM_COMMAND_MASK); + value32 |= NVRAM_READ_COMMAND(0x57); + REG_WR( pDevice, Nvram.Config3, value32 ); + + REG_WR( pDevice, Nvram.Addr, 0x0 ); + + status = LM_NVRAM_Read_UINT32(pDevice, 0x0, &value32); + + /* Restore the original read command. */ + REG_WR( pDevice, Nvram.Config3, config3 ); + if( status == LM_STATUS_SUCCESS ) + { + switch( value32 & 0x3c ) + { + case 0x0c: + *size = (1 * (1<<20))/8; + break; + case 0x14: + *size = (2 * (1<<20))/8; + break; + case 0x1c: + *size = (4 * (1<<20))/8; + break; + case 0x24: + *size = (8 * (1<<20))/8; + break; + } + } + + return status; +} /* LM_FLASH_Atmel_Buffered_ReadSize */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +STATIC LM_STATUS +LM_FLASH_ST_ReadSize( PLM_DEVICE_BLOCK pDevice, LM_UINT32 * size ) +{ + LM_STATUS status; + LM_UINT32 i; + LM_UINT32 ctrlreg; + LM_UINT32 value32; + LM_UINT32 config1; + + /* We need to get the size through pass-thru mode. */ + config1 = REG_RD( pDevice, Nvram.Config1 ); + value32 = config1 | FLASH_PASS_THRU_MODE; + REG_WR( pDevice, Nvram.Config1, value32 ); + + /* Issue the "read ID" command. */ + REG_WR( pDevice, Nvram.WriteData, 0x9f ); + + ctrlreg = NVRAM_CMD_DO_IT | NVRAM_CMD_DONE | NVRAM_CMD_FIRST | NVRAM_CMD_WR; + status = LM_NVRAM_ExecuteCommand( pDevice, ctrlreg ); + if( status == LM_STATUS_FAILURE ) + { + goto done; + } + + /* Read in the "read ID" response. */ + ctrlreg = NVRAM_CMD_DO_IT | NVRAM_CMD_DONE; + + /* Discard the first three bytes. */ + for( i = 0; i < 2; i++ ) + { + status = LM_NVRAM_ExecuteCommand( pDevice, ctrlreg ); + if( status == LM_STATUS_FAILURE ) + { + goto done; + } + + value32 = REG_RD(pDevice, Nvram.ReadData); + } + + ctrlreg |= NVRAM_CMD_LAST; + + status = LM_NVRAM_ExecuteCommand( pDevice, ctrlreg ); + if( status == LM_STATUS_SUCCESS ) + { + value32 = REG_RD(pDevice, Nvram.ReadData) & 0xff; + switch( value32 ) + { + case 0x11: + *size = (1 * (1<<20)) / 8; + break; + case 0x12: + *size = (2 * (1<<20)) / 8; + break; + case 0x13: + *size = (4 * (1<<20)) / 8; + break; + case 0x14: + *size = (8 * (1<<20)) / 8; + break; + } + } + +done: + + /* Restore the previous flash mode. */ + REG_WR( pDevice, Nvram.Config1, config1 ); + + return status; +} /* LM_FLASH_ST_ReadSize */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +STATIC LM_STATUS +LM_FLASH_Saifun_ReadSize( PLM_DEVICE_BLOCK pDevice, LM_UINT32 * size ) +{ + LM_UINT32 config3; + LM_UINT32 value32; + LM_STATUS status; + + /* Temporarily replace the read command with a "read ID" command. */ + config3 = REG_RD( pDevice, Nvram.Config3 ); + value32 = config3 & ~NVRAM_READ_COMMAND(NVRAM_COMMAND_MASK); + value32 |= NVRAM_READ_COMMAND(0xab); + REG_WR( pDevice, Nvram.Config3, value32 ); + + REG_WR( pDevice, Nvram.Addr, 0x0 ); + + status = LM_NVRAM_Read_UINT32(pDevice, 0x0, &value32); + + /* Restore the original read command. */ + REG_WR( pDevice, Nvram.Config3, config3 ); + + if( status == LM_STATUS_SUCCESS ) + { + switch( value32 & 0xff ) + { + case 0x05: + *size = (512 * (1<<10)/8); + break; + case 0x10: + *size = (1 * (1<<20)/8); + break; + case 0x11: + *size = (2 * (1<<20)/8); + break; + } + } + + return status; +} /* LM_FLASH_Saifun_ReadSize */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +STATIC LM_STATUS +LM_FLASH_ReadSize( PLM_DEVICE_BLOCK pDevice, LM_UINT32 * size ) +{ + LM_UINT32 value32; + LM_STATUS status; + + status = LM_NVRAM_AcquireLock( pDevice ); + if( status == LM_STATUS_FAILURE ) + { + return status; + } + + if(T3_ASIC_IS_575X_PLUS(pDevice->ChipRevId)) + { + if( (pDevice->Flags & PROTECTED_NVRAM_FLAG) == 0) + { + value32 = REG_RD( pDevice, Nvram.NvmAccess ); + value32 |= NVRAM_ACCESS_ENABLE | NVRAM_ACCESS_WRITE_ENABLE; + REG_WR( pDevice, Nvram.NvmAccess, value32 ); + } + } + + switch( pDevice->flashinfo.jedecnum ) + { + case JEDEC_ST: + status = LM_FLASH_ST_ReadSize( pDevice, size ); + break; + case JEDEC_ATMEL: + if( pDevice->flashinfo.buffered == TRUE ) + { + status = LM_FLASH_Atmel_Buffered_ReadSize( pDevice, size ); + } + else + { + status = LM_STATUS_FAILURE; + } + break; + case JEDEC_SAIFUN: + status = LM_FLASH_Saifun_ReadSize( pDevice, size ); + break; + case JEDEC_SST: + default: + status = LM_STATUS_FAILURE; + } + + if(T3_ASIC_IS_575X_PLUS(pDevice->ChipRevId)) + { + if( (pDevice->Flags & PROTECTED_NVRAM_FLAG) == 0) + { + value32 = REG_RD( pDevice, Nvram.NvmAccess ); + value32 &= ~(NVRAM_ACCESS_ENABLE | NVRAM_ACCESS_WRITE_ENABLE); + REG_WR( pDevice, Nvram.NvmAccess, value32 ); + } + } + + LM_NVRAM_ReleaseLock( pDevice ); + + return status; +} /* LM_FLASH_ReadSize */ + +STATIC LM_VOID LM_NVRAM_Detect_570X( PLM_DEVICE_BLOCK pDevice ) +{ + LM_UINT32 value32; + + value32 = REG_RD(pDevice, Nvram.Config1); + + if( (value32 & FLASH_INTERFACE_ENABLE) == 0 ) + { + pDevice->flashinfo.romtype = ROM_TYPE_EEPROM; + } + else + { + /* + * 5705 and older products do not have bits 24 and 25 defined. + * If we've gotten here, then we can guarantee the flash is + * an Atmel AT45DB011DB. + */ + pDevice->flashinfo.jedecnum = JEDEC_ATMEL; + pDevice->flashinfo.romtype = ROM_TYPE_FLASH; + pDevice->flashinfo.pagesize = ATMEL_AT45DB0X1B_PAGE_SIZE; + pDevice->flashinfo.buffered = TRUE; + } +} /* LM_NVRAM_Detect_570X */ + +STATIC LM_VOID LM_NVRAM_Detect_5750( PLM_DEVICE_BLOCK pDevice ) +{ + LM_UINT32 value32; + + value32 = REG_RD(pDevice, Nvram.Config1); + + if( (value32 & FLASH_INTERFACE_ENABLE) == 0 ) + { + pDevice->flashinfo.romtype = ROM_TYPE_EEPROM; + return; + } + + pDevice->flashinfo.romtype = ROM_TYPE_FLASH; + + switch( value32 & FLASH_PART_5750_TYPEMASK ) + { + case FLASH_VENDOR_ATMEL_FLASH_BUFFERED: + pDevice->flashinfo.jedecnum = JEDEC_ATMEL; + pDevice->flashinfo.pagesize = ATMEL_AT45DB0X1B_PAGE_SIZE; + pDevice->flashinfo.buffered = TRUE; + break; + case FLASH_VENDOR_ATMEL_FLASH_UNBUFFERED: + pDevice->flashinfo.jedecnum = JEDEC_ATMEL; + pDevice->flashinfo.pagesize = ATMEL_AT25F512_PAGE_SIZE; + pDevice->flashinfo.buffered = FALSE; + break; + case FLASH_VENDOR_ST: + pDevice->flashinfo.jedecnum = JEDEC_ST; + pDevice->flashinfo.pagesize = ST_M45PEX0_PAGE_SIZE; + pDevice->flashinfo.buffered = TRUE; + break; + case FLASH_VENDOR_SAIFUN: + pDevice->flashinfo.jedecnum = JEDEC_SAIFUN; + pDevice->flashinfo.pagesize = SAIFUN_SA25F0XX_PAGE_SIZE; + pDevice->flashinfo.buffered = FALSE; + break; + case FLASH_VENDOR_SST_SMALL: + case FLASH_VENDOR_SST_LARGE: + pDevice->flashinfo.jedecnum = JEDEC_SST; + pDevice->flashinfo.pagesize = SST_25VF0X0_PAGE_SIZE; + pDevice->flashinfo.buffered = FALSE; + break; + default: + B57_ERR(("bcm57xx : Unknown NVRAM type.\n")); + pDevice->flashinfo.jedecnum = 0; + pDevice->flashinfo.romtype = 0; + pDevice->flashinfo.buffered = FALSE; + pDevice->flashinfo.pagesize = 0; + } +} /* LM_NVRAM_Detect_5750 */ + +STATIC LM_VOID LM_NVRAM_Detect_5752( PLM_DEVICE_BLOCK pDevice ) +{ + LM_BOOL supported; + LM_UINT32 value32; + + supported = FALSE; + + value32 = REG_RD(pDevice, Nvram.Config1); + + if(value32 & BIT_27) + pDevice->Flags |= PROTECTED_NVRAM_FLAG; + + switch( value32 & FLASH_PART_5752_TYPEMASK ) + { + case FLASH_PART_5752_EEPROM_ATMEL_64K: + pDevice->flashinfo.jedecnum = JEDEC_ATMEL; + pDevice->flashinfo.romtype = ROM_TYPE_EEPROM; + pDevice->flashinfo.buffered = FALSE; + pDevice->flashinfo.chipsize = (64 * (1<<10)/8); + supported = TRUE; + break; + + case FLASH_PART_5752_EEPROM_ATMEL_376K: + pDevice->flashinfo.jedecnum = JEDEC_ATMEL; + pDevice->flashinfo.romtype = ROM_TYPE_EEPROM; + pDevice->flashinfo.buffered = FALSE; + pDevice->flashinfo.chipsize = (512 * (1<<10)/8); + supported = TRUE; + break; + + case FLASH_PART_5752_FLASH_ATMEL_AT45DB041: + pDevice->flashinfo.jedecnum = JEDEC_ATMEL; + pDevice->flashinfo.romtype = ROM_TYPE_FLASH; + pDevice->flashinfo.buffered = TRUE; + pDevice->flashinfo.chipsize = (4 * (1<<20)) / 8; + supported = TRUE; + break; + + case FLASH_PART_5752_FLASH_ATMEL_AT25F512: + pDevice->flashinfo.jedecnum = JEDEC_ATMEL; + pDevice->flashinfo.romtype = ROM_TYPE_FLASH; + pDevice->flashinfo.buffered = FALSE; + pDevice->flashinfo.chipsize = (512 * (1<<10)/8); + supported = TRUE; + break; + + case FLASH_PART_5752_FLASH_ST_M25P10A: + pDevice->flashinfo.jedecnum = JEDEC_ST; + pDevice->flashinfo.romtype = ROM_TYPE_FLASH; + pDevice->flashinfo.buffered = TRUE; + pDevice->flashinfo.chipsize = (1 * (1<<20)) / 8; + supported = TRUE; + break; + case FLASH_PART_5752_FLASH_ST_M25P05A: + pDevice->flashinfo.jedecnum = JEDEC_ST; + pDevice->flashinfo.romtype = ROM_TYPE_FLASH; + pDevice->flashinfo.buffered = TRUE; + pDevice->flashinfo.chipsize = (512 * (1<<10)/8); + supported = TRUE; + break; + + case FLASH_PART_5752_FLASH_ST_M45PE10: + pDevice->flashinfo.jedecnum = JEDEC_ST; + pDevice->flashinfo.romtype = ROM_TYPE_FLASH; + pDevice->flashinfo.buffered = TRUE; + pDevice->flashinfo.chipsize = (1 * (1<<20)) / 8; + supported = TRUE; + break; + + case FLASH_PART_5752_FLASH_ST_M45PE20: + pDevice->flashinfo.jedecnum = JEDEC_ST; + pDevice->flashinfo.romtype = ROM_TYPE_FLASH; + pDevice->flashinfo.buffered = TRUE; + pDevice->flashinfo.chipsize = (2 * (1<<20)) / 8; + supported = TRUE; + break; + + case FLASH_PART_5752_FLASH_ST_M45PE40: + pDevice->flashinfo.jedecnum = JEDEC_ST; + pDevice->flashinfo.romtype = ROM_TYPE_FLASH; + pDevice->flashinfo.buffered = TRUE; + pDevice->flashinfo.chipsize = (4 * (1<<20)) / 8; + supported = TRUE; + break; + default: + B57_ERR(("bcm57xx : Unknown NVRAM type.\n")); + } + + if( pDevice->flashinfo.romtype == ROM_TYPE_FLASH ) + { + switch( value32 & FLASH_PART_5752_PAGEMASK ) + { + case FLASH_PART_5752_PAGE_SIZE_256B: + pDevice->flashinfo.pagesize = 256; + break; + case FLASH_PART_5752_PAGE_SIZE_512B: + pDevice->flashinfo.pagesize = 512; + break; + case FLASH_PART_5752_PAGE_SIZE_1K: + pDevice->flashinfo.pagesize = 1024; + break; + case FLASH_PART_5752_PAGE_SIZE_2K: + pDevice->flashinfo.pagesize = 2048; + break; + case FLASH_PART_5752_PAGE_SIZE_4K: + pDevice->flashinfo.pagesize = 4096; + break; + case FLASH_PART_5752_PAGE_SIZE_264B: + pDevice->flashinfo.pagesize = 264; + break; + default: + B57_ERR(("bcm57xx : Unknown NVRAM page size.\n")); + supported = FALSE; + } + } + + if( supported != TRUE ) + { + B57_ERR(("Flash type unsupported!!!\n")); + pDevice->flashinfo.jedecnum = 0; + pDevice->flashinfo.romtype = 0; + pDevice->flashinfo.buffered = FALSE; + pDevice->flashinfo.pagesize = 0; + } + + +} /* LM_NVRAM_Detect_5752 */ + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +STATIC LM_VOID LM_NVRAM_Init( PLM_DEVICE_BLOCK pDevice ) +{ + LM_UINT32 Value32; + + /* BCM4785: Avoid all access to NVRAM & EEPROM. */ + if (pDevice->Flags & SB_CORE_FLAG) + return; + + pDevice->NvramSize = 0; + + /* Intialize clock period and state machine. */ + Value32 = SEEPROM_ADDR_CLK_PERD(SEEPROM_CLOCK_PERIOD) | + SEEPROM_ADDR_FSM_RESET; + REG_WR(pDevice, Grc.EepromAddr, Value32); + REG_RD_BACK(pDevice, Grc.EepromAddr); + + MM_Wait(100); + + /* Serial eeprom access using the Grc.EepromAddr/EepromData registers. */ + Value32 = REG_RD(pDevice, Grc.LocalCtrl); + REG_WR(pDevice, Grc.LocalCtrl, Value32 | GRC_MISC_LOCAL_CTRL_AUTO_SEEPROM); + + switch( T3_ASIC_REV(pDevice->ChipRevId) ) + { + case T3_ASIC_REV_5700: + case T3_ASIC_REV_5701: + pDevice->flashinfo.romtype = ROM_TYPE_EEPROM; + break; + case T3_ASIC_REV_5752: + LM_NVRAM_Detect_5752(pDevice); + break; + case T3_ASIC_REV_5714_A0: + case T3_ASIC_REV_5780: + case T3_ASIC_REV_5714: + case T3_ASIC_REV_5750: + LM_NVRAM_Detect_5750(pDevice); + break; + default: + LM_NVRAM_Detect_570X(pDevice); + } + + /* Set the 5701 compatibility mode if we are using EEPROM. */ + if( T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5700 && + T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5701 && + pDevice->flashinfo.romtype == ROM_TYPE_EEPROM ) + { + Value32 = REG_RD(pDevice, Nvram.Config1); + + if( T3_ASIC_IS_575X_PLUS(pDevice->ChipRevId)) + { + if( (pDevice->Flags & PROTECTED_NVRAM_FLAG) == 0) + { + REG_WR(pDevice, Nvram.NvmAccess, + REG_RD(pDevice, Nvram.NvmAccess) | ACCESS_EN); + } + } + + /* Use the new interface to read EEPROM. */ + Value32 &= ~FLASH_COMPAT_BYPASS; + + REG_WR(pDevice, Nvram.Config1, Value32); + + if( T3_ASIC_IS_575X_PLUS(pDevice->ChipRevId)) + { + if( (pDevice->Flags & PROTECTED_NVRAM_FLAG) == 0) + { + REG_WR(pDevice, Nvram.NvmAccess, + REG_RD(pDevice, Nvram.NvmAccess) & ~ACCESS_EN); + } + } + } + + if( !(T3_ASIC_5752(pDevice->ChipRevId)) ) + { + if( pDevice->flashinfo.romtype == ROM_TYPE_EEPROM ) + { + /* The only EEPROM we support is an ATMEL */ + pDevice->flashinfo.jedecnum = JEDEC_ATMEL; + pDevice->flashinfo.pagesize = 0; + pDevice->flashinfo.buffered = FALSE; + + LM_EEPROM_ReadSize( pDevice, &pDevice->flashinfo.chipsize ); + } + else + { + LM_FLASH_ReadSize( pDevice, &pDevice->flashinfo.chipsize ); + pDevice->Flags |= FLASH_DETECTED_FLAG; + } + } + + pDevice->NvramSize = pDevice->flashinfo.chipsize; + + B57_INFO(("*nvram:size=0x%x jnum=0x%x page=0x%x buff=0x%x \n", + pDevice->NvramSize, pDevice->flashinfo.jedecnum, + pDevice->flashinfo.pagesize, pDevice->flashinfo.buffered)); + +} /* LM_NVRAM_Init */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_STATUS +LM_NvramRead( PLM_DEVICE_BLOCK pDevice, LM_UINT32 offset, LM_UINT32 * data ) +{ + LM_UINT32 value32; + LM_STATUS status; + + /* BCM4785: Avoid all access to NVRAM & EEPROM. */ + if (pDevice->Flags & SB_CORE_FLAG) { + *data = 0xffffffff; + return LM_STATUS_FAILURE; + } + + if( offset >= pDevice->flashinfo.chipsize ) + { + return LM_STATUS_FAILURE; + } + + if( T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700 || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701 ) + { + status = LM_EEPROM_Read_UINT32( pDevice, offset, data ); + } + else + { + status = LM_NVRAM_AcquireLock( pDevice ); + if( status == LM_STATUS_FAILURE ) + { + return status; + } + + if(T3_ASIC_IS_575X_PLUS(pDevice->ChipRevId)) + { + if( (pDevice->Flags & PROTECTED_NVRAM_FLAG) == 0) + { + value32 = REG_RD( pDevice, Nvram.NvmAccess ); + value32 |= NVRAM_ACCESS_ENABLE; + REG_WR( pDevice, Nvram.NvmAccess, value32 ); + } + } + + status = LM_NVRAM_Read_UINT32(pDevice, offset, data); + + if(T3_ASIC_IS_575X_PLUS(pDevice->ChipRevId)) + { + if( (pDevice->Flags & PROTECTED_NVRAM_FLAG) == 0) + { + value32 = REG_RD( pDevice, Nvram.NvmAccess ); + value32 &= ~NVRAM_ACCESS_ENABLE; + REG_WR( pDevice, Nvram.NvmAccess, value32 ); + } + } + + LM_NVRAM_ReleaseLock( pDevice ); + } + + return status; +} /* LM_NvramRead */ + + + +#ifdef ETHTOOL_SEEPROM + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +STATIC LM_STATUS +LM_NVRAM_ReadBlock(PLM_DEVICE_BLOCK pDevice, LM_UINT32 offset, + LM_UINT8 *data, LM_UINT32 size) +{ + LM_STATUS status; + LM_UINT32 value32; + LM_UINT32 bytecnt; + LM_UINT8 * srcptr; + + status = LM_STATUS_SUCCESS; + + while( size > 0 ) + { + /* Make sure the read is word aligned. */ + value32 = offset & 0x3; + if( value32 ) + { + bytecnt = sizeof(LM_UINT32) - value32; + offset -= value32; + srcptr = (LM_UINT8 *)(&value32) + value32; + } + else + { + bytecnt = sizeof(LM_UINT32); + srcptr = (LM_UINT8 *)(&value32); + } + + if( bytecnt > size ) + { + bytecnt = size; + } + + if( T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5700 && + T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5701 ) + { + status = LM_NVRAM_Read_UINT32( pDevice, offset, &value32 ); + } + else + { + status = LM_EEPROM_Read_UINT32( pDevice, offset, &value32 ); + } + + if( status != LM_STATUS_SUCCESS ) + { + break; + } + + memcpy( data, srcptr, bytecnt ); + + offset += sizeof(LM_UINT32); + data += bytecnt; + size -= bytecnt; + } + + return status; +} /* LM_NVRAM_ReadBlock */ + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +STATIC LM_STATUS +LM_EEPROM_WriteBlock( PLM_DEVICE_BLOCK pDevice, LM_UINT32 offset, + LM_UINT8 * data, LM_UINT32 size ) +{ + LM_UINT8 * dstptr; + LM_UINT32 value32; + LM_UINT32 bytecnt; + LM_UINT32 subword1; + LM_UINT32 subword2; + LM_UINT32 Addr; + LM_UINT32 Dev; + LM_STATUS status; + + if( offset > pDevice->flashinfo.chipsize ) + { + return LM_STATUS_FAILURE; + } + + status = LM_STATUS_SUCCESS; + + if( size == 0 ) + { + return status; + } + + if( offset & 0x3 ) + { + /* + * If our initial offset does not fall on a word boundary, we + * have to do a read / modify / write to preserve the + * preceding bits we are not interested in. + */ + status = LM_EEPROM_Read_UINT32(pDevice, offset & ~0x3, &subword1); + if( status == LM_STATUS_FAILURE ) + { + return status; + } + } + + if( (offset + size) & 0x3 ) + { + /* + * Likewise, if our ending offset does not fall on a word + * boundary, we have to do a read / modify / write to + * preserve the trailing bits we are not interested in. + */ + status = LM_EEPROM_Read_UINT32( pDevice, (offset + size) & ~0x3, + &subword2 ); + if( status == LM_STATUS_FAILURE ) + { + return status; + } + } + + /* Enable EEPROM write. */ + if( pDevice->Flags & EEPROM_WP_FLAG ) + { + REG_WR( pDevice, Grc.LocalCtrl, + pDevice->GrcLocalCtrl | GRC_MISC_LOCAL_CTRL_GPIO_OE1 ); + REG_RD_BACK( pDevice, Grc.LocalCtrl ); + MM_Wait(40); + + value32 = REG_RD( pDevice, Grc.LocalCtrl ); + if( value32 & GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1 ) + { + return LM_STATUS_FAILURE; + } + } + + while( size > 0 ) + { + value32 = offset & 0x3; + if( value32 ) + { + /* + * We have to read / modify / write the data to + * preserve the flash contents preceding the offset. + */ + offset &= ~0x3; + + dstptr = ((LM_UINT8 *)(&value32)) + value32; + bytecnt = sizeof(LM_UINT32) - value32; + value32 = subword1; + } + else if( size < sizeof(LM_UINT32) ) + { + dstptr = (LM_UINT8 *)(&value32); + bytecnt = size; + value32 = subword2; + } + else + { + dstptr = (LM_UINT8 *)(&value32); + bytecnt = sizeof(LM_UINT32); + } + + if( size < bytecnt ) + { + bytecnt = size; + } + + memcpy( dstptr, (void *)data, bytecnt ); + + data += bytecnt; + size -= bytecnt; + + /* + * Swap the data so that the byte stream will be + * written the same in little and big endian systems. + */ + value32 = MM_SWAP_LE32(value32); + + /* Set the write value to the eeprom */ + REG_WR( pDevice, Grc.EepromData, value32 ); + + Dev = offset / pDevice->flashinfo.chipsize; + Addr = offset % pDevice->flashinfo.chipsize; + + value32 = REG_RD( pDevice, Grc.EepromAddr ); + value32 &= ~(SEEPROM_ADDR_DEV_ID_MASK | SEEPROM_ADDR_ADDRESS_MASK | + SEEPROM_ADDR_RW_MASK); + value32 |= SEEPROM_ADDR_DEV_ID(Dev) | SEEPROM_ADDR_ADDRESS(Addr) | + SEEPROM_ADDR_START | SEEPROM_ADDR_WRITE; + + status = LM_EEPROM_ExecuteCommand( pDevice, value32 ); + if( status != LM_STATUS_SUCCESS ) + { + break; + } + + offset += sizeof(LM_UINT32); + } + + /* Write-protect EEPROM. */ + if( pDevice->Flags & EEPROM_WP_FLAG ) + { + REG_WR(pDevice, Grc.LocalCtrl, pDevice->GrcLocalCtrl | + GRC_MISC_LOCAL_CTRL_GPIO_OE1 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1); + REG_RD_BACK(pDevice, Grc.LocalCtrl); + MM_Wait(40); + } + + return status; +} /* LM_EEPROM_WriteBlock */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +STATIC LM_STATUS +LM_NVRAM_WriteBlockUnBuffered( PLM_DEVICE_BLOCK pDevice, LM_UINT32 offset, + LM_UINT8 * data, LM_UINT32 size ) +{ + LM_UINT i; + LM_STATUS status; + LM_UINT32 tgtoff; + LM_UINT32 value32; + LM_UINT32 ctrlreg; + LM_UINT32 pagesize; + LM_UINT32 pagemask; + LM_UINT32 physaddr; + + /* Cache the pagesize. */ + pagesize = pDevice->flashinfo.pagesize; + + if( pDevice->flashinfo.jedecnum == JEDEC_SAIFUN ) + { + /* Config2 = 0x500d8 */ + /* Config3 = 0x3840253 */ + /* Write1 = 0xaf000400 */ + + /* Configure the erase command to be "page erase". */ + /* Configure the status command to be "read status register". */ + value32 = REG_RD( pDevice, Nvram.Config2 ); + value32 &= ~(NVRAM_STATUS_COMMAND( NVRAM_COMMAND_MASK ) | + NVRAM_ERASE_COMMAND( NVRAM_COMMAND_MASK )); + value32 |= NVRAM_STATUS_COMMAND( SAIFUN_SA25F0XX_READ_STATUS_CMD ) | + NVRAM_ERASE_COMMAND( SAIFUN_SA25F0XX_PAGE_ERASE_CMD ); + REG_WR( pDevice, Nvram.Config2, value32 ); + + /* Configure the write command to be "page write". */ + value32 = REG_RD( pDevice, Nvram.Config3 ); + value32 &= ~NVRAM_WRITE_UNBUFFERED_COMMAND( NVRAM_COMMAND_MASK ); + value32 |= NVRAM_WRITE_UNBUFFERED_COMMAND( SAIFUN_SA25F0XX_PAGE_WRITE_CMD ); + REG_WR( pDevice, Nvram.Config3, value32 ); + + /* Make sure the "write enable" command is correct. */ + value32 = REG_RD( pDevice, Nvram.Write1 ); + value32 &= ~NVRAM_WRITE1_WRENA_CMD( NVRAM_COMMAND_MASK ); + value32 |= NVRAM_WRITE1_WRENA_CMD( SAIFUN_SA25F0XX_WRENA_CMD ); + REG_WR( pDevice, Nvram.Write1, value32 ); + + pagemask = SAIFUN_SA25F0XX_PAGE_MASK; + } + else + { + /* Unsupported flash type */ + return LM_STATUS_FAILURE; + } + + if( size == 0 ) + { + status = LM_STATUS_SUCCESS; + goto done; + } + + while( size > 0 ) + { + /* Align the offset to a page boundary. */ + physaddr = offset & ~pagemask; + + status = LM_NVRAM_ReadBlock( pDevice, physaddr, + pDevice->flashbuffer, + pagesize ); + if( status == LM_STATUS_FAILURE ) + { + break; + } + + /* Calculate the target index. */ + tgtoff = offset & pagemask; + + /* Copy the new data into the save buffer. */ + for( i = tgtoff; i < pagesize && size > 0; i++ ) + { + pDevice->flashbuffer[i] = *data++; + size--; + } + + /* Move the offset to the next page. */ + offset = offset + (pagesize - tgtoff); + + /* + * The LM_NVRAM_ReadBlock() function releases + * the access enable bit. Reacquire it. + */ + if( (pDevice->Flags & PROTECTED_NVRAM_FLAG) == 0) + REG_WR(pDevice, Nvram.NvmAccess, NVRAM_ACCESS_ENABLE); + + + /* + * Before we can erase the flash page, we need + * to issue a special "write enable" command. + */ + ctrlreg = NVRAM_CMD_WRITE_ENABLE | NVRAM_CMD_DO_IT | NVRAM_CMD_DONE; + + status = LM_NVRAM_ExecuteCommand( pDevice, ctrlreg ); + if( status == LM_STATUS_FAILURE ) + { + break; + } + + /* Erase the target page */ + REG_WR(pDevice, Nvram.Addr, physaddr); + + ctrlreg = NVRAM_CMD_DO_IT | NVRAM_CMD_DONE | NVRAM_CMD_WR | + NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_ERASE; + + status = LM_NVRAM_ExecuteCommand( pDevice, ctrlreg ); + if( status == LM_STATUS_FAILURE ) + { + break; + } + + /* Issue another write enable to start the write. */ + ctrlreg = NVRAM_CMD_WRITE_ENABLE | NVRAM_CMD_DO_IT | NVRAM_CMD_DONE; + + status = LM_NVRAM_ExecuteCommand( pDevice, ctrlreg ); + if( status == LM_STATUS_FAILURE ) + { + break; + } + + /* Copy the data into our NIC's buffers. */ + for( i = 0; i < pagesize; i+= 4 ) + { + value32 = *((LM_UINT32 *)(&pDevice->flashbuffer[i])); + value32 = MM_SWAP_BE32( value32 ); + + /* Write the location we wish to write to. */ + REG_WR( pDevice, Nvram.Addr, physaddr ); + + /* Write the data we wish to write. */ + REG_WR( pDevice, Nvram.WriteData, value32 ); + + ctrlreg = NVRAM_CMD_DO_IT | NVRAM_CMD_DONE | NVRAM_CMD_WR; + + if( i == 0 ) + { + ctrlreg |= NVRAM_CMD_FIRST; + } + else if( i == (pagesize - 4) ) + { + ctrlreg |= NVRAM_CMD_LAST; + } + + status = LM_NVRAM_ExecuteCommand( pDevice, ctrlreg ); + if( status == LM_STATUS_FAILURE ) + { + size = 0; + break; + } + + physaddr += sizeof(LM_UINT32); + } + } + + /* Paranoia. Turn off the "write enable" flag. */ + ctrlreg = NVRAM_CMD_WRITE_DISABLE | NVRAM_CMD_DO_IT | NVRAM_CMD_DONE; + + status = LM_NVRAM_ExecuteCommand( pDevice, ctrlreg ); + +done: + + return status; +} /* LM_NVRAM_WriteBlockUnBuffered */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +STATIC LM_STATUS +LM_NVRAM_WriteBlockBuffered( PLM_DEVICE_BLOCK pDevice, LM_UINT32 offset, + LM_UINT8 * data, LM_UINT32 size ) +{ + LM_STATUS status; + LM_UINT32 value32; + LM_UINT32 bytecnt; + LM_UINT32 ctrlreg; + LM_UINT32 pageoff; + LM_UINT32 physaddr; + LM_UINT32 subword1; + LM_UINT32 subword2; + LM_UINT8 * dstptr; + + if(T3_ASIC_5752(pDevice->ChipRevId) && + (pDevice->flashinfo.jedecnum == JEDEC_ST || + pDevice->flashinfo.jedecnum == JEDEC_ATMEL )) + { + /* Do nothing as the 5752 does will take care of it */ + } + else if( pDevice->flashinfo.jedecnum == JEDEC_ST ) + { + /* + * Program our chip to look at bit0 of the NVRAM's status + * register when polling the write or erase operation status. + */ + value32 = REG_RD(pDevice, Nvram.Config1); + value32 &= ~FLASH_STATUS_BITS_MASK; + REG_WR( pDevice, Nvram.Config1, value32 ); + + /* Program the "read status" and "page erase" commands. */ + value32 = NVRAM_STATUS_COMMAND( ST_M45PEX0_READ_STATUS_CMD ) | + NVRAM_ERASE_COMMAND( ST_M45PEX0_PAGE_ERASE_CMD ); + REG_WR( pDevice, Nvram.Config2, value32 ); + + /* Set the write command to be "page program". */ + value32 = REG_RD(pDevice, Nvram.Config3); /* default = 0x03840a53 */ + value32 &= ~NVRAM_WRITE_UNBUFFERED_COMMAND( NVRAM_COMMAND_MASK ); + value32 |= NVRAM_WRITE_UNBUFFERED_COMMAND( ST_M45PEX0_PAGE_PRGM_CMD ); + REG_WR( pDevice, Nvram.Config3, value32 ); + + /* Set the "write enable" and "write disable" commands. */ + value32 = NVRAM_WRITE1_WRENA_CMD( ST_M45PEX0_WRENA_CMD ) | + NVRAM_WRITE1_WRDIS_CMD( ST_M45PEX0_WRDIS_CMD ); + REG_WR( pDevice, Nvram.Write1, value32 ); + } + else if( pDevice->flashinfo.jedecnum == JEDEC_ATMEL ) + { + if( pDevice->flashinfo.romtype == ROM_TYPE_EEPROM ) + { + #if 0 + Config1 = 0x2008200 + Config2 = 0x9f0081 + Config3 = 0xa184a053 + Write1 = 0xaf000400 + #endif + } + else if( pDevice->flashinfo.buffered == TRUE ) + { + /* + * Program our chip to look at bit7 of the NVRAM's status + * register when polling the write operation status. + */ + value32 = REG_RD(pDevice, Nvram.Config1); + value32 |= FLASH_STATUS_BITS_MASK; + REG_WR( pDevice, Nvram.Config1, value32 ); + + /* Set the write command to be "page program". */ + value32 = REG_RD(pDevice, Nvram.Config3); /* default = 0x03840a53 */ + value32 &= ~NVRAM_WRITE_UNBUFFERED_COMMAND( NVRAM_COMMAND_MASK ); + value32 |= NVRAM_WRITE_UNBUFFERED_COMMAND( ATMEL_AT45DB0X1B_BUFFER_WRITE_CMD ); + REG_WR( pDevice, Nvram.Config3, value32 ); + /* Config1 = 0x2008273 */ + /* Config2 = 0x00570081 */ + /* Config3 = 0x68848353 */ + } + else + { + /* NVRAM type unsupported. */ + return LM_STATUS_FAILURE; + } + } + else + { + /* NVRAM type unsupported. */ + return LM_STATUS_FAILURE; + } + + status = LM_STATUS_SUCCESS; + + if( offset & 0x3 ) + { + /* + * If our initial offset does not fall on a word boundary, we + * have to do a read / modify / write to preserve the + * preceding bits we are not interested in. + */ + status = LM_NVRAM_ReadBlock( pDevice, offset & ~0x3, + (LM_UINT8 *)&subword1, + sizeof(subword1) ); + if( status == LM_STATUS_FAILURE ) + { + return status; + } + } + + if( (offset + size) & 0x3 ) + { + /* + * Likewise, if our ending offset does not fall on a word + * boundary, we have to do a read / modify / write to + * preserve the trailing bits we are not interested in. + */ + status = LM_NVRAM_ReadBlock( pDevice, (offset + size) & ~0x3, + (LM_UINT8 *)&subword2, + sizeof(subword2) ); + if( status == LM_STATUS_FAILURE ) + { + return status; + } + } + + ctrlreg = NVRAM_CMD_FIRST; + + while( size > 0 ) + { + value32 = offset & 0x3; + if( value32 ) + { + /* + * We have to read / modify / write the data to + * preserve the flash contents preceding the offset. + */ + offset &= ~0x3; + + dstptr = ((LM_UINT8 *)(&value32)) + value32; + bytecnt = sizeof(LM_UINT32) - value32; + value32 = subword1; + } + else if( size < sizeof(LM_UINT32) ) + { + dstptr = (LM_UINT8 *)(&value32); + bytecnt = size; + value32 = subword2; + } + else + { + dstptr = (LM_UINT8 *)(&value32); + bytecnt = sizeof(LM_UINT32); + } + + if( size < bytecnt ) + { + bytecnt = size; + } + + memcpy( dstptr, (void *)data, bytecnt ); + + data += bytecnt; + size -= bytecnt; + + /* + * Swap the data so that the byte stream will be + * written the same in little and big endian systems. + */ + value32 = MM_SWAP_BE32(value32); + + /* Set the desired write data value to the flash. */ + REG_WR(pDevice, Nvram.WriteData, value32); + + pageoff = offset % pDevice->flashinfo.pagesize; + + /* Set the target address. */ + if( pDevice->flashinfo.jedecnum == JEDEC_ATMEL && + pDevice->flashinfo.romtype == ROM_TYPE_FLASH ) + { + /* + * If we're dealing with the special ATMEL part, we need to + * convert the submitted offset before it can be considered + * a physical address. + */ + LM_UINT32 pagenmbr; + + pagenmbr = offset / pDevice->flashinfo.pagesize; + pagenmbr = pagenmbr << ATMEL_AT45DB0X1B_PAGE_POS; + + physaddr = pagenmbr + pageoff; + } + else + { + physaddr = offset; + } + + REG_WR(pDevice, Nvram.Addr, physaddr); + + ctrlreg |= (NVRAM_CMD_DO_IT | NVRAM_CMD_DONE | NVRAM_CMD_WR); + + if( pageoff == 0 ) + { + /* Set CMD_FIRST when we are at the beginning of a page. */ + ctrlreg |= NVRAM_CMD_FIRST; + } + else if( pageoff == (pDevice->flashinfo.pagesize - 4) ) + { + /* + * Enable the write to the current page + * before moving on to the next one. + */ + ctrlreg |= NVRAM_CMD_LAST; + } + + if( size == 0 ) + { + ctrlreg |= NVRAM_CMD_LAST; + } + + if( pDevice->flashinfo.jedecnum == JEDEC_ST && + ((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5750) || + (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5714)) && + (ctrlreg & NVRAM_CMD_FIRST) ) + { + LM_UINT32 wrencmd; + + REG_WR(pDevice, Nvram.Write1, ST_M45PEX0_WRENA_CMD); + + /* We need to issue a special "write enable" command first. */ + wrencmd = NVRAM_CMD_WRITE_ENABLE | NVRAM_CMD_DO_IT | NVRAM_CMD_DONE; + + status = LM_NVRAM_ExecuteCommand( pDevice, wrencmd ); + if( status == LM_STATUS_FAILURE ) + { + return status; + } + } + + if( pDevice->flashinfo.romtype == ROM_TYPE_EEPROM ) + { + /* We always do complete word writes to eeprom. */ + ctrlreg |= (NVRAM_CMD_FIRST | NVRAM_CMD_LAST); + } + + status = LM_NVRAM_ExecuteCommand( pDevice, ctrlreg ); + if( status == LM_STATUS_FAILURE ) + { + break; + } + + offset += sizeof(LM_UINT32); + ctrlreg = 0; + } + + return status; +} /* LM_NVRAM_WriteBlockBuffered */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_STATUS LM_NVRAM_WriteBlock( PLM_DEVICE_BLOCK pDevice, LM_UINT32 offset, + LM_UINT8 * data, LM_UINT32 size ) +{ + LM_UINT32 value32; + LM_STATUS status; + + if( offset > pDevice->flashinfo.chipsize || + (offset + size) > pDevice->flashinfo.chipsize ) + { + return LM_STATUS_FAILURE; + } + + if( size == 0 ) + { + return LM_STATUS_SUCCESS; + } + + if( T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700 || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701 ) + { + status = LM_EEPROM_WriteBlock( pDevice, offset, data, size ); + } + else + { + status = LM_NVRAM_AcquireLock( pDevice ); + if( status == LM_STATUS_FAILURE ) + { + return status; + } + + if(T3_ASIC_IS_575X_PLUS(pDevice->ChipRevId)) + { + if( (pDevice->Flags & PROTECTED_NVRAM_FLAG) == 0) + { + value32 = REG_RD( pDevice, Nvram.NvmAccess ); + value32 |= (NVRAM_ACCESS_ENABLE | NVRAM_ACCESS_WRITE_ENABLE); + REG_WR( pDevice, Nvram.NvmAccess, value32 ); + } + } + + /* Enable EEPROM write. */ + if( pDevice->Flags & EEPROM_WP_FLAG ) + { + REG_WR(pDevice, Grc.LocalCtrl, + pDevice->GrcLocalCtrl | GRC_MISC_LOCAL_CTRL_GPIO_OE1); + REG_RD_BACK(pDevice, Grc.LocalCtrl); + MM_Wait(40); + + value32 = REG_RD(pDevice, Grc.LocalCtrl); + if( value32 & GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1 ) + { + status = LM_STATUS_FAILURE; + goto error; + } + } + + value32 = REG_RD(pDevice, Grc.Mode); + value32 |= GRC_MODE_NVRAM_WRITE_ENABLE; + REG_WR(pDevice, Grc.Mode, value32); + + if( pDevice->flashinfo.buffered == TRUE || + pDevice->flashinfo.romtype == ROM_TYPE_EEPROM ) + { + status = LM_NVRAM_WriteBlockBuffered(pDevice, offset, data, size); + } + else + { + status = LM_NVRAM_WriteBlockUnBuffered(pDevice, offset, data, size); + } + + value32 = REG_RD(pDevice, Grc.Mode); + value32 &= ~GRC_MODE_NVRAM_WRITE_ENABLE; + REG_WR(pDevice, Grc.Mode, value32); + + if( pDevice->Flags & EEPROM_WP_FLAG ) + { + REG_WR(pDevice, Grc.LocalCtrl, pDevice->GrcLocalCtrl | + GRC_MISC_LOCAL_CTRL_GPIO_OE1 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1); + REG_RD_BACK(pDevice, Grc.LocalCtrl); + MM_Wait(40); + } + +error: + + if(T3_ASIC_IS_575X_PLUS(pDevice->ChipRevId)) + { + if( (pDevice->Flags & PROTECTED_NVRAM_FLAG) == 0) + { + value32 = REG_RD(pDevice, Nvram.NvmAccess); + value32 &= ~(NVRAM_ACCESS_ENABLE | NVRAM_ACCESS_WRITE_ENABLE); + REG_WR(pDevice, Nvram.NvmAccess, value32); + } + } + + LM_NVRAM_ReleaseLock( pDevice ); + } + + return status; +} /* LM_NVRAM_WriteBlock */ + + +LM_STATUS LM_NvramWriteBlock( PLM_DEVICE_BLOCK pDevice, LM_UINT32 offset, + LM_UINT32 * data, LM_UINT32 size ) +{ + /* BCM4785: Avoid all access to NVRAM & EEPROM. */ + if (pDevice->Flags & SB_CORE_FLAG) + return LM_STATUS_FAILURE; + + return LM_NVRAM_WriteBlock( pDevice, offset, (LM_UINT8 *)data, size * 4 ); +} + +#endif /* ETHTOOL_SEEPROM */ + + +static int +bcm_ether_atoe(char *p, struct ether_addr *ea) +{ + int i = 0; + + for (;;) { + ea->octet[i++] = (char) simple_strtoul(p, &p, 16); + if (!*p++ || i == 6) + break; + } + + return (i == 6); +} + +/******************************************************************************/ +/* Description: */ +/* This routine initializes default parameters and reads the PCI */ +/* configurations. */ +/* */ +/* Return: */ +/* LM_STATUS_SUCCESS */ +/******************************************************************************/ +LM_STATUS +LM_GetAdapterInfo( +PLM_DEVICE_BLOCK pDevice) +{ + PLM_ADAPTER_INFO pAdapterInfo; + LM_UINT32 Value32, LedCfg, Ver; + LM_STATUS Status; + LM_UINT32 EeSigFound; + LM_UINT32 EePhyTypeSerdes = 0; + LM_UINT32 EePhyId = 0; + + /* Get Device Id and Vendor Id */ + Status = MM_ReadConfig32(pDevice, PCI_VENDOR_ID_REG, &Value32); + if(Status != LM_STATUS_SUCCESS) + { + return Status; + } + pDevice->PciVendorId = (LM_UINT16) Value32; + pDevice->PciDeviceId = (LM_UINT16) (Value32 >> 16); + + Status = MM_ReadConfig32(pDevice, PCI_REV_ID_REG, &Value32); + if(Status != LM_STATUS_SUCCESS) + { + return Status; + } + pDevice->PciRevId = (LM_UINT8) Value32; + + /* Get chip revision id. */ + Status = MM_ReadConfig32(pDevice, T3_PCI_MISC_HOST_CTRL_REG, &Value32); + pDevice->ChipRevId = Value32 >> 16; + + /* determine if it is PCIE system */ + if( (Value32 = MM_FindCapability(pDevice, T3_PCIE_CAPABILITY_ID)) != 0) + { + pDevice->Flags |= PCI_EXPRESS_FLAG; + } + + /* Get subsystem vendor. */ + Status = MM_ReadConfig32(pDevice, PCI_SUBSYSTEM_VENDOR_ID_REG, &Value32); + if(Status != LM_STATUS_SUCCESS) + { + return Status; + } + pDevice->SubsystemVendorId = (LM_UINT16) Value32; + + /* Get PCI subsystem id. */ + pDevice->SubsystemId = (LM_UINT16) (Value32 >> 16); + + /* Read bond id for baxter A0 since it has same rev id as hamilton A0*/ + + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5714_A0) { + MM_WriteConfig32(pDevice, T3_PCI_MISC_HOST_CTRL_REG, Value32 | MISC_HOST_CTRL_ENABLE_INDIRECT_ACCESS); + + Value32 = LM_RegRdInd(pDevice, 0x6804); + Value32 &= GRC_MISC_BD_ID_MASK; + + if((Value32 == 0)||(Value32 == 0x8000)) { + pDevice->ChipRevId = T3_CHIP_ID_5752_A0; + }else{ + pDevice->ChipRevId = T3_CHIP_ID_5714_A0; + } + + Status = MM_ReadConfig32(pDevice, T3_PCI_MISC_HOST_CTRL_REG, &Value32); + MM_WriteConfig32(pDevice, T3_PCI_MISC_HOST_CTRL_REG, Value32 & ~ MISC_HOST_CTRL_ENABLE_INDIRECT_ACCESS); + } + + + /* Get the cache line size. */ + MM_ReadConfig32(pDevice, PCI_CACHE_LINE_SIZE_REG, &Value32); + pDevice->CacheLineSize = (LM_UINT8) Value32; + pDevice->SavedCacheLineReg = Value32; + + if(pDevice->ChipRevId != T3_CHIP_ID_5703_A1 && + pDevice->ChipRevId != T3_CHIP_ID_5703_A2 && + pDevice->ChipRevId != T3_CHIP_ID_5704_A0) + { + pDevice->Flags &= ~UNDI_FIX_FLAG; + } +#ifndef PCIX_TARGET_WORKAROUND + pDevice->Flags &= ~UNDI_FIX_FLAG; +#endif + /* Map the memory base to system address space. */ + if (!(pDevice->Flags & UNDI_FIX_FLAG)) + { + Status = MM_MapMemBase(pDevice); + if(Status != LM_STATUS_SUCCESS) + { + return Status; + } + /* Initialize the memory view pointer. */ + pDevice->pMemView = (PT3_STD_MEM_MAP) pDevice->pMappedMemBase; + } + + if ((T3_CHIP_REV(pDevice->ChipRevId) == T3_CHIP_REV_5700_BX) || + (T3_CHIP_REV(pDevice->ChipRevId) == T3_CHIP_REV_5704_AX)) + { + pDevice->Flags |= TX_4G_WORKAROUND_FLAG; + } + if ( (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) || + (pDevice->Flags == PCI_EXPRESS_FLAG)) + { + pDevice->Flags |= REG_RD_BACK_FLAG; + } + + if(pDevice->ChipRevId==T3_CHIP_ID_5750_A0) + return LM_STATUS_UNKNOWN_ADAPTER; + +#ifdef PCIX_TARGET_WORKAROUND + MM_ReadConfig32(pDevice, T3_PCI_STATE_REG, &Value32); + if((Value32 & T3_PCI_STATE_CONVENTIONAL_PCI_MODE) == 0) + { + if(T3_CHIP_REV(pDevice->ChipRevId) == T3_CHIP_REV_5700_BX) + { + pDevice->Flags |= ENABLE_PCIX_FIX_FLAG; + } + } + if (pDevice->Flags & UNDI_FIX_FLAG) + { + pDevice->Flags |= ENABLE_PCIX_FIX_FLAG; + } +#endif + /* Bx bug: due to the "byte_enable bug" in PCI-X mode, the power */ + /* management register may be clobbered which may cause the */ + /* BCM5700 to go into D3 state. While in this state, we will */ + /* need to restore the device to D0 state. */ + MM_ReadConfig32(pDevice, T3_PCI_PM_STATUS_CTRL_REG, &Value32); + Value32 |= T3_PM_PME_ASSERTED; + Value32 &= ~T3_PM_POWER_STATE_MASK; + Value32 |= T3_PM_POWER_STATE_D0; + MM_WriteConfig32(pDevice, T3_PCI_PM_STATUS_CTRL_REG, Value32); + + /* read the current PCI command word */ + MM_ReadConfig32(pDevice, PCI_COMMAND_REG, &Value32); + + /* Make sure bus-mastering is enabled. */ + Value32 |= PCI_BUSMASTER_ENABLE; + +#ifdef PCIX_TARGET_WORKAROUND + /* if we are in PCI-X mode, also make sure mem-mapping and SERR#/PERR# + are enabled */ + if (pDevice->Flags & ENABLE_PCIX_FIX_FLAG) { + Value32 |= (PCI_MEM_SPACE_ENABLE | PCI_SYSTEM_ERROR_ENABLE | + PCI_PARITY_ERROR_ENABLE); + } + if (pDevice->Flags & UNDI_FIX_FLAG) + { + Value32 &= ~PCI_MEM_SPACE_ENABLE; + } + +#endif + + if (pDevice->Flags & ENABLE_MWI_FLAG) + { + Value32 |= PCI_MEMORY_WRITE_INVALIDATE; + } + else { + Value32 &= (~PCI_MEMORY_WRITE_INVALIDATE); + } + + /* save the value we are going to write into the PCI command word */ + pDevice->PciCommandStatusWords = Value32; + + Status = MM_WriteConfig32(pDevice, PCI_COMMAND_REG, Value32); + if(Status != LM_STATUS_SUCCESS) + { + return Status; + } + + /* Setup the mode registers. */ + pDevice->MiscHostCtrl = + MISC_HOST_CTRL_MASK_PCI_INT | + MISC_HOST_CTRL_ENABLE_ENDIAN_WORD_SWAP | +#ifdef BIG_ENDIAN_HOST + MISC_HOST_CTRL_ENABLE_ENDIAN_BYTE_SWAP | +#endif /* BIG_ENDIAN_HOST */ + MISC_HOST_CTRL_ENABLE_INDIRECT_ACCESS | + MISC_HOST_CTRL_ENABLE_PCI_STATE_REG_RW; + /* write to PCI misc host ctr first in order to enable indirect accesses */ + MM_WriteConfig32(pDevice, T3_PCI_MISC_HOST_CTRL_REG, pDevice->MiscHostCtrl); + + /* Set power state to D0. */ + LM_SetPowerState(pDevice, LM_POWER_STATE_D0); + + /* Preserve HOST_STACK_UP bit in case ASF firmware is running */ + Value32 = REG_RD(pDevice, Grc.Mode) & GRC_MODE_HOST_STACK_UP; +#ifdef BIG_ENDIAN_HOST + Value32 |= GRC_MODE_BYTE_SWAP_NON_FRAME_DATA | + GRC_MODE_WORD_SWAP_NON_FRAME_DATA; +#else + Value32 |= GRC_MODE_BYTE_SWAP_NON_FRAME_DATA | GRC_MODE_BYTE_SWAP_DATA; +#endif + REG_WR(pDevice, Grc.Mode, Value32); + + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700) + { + REG_WR(pDevice, Grc.LocalCtrl, GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1 | + GRC_MISC_LOCAL_CTRL_GPIO_OE1); + REG_RD_BACK(pDevice, Grc.LocalCtrl); + } + MM_Wait(40); + + /* Enable memory arbiter*/ + if(T3_ASIC_5714_FAMILY(pDevice->ChipRevId) ) + { + Value32 = REG_RD(pDevice,MemArbiter.Mode); + REG_WR(pDevice, MemArbiter.Mode, T3_MEM_ARBITER_MODE_ENABLE | Value32); + } + else + { + REG_WR(pDevice, MemArbiter.Mode, T3_MEM_ARBITER_MODE_ENABLE); + } + + + LM_SwitchClocks(pDevice); + + REG_WR(pDevice, PciCfg.MemWindowBaseAddr, 0); + + /* Check to see if PXE ran and did not shutdown properly */ + if ((REG_RD(pDevice, DmaWrite.Mode) & DMA_WRITE_MODE_ENABLE) || + !(REG_RD(pDevice, PciCfg.MiscHostCtrl) & MISC_HOST_CTRL_MASK_PCI_INT)) + { + LM_DisableInterrupt(pDevice); + /* assume ASF is enabled */ + pDevice->AsfFlags = ASF_ENABLED; + if (T3_ASIC_IS_575X_PLUS(pDevice->ChipRevId)) + { + pDevice->AsfFlags |= ASF_NEW_HANDSHAKE; + } + LM_ShutdownChip(pDevice, LM_SHUTDOWN_RESET); + pDevice->AsfFlags = 0; + } +#ifdef PCIX_TARGET_WORKAROUND + MM_ReadConfig32(pDevice, T3_PCI_STATE_REG, &Value32); + if (!(pDevice->Flags & ENABLE_PCIX_FIX_FLAG) && + ((Value32 & T3_PCI_STATE_CONVENTIONAL_PCI_MODE) == 0)) + { + if (pDevice->ChipRevId == T3_CHIP_ID_5701_A0 || + pDevice->ChipRevId == T3_CHIP_ID_5701_B0 || + pDevice->ChipRevId == T3_CHIP_ID_5701_B2 || + pDevice->ChipRevId == T3_CHIP_ID_5701_B5) + { + MM_MEMWRITEL(&(pDevice->pMemView->uIntMem.MemBlock32K[0x300]), 0); + MM_MEMWRITEL(&(pDevice->pMemView->uIntMem.MemBlock32K[0x301]), 0); + MM_MEMWRITEL(&(pDevice->pMemView->uIntMem.MemBlock32K[0x301]), + 0xffffffff); + if (MM_MEMREADL(&(pDevice->pMemView->uIntMem.MemBlock32K[0x300]))) + { + pDevice->Flags |= ENABLE_PCIX_FIX_FLAG; + } + } + } +#endif + + LM_NVRAM_Init(pDevice); + + Status = LM_STATUS_FAILURE; + + /* BCM4785: Use the MAC address stored in the main flash. */ + if (pDevice->Flags & SB_CORE_FLAG) { + bcm_ether_atoe(getvar(NULL, "et0macaddr"), (struct ether_addr *)pDevice->NodeAddress); + Status = LM_STATUS_SUCCESS; + } else { + /* Get the node address. First try to get in from the shared memory. */ + /* If the signature is not present, then get it from the NVRAM. */ + Value32 = MEM_RD_OFFSET(pDevice, T3_MAC_ADDR_HIGH_MAILBOX); + if((Value32 >> 16) == 0x484b) + { + int i; + + pDevice->NodeAddress[0] = (LM_UINT8) (Value32 >> 8); + pDevice->NodeAddress[1] = (LM_UINT8) Value32; + + Value32 = MEM_RD_OFFSET(pDevice, T3_MAC_ADDR_LOW_MAILBOX); + + pDevice->NodeAddress[2] = (LM_UINT8) (Value32 >> 24); + pDevice->NodeAddress[3] = (LM_UINT8) (Value32 >> 16); + pDevice->NodeAddress[4] = (LM_UINT8) (Value32 >> 8); + pDevice->NodeAddress[5] = (LM_UINT8) Value32; + + /* Check for null MAC address which can happen with older boot code */ + for (i = 0; i < 6; i++) + { + if (pDevice->NodeAddress[i] != 0) + { + Status = LM_STATUS_SUCCESS; + break; + } + } + } + } + + if (Status != LM_STATUS_SUCCESS) + { + int MacOffset; + + MacOffset = 0x7c; + if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5704 || + (T3_ASIC_5714_FAMILY(pDevice->ChipRevId)) ) + { + if (REG_RD(pDevice, PciCfg.DualMacCtrl) & T3_DUAL_MAC_ID) + { + MacOffset = 0xcc; + } + /* the boot code is not running */ + if (LM_NVRAM_AcquireLock(pDevice) != LM_STATUS_SUCCESS) + { + REG_WR(pDevice, Nvram.Cmd, NVRAM_CMD_RESET); + } + else + { + LM_NVRAM_ReleaseLock(pDevice); + } + } + + Status = LM_NvramRead(pDevice, MacOffset, &Value32); + if(Status == LM_STATUS_SUCCESS) + { + LM_UINT8 *c = (LM_UINT8 *) &Value32; + + pDevice->NodeAddress[0] = c[2]; + pDevice->NodeAddress[1] = c[3]; + + Status = LM_NvramRead(pDevice, MacOffset + 4, &Value32); + + c = (LM_UINT8 *) &Value32; + pDevice->NodeAddress[2] = c[0]; + pDevice->NodeAddress[3] = c[1]; + pDevice->NodeAddress[4] = c[2]; + pDevice->NodeAddress[5] = c[3]; + } + } + + if(Status != LM_STATUS_SUCCESS) + { + Value32 = REG_RD(pDevice, MacCtrl.MacAddr[0].High); + pDevice->NodeAddress[0] = (Value32 >> 8) & 0xff; + pDevice->NodeAddress[1] = Value32 & 0xff; + Value32 = REG_RD(pDevice, MacCtrl.MacAddr[0].Low); + pDevice->NodeAddress[2] = (Value32 >> 24) & 0xff; + pDevice->NodeAddress[3] = (Value32 >> 16) & 0xff; + pDevice->NodeAddress[4] = (Value32 >> 8) & 0xff; + pDevice->NodeAddress[5] = Value32 & 0xff; + B57_ERR(("WARNING: Cannot get MAC addr from NVRAM, using %2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", + pDevice->NodeAddress[0], pDevice->NodeAddress[1], + pDevice->NodeAddress[2], pDevice->NodeAddress[3], + pDevice->NodeAddress[4], pDevice->NodeAddress[5])); + } + + memcpy(pDevice->PermanentNodeAddress, pDevice->NodeAddress, 6); + + /* Initialize the default values. */ + pDevice->TxPacketDescCnt = DEFAULT_TX_PACKET_DESC_COUNT; + pDevice->RxStdDescCnt = DEFAULT_STD_RCV_DESC_COUNT; + pDevice->RxCoalescingTicks = DEFAULT_RX_COALESCING_TICKS; + pDevice->TxCoalescingTicks = DEFAULT_TX_COALESCING_TICKS; + pDevice->RxMaxCoalescedFrames = DEFAULT_RX_MAX_COALESCED_FRAMES; + pDevice->TxMaxCoalescedFrames = DEFAULT_TX_MAX_COALESCED_FRAMES; + pDevice->RxCoalescingTicksDuringInt = BAD_DEFAULT_VALUE; + pDevice->TxCoalescingTicksDuringInt = BAD_DEFAULT_VALUE; + pDevice->RxMaxCoalescedFramesDuringInt = BAD_DEFAULT_VALUE; + pDevice->TxMaxCoalescedFramesDuringInt = BAD_DEFAULT_VALUE; + pDevice->StatsCoalescingTicks = DEFAULT_STATS_COALESCING_TICKS; + pDevice->TxMtu = MAX_ETHERNET_PACKET_SIZE_NO_CRC; + pDevice->RxMtu = MAX_ETHERNET_PACKET_SIZE_NO_CRC; + pDevice->DisableAutoNeg = FALSE; + pDevice->PhyIntMode = T3_PHY_INT_MODE_AUTO; + pDevice->LinkChngMode = T3_LINK_CHNG_MODE_AUTO; + + pDevice->PhyFlags = 0; + + if (!(pDevice->Flags & PCI_EXPRESS_FLAG)) + pDevice->Flags |= DELAY_PCI_GRANT_FLAG; + + pDevice->RequestedLineSpeed = LM_LINE_SPEED_AUTO; + pDevice->TaskOffloadCap = LM_TASK_OFFLOAD_NONE; + pDevice->TaskToOffload = LM_TASK_OFFLOAD_NONE; + pDevice->FlowControlCap = LM_FLOW_CONTROL_AUTO_PAUSE; +#ifdef INCLUDE_TBI_SUPPORT + pDevice->TbiFlags = 0; + pDevice->IgnoreTbiLinkChange = FALSE; +#endif +#ifdef INCLUDE_TCP_SEG_SUPPORT + pDevice->LargeSendMaxSize = T3_TCP_SEG_MAX_OFFLOAD_SIZE; + pDevice->LargeSendMinNumSeg = T3_TCP_SEG_MIN_NUM_SEG; +#endif + + if ((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5703) || + (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5704) || + (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5705)) + { + pDevice->PhyFlags |= PHY_RESET_ON_LINKDOWN; + pDevice->PhyFlags |= PHY_CHECK_TAPS_AFTER_RESET; + } + if ((T3_CHIP_REV(pDevice->ChipRevId) == T3_CHIP_REV_5703_AX) || + (T3_CHIP_REV(pDevice->ChipRevId) == T3_CHIP_REV_5704_AX)) + { + pDevice->PhyFlags |= PHY_ADC_FIX; + } + if (pDevice->ChipRevId == T3_CHIP_ID_5704_A0) + { + pDevice->PhyFlags |= PHY_5704_A0_FIX; + } + if (T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) + { + pDevice->PhyFlags |= PHY_5705_5750_FIX; + } + /* Ethernet@Wirespeed is supported on 5701,5702,5703,5704,5705a0,5705a1 */ + if ((T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5700) && + !((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5705) && + (pDevice->ChipRevId != T3_CHIP_ID_5705_A0) && + (pDevice->ChipRevId != T3_CHIP_ID_5705_A1))) + { + pDevice->PhyFlags |= PHY_ETHERNET_WIRESPEED; + } + + switch (T3_ASIC_REV(pDevice->ChipRevId)) + { + case T3_ASIC_REV_5704: + pDevice->MbufBase = T3_NIC_MBUF_POOL_ADDR; + pDevice->MbufSize = T3_NIC_MBUF_POOL_SIZE64; + break; + default: + pDevice->MbufBase = T3_NIC_MBUF_POOL_ADDR; + pDevice->MbufSize = T3_NIC_MBUF_POOL_SIZE96; + break; + } + + pDevice->LinkStatus = LM_STATUS_LINK_DOWN; + pDevice->QueueRxPackets = TRUE; + +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + + if(T3_ASIC_IS_JUMBO_CAPABLE(pDevice->ChipRevId)){ + if( ! T3_ASIC_5714_FAMILY(pDevice->ChipRevId)) + pDevice->RxJumboDescCnt = DEFAULT_JUMBO_RCV_DESC_COUNT; + pDevice->Flags |= JUMBO_CAPABLE_FLAG; + } + +#endif /* T3_JUMBO_RCV_RCB_ENTRY_COUNT */ + + pDevice->BondId = REG_RD(pDevice, Grc.MiscCfg) & GRC_MISC_BD_ID_MASK; + + if(((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) && + ((pDevice->BondId == 0x10000) || (pDevice->BondId == 0x18000))) || + ((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5703) && + ((pDevice->BondId == 0x14000) || (pDevice->BondId == 0x1c000)))) + { + return LM_STATUS_UNKNOWN_ADAPTER; + } + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5703) + { + if ((pDevice->BondId == 0x8000) || (pDevice->BondId == 0x4000)) + { + pDevice->PhyFlags |= PHY_NO_GIGABIT; + } + } + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5705) + { + if ((pDevice->BondId == GRC_MISC_BD_ID_5788) || + (pDevice->BondId == GRC_MISC_BD_ID_5788M)) + { + pDevice->Flags |= BCM5788_FLAG; + } + + if ((pDevice->PciDeviceId == T3_PCI_DEVICE_ID(T3_PCI_ID_BCM5901)) || + (pDevice->PciDeviceId == T3_PCI_DEVICE_ID(T3_PCI_ID_BCM5901A2)) || + (pDevice->PciDeviceId == T3_PCI_DEVICE_ID(T3_PCI_ID_BCM5705F))) + { + pDevice->PhyFlags |= PHY_NO_GIGABIT; + } + } + + if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5750) + { + if ( (pDevice->PciDeviceId == T3_PCI_DEVICE_ID(T3_PCI_ID_BCM5751F))|| + (pDevice->PciDeviceId == T3_PCI_DEVICE_ID(T3_PCI_ID_BCM5753F))) + { + pDevice->PhyFlags |= PHY_NO_GIGABIT; + } + } + + /* CIOBE multisplit has a bug */ + + /* Get Eeprom info. */ + Value32 = MEM_RD_OFFSET(pDevice, T3_NIC_DATA_SIG_ADDR); + if (Value32 == T3_NIC_DATA_SIG) + { + EeSigFound = TRUE; + Value32 = MEM_RD_OFFSET(pDevice, T3_NIC_DATA_NIC_CFG_ADDR); + + /* For now the 5753 cannot drive gpio2 or ASF will blow */ + if(Value32 & T3_NIC_GPIO2_NOT_AVAILABLE) + { + pDevice->Flags |= GPIO2_DONOT_OUTPUT; + } + + if (Value32 & T3_NIC_MINI_PCI) + { + pDevice->Flags |= MINI_PCI_FLAG; + } + /* Determine PHY type. */ + switch (Value32 & T3_NIC_CFG_PHY_TYPE_MASK) + { + case T3_NIC_CFG_PHY_TYPE_COPPER: + EePhyTypeSerdes = FALSE; + break; + + case T3_NIC_CFG_PHY_TYPE_FIBER: + EePhyTypeSerdes = TRUE; + break; + + default: + EePhyTypeSerdes = FALSE; + break; + } + + if ( T3_ASIC_IS_575X_PLUS(pDevice->ChipRevId)) + { + LedCfg = MEM_RD_OFFSET(pDevice, T3_NIC_DATA_NIC_CFG_ADDR2); + LedCfg = LedCfg & (T3_NIC_CFG_LED_MODE_MASK | + T3_SHASTA_EXT_LED_MODE_MASK); + } + else + { + /* Determine PHY led mode. for legacy devices */ + LedCfg = Value32 & T3_NIC_CFG_LED_MODE_MASK; + } + + switch (LedCfg) + { + default: + case T3_NIC_CFG_LED_PHY_MODE_1: + pDevice->LedCtrl = LED_CTRL_PHY_MODE_1; + break; + + case T3_NIC_CFG_LED_PHY_MODE_2: + pDevice->LedCtrl = LED_CTRL_PHY_MODE_2; + break; + + case T3_NIC_CFG_LED_MAC_MODE: + pDevice->LedCtrl = LED_CTRL_MAC_MODE; + break; + + case T3_SHASTA_EXT_LED_SHARED_TRAFFIC_LINK_MODE: + pDevice->LedCtrl = LED_CTRL_SHARED_TRAFFIC_LINK; + if ((pDevice->ChipRevId != T3_CHIP_ID_5750_A0) && + (pDevice->ChipRevId != T3_CHIP_ID_5750_A1)) + { + pDevice->LedCtrl |= LED_CTRL_PHY_MODE_1 | + LED_CTRL_PHY_MODE_2; + } + break; + + case T3_SHASTA_EXT_LED_MAC_MODE: + pDevice->LedCtrl = LED_CTRL_SHASTA_MAC_MODE; + break; + + case T3_SHASTA_EXT_LED_WIRELESS_COMBO_MODE: + pDevice->LedCtrl = LED_CTRL_WIRELESS_COMBO; + if (pDevice->ChipRevId != T3_CHIP_ID_5750_A0) + { + pDevice->LedCtrl |= LED_CTRL_PHY_MODE_1 | + LED_CTRL_PHY_MODE_2; + } + break; + + } + + if (((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700 || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701)) && + (pDevice->SubsystemVendorId == T3_SVID_DELL)) + { + pDevice->LedCtrl = LED_CTRL_PHY_MODE_2; + } + + if((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5703) || + (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5704) || + (T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) ) + { + /* Enable EEPROM write protection. */ + if(Value32 & T3_NIC_EEPROM_WP) + { + pDevice->Flags |= EEPROM_WP_FLAG; + } + } + pDevice->AsfFlags = 0; +#ifdef BCM_ASF + if (Value32 & T3_NIC_CFG_ENABLE_ASF) + { + pDevice->AsfFlags |= ASF_ENABLED; + if (T3_ASIC_IS_575X_PLUS(pDevice->ChipRevId)) + { + pDevice->AsfFlags |= ASF_NEW_HANDSHAKE; + } + } +#endif + if (Value32 & T3_NIC_FIBER_WOL_CAPABLE) + { + pDevice->Flags |= FIBER_WOL_CAPABLE_FLAG; + } + if (Value32 & T3_NIC_WOL_LIMIT_10) + { + pDevice->Flags |= WOL_LIMIT_10MBPS_FLAG; + } + + /* Get the PHY Id. */ + Value32 = MEM_RD_OFFSET(pDevice, T3_NIC_DATA_PHY_ID_ADDR); + if (Value32) + { + EePhyId = (((Value32 & T3_NIC_PHY_ID1_MASK) >> 16) & + PHY_ID1_OUI_MASK) << 10; + + Value32 = Value32 & T3_NIC_PHY_ID2_MASK; + + EePhyId |= ((Value32 & PHY_ID2_OUI_MASK) << 16) | + (Value32 & PHY_ID2_MODEL_MASK) | (Value32 & PHY_ID2_REV_MASK); + } + else + { + EePhyId = 0; + if (!EePhyTypeSerdes && !(pDevice->AsfFlags & ASF_ENABLED)) + { + /* reset PHY if boot code couldn't read the PHY ID */ + LM_ResetPhy(pDevice); + } + } + + Ver = MEM_RD_OFFSET(pDevice, T3_NIC_DATA_VER); + Ver >>= T3_NIC_DATA_VER_SHIFT; + + Value32 = 0; + if((T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5700) && + (T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5701) && + (T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5703) && + (Ver > 0) && (Ver < 0x100)){ + + Value32 = MEM_RD_OFFSET(pDevice, T3_NIC_DATA_NIC_CFG_ADDR2); + + if (Value32 & T3_NIC_CFG_CAPACITIVE_COUPLING) + { + pDevice->PhyFlags |= PHY_CAPACITIVE_COUPLING; + } + + if (Value32 & T3_NIC_CFG_PRESERVE_PREEMPHASIS) + { + pDevice->TbiFlags |= TBI_DO_PREEMPHASIS; + } + + } + + } + else + { + EeSigFound = FALSE; + } + + /* Set the PHY address. */ + pDevice->PhyAddr = PHY_DEVICE_ID; + + /* Disable auto polling. */ + pDevice->MiMode = 0xc0000; + REG_WR(pDevice, MacCtrl.MiMode, pDevice->MiMode); + REG_RD_BACK(pDevice, MacCtrl.MiMode); + MM_Wait(80); + + if (pDevice->AsfFlags & ASF_ENABLED) + { + /* Reading PHY registers will contend with ASF */ + pDevice->PhyId = 0; + } + else + { + /* Get the PHY id. */ + LM_GetPhyId(pDevice); + } + + /* Set the EnableTbi flag to false if we have a copper PHY. */ + switch(pDevice->PhyId & PHY_ID_MASK) + { + case PHY_BCM5400_PHY_ID: + case PHY_BCM5401_PHY_ID: + case PHY_BCM5411_PHY_ID: + case PHY_BCM5461_PHY_ID: + case PHY_BCM5701_PHY_ID: + case PHY_BCM5703_PHY_ID: + case PHY_BCM5704_PHY_ID: + case PHY_BCM5705_PHY_ID: + case PHY_BCM5750_PHY_ID: + break; + case PHY_BCM5714_PHY_ID: + case PHY_BCM5780_PHY_ID: + if(EePhyTypeSerdes == TRUE) + { + pDevice->PhyFlags |= PHY_IS_FIBER; + } + break; + case PHY_BCM5752_PHY_ID: + break; + + case PHY_BCM8002_PHY_ID: + pDevice->TbiFlags |= ENABLE_TBI_FLAG; + break; + + default: + + if (EeSigFound) + { + pDevice->PhyId = EePhyId; + + if (EePhyTypeSerdes && ((pDevice->PhyId == PHY_BCM5780_PHY_ID)) ) + { + pDevice->PhyFlags |= PHY_IS_FIBER; + } + else if (EePhyTypeSerdes) + { + pDevice->TbiFlags |= ENABLE_TBI_FLAG; + } + } + else if ((pAdapterInfo = LM_GetAdapterInfoBySsid( + pDevice->SubsystemVendorId, + pDevice->SubsystemId))) + { + pDevice->PhyId = pAdapterInfo->PhyId; + if (pAdapterInfo->Serdes) + { + pDevice->TbiFlags |= ENABLE_TBI_FLAG; + } + } + else + { + if (UNKNOWN_PHY_ID(pDevice->PhyId)) + { + LM_ResetPhy(pDevice); + LM_GetPhyId(pDevice); + } + } + break; + } + + if(UNKNOWN_PHY_ID(pDevice->PhyId) && + !(pDevice->TbiFlags & ENABLE_TBI_FLAG)) + { + if (pDevice->Flags & ROBO_SWITCH_FLAG) { + B57_ERR(("PHY ID unknown, assume it is a copper PHY.\n")); + } else { + pDevice->TbiFlags |= ENABLE_TBI_FLAG; + B57_ERR(("PHY ID unknown, assume it is SerDes\n")); + } + } + + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5703) + { + if((pDevice->SavedCacheLineReg & 0xff00) < 0x4000) + { + pDevice->SavedCacheLineReg &= 0xffff00ff; + pDevice->SavedCacheLineReg |= 0x4000; + } + } + + pDevice->ReceiveMask = LM_ACCEPT_MULTICAST | LM_ACCEPT_BROADCAST | + LM_ACCEPT_UNICAST; + + pDevice->TaskOffloadCap = LM_TASK_OFFLOAD_TX_TCP_CHECKSUM | + LM_TASK_OFFLOAD_TX_UDP_CHECKSUM | LM_TASK_OFFLOAD_RX_TCP_CHECKSUM | + LM_TASK_OFFLOAD_RX_UDP_CHECKSUM; + + if (pDevice->ChipRevId == T3_CHIP_ID_5700_B0) + { + pDevice->TaskOffloadCap &= ~(LM_TASK_OFFLOAD_TX_TCP_CHECKSUM | + LM_TASK_OFFLOAD_TX_UDP_CHECKSUM); + } + +#ifdef INCLUDE_TCP_SEG_SUPPORT + pDevice->TaskOffloadCap |= LM_TASK_OFFLOAD_TCP_SEGMENTATION; + + if ((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700) || + (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) || + (pDevice->ChipRevId == T3_CHIP_ID_5705_A0)) + { + pDevice->TaskOffloadCap &= ~LM_TASK_OFFLOAD_TCP_SEGMENTATION; + } +#endif + +#ifdef BCM_ASF + if (pDevice->AsfFlags & ASF_ENABLED) + { + if (!T3_ASIC_IS_575X_PLUS(pDevice->ChipRevId)) + { + pDevice->TaskOffloadCap &= ~LM_TASK_OFFLOAD_TCP_SEGMENTATION; + } + } +#endif + + /* Change driver parameters. */ + Status = MM_GetConfig(pDevice); + if(Status != LM_STATUS_SUCCESS) + { + return Status; + } + + if (T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) + { + pDevice->Flags &= ~NIC_SEND_BD_FLAG; + } + + /* Save the current phy link status. */ + if (!(pDevice->TbiFlags & ENABLE_TBI_FLAG) && + !(pDevice->AsfFlags & ASF_ENABLED)) + { + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + + /* If we don't have link reset the PHY. */ + if(!(Value32 & PHY_STATUS_LINK_PASS) || + (pDevice->PhyFlags & PHY_RESET_ON_INIT)) + { + + LM_ResetPhy(pDevice); + + if (LM_PhyAdvertiseAll(pDevice) != LM_STATUS_SUCCESS) + { + Value32 = PHY_AN_AD_PROTOCOL_802_3_CSMA_CD | + PHY_AN_AD_ALL_SPEEDS; + Value32 |= GetPhyAdFlowCntrlSettings(pDevice); + LM_WritePhy(pDevice, PHY_AN_AD_REG, Value32); + + if(!(pDevice->PhyFlags & PHY_NO_GIGABIT)) + Value32 = BCM540X_AN_AD_ALL_1G_SPEEDS ; + else + Value32 =0; + +#ifdef INCLUDE_5701_AX_FIX + if(pDevice->ChipRevId == T3_CHIP_ID_5701_A0 || + pDevice->ChipRevId == T3_CHIP_ID_5701_B0) + { + Value32 |= BCM540X_CONFIG_AS_MASTER | + BCM540X_ENABLE_CONFIG_AS_MASTER; + } +#endif + LM_WritePhy(pDevice, BCM540X_1000BASET_CTRL_REG, Value32); + + LM_WritePhy(pDevice, PHY_CTRL_REG, PHY_CTRL_AUTO_NEG_ENABLE | + PHY_CTRL_RESTART_AUTO_NEG); + } + + } + LM_SetEthWireSpeed(pDevice); + + LM_ReadPhy(pDevice, PHY_AN_AD_REG, &pDevice->advertising); + LM_ReadPhy(pDevice, BCM540X_1000BASET_CTRL_REG, + &pDevice->advertising1000); + + } + /* Currently 5401 phy only */ + LM_PhyTapPowerMgmt(pDevice); + +#ifdef INCLUDE_TBI_SUPPORT + if(pDevice->TbiFlags & ENABLE_TBI_FLAG) + { + if (!(pDevice->Flags & FIBER_WOL_CAPABLE_FLAG)) + { + pDevice->WakeUpModeCap = LM_WAKE_UP_MODE_NONE; + } + pDevice->PhyIntMode = T3_PHY_INT_MODE_LINK_READY; + if (pDevice->TbiFlags & TBI_PURE_POLLING_FLAG) + { + pDevice->IgnoreTbiLinkChange = TRUE; + } + } + else + { + pDevice->TbiFlags = 0; + } + +#endif /* INCLUDE_TBI_SUPPORT */ + + /* UseTaggedStatus is only valid for 5701 and later. */ + if ((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700) || + ((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5705) && + ((pDevice->BondId == GRC_MISC_BD_ID_5788) || + (pDevice->BondId == GRC_MISC_BD_ID_5788M)))) + { + pDevice->Flags &= ~USE_TAGGED_STATUS_FLAG; + pDevice->CoalesceMode = 0; + } + else + { + pDevice->CoalesceMode = HOST_COALESCE_CLEAR_TICKS_ON_RX_BD_EVENT | + HOST_COALESCE_CLEAR_TICKS_ON_TX_BD_EVENT; + } + + /* Set the status block size. */ + if(T3_CHIP_REV(pDevice->ChipRevId) != T3_CHIP_REV_5700_AX && + T3_CHIP_REV(pDevice->ChipRevId) != T3_CHIP_REV_5700_BX) + { + pDevice->CoalesceMode |= HOST_COALESCE_32_BYTE_STATUS_MODE; + } + + /* Check the DURING_INT coalescing ticks parameters. */ + if (pDevice->Flags & USE_TAGGED_STATUS_FLAG) + { + if(pDevice->RxCoalescingTicksDuringInt == BAD_DEFAULT_VALUE) + { + pDevice->RxCoalescingTicksDuringInt = + DEFAULT_RX_COALESCING_TICKS_DURING_INT; + } + + if(pDevice->TxCoalescingTicksDuringInt == BAD_DEFAULT_VALUE) + { + pDevice->TxCoalescingTicksDuringInt = + DEFAULT_TX_COALESCING_TICKS_DURING_INT; + } + + if(pDevice->RxMaxCoalescedFramesDuringInt == BAD_DEFAULT_VALUE) + { + pDevice->RxMaxCoalescedFramesDuringInt = + DEFAULT_RX_MAX_COALESCED_FRAMES_DURING_INT; + } + + if(pDevice->TxMaxCoalescedFramesDuringInt == BAD_DEFAULT_VALUE) + { + pDevice->TxMaxCoalescedFramesDuringInt = + DEFAULT_TX_MAX_COALESCED_FRAMES_DURING_INT; + } + } + else + { + if(pDevice->RxCoalescingTicksDuringInt == BAD_DEFAULT_VALUE) + { + pDevice->RxCoalescingTicksDuringInt = 0; + } + + if(pDevice->TxCoalescingTicksDuringInt == BAD_DEFAULT_VALUE) + { + pDevice->TxCoalescingTicksDuringInt = 0; + } + + if(pDevice->RxMaxCoalescedFramesDuringInt == BAD_DEFAULT_VALUE) + { + pDevice->RxMaxCoalescedFramesDuringInt = 0; + } + + if(pDevice->TxMaxCoalescedFramesDuringInt == BAD_DEFAULT_VALUE) + { + pDevice->TxMaxCoalescedFramesDuringInt = 0; + } + } + +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + if(pDevice->RxMtu <= (MAX_STD_RCV_BUFFER_SIZE - 8 /* CRC */)) + { + pDevice->RxJumboDescCnt = 0; + if(pDevice->RxMtu <= MAX_ETHERNET_PACKET_SIZE_NO_CRC) + { + pDevice->RxMtu = MAX_ETHERNET_PACKET_SIZE_NO_CRC; + } + } + else if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5705) + { + pDevice->RxMtu = MAX_ETHERNET_PACKET_SIZE_NO_CRC; + pDevice->RxJumboDescCnt = 0; + } + else + { + pDevice->RxJumboBufferSize = (pDevice->RxMtu + 8 /* CRC + VLAN */ + + COMMON_CACHE_LINE_SIZE-1) & ~COMMON_CACHE_LINE_MASK; + + if(pDevice->RxJumboBufferSize > MAX_JUMBO_RCV_BUFFER_SIZE) + { + pDevice->RxJumboBufferSize = DEFAULT_JUMBO_RCV_BUFFER_SIZE; + pDevice->RxMtu = pDevice->RxJumboBufferSize - 8 /* CRC + VLAN */; + } + pDevice->TxMtu = pDevice->RxMtu; + } +#else + pDevice->RxMtu = MAX_ETHERNET_PACKET_SIZE_NO_CRC; +#endif /* T3_JUMBO_RCV_RCB_ENTRY_COUNT */ + + pDevice->RxPacketDescCnt = +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + pDevice->RxJumboDescCnt + +#endif /* T3_JUMBO_RCV_RCB_ENTRY_COUNT */ + pDevice->RxStdDescCnt; + + if(pDevice->TxMtu < MAX_ETHERNET_PACKET_SIZE_NO_CRC) + { + pDevice->TxMtu = MAX_ETHERNET_PACKET_SIZE_NO_CRC; + } + + if(pDevice->TxMtu > MAX_JUMBO_TX_BUFFER_SIZE) + { + pDevice->TxMtu = MAX_JUMBO_TX_BUFFER_SIZE; + } + + /* Configure the proper ways to get link change interrupt. */ + if(pDevice->PhyIntMode == T3_PHY_INT_MODE_AUTO) + { + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700) + { + pDevice->PhyIntMode = T3_PHY_INT_MODE_MI_INTERRUPT; + } + else + { + pDevice->PhyIntMode = T3_PHY_INT_MODE_LINK_READY; + } + } + else if(pDevice->PhyIntMode == T3_PHY_INT_MODE_AUTO_POLLING) + { + /* Auto-polling does not work on 5700_AX and 5700_BX. */ + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700) + { + pDevice->PhyIntMode = T3_PHY_INT_MODE_MI_INTERRUPT; + } + } + + /* Determine the method to get link change status. */ + if(pDevice->LinkChngMode == T3_LINK_CHNG_MODE_AUTO) + { + /* The link status bit in the status block does not work on 5700_AX */ + /* and 5700_BX chips. */ + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700) + { + pDevice->LinkChngMode = T3_LINK_CHNG_MODE_USE_STATUS_REG; + } + else + { + pDevice->LinkChngMode = T3_LINK_CHNG_MODE_USE_STATUS_BLOCK; + } + } + + if(pDevice->PhyIntMode == T3_PHY_INT_MODE_MI_INTERRUPT || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700) + { + pDevice->LinkChngMode = T3_LINK_CHNG_MODE_USE_STATUS_REG; + } + + if (!EeSigFound) + { + pDevice->LedCtrl = LED_CTRL_PHY_MODE_1; + } + + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700 || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) + { + /* bug? 5701 in LINK10 mode does not seem to work when */ + /* PhyIntMode is LINK_READY. */ + if(T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5700 && +#ifdef INCLUDE_TBI_SUPPORT + !(pDevice->TbiFlags & ENABLE_TBI_FLAG) && +#endif + pDevice->LedCtrl == LED_CTRL_PHY_MODE_2) + { + pDevice->PhyIntMode = T3_PHY_INT_MODE_MI_INTERRUPT; + pDevice->LinkChngMode = T3_LINK_CHNG_MODE_USE_STATUS_REG; + } + if (pDevice->TbiFlags & ENABLE_TBI_FLAG) + { + pDevice->LedCtrl = LED_CTRL_PHY_MODE_1; + } + } + +#ifdef BCM_WOL + if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700 || + pDevice->ChipRevId == T3_CHIP_ID_5701_A0 || + pDevice->ChipRevId == T3_CHIP_ID_5701_B0 || + pDevice->ChipRevId == T3_CHIP_ID_5701_B2) + { + pDevice->WolSpeed = WOL_SPEED_10MB; + } + else + { + if (pDevice->Flags & WOL_LIMIT_10MBPS_FLAG) + { + pDevice->WolSpeed = WOL_SPEED_10MB; + } + else + { + pDevice->WolSpeed = WOL_SPEED_100MB; + } + } +#endif + + pDevice->PciState = REG_RD(pDevice, PciCfg.PciState); + + pDevice->DmaReadFifoSize = 0; + if (((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5705) && + (pDevice->ChipRevId != T3_CHIP_ID_5705_A0)) || + T3_ASIC_IS_575X_PLUS(pDevice->ChipRevId) ) + { +#ifdef INCLUDE_TCP_SEG_SUPPORT + if ((pDevice->TaskToOffload & LM_TASK_OFFLOAD_TCP_SEGMENTATION) && + ((pDevice->ChipRevId == T3_CHIP_ID_5705_A1) || + (pDevice->ChipRevId == T3_CHIP_ID_5705_A2))) + { + pDevice->DmaReadFifoSize = DMA_READ_MODE_FIFO_SIZE_128; + } + else +#endif + { + if (!(pDevice->PciState & T3_PCI_STATE_HIGH_BUS_SPEED) && + !(pDevice->Flags & BCM5788_FLAG) && + !(pDevice->Flags & PCI_EXPRESS_FLAG)) + { + pDevice->DmaReadFifoSize = DMA_READ_MODE_FIFO_LONG_BURST; + if (pDevice->ChipRevId == T3_CHIP_ID_5705_A1) + { + pDevice->Flags |= RX_BD_LIMIT_64_FLAG; + } + pDevice->Flags |= DMA_WR_MODE_RX_ACCELERATE_FLAG; + } + else if (pDevice->Flags & PCI_EXPRESS_FLAG) + { + pDevice->DmaReadFifoSize = DMA_READ_MODE_FIFO_LONG_BURST; + } + } + } + + pDevice->Flags &= ~T3_HAS_TWO_CPUS; + if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700 || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701 || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5703 || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5704) + { + pDevice->Flags |= T3_HAS_TWO_CPUS; + } + + return LM_STATUS_SUCCESS; +} /* LM_GetAdapterInfo */ + +STATIC PLM_ADAPTER_INFO +LM_GetAdapterInfoBySsid( + LM_UINT16 Svid, + LM_UINT16 Ssid) +{ + static LM_ADAPTER_INFO AdapterArr[] = + { + { T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95700A6, PHY_BCM5401_PHY_ID, 0}, + { T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95701A5, PHY_BCM5701_PHY_ID, 0}, + { T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95700T6, PHY_BCM8002_PHY_ID, 1}, + { T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95700A9, 0, 1 }, + { T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95701T1, PHY_BCM5701_PHY_ID, 0}, + { T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95701T8, PHY_BCM5701_PHY_ID, 0}, + { T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95701A7, 0, 1}, + { T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95701A10, PHY_BCM5701_PHY_ID, 0}, + { T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95701A12, PHY_BCM5701_PHY_ID, 0}, + { T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95703Ax1, PHY_BCM5703_PHY_ID, 0}, + { T3_SVID_BROADCOM, T3_SSID_BROADCOM_BCM95703Ax2, PHY_BCM5703_PHY_ID, 0}, + + { T3_SVID_3COM, T3_SSID_3COM_3C996T, PHY_BCM5401_PHY_ID, 0 }, + { T3_SVID_3COM, T3_SSID_3COM_3C996BT, PHY_BCM5701_PHY_ID, 0 }, + { T3_SVID_3COM, T3_SSID_3COM_3C996SX, 0, 1 }, + { T3_SVID_3COM, T3_SSID_3COM_3C1000T, PHY_BCM5701_PHY_ID, 0 }, + { T3_SVID_3COM, T3_SSID_3COM_3C940BR01, PHY_BCM5701_PHY_ID, 0 }, + + { T3_SVID_DELL, T3_SSID_DELL_VIPER, PHY_BCM5401_PHY_ID, 0 }, + { T3_SVID_DELL, T3_SSID_DELL_JAGUAR, PHY_BCM5401_PHY_ID, 0 }, + { T3_SVID_DELL, T3_SSID_DELL_MERLOT, PHY_BCM5411_PHY_ID, 0 }, + { T3_SVID_DELL, T3_SSID_DELL_SLIM_MERLOT, PHY_BCM5411_PHY_ID, 0 }, + + { T3_SVID_COMPAQ, T3_SSID_COMPAQ_BANSHEE, PHY_BCM5701_PHY_ID, 0 }, + { T3_SVID_COMPAQ, T3_SSID_COMPAQ_BANSHEE_2, PHY_BCM5701_PHY_ID, 0 }, + { T3_SVID_COMPAQ, T3_SSID_COMPAQ_CHANGELING, 0, 1 }, + { T3_SVID_COMPAQ, T3_SSID_COMPAQ_NC7780, PHY_BCM5701_PHY_ID, 0 }, + { T3_SVID_COMPAQ, T3_SSID_COMPAQ_NC7780_2, PHY_BCM5701_PHY_ID, 0 }, + + { 0x1014, 0x0281, 0, 1 }, + }; + LM_UINT32 j; + + for(j = 0; j < sizeof(AdapterArr)/sizeof(LM_ADAPTER_INFO); j++) + { + if(AdapterArr[j].Svid == Svid && AdapterArr[j].Ssid == Ssid) + { + return &AdapterArr[j]; + } + } + + return NULL; +} + + + +/******************************************************************************/ +/* Description: */ +/* This routine sets up receive/transmit buffer descriptions queues. */ +/* */ +/* Return: */ +/* LM_STATUS_SUCCESS */ +/******************************************************************************/ +LM_STATUS +LM_InitializeAdapter( +PLM_DEVICE_BLOCK pDevice) +{ + LM_PHYSICAL_ADDRESS MemPhy; + PLM_UINT8 pMemVirt; + PLM_PACKET pPacket; + LM_STATUS Status; + LM_UINT32 Size; + LM_UINT32 Value32, j; + LM_UINT32 DmaWrCmd, DmaRdCmd, DmaWrBdry, DmaRdBdry; + + MM_ReadConfig32(pDevice, PCI_COMMAND_REG, &Value32); + j = 0; + while (((Value32 & 0x3ff) != (pDevice->PciCommandStatusWords & 0x3ff)) && + (j < 1000)) + { + /* On PCIE devices, there are some rare cases where the device */ + /* is in the process of link-training at this point */ + MM_Wait(200); + MM_WriteConfig32(pDevice, PCI_COMMAND_REG, pDevice->PciCommandStatusWords); + MM_ReadConfig32(pDevice, PCI_COMMAND_REG, &Value32); + j++; + } + MM_WriteConfig32(pDevice, T3_PCI_MISC_HOST_CTRL_REG, pDevice->MiscHostCtrl); + /* Set power state to D0. */ + LM_SetPowerState(pDevice, LM_POWER_STATE_D0); + + /* Intialize the queues. */ + QQ_InitQueue(&pDevice->RxPacketReceivedQ.Container, + MAX_RX_PACKET_DESC_COUNT); + QQ_InitQueue(&pDevice->RxPacketFreeQ.Container, + MAX_RX_PACKET_DESC_COUNT); + + QQ_InitQueue(&pDevice->TxPacketFreeQ.Container,MAX_TX_PACKET_DESC_COUNT); + QQ_InitQueue(&pDevice->TxPacketXmittedQ.Container,MAX_TX_PACKET_DESC_COUNT); + + if(T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId) ) + { + pDevice->RcvRetRcbEntryCount = 512; + pDevice->RcvRetRcbEntryCountMask = 511; + } + else + { + pDevice->RcvRetRcbEntryCount = T3_RCV_RETURN_RCB_ENTRY_COUNT; + pDevice->RcvRetRcbEntryCountMask = T3_RCV_RETURN_RCB_ENTRY_COUNT_MASK; + } + + /* Allocate shared memory for: status block, the buffers for receive */ + /* rings -- standard, mini, jumbo, and return rings. */ + Size = T3_STATUS_BLOCK_SIZE + sizeof(T3_STATS_BLOCK) + + T3_STD_RCV_RCB_ENTRY_COUNT * sizeof(T3_RCV_BD) + +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + T3_JUMBO_RCV_RCB_ENTRY_COUNT * sizeof(T3_RCV_BD) + +#endif /* T3_JUMBO_RCV_RCB_ENTRY_COUNT */ + (pDevice->RcvRetRcbEntryCount * sizeof(T3_RCV_BD)); + + /* Memory for host based Send BD. */ + if (!(pDevice->Flags & NIC_SEND_BD_FLAG)) + { + Size += sizeof(T3_SND_BD) * T3_SEND_RCB_ENTRY_COUNT; + } + + /* Allocate the memory block. */ + Status = MM_AllocateSharedMemory(pDevice, Size, (PLM_VOID) &pMemVirt, &MemPhy, FALSE); + if(Status != LM_STATUS_SUCCESS) + { + return Status; + } + + DmaWrCmd = DMA_CTRL_WRITE_CMD; + DmaRdCmd = DMA_CTRL_READ_CMD; + DmaWrBdry = DMA_CTRL_WRITE_BOUNDARY_DISABLE; + DmaRdBdry = DMA_CTRL_READ_BOUNDARY_DISABLE; +#ifdef BCM_DISCONNECT_AT_CACHELINE + /* This code is intended for PPC64 and other similar architectures */ + /* Only the following chips support this */ + if ((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700) || + (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) || + (pDevice->Flags & PCI_EXPRESS_FLAG)) + { + switch(pDevice->CacheLineSize * 4) + { + case 16: + case 32: + case 64: + case 128: + if (!(pDevice->PciState & T3_PCI_STATE_NOT_PCI_X_BUS) && + !(pDevice->Flags & PCI_EXPRESS_FLAG)) + { + /* PCI-X */ + /* use 384 which is a multiple of 16,32,64,128 */ + DmaWrBdry = DMA_CTRL_WRITE_BOUNDARY_384_PCIX; + break; + } + else if (pDevice->Flags & PCI_EXPRESS_FLAG) + { + /* PCI Express */ + /* use 128 which is a multiple of 16,32,64,128 */ + DmaWrCmd = DMA_CTRL_WRITE_BOUNDARY_128_PCIE; + break; + } + /* fall through */ + case 256: + /* use 256 which is a multiple of 16,32,64,128,256 */ + if ((pDevice->PciState & T3_PCI_STATE_NOT_PCI_X_BUS) && + !(pDevice->Flags & PCI_EXPRESS_FLAG)) + { + /* PCI */ + DmaWrBdry = DMA_CTRL_WRITE_BOUNDARY_256; + } + else if (!(pDevice->Flags & PCI_EXPRESS_FLAG)) + { + /* PCI-X */ + DmaWrBdry = DMA_CTRL_WRITE_BOUNDARY_256_PCIX; + } + break; + } + } +#endif + pDevice->DmaReadWriteCtrl = DmaWrCmd | DmaRdCmd | DmaWrBdry | DmaRdBdry; + /* Program DMA Read/Write */ + if (pDevice->Flags & PCI_EXPRESS_FLAG) + { + + /* !=0 is 256 max or greater payload size so set water mark accordingly*/ + Value32 = (REG_RD(pDevice, PciCfg.DeviceCtrl) & MAX_PAYLOAD_SIZE_MASK); + if (Value32) + { + pDevice->DmaReadWriteCtrl |= DMA_CTRL_WRITE_PCIE_H20MARK_256; + }else + { + pDevice->DmaReadWriteCtrl |= DMA_CTRL_WRITE_PCIE_H20MARK_128; + } + + } + else if (pDevice->PciState & T3_PCI_STATE_NOT_PCI_X_BUS) + { + if(T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) + { + pDevice->DmaReadWriteCtrl |= 0x003f0000; + } + else + { + pDevice->DmaReadWriteCtrl |= 0x003f000f; + } + } + else /* pci-x */ + { + if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5704) + { + pDevice->DmaReadWriteCtrl |= 0x009f0000; + } + + if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5703) + { + pDevice->DmaReadWriteCtrl |= 0x009C0000; + } + + if( T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5704 || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5703 ) + { + Value32 = REG_RD(pDevice, PciCfg.ClockCtrl) & 0x1f; + if ((Value32 == 0x6) || (Value32 == 0x7)) + { + pDevice->Flags |= ONE_DMA_AT_ONCE_FLAG; + } + } + else if(T3_ASIC_5714_FAMILY(pDevice->ChipRevId) ) + { + pDevice->DmaReadWriteCtrl &= ~DMA_CTRL_WRITE_ONE_DMA_AT_ONCE; + if( T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5780) + pDevice->DmaReadWriteCtrl |= (BIT_20 | BIT_18 | DMA_CTRL_WRITE_ONE_DMA_AT_ONCE); + else + pDevice->DmaReadWriteCtrl |= (BIT_20 | BIT_18 | BIT_15); + /* bit 15 is the current CQ 13140 Fix */ + } + else + { + pDevice->DmaReadWriteCtrl |= 0x001b000f; + } + } + if((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5703) || + (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5704)) + { + pDevice->DmaReadWriteCtrl &= 0xfffffff0; + } + + if (pDevice->Flags & ONE_DMA_AT_ONCE_FLAG) + { + pDevice->DmaReadWriteCtrl |= DMA_CTRL_WRITE_ONE_DMA_AT_ONCE; + } + + REG_WR(pDevice, PciCfg.DmaReadWriteCtrl, pDevice->DmaReadWriteCtrl); + + LM_SwitchClocks(pDevice); + + if (LM_DmaTest(pDevice, pMemVirt, MemPhy, 0x400) != LM_STATUS_SUCCESS) + { + return LM_STATUS_FAILURE; + } + + /* Status block. */ + pDevice->pStatusBlkVirt = (PT3_STATUS_BLOCK) pMemVirt; + pDevice->StatusBlkPhy = MemPhy; + pMemVirt += T3_STATUS_BLOCK_SIZE; + LM_INC_PHYSICAL_ADDRESS(&MemPhy, T3_STATUS_BLOCK_SIZE); + + /* Statistics block. */ + pDevice->pStatsBlkVirt = (PT3_STATS_BLOCK) pMemVirt; + pDevice->StatsBlkPhy = MemPhy; + pMemVirt += sizeof(T3_STATS_BLOCK); + LM_INC_PHYSICAL_ADDRESS(&MemPhy, sizeof(T3_STATS_BLOCK)); + + /* Receive standard BD buffer. */ + pDevice->pRxStdBdVirt = (PT3_RCV_BD) pMemVirt; + pDevice->RxStdBdPhy = MemPhy; + + pMemVirt += T3_STD_RCV_RCB_ENTRY_COUNT * sizeof(T3_RCV_BD); + LM_INC_PHYSICAL_ADDRESS(&MemPhy, + T3_STD_RCV_RCB_ENTRY_COUNT * sizeof(T3_RCV_BD)); + +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + /* Receive jumbo BD buffer. */ + pDevice->pRxJumboBdVirt = (PT3_RCV_BD) pMemVirt; + pDevice->RxJumboBdPhy = MemPhy; + + pMemVirt += T3_JUMBO_RCV_RCB_ENTRY_COUNT * sizeof(T3_RCV_BD); + LM_INC_PHYSICAL_ADDRESS(&MemPhy, + T3_JUMBO_RCV_RCB_ENTRY_COUNT * sizeof(T3_RCV_BD)); +#endif /* T3_JUMBO_RCV_RCB_ENTRY_COUNT */ + + /* Receive return BD buffer. */ + pDevice->pRcvRetBdVirt = (PT3_RCV_BD) pMemVirt; + pDevice->RcvRetBdPhy = MemPhy; + + pMemVirt += pDevice->RcvRetRcbEntryCount * sizeof(T3_RCV_BD); + LM_INC_PHYSICAL_ADDRESS(&MemPhy, + pDevice->RcvRetRcbEntryCount * sizeof(T3_RCV_BD)); + + /* Set up Send BD. */ + if (!(pDevice->Flags & NIC_SEND_BD_FLAG)) + { + pDevice->pSendBdVirt = (PT3_SND_BD) pMemVirt; + pDevice->SendBdPhy = MemPhy; + + pMemVirt += sizeof(T3_SND_BD) * T3_SEND_RCB_ENTRY_COUNT; + LM_INC_PHYSICAL_ADDRESS(&MemPhy, + sizeof(T3_SND_BD) * T3_SEND_RCB_ENTRY_COUNT); + } +#ifdef BCM_NIC_SEND_BD + else + { + pDevice->pSendBdVirt = (PT3_SND_BD) + pDevice->pMemView->uIntMem.First32k.BufferDesc; + pDevice->SendBdPhy.High = 0; + pDevice->SendBdPhy.Low = T3_NIC_SND_BUFFER_DESC_ADDR; + } +#endif + + /* Allocate memory for packet descriptors. */ + Size = (pDevice->RxPacketDescCnt + + pDevice->TxPacketDescCnt) * MM_PACKET_DESC_SIZE; + Status = MM_AllocateMemory(pDevice, Size, (PLM_VOID *) &pPacket); + if(Status != LM_STATUS_SUCCESS) + { + return Status; + } + pDevice->pPacketDescBase = (PLM_VOID) pPacket; + + /* Create transmit packet descriptors from the memory block and add them */ + /* to the TxPacketFreeQ for each send ring. */ + for(j = 0; j < pDevice->TxPacketDescCnt; j++) + { + /* Ring index. */ + pPacket->Flags = 0; + + /* Queue the descriptor in the TxPacketFreeQ of the 'k' ring. */ + QQ_PushTail(&pDevice->TxPacketFreeQ.Container, pPacket); + + /* Get the pointer to the next descriptor. MM_PACKET_DESC_SIZE */ + /* is the total size of the packet descriptor including the */ + /* os-specific extensions in the UM_PACKET structure. */ + pPacket = (PLM_PACKET) ((PLM_UINT8) pPacket + MM_PACKET_DESC_SIZE); + } /* for(j.. */ + + /* Create receive packet descriptors from the memory block and add them */ + /* to the RxPacketFreeQ. Create the Standard packet descriptors. */ + for(j = 0; j < pDevice->RxStdDescCnt; j++) + { + /* Receive producer ring. */ + pPacket->u.Rx.RcvProdRing = T3_STD_RCV_PROD_RING; + + /* Receive buffer size. */ + if (T3_ASIC_5714_FAMILY(pDevice->ChipRevId) && + (pDevice->RxJumboBufferSize) ) + { + pPacket->u.Rx.RxBufferSize = pDevice->RxJumboBufferSize; + }else{ + pPacket->u.Rx.RxBufferSize = MAX_STD_RCV_BUFFER_SIZE; + } + + /* Add the descriptor to RxPacketFreeQ. */ + QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket); + + /* Get the pointer to the next descriptor. MM_PACKET_DESC_SIZE */ + /* is the total size of the packet descriptor including the */ + /* os-specific extensions in the UM_PACKET structure. */ + pPacket = (PLM_PACKET) ((PLM_UINT8) pPacket + MM_PACKET_DESC_SIZE); + } /* for */ + + +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + /* Create the Jumbo packet descriptors. */ + for(j = 0; j < pDevice->RxJumboDescCnt; j++) + { + /* Receive producer ring. */ + pPacket->u.Rx.RcvProdRing = T3_JUMBO_RCV_PROD_RING; + + /* Receive buffer size. */ + pPacket->u.Rx.RxBufferSize = pDevice->RxJumboBufferSize; + + /* Add the descriptor to RxPacketFreeQ. */ + QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket); + + /* Get the pointer to the next descriptor. MM_PACKET_DESC_SIZE */ + /* is the total size of the packet descriptor including the */ + /* os-specific extensions in the UM_PACKET structure. */ + pPacket = (PLM_PACKET) ((PLM_UINT8) pPacket + MM_PACKET_DESC_SIZE); + } /* for */ +#endif /* T3_JUMBO_RCV_RCB_ENTRY_COUNT */ + + /* Initialize the rest of the packet descriptors. */ + Status = MM_InitializeUmPackets(pDevice); + if(Status != LM_STATUS_SUCCESS) + { + return Status; + } /* if */ + + /* Default receive mask. */ + pDevice->ReceiveMask &= LM_KEEP_VLAN_TAG; + pDevice->ReceiveMask |= LM_ACCEPT_MULTICAST | LM_ACCEPT_BROADCAST | + LM_ACCEPT_UNICAST; + + /* Make sure we are in the first 32k memory window or NicSendBd. */ + REG_WR(pDevice, PciCfg.MemWindowBaseAddr, 0); + + /* Initialize the hardware. */ + Status = LM_ResetAdapter(pDevice); + if(Status != LM_STATUS_SUCCESS) + { + return Status; + } + + /* We are done with initialization. */ + pDevice->InitDone = TRUE; + + return LM_STATUS_SUCCESS; +} /* LM_InitializeAdapter */ + + +LM_STATUS +LM_DisableChip(PLM_DEVICE_BLOCK pDevice) +{ + LM_UINT32 data; + + pDevice->RxMode &= ~RX_MODE_ENABLE; + REG_WR(pDevice, MacCtrl.RxMode, pDevice->RxMode); + if(!(REG_RD(pDevice, MacCtrl.RxMode) & RX_MODE_ENABLE)) + { + MM_Wait(20); + } + data = REG_RD(pDevice, RcvBdIn.Mode); + data &= ~RCV_BD_IN_MODE_ENABLE; + REG_WR(pDevice, RcvBdIn.Mode,data); + if(!(REG_RD(pDevice, RcvBdIn.Mode) & RCV_BD_IN_MODE_ENABLE)) + { + MM_Wait(20); + } + data = REG_RD(pDevice, RcvListPlmt.Mode); + data &= ~RCV_LIST_PLMT_MODE_ENABLE; + REG_WR(pDevice, RcvListPlmt.Mode,data); + if(!(REG_RD(pDevice, RcvListPlmt.Mode) & RCV_LIST_PLMT_MODE_ENABLE)) + { + MM_Wait(20); + } + if(!T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) + { + data = REG_RD(pDevice, RcvListSel.Mode); + data &= ~RCV_LIST_SEL_MODE_ENABLE; + REG_WR(pDevice, RcvListSel.Mode,data); + if(!(REG_RD(pDevice, RcvListSel.Mode) & RCV_LIST_SEL_MODE_ENABLE)) + { + MM_Wait(20); + } + } + data = REG_RD(pDevice, RcvDataBdIn.Mode); + data &= ~RCV_DATA_BD_IN_MODE_ENABLE; + REG_WR(pDevice, RcvDataBdIn.Mode,data); + if(!(REG_RD(pDevice, RcvDataBdIn.Mode) & RCV_DATA_BD_IN_MODE_ENABLE)) + { + MM_Wait(20); + } + data = REG_RD(pDevice, RcvDataComp.Mode); + data &= ~RCV_DATA_COMP_MODE_ENABLE; + REG_WR(pDevice, RcvDataComp.Mode,data); + if(!(REG_RD(pDevice, RcvDataBdIn.Mode) & RCV_DATA_COMP_MODE_ENABLE)) + { + MM_Wait(20); + } + data = REG_RD(pDevice, RcvBdComp.Mode); + data &= ~RCV_BD_COMP_MODE_ENABLE; + REG_WR(pDevice, RcvBdComp.Mode,data); + if(!(REG_RD(pDevice, RcvBdComp.Mode) & RCV_BD_COMP_MODE_ENABLE)) + { + MM_Wait(20); + } + data = REG_RD(pDevice, SndBdSel.Mode); + data &= ~SND_BD_SEL_MODE_ENABLE; + REG_WR(pDevice, SndBdSel.Mode, data); + if(!(REG_RD(pDevice, SndBdSel.Mode) & SND_BD_SEL_MODE_ENABLE)) + { + MM_Wait(20); + } + data = REG_RD(pDevice, SndBdIn.Mode); + data &= ~SND_BD_IN_MODE_ENABLE; + REG_WR(pDevice, SndBdIn.Mode, data); + if(!(REG_RD(pDevice, SndBdIn.Mode) & SND_BD_IN_MODE_ENABLE)) + { + MM_Wait(20); + } + data = REG_RD(pDevice, SndDataIn.Mode); + data &= ~T3_SND_DATA_IN_MODE_ENABLE; + REG_WR(pDevice, SndDataIn.Mode,data); + if(!(REG_RD(pDevice, SndDataIn.Mode) & T3_SND_DATA_IN_MODE_ENABLE)) + { + MM_Wait(20); + } + data = REG_RD(pDevice, DmaRead.Mode); + data &= ~DMA_READ_MODE_ENABLE; + REG_WR(pDevice, DmaRead.Mode, data); + if(!(REG_RD(pDevice, DmaRead.Mode) & DMA_READ_MODE_ENABLE)) + { + MM_Wait(20); + } + data = REG_RD(pDevice, SndDataComp.Mode); + data &= ~SND_DATA_COMP_MODE_ENABLE; + REG_WR(pDevice, SndDataComp.Mode, data); + if(!(REG_RD(pDevice, SndDataComp.Mode) & SND_DATA_COMP_MODE_ENABLE)) + { + MM_Wait(20); + } + + if(!T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) + { + data = REG_RD(pDevice,DmaComp.Mode); + data &= ~DMA_COMP_MODE_ENABLE; + REG_WR(pDevice, DmaComp.Mode, data); + if(!(REG_RD(pDevice, DmaComp.Mode) & DMA_COMP_MODE_ENABLE)) + { + MM_Wait(20); + } + } + data = REG_RD(pDevice, SndBdComp.Mode); + data &= ~SND_BD_COMP_MODE_ENABLE; + REG_WR(pDevice, SndBdComp.Mode, data); + if(!(REG_RD(pDevice, SndBdComp.Mode) & SND_BD_COMP_MODE_ENABLE)) + { + MM_Wait(20); + } + /* Clear TDE bit */ + pDevice->MacMode &= ~MAC_MODE_ENABLE_TDE; + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode); + pDevice->TxMode &= ~TX_MODE_ENABLE; + REG_WR(pDevice, MacCtrl.TxMode, pDevice->TxMode); + if(!(REG_RD(pDevice, MacCtrl.TxMode) & TX_MODE_ENABLE)) + { + MM_Wait(20); + } + data = REG_RD(pDevice, HostCoalesce.Mode); + data &= ~HOST_COALESCE_ENABLE; + REG_WR(pDevice, HostCoalesce.Mode, data); + if(!(REG_RD(pDevice, SndBdIn.Mode) & HOST_COALESCE_ENABLE)) + { + MM_Wait(20); + } + data = REG_RD(pDevice, DmaWrite.Mode); + data &= ~DMA_WRITE_MODE_ENABLE; + REG_WR(pDevice, DmaWrite.Mode,data); + if(!(REG_RD(pDevice, DmaWrite.Mode) & DMA_WRITE_MODE_ENABLE)) + { + MM_Wait(20); + } + + if(!T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) + { + data = REG_RD(pDevice, MbufClusterFree.Mode); + data &= ~MBUF_CLUSTER_FREE_MODE_ENABLE; + REG_WR(pDevice, MbufClusterFree.Mode,data); + if(!(REG_RD(pDevice, MbufClusterFree.Mode) & MBUF_CLUSTER_FREE_MODE_ENABLE)) + { + MM_Wait(20); + } + } + /* Reset all FTQs */ + REG_WR(pDevice, Ftq.Reset, 0xffffffff); + REG_WR(pDevice, Ftq.Reset, 0x0); + + if(!T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) + { + data = REG_RD(pDevice, BufMgr.Mode); + data &= ~BUFMGR_MODE_ENABLE; + REG_WR(pDevice, BufMgr.Mode,data); + if(!(REG_RD(pDevice, BufMgr.Mode) & BUFMGR_MODE_ENABLE)) + { + MM_Wait(20); + } + data = REG_RD(pDevice, MemArbiter.Mode); + data &= ~T3_MEM_ARBITER_MODE_ENABLE; + REG_WR(pDevice, MemArbiter.Mode, data); + if(!(REG_RD(pDevice, MemArbiter.Mode) & T3_MEM_ARBITER_MODE_ENABLE)) + { + MM_Wait(20); + } + } + return LM_STATUS_SUCCESS; +} + +LM_STATUS +LM_DisableFW(PLM_DEVICE_BLOCK pDevice) +{ +#ifdef BCM_ASF + int j; + LM_UINT32 Value32; + + if (pDevice->AsfFlags & ASF_ENABLED) + { + MEM_WR_OFFSET(pDevice, T3_CMD_MAILBOX, T3_CMD_NICDRV_PAUSE_FW); + Value32 = REG_RD(pDevice, Grc.RxCpuEvent); + REG_WR(pDevice, Grc.RxCpuEvent, Value32 | BIT_14); + for (j = 0; j < 100; j++) + { + Value32 = REG_RD(pDevice, Grc.RxCpuEvent); + if (!(Value32 & BIT_14)) + { + break; + } + MM_Wait(1); + } + } +#endif + return LM_STATUS_SUCCESS; +} + +/******************************************************************************/ +/* Description: */ +/* This function reinitializes the adapter. */ +/* */ +/* Return: */ +/* LM_STATUS_SUCCESS */ +/******************************************************************************/ +LM_STATUS +LM_ResetAdapter( +PLM_DEVICE_BLOCK pDevice) +{ + LM_UINT32 Value32; + LM_UINT32 j, k; + int reset_count = 0; + + /* Disable interrupt. */ + LM_DisableInterrupt(pDevice); + +restart_reset: + LM_DisableFW(pDevice); + + /* May get a spurious interrupt */ + pDevice->pStatusBlkVirt->Status = STATUS_BLOCK_UPDATED; + + LM_WritePreResetSignatures(pDevice, LM_INIT_RESET); + /* Disable transmit and receive DMA engines. Abort all pending requests. */ + if(pDevice->InitDone) + { + LM_Abort(pDevice); + } + + pDevice->ShuttingDown = FALSE; + + LM_ResetChip(pDevice); + + LM_WriteLegacySignatures(pDevice, LM_INIT_RESET); + + /* Bug: Athlon fix for B3 silicon only. This bit does not do anything */ + /* in other chip revisions except 5750 */ + if ((pDevice->Flags & DELAY_PCI_GRANT_FLAG) && + !(pDevice->Flags & PCI_EXPRESS_FLAG)) + { + REG_WR(pDevice, PciCfg.ClockCtrl, pDevice->ClockCtrl | BIT_31); + } + + if(pDevice->ChipRevId == T3_CHIP_ID_5704_A0) + { + if (!(pDevice->PciState & T3_PCI_STATE_CONVENTIONAL_PCI_MODE)) + { + Value32 = REG_RD(pDevice, PciCfg.PciState); + Value32 |= T3_PCI_STATE_RETRY_SAME_DMA; + REG_WR(pDevice, PciCfg.PciState, Value32); + } + } + if (T3_CHIP_REV(pDevice->ChipRevId) == T3_CHIP_REV_5704_BX) + { + /* New bits defined in register 0x64 to enable some h/w fixes */ + /* These new bits are 'write-only' */ + Value32 = REG_RD(pDevice, PciCfg.MsiData); + REG_WR(pDevice, PciCfg.MsiData, Value32 | BIT_26 | BIT_28 | BIT_29); + } + + /* Enable TaggedStatus mode. */ + if (pDevice->Flags & USE_TAGGED_STATUS_FLAG) + { + pDevice->MiscHostCtrl |= MISC_HOST_CTRL_ENABLE_TAGGED_STATUS_MODE; + } + + /* Restore PCI configuration registers. */ + MM_WriteConfig32(pDevice, PCI_CACHE_LINE_SIZE_REG, + pDevice->SavedCacheLineReg); + MM_WriteConfig32(pDevice, PCI_SUBSYSTEM_VENDOR_ID_REG, + (pDevice->SubsystemId << 16) | pDevice->SubsystemVendorId); + + /* Initialize the statistis Block */ + pDevice->pStatusBlkVirt->Status = 0; + pDevice->pStatusBlkVirt->RcvStdConIdx = 0; + pDevice->pStatusBlkVirt->RcvJumboConIdx = 0; + pDevice->pStatusBlkVirt->RcvMiniConIdx = 0; + + for(j = 0; j < 16; j++) + { + pDevice->pStatusBlkVirt->Idx[j].RcvProdIdx = 0; + pDevice->pStatusBlkVirt->Idx[j].SendConIdx = 0; + } + + for(k = 0; k < T3_STD_RCV_RCB_ENTRY_COUNT ;k++) + { + pDevice->pRxStdBdVirt[k].HostAddr.High = 0; + pDevice->pRxStdBdVirt[k].HostAddr.Low = 0; + pDevice->pRxStdBdVirt[k].Flags = RCV_BD_FLAG_END; + if(T3_ASIC_5714_FAMILY(pDevice->ChipRevId) && + (pDevice->RxJumboBufferSize) ) + pDevice->pRxStdBdVirt[k].Len = pDevice->RxJumboBufferSize; + else + pDevice->pRxStdBdVirt[k].Len = MAX_STD_RCV_BUFFER_SIZE; + } + +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + /* Receive jumbo BD buffer. */ + for(k = 0; k < T3_JUMBO_RCV_RCB_ENTRY_COUNT; k++) + { + pDevice->pRxJumboBdVirt[k].HostAddr.High = 0; + pDevice->pRxJumboBdVirt[k].HostAddr.Low = 0; + pDevice->pRxJumboBdVirt[k].Flags = RCV_BD_FLAG_END | + RCV_BD_FLAG_JUMBO_RING; + pDevice->pRxJumboBdVirt[k].Len = (LM_UINT16) pDevice->RxJumboBufferSize; + } +#endif + + REG_WR(pDevice, PciCfg.DmaReadWriteCtrl, pDevice->DmaReadWriteCtrl); + + /* GRC mode control register. */ + Value32 = +#ifdef BIG_ENDIAN_HOST + GRC_MODE_BYTE_SWAP_NON_FRAME_DATA | + GRC_MODE_WORD_SWAP_NON_FRAME_DATA | + GRC_MODE_BYTE_SWAP_DATA | + GRC_MODE_WORD_SWAP_DATA | +#else + GRC_MODE_WORD_SWAP_NON_FRAME_DATA | + GRC_MODE_BYTE_SWAP_DATA | + GRC_MODE_WORD_SWAP_DATA | +#endif + GRC_MODE_INT_ON_MAC_ATTN | + GRC_MODE_HOST_STACK_UP; + + /* Configure send BD mode. */ + if (!(pDevice->Flags & NIC_SEND_BD_FLAG)) + { + Value32 |= GRC_MODE_HOST_SEND_BDS; + } +#ifdef BCM_NIC_SEND_BD + else + { + Value32 |= GRC_MODE_4X_NIC_BASED_SEND_RINGS; + } +#endif + + /* Configure pseudo checksum mode. */ + if (pDevice->Flags & NO_TX_PSEUDO_HDR_CSUM_FLAG) + { + Value32 |= GRC_MODE_TX_NO_PSEUDO_HEADER_CHKSUM; + } + + if (pDevice->Flags & NO_RX_PSEUDO_HDR_CSUM_FLAG) + { + Value32 |= GRC_MODE_RX_NO_PSEUDO_HEADER_CHKSUM; + } + + pDevice->GrcMode = Value32; + REG_WR(pDevice, Grc.Mode, Value32); + + /* Setup the timer prescalar register. */ + Value32 = REG_RD(pDevice, Grc.MiscCfg) & ~0xff; + /* Clock is always 66Mhz. */ + REG_WR(pDevice, Grc.MiscCfg, Value32 | (65 << 1)); + + /* Set up the MBUF pool base address and size. */ + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5705) + { +#ifdef INCLUDE_TCP_SEG_SUPPORT + if (pDevice->TaskToOffload & LM_TASK_OFFLOAD_TCP_SEGMENTATION) + { + Value32 = LM_GetStkOffLdFirmwareSize(pDevice); + Value32 = (Value32 + 0x7f) & ~0x7f; + pDevice->MbufBase = T3_NIC_BCM5705_MBUF_POOL_ADDR + Value32; + pDevice->MbufSize = T3_NIC_BCM5705_MBUF_POOL_SIZE - Value32 - 0xa00; + REG_WR(pDevice, BufMgr.MbufPoolAddr, pDevice->MbufBase); + REG_WR(pDevice, BufMgr.MbufPoolSize, pDevice->MbufSize); + } +#endif + } + else if (!T3_ASIC_IS_575X_PLUS(pDevice->ChipRevId)) + { + REG_WR(pDevice, BufMgr.MbufPoolAddr, pDevice->MbufBase); + REG_WR(pDevice, BufMgr.MbufPoolSize, pDevice->MbufSize); + + /* Set up the DMA descriptor pool base address and size. */ + REG_WR(pDevice, BufMgr.DmaDescPoolAddr, T3_NIC_DMA_DESC_POOL_ADDR); + REG_WR(pDevice, BufMgr.DmaDescPoolSize, T3_NIC_DMA_DESC_POOL_SIZE); + + } + + /* Configure MBUF and Threshold watermarks */ + /* Configure the DMA read MBUF low water mark. */ + if(pDevice->TxMtu < MAX_ETHERNET_PACKET_BUFFER_SIZE) + { + if(T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) + { + REG_WR(pDevice, BufMgr.MbufReadDmaLowWaterMark, + T3_DEF_DMA_MBUF_LOW_WMARK_5705); + REG_WR(pDevice, BufMgr.MbufMacRxLowWaterMark, + T3_DEF_RX_MAC_MBUF_LOW_WMARK_5705); + REG_WR(pDevice, BufMgr.MbufHighWaterMark, + T3_DEF_MBUF_HIGH_WMARK_5705); + } + else + { + REG_WR(pDevice, BufMgr.MbufReadDmaLowWaterMark, + T3_DEF_DMA_MBUF_LOW_WMARK); + REG_WR(pDevice, BufMgr.MbufMacRxLowWaterMark, + T3_DEF_RX_MAC_MBUF_LOW_WMARK); + REG_WR(pDevice, BufMgr.MbufHighWaterMark, + T3_DEF_MBUF_HIGH_WMARK); + } + }else if( T3_ASIC_5714_FAMILY(pDevice->ChipRevId)){ + + REG_WR(pDevice, BufMgr.MbufReadDmaLowWaterMark,0); + REG_WR(pDevice, BufMgr.MbufMacRxLowWaterMark,0x4b); + REG_WR(pDevice, BufMgr.MbufHighWaterMark,0x96); + } + else + { + REG_WR(pDevice, BufMgr.MbufReadDmaLowWaterMark, + T3_DEF_DMA_MBUF_LOW_WMARK_JUMBO); + REG_WR(pDevice, BufMgr.MbufMacRxLowWaterMark, + T3_DEF_RX_MAC_MBUF_LOW_WMARK_JUMBO); + REG_WR(pDevice, BufMgr.MbufHighWaterMark, + T3_DEF_MBUF_HIGH_WMARK_JUMBO); + } + + REG_WR(pDevice, BufMgr.DmaLowWaterMark, T3_DEF_DMA_DESC_LOW_WMARK); + REG_WR(pDevice, BufMgr.DmaHighWaterMark, T3_DEF_DMA_DESC_HIGH_WMARK); + + /* Enable buffer manager. */ + REG_WR(pDevice, BufMgr.Mode, BUFMGR_MODE_ENABLE | BUFMGR_MODE_ATTN_ENABLE); + + for(j = 0 ;j < 2000; j++) + { + if(REG_RD(pDevice, BufMgr.Mode) & BUFMGR_MODE_ENABLE) + break; + MM_Wait(10); + } + + if(j >= 2000) + { + return LM_STATUS_FAILURE; + } + +/* GRC reset will reset FTQ */ + + /* Receive BD Ring replenish threshold. */ + REG_WR(pDevice, RcvBdIn.StdRcvThreshold, pDevice->RxStdDescCnt/8); + + /* Initialize the Standard Receive RCB. */ + REG_WR(pDevice, RcvDataBdIn.StdRcvRcb.HostRingAddr.High, + pDevice->RxStdBdPhy.High); + REG_WR(pDevice, RcvDataBdIn.StdRcvRcb.HostRingAddr.Low, + pDevice->RxStdBdPhy.Low); + REG_WR(pDevice, RcvDataBdIn.StdRcvRcb.NicRingAddr, + (LM_UINT32) T3_NIC_STD_RCV_BUFFER_DESC_ADDR); + + if(T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) + { + REG_WR(pDevice, RcvDataBdIn.StdRcvRcb.u.MaxLen_Flags, + 512 << 16); + } + else + { + REG_WR(pDevice, RcvDataBdIn.StdRcvRcb.u.MaxLen_Flags, + MAX_STD_RCV_BUFFER_SIZE << 16); + + /* Initialize the Jumbo Receive RCB. */ + REG_WR(pDevice, RcvDataBdIn.JumboRcvRcb.u.MaxLen_Flags, + T3_RCB_FLAG_RING_DISABLED); +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + REG_WR(pDevice, RcvDataBdIn.JumboRcvRcb.HostRingAddr.High, + pDevice->RxJumboBdPhy.High); + REG_WR(pDevice, RcvDataBdIn.JumboRcvRcb.HostRingAddr.Low, + pDevice->RxJumboBdPhy.Low); + REG_WR(pDevice, RcvDataBdIn.JumboRcvRcb.u.MaxLen_Flags, 0); + REG_WR(pDevice, RcvDataBdIn.JumboRcvRcb.NicRingAddr, + (LM_UINT32) T3_NIC_JUMBO_RCV_BUFFER_DESC_ADDR); + + REG_WR(pDevice, RcvBdIn.JumboRcvThreshold, pDevice->RxJumboDescCnt/8); + +#endif /* T3_JUMBO_RCV_RCB_ENTRY_COUNT */ + + /* Initialize the Mini Receive RCB. */ + REG_WR(pDevice, RcvDataBdIn.MiniRcvRcb.u.MaxLen_Flags, + T3_RCB_FLAG_RING_DISABLED); + + /* Disable all the unused rings. */ + for(j = 0; j < T3_MAX_SEND_RCB_COUNT; j++) { + MEM_WR(pDevice, SendRcb[j].u.MaxLen_Flags, + T3_RCB_FLAG_RING_DISABLED); + } /* for */ + + } + + /* Initialize the indices. */ + pDevice->SendProdIdx = 0; + pDevice->SendConIdx = 0; + + MB_REG_WR(pDevice, Mailbox.SendHostProdIdx[0].Low, 0); + MB_REG_RD(pDevice, Mailbox.SendHostProdIdx[0].Low); + MB_REG_WR(pDevice, Mailbox.SendNicProdIdx[0].Low, 0); + MB_REG_RD(pDevice, Mailbox.SendNicProdIdx[0].Low); + + /* Set up host or NIC based send RCB. */ + if (!(pDevice->Flags & NIC_SEND_BD_FLAG)) + { + MEM_WR(pDevice, SendRcb[0].HostRingAddr.High, + pDevice->SendBdPhy.High); + MEM_WR(pDevice, SendRcb[0].HostRingAddr.Low, + pDevice->SendBdPhy.Low); + + /* Setup the RCB. */ + MEM_WR(pDevice, SendRcb[0].u.MaxLen_Flags, + T3_SEND_RCB_ENTRY_COUNT << 16); + + if(!T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) + { + /* Set up the NIC ring address in the RCB. */ + MEM_WR(pDevice, SendRcb[0].NicRingAddr,T3_NIC_SND_BUFFER_DESC_ADDR); + } + for(k = 0; k < T3_SEND_RCB_ENTRY_COUNT; k++) + { + pDevice->pSendBdVirt[k].HostAddr.High = 0; + pDevice->pSendBdVirt[k].HostAddr.Low = 0; + } + } +#ifdef BCM_NIC_SEND_BD + else + { + MEM_WR(pDevice, SendRcb[0].HostRingAddr.High, 0); + MEM_WR(pDevice, SendRcb[0].HostRingAddr.Low, 0); + MEM_WR(pDevice, SendRcb[0].NicRingAddr, + pDevice->SendBdPhy.Low); + + for(k = 0; k < T3_SEND_RCB_ENTRY_COUNT; k++) + { + MM_MEMWRITEL(&(pDevice->pSendBdVirt[k].HostAddr.High), 0); + MM_MEMWRITEL(&(pDevice->pSendBdVirt[k].HostAddr.Low), 0); + MM_MEMWRITEL(&(pDevice->pSendBdVirt[k].u1.Len_Flags), 0); + pDevice->ShadowSendBd[k].HostAddr.High = 0; + pDevice->ShadowSendBd[k].u1.Len_Flags = 0; + } + } +#endif + MM_ATOMIC_SET(&pDevice->SendBdLeft, T3_SEND_RCB_ENTRY_COUNT-1); + + /* Configure the receive return rings. */ + for(j = 0; j < T3_MAX_RCV_RETURN_RCB_COUNT; j++) + { + MEM_WR(pDevice, RcvRetRcb[j].u.MaxLen_Flags, T3_RCB_FLAG_RING_DISABLED); + } + + pDevice->RcvRetConIdx = 0; + + MEM_WR(pDevice, RcvRetRcb[0].HostRingAddr.High, + pDevice->RcvRetBdPhy.High); + MEM_WR(pDevice, RcvRetRcb[0].HostRingAddr.Low, + pDevice->RcvRetBdPhy.Low); + + MEM_WR(pDevice, RcvRetRcb[0].NicRingAddr, 0); + + /* Setup the RCB. */ + MEM_WR(pDevice, RcvRetRcb[0].u.MaxLen_Flags, + pDevice->RcvRetRcbEntryCount << 16); + + /* Reinitialize RX ring producer index */ + MB_REG_WR(pDevice, Mailbox.RcvStdProdIdx.Low, 0); + MB_REG_RD(pDevice, Mailbox.RcvStdProdIdx.Low); + MB_REG_WR(pDevice, Mailbox.RcvJumboProdIdx.Low, 0); + MB_REG_RD(pDevice, Mailbox.RcvJumboProdIdx.Low); + MB_REG_WR(pDevice, Mailbox.RcvMiniProdIdx.Low, 0); + MB_REG_RD(pDevice, Mailbox.RcvMiniProdIdx.Low); + +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + pDevice->RxJumboProdIdx = 0; + pDevice->RxJumboQueuedCnt = 0; +#endif + + /* Reinitialize our copy of the indices. */ + pDevice->RxStdProdIdx = 0; + pDevice->RxStdQueuedCnt = 0; + +#if T3_JUMBO_RCV_ENTRY_COUNT + pDevice->RxJumboProdIdx = 0; +#endif /* T3_JUMBO_RCV_ENTRY_COUNT */ + + /* Configure the MAC address. */ + LM_SetMacAddress(pDevice, pDevice->NodeAddress); + + /* Initialize the transmit random backoff seed. */ + Value32 = (pDevice->NodeAddress[0] + pDevice->NodeAddress[1] + + pDevice->NodeAddress[2] + pDevice->NodeAddress[3] + + pDevice->NodeAddress[4] + pDevice->NodeAddress[5]) & + MAC_TX_BACKOFF_SEED_MASK; + REG_WR(pDevice, MacCtrl.TxBackoffSeed, Value32); + + /* Receive MTU. Frames larger than the MTU is marked as oversized. */ + REG_WR(pDevice, MacCtrl.MtuSize, pDevice->RxMtu + 8); /* CRC + VLAN. */ + + /* Configure Time slot/IPG per 802.3 */ + REG_WR(pDevice, MacCtrl.TxLengths, 0x2620); + + /* + * Configure Receive Rules so that packets don't match + * Programmble rule will be queued to Return Ring 1 + */ + REG_WR(pDevice, MacCtrl.RcvRuleCfg, RX_RULE_DEFAULT_CLASS); + + /* + * Configure to have 16 Classes of Services (COS) and one + * queue per class. Bad frames are queued to RRR#1. + * And frames don't match rules are also queued to COS#1. + */ + REG_WR(pDevice, RcvListPlmt.Config, 0x181); + + /* Enable Receive Placement Statistics */ + if ((pDevice->DmaReadFifoSize == DMA_READ_MODE_FIFO_LONG_BURST) && + (pDevice->TaskToOffload & LM_TASK_OFFLOAD_TCP_SEGMENTATION)) + { + Value32 = REG_RD(pDevice, RcvListPlmt.StatsEnableMask); + Value32 &= ~T3_DISABLE_LONG_BURST_READ_DYN_FIX; + REG_WR(pDevice, RcvListPlmt.StatsEnableMask, Value32); + } + else + { + REG_WR(pDevice, RcvListPlmt.StatsEnableMask,0xffffff); + } + REG_WR(pDevice, RcvListPlmt.StatsCtrl, RCV_LIST_STATS_ENABLE); + + /* Enable Send Data Initator Statistics */ + REG_WR(pDevice, SndDataIn.StatsEnableMask,0xffffff); + REG_WR(pDevice, SndDataIn.StatsCtrl, + T3_SND_DATA_IN_STATS_CTRL_ENABLE | \ + T3_SND_DATA_IN_STATS_CTRL_FASTER_UPDATE); + + /* Disable the host coalescing state machine before configuring it's */ + /* parameters. */ + REG_WR(pDevice, HostCoalesce.Mode, 0); + for(j = 0; j < 2000; j++) + { + Value32 = REG_RD(pDevice, HostCoalesce.Mode); + if(!(Value32 & HOST_COALESCE_ENABLE)) + { + break; + } + MM_Wait(10); + } + + /* Host coalescing configurations. */ + REG_WR(pDevice, HostCoalesce.RxCoalescingTicks, pDevice->RxCoalescingTicks); + REG_WR(pDevice, HostCoalesce.TxCoalescingTicks, pDevice->TxCoalescingTicks); + REG_WR(pDevice, HostCoalesce.RxMaxCoalescedFrames, + pDevice->RxMaxCoalescedFrames); + REG_WR(pDevice, HostCoalesce.TxMaxCoalescedFrames, + pDevice->TxMaxCoalescedFrames); + + if(!T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) + { + REG_WR(pDevice, HostCoalesce.RxCoalescedTickDuringInt, + pDevice->RxCoalescingTicksDuringInt); + REG_WR(pDevice, HostCoalesce.TxCoalescedTickDuringInt, + pDevice->TxCoalescingTicksDuringInt); + } + REG_WR(pDevice, HostCoalesce.RxMaxCoalescedFramesDuringInt, + pDevice->RxMaxCoalescedFramesDuringInt); + REG_WR(pDevice, HostCoalesce.TxMaxCoalescedFramesDuringInt, + pDevice->TxMaxCoalescedFramesDuringInt); + + /* Initialize the address of the status block. The NIC will DMA */ + /* the status block to this memory which resides on the host. */ + REG_WR(pDevice, HostCoalesce.StatusBlkHostAddr.High, + pDevice->StatusBlkPhy.High); + REG_WR(pDevice, HostCoalesce.StatusBlkHostAddr.Low, + pDevice->StatusBlkPhy.Low); + + /* Initialize the address of the statistics block. The NIC will DMA */ + /* the statistics to this block of memory. */ + if(!T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) + { + REG_WR(pDevice, HostCoalesce.StatsBlkHostAddr.High, + pDevice->StatsBlkPhy.High); + REG_WR(pDevice, HostCoalesce.StatsBlkHostAddr.Low, + pDevice->StatsBlkPhy.Low); + + REG_WR(pDevice, HostCoalesce.StatsCoalescingTicks, + pDevice->StatsCoalescingTicks); + + REG_WR(pDevice, HostCoalesce.StatsBlkNicAddr, 0x300); + REG_WR(pDevice, HostCoalesce.StatusBlkNicAddr,0xb00); + } + + /* Enable Host Coalesing state machine */ + REG_WR(pDevice, HostCoalesce.Mode, HOST_COALESCE_ENABLE | + pDevice->CoalesceMode); + + /* Enable the Receive BD Completion state machine. */ + REG_WR(pDevice, RcvBdComp.Mode, RCV_BD_COMP_MODE_ENABLE | + RCV_BD_COMP_MODE_ATTN_ENABLE); + + /* Enable the Receive List Placement state machine. */ + REG_WR(pDevice, RcvListPlmt.Mode, RCV_LIST_PLMT_MODE_ENABLE); + + if(!T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) + { + /* Enable the Receive List Selector state machine. */ + REG_WR(pDevice, RcvListSel.Mode, RCV_LIST_SEL_MODE_ENABLE | + RCV_LIST_SEL_MODE_ATTN_ENABLE); + } + + /* Reset the Rx MAC State Machine. + * + * The Rx MAC State Machine must be reset when using fiber to prevent the + * first packet being lost. This is needed primarily so that the loopback + * test (which currently only sends one packet) doesn't fail. + * + * Also note that the Rx MAC State Machine (0x468) should be reset _before_ + * writting to the MAC Mode register (0x400). Failures have been seen on + * 5780/5714's using fiber where they stopped receiving packets in a simple + * ping test when the Rx MAC State Machine was reset _after_ the MAC Mode + * register was set. + */ + + if ((pDevice->TbiFlags & ENABLE_TBI_FLAG) || + (pDevice->PhyFlags & PHY_IS_FIBER)) + { + REG_WR(pDevice, MacCtrl.RxMode, RX_MODE_RESET); + REG_RD_BACK(pDevice, MacCtrl.RxMode); + MM_Wait(10); + REG_WR(pDevice, MacCtrl.RxMode, pDevice->RxMode); + REG_RD_BACK(pDevice, MacCtrl.RxMode); + } + + /* Clear the statistics block. */ + for(j = 0x0300; j < 0x0b00; j = j + 4) + { + MEM_WR_OFFSET(pDevice, j, 0); + } + + /* Set Mac Mode */ + if (pDevice->TbiFlags & ENABLE_TBI_FLAG) + { + pDevice->MacMode = MAC_MODE_PORT_MODE_TBI; + } + else if(pDevice->PhyFlags & PHY_IS_FIBER) + { + pDevice->MacMode = MAC_MODE_PORT_MODE_GMII; + } + else + { + pDevice->MacMode = 0; + } + + /* Enable transmit DMA, clear statistics. */ + pDevice->MacMode |= MAC_MODE_ENABLE_TX_STATISTICS | + MAC_MODE_ENABLE_RX_STATISTICS | MAC_MODE_ENABLE_TDE | + MAC_MODE_ENABLE_RDE | MAC_MODE_ENABLE_FHDE; + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode | + MAC_MODE_CLEAR_RX_STATISTICS | MAC_MODE_CLEAR_TX_STATISTICS); + + /* GRC miscellaneous local control register. */ + pDevice->GrcLocalCtrl = GRC_MISC_LOCAL_CTRL_INT_ON_ATTN | + GRC_MISC_LOCAL_CTRL_AUTO_SEEPROM; + + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700) + { + pDevice->GrcLocalCtrl |= GRC_MISC_LOCAL_CTRL_GPIO_OE1 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1; + } + else if ((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5704) && + !(pDevice->Flags & EEPROM_WP_FLAG)) + { + /* Make sure we're on Vmain */ + /* The other port may cause us to be on Vaux */ + pDevice->GrcLocalCtrl |= GRC_MISC_LOCAL_CTRL_GPIO_OE2 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT2; + } + + RAW_REG_WR(pDevice, Grc.LocalCtrl, pDevice->GrcLocalCtrl); + MM_Wait(40); + + /* Reset RX counters. */ + for(j = 0; j < sizeof(LM_RX_COUNTERS); j++) + { + ((PLM_UINT8) &pDevice->RxCounters)[j] = 0; + } + + /* Reset TX counters. */ + for(j = 0; j < sizeof(LM_TX_COUNTERS); j++) + { + ((PLM_UINT8) &pDevice->TxCounters)[j] = 0; + } + + MB_REG_WR(pDevice, Mailbox.Interrupt[0].Low, 0); + MB_REG_RD(pDevice, Mailbox.Interrupt[0].Low); + pDevice->LastTag = 0; + + if(!T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) + { + /* Enable the DMA Completion state machine. */ + REG_WR(pDevice, DmaComp.Mode, DMA_COMP_MODE_ENABLE); + } + + /* Enable the DMA Write state machine. */ + Value32 = DMA_WRITE_MODE_ENABLE | + DMA_WRITE_MODE_TARGET_ABORT_ATTN_ENABLE | + DMA_WRITE_MODE_MASTER_ABORT_ATTN_ENABLE | + DMA_WRITE_MODE_PARITY_ERROR_ATTN_ENABLE | + DMA_WRITE_MODE_ADDR_OVERFLOW_ATTN_ENABLE | + DMA_WRITE_MODE_FIFO_OVERRUN_ATTN_ENABLE | + DMA_WRITE_MODE_FIFO_UNDERRUN_ATTN_ENABLE | + DMA_WRITE_MODE_FIFO_OVERREAD_ATTN_ENABLE | + DMA_WRITE_MODE_LONG_READ_ATTN_ENABLE; + + if (pDevice->Flags & DMA_WR_MODE_RX_ACCELERATE_FLAG) + { + Value32 |= DMA_WRITE_MODE_RECEIVE_ACCELERATE; + } + + if (pDevice->Flags & HOST_COALESCING_BUG_FIX) + { + Value32 |= (1 << 29); + } + + REG_WR(pDevice, DmaWrite.Mode, Value32); + + if (!(pDevice->PciState & T3_PCI_STATE_CONVENTIONAL_PCI_MODE)) + { + if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5703) + { + Value32 = REG_RD(pDevice, PciCfg.PciXCapabilities); + Value32 &= ~PCIX_CMD_MAX_BURST_MASK; + Value32 |= PCIX_CMD_MAX_BURST_CPIOB << PCIX_CMD_MAX_BURST_SHL; + REG_WR(pDevice, PciCfg.PciXCapabilities, Value32); + } + else if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5704) + { + Value32 = REG_RD(pDevice, PciCfg.PciXCapabilities); + Value32 &= ~(PCIX_CMD_MAX_SPLIT_MASK | PCIX_CMD_MAX_BURST_MASK); + Value32 |= ((PCIX_CMD_MAX_BURST_CPIOB << PCIX_CMD_MAX_BURST_SHL) & + PCIX_CMD_MAX_BURST_MASK); + if (pDevice->Flags & MULTI_SPLIT_ENABLE_FLAG) + { + Value32 |= (pDevice->SplitModeMaxReq << PCIX_CMD_MAX_SPLIT_SHL) + & PCIX_CMD_MAX_SPLIT_MASK; + } + REG_WR(pDevice, PciCfg.PciXCapabilities, Value32); + } + } + + /* Enable the Read DMA state machine. */ + Value32 = DMA_READ_MODE_ENABLE | + DMA_READ_MODE_TARGET_ABORT_ATTN_ENABLE | + DMA_READ_MODE_MASTER_ABORT_ATTN_ENABLE | + DMA_READ_MODE_PARITY_ERROR_ATTN_ENABLE | + DMA_READ_MODE_ADDR_OVERFLOW_ATTN_ENABLE | + DMA_READ_MODE_FIFO_OVERRUN_ATTN_ENABLE | + DMA_READ_MODE_FIFO_UNDERRUN_ATTN_ENABLE | + DMA_READ_MODE_FIFO_OVERREAD_ATTN_ENABLE | + DMA_READ_MODE_LONG_READ_ATTN_ENABLE; + + if (pDevice->Flags & MULTI_SPLIT_ENABLE_FLAG) + { + Value32 |= DMA_READ_MODE_MULTI_SPLIT_ENABLE; + } + + if (T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) + { + Value32 |= pDevice->DmaReadFifoSize; + } +#ifdef INCLUDE_TCP_SEG_SUPPORT + if (T3_ASIC_IS_575X_PLUS(pDevice->ChipRevId)) + { + Value32 |= BIT_27; + } +#endif + + + REG_WR(pDevice, DmaRead.Mode, Value32); + + /* Enable the Receive Data Completion state machine. */ + REG_WR(pDevice, RcvDataComp.Mode, RCV_DATA_COMP_MODE_ENABLE | + RCV_DATA_COMP_MODE_ATTN_ENABLE); + + if (!T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) + { + /* Enable the Mbuf Cluster Free state machine. */ + REG_WR(pDevice, MbufClusterFree.Mode, MBUF_CLUSTER_FREE_MODE_ENABLE); + } + + /* Enable the Send Data Completion state machine. */ + REG_WR(pDevice, SndDataComp.Mode, SND_DATA_COMP_MODE_ENABLE); + + /* Enable the Send BD Completion state machine. */ + REG_WR(pDevice, SndBdComp.Mode, SND_BD_COMP_MODE_ENABLE | + SND_BD_COMP_MODE_ATTN_ENABLE); + + /* Enable the Receive BD Initiator state machine. */ + REG_WR(pDevice, RcvBdIn.Mode, RCV_BD_IN_MODE_ENABLE | + RCV_BD_IN_MODE_BD_IN_DIABLED_RCB_ATTN_ENABLE); + + /* Enable the Receive Data and Receive BD Initiator state machine. */ + REG_WR(pDevice, RcvDataBdIn.Mode, RCV_DATA_BD_IN_MODE_ENABLE | + RCV_DATA_BD_IN_MODE_INVALID_RING_SIZE); + + /* Enable the Send Data Initiator state machine. */ + REG_WR(pDevice, SndDataIn.Mode, T3_SND_DATA_IN_MODE_ENABLE); + +#ifdef INCLUDE_TCP_SEG_SUPPORT + if (T3_ASIC_IS_575X_PLUS(pDevice->ChipRevId)) + { + REG_WR(pDevice, SndDataIn.Mode, T3_SND_DATA_IN_MODE_ENABLE | 0x8); + } +#endif + + /* Enable the Send BD Initiator state machine. */ + REG_WR(pDevice, SndBdIn.Mode, SND_BD_IN_MODE_ENABLE | + SND_BD_IN_MODE_ATTN_ENABLE); + + /* Enable the Send BD Selector state machine. */ + REG_WR(pDevice, SndBdSel.Mode, SND_BD_SEL_MODE_ENABLE | + SND_BD_SEL_MODE_ATTN_ENABLE); + +#ifdef INCLUDE_5701_AX_FIX + if(pDevice->ChipRevId == T3_CHIP_ID_5701_A0) + { + LM_LoadRlsFirmware(pDevice); + } +#endif + + /* Queue Rx packet buffers. */ + if(pDevice->QueueRxPackets) + { + LM_QueueRxPackets(pDevice); + } + + if (pDevice->ChipRevId == T3_CHIP_ID_5705_A0) + { + Value32 = MEM_RD_OFFSET(pDevice, T3_NIC_STD_RCV_BUFFER_DESC_ADDR + 8); + j = 0; + while ((Value32 != MAX_STD_RCV_BUFFER_SIZE) && (j < 10)) + { + MM_Wait(20); + Value32 = MEM_RD_OFFSET(pDevice, T3_NIC_STD_RCV_BUFFER_DESC_ADDR + 8); + j++; + } + if (j >= 10) + { + reset_count++; + LM_Abort(pDevice); + if (reset_count > 5) + return LM_STATUS_FAILURE; + goto restart_reset; + } + } + + /* Enable the transmitter. */ + pDevice->TxMode = TX_MODE_ENABLE; + REG_WR(pDevice, MacCtrl.TxMode, pDevice->TxMode); + + /* Enable the receiver. */ + pDevice->RxMode = (pDevice->RxMode & RX_MODE_KEEP_VLAN_TAG) | + RX_MODE_ENABLE; + REG_WR(pDevice, MacCtrl.RxMode, pDevice->RxMode); + +#ifdef BCM_WOL + if (pDevice->RestoreOnWakeUp) + { + pDevice->RestoreOnWakeUp = FALSE; + pDevice->DisableAutoNeg = pDevice->WakeUpDisableAutoNeg; + pDevice->RequestedLineSpeed = pDevice->WakeUpRequestedLineSpeed; + pDevice->RequestedDuplexMode = pDevice->WakeUpRequestedDuplexMode; + } +#endif + + /* Disable auto polling. */ + pDevice->MiMode = 0xc0000; + REG_WR(pDevice, MacCtrl.MiMode, pDevice->MiMode); + + REG_WR(pDevice, MacCtrl.LedCtrl, pDevice->LedCtrl); + + /* Activate Link to enable MAC state machine */ + REG_WR(pDevice, MacCtrl.MiStatus, MI_STATUS_ENABLE_LINK_STATUS_ATTN); + + if (pDevice->TbiFlags & ENABLE_TBI_FLAG) + { + if (pDevice->ChipRevId == T3_CHIP_ID_5703_A1) + { + REG_WR(pDevice, MacCtrl.SerdesCfg, 0x616000); + } + if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5704) + { + + if(!(pDevice->TbiFlags & TBI_DO_PREEMPHASIS)) + { + /* Set SerDes drive transmission level to 1.2V */ + Value32 = REG_RD(pDevice, MacCtrl.SerdesCfg) & 0xfffff000; + REG_WR(pDevice, MacCtrl.SerdesCfg, Value32 | 0x880); + } + } + } + + REG_WR(pDevice, MacCtrl.LowWaterMarkMaxRxFrame, 2); + + if(pDevice->PhyFlags & PHY_IS_FIBER) + { + Value32 = REG_RD_OFFSET(pDevice, 0x5b0); + REG_WR_OFFSET(pDevice, 0x5b0, Value32 | BIT_10 ); + + pDevice->GrcLocalCtrl |= BIT_4 ; + pDevice->GrcLocalCtrl &= ~BIT_5 ; + + REG_WR(pDevice, Grc.LocalCtrl, pDevice->GrcLocalCtrl); + Value32 = REG_RD(pDevice, Grc.LocalCtrl); + MM_Wait(40); + } + + if (!pDevice->InitDone) + { + if(UNKNOWN_PHY_ID(pDevice->PhyId) && (pDevice->Flags & ROBO_SWITCH_FLAG)) { + pDevice->LinkStatus = LM_STATUS_LINK_ACTIVE; + } else { + pDevice->LinkStatus = LM_STATUS_LINK_DOWN; + } + } + + if (!(pDevice->TbiFlags & ENABLE_TBI_FLAG) && + ( ((pDevice->PhyId & PHY_ID_MASK) != PHY_BCM5401_PHY_ID)&& + ((pDevice->PhyId & PHY_ID_MASK) != PHY_BCM5411_PHY_ID) )) + { + /* 5401/5411 PHY needs a delay of about 1 second after PHY reset */ + /* Without the delay, it has problem linking at forced 10 half */ + /* So skip the reset... */ + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5780) + for(j =0; j<0x5000; j++) + MM_Wait(1); + + LM_ResetPhy(pDevice); + } + + /* Setup the phy chip. */ + LM_SetupPhy(pDevice); + + if (!(pDevice->TbiFlags & ENABLE_TBI_FLAG)){ + /* Clear CRC stats */ + LM_ReadPhy(pDevice, 0x1e, &Value32); + LM_WritePhy(pDevice, 0x1e, Value32 | 0x8000); + LM_ReadPhy(pDevice, 0x14, &Value32); + } + + /* Set up the receive mask. */ + LM_SetReceiveMask(pDevice, pDevice->ReceiveMask); + +#ifdef INCLUDE_TCP_SEG_SUPPORT + if (pDevice->TaskToOffload & LM_TASK_OFFLOAD_TCP_SEGMENTATION) + { + if (LM_LoadStkOffLdFirmware(pDevice) == LM_STATUS_FAILURE) + { + return LM_STATUS_FAILURE; + } + } +#endif + LM_WritePostResetSignatures(pDevice, LM_INIT_RESET); + + return LM_STATUS_SUCCESS; +} /* LM_ResetAdapter */ + + +/******************************************************************************/ +/* Description: */ +/* This routine disables the adapter from generating interrupts. */ +/* */ +/* Return: */ +/* LM_STATUS_SUCCESS */ +/******************************************************************************/ +LM_STATUS +LM_DisableInterrupt( + PLM_DEVICE_BLOCK pDevice) +{ + REG_WR(pDevice, PciCfg.MiscHostCtrl, pDevice->MiscHostCtrl | + MISC_HOST_CTRL_MASK_PCI_INT); + MB_REG_WR(pDevice, Mailbox.Interrupt[0].Low, 1); + if (pDevice->Flags & FLUSH_POSTED_WRITE_FLAG) + { + MB_REG_RD(pDevice, Mailbox.Interrupt[0].Low); + } + + return LM_STATUS_SUCCESS; +} + + + +/******************************************************************************/ +/* Description: */ +/* This routine enables the adapter to generate interrupts. */ +/* */ +/* Return: */ +/* LM_STATUS_SUCCESS */ +/******************************************************************************/ +LM_STATUS +LM_EnableInterrupt( + PLM_DEVICE_BLOCK pDevice) +{ + MB_REG_WR(pDevice, Mailbox.Interrupt[0].Low, pDevice->LastTag << 24); + if (pDevice->Flags & FLUSH_POSTED_WRITE_FLAG) + { + MB_REG_RD(pDevice, Mailbox.Interrupt[0].Low); + } + + REG_WR(pDevice, PciCfg.MiscHostCtrl, pDevice->MiscHostCtrl & + ~MISC_HOST_CTRL_MASK_PCI_INT); + + REG_WR(pDevice, HostCoalesce.Mode, pDevice->CoalesceMode | + HOST_COALESCE_ENABLE | HOST_COALESCE_NOW); + + return LM_STATUS_SUCCESS; +} + + + +/******************************************************************************/ +/* Description: */ +/* This routine puts a packet on the wire if there is a transmit DMA */ +/* descriptor available; otherwise the packet is queued for later */ +/* transmission. If the second argue is NULL, this routine will put */ +/* the queued packet on the wire if possible. */ +/* */ +/* Return: */ +/* LM_STATUS_SUCCESS */ +/******************************************************************************/ +LM_STATUS +LM_SendPacket(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket) +{ + LM_UINT32 FragCount; + PT3_SND_BD pSendBd, pTmpSendBd; +#ifdef BCM_NIC_SEND_BD + PT3_SND_BD pShadowSendBd; + T3_SND_BD NicSendBdArr[MAX_FRAGMENT_COUNT]; +#endif + LM_UINT32 StartIdx, Idx; + + while (1) + { + /* Initalize the send buffer descriptors. */ + StartIdx = Idx = pDevice->SendProdIdx; + +#ifdef BCM_NIC_SEND_BD + if (pDevice->Flags & NIC_SEND_BD_FLAG) + { + pTmpSendBd = pSendBd = &NicSendBdArr[0]; + } + else +#endif + { + pTmpSendBd = pSendBd = &pDevice->pSendBdVirt[Idx]; + } + + /* Next producer index. */ + for(FragCount = 0; ; ) + { + LM_UINT32 Value32, Len; + + /* Initialize the pointer to the send buffer fragment. */ + MM_MapTxDma(pDevice, pPacket, &pSendBd->HostAddr, &Len, FragCount); + + pSendBd->u2.VlanTag = pPacket->VlanTag; + + /* Setup the control flags and send buffer size. */ + Value32 = (Len << 16) | pPacket->Flags; + +#ifdef INCLUDE_TCP_SEG_SUPPORT + if (Value32 & (SND_BD_FLAG_CPU_PRE_DMA | SND_BD_FLAG_CPU_POST_DMA)) + { + if(T3_ASIC_IS_575X_PLUS(pDevice->ChipRevId)) + { + pSendBd->u2.s2.Reserved = pPacket->u.Tx.MaxSegmentSize; + } + else if (FragCount == 0) + { + pSendBd->u2.s2.Reserved = pPacket->u.Tx.MaxSegmentSize; + } + else + { + pSendBd->u2.s2.Reserved = 0; + Value32 &= 0xffff0fff; + } + } +#endif + Idx = (Idx + 1) & T3_SEND_RCB_ENTRY_COUNT_MASK; + + FragCount++; + if (FragCount >= pPacket->u.Tx.FragCount) + { + pSendBd->u1.Len_Flags = Value32 | SND_BD_FLAG_END; + break; + } + else + { + pSendBd->u1.Len_Flags = Value32; + } + + pSendBd++; + if ((Idx == 0) && + !(pDevice->Flags & NIC_SEND_BD_FLAG)) + { + pSendBd = &pDevice->pSendBdVirt[0]; + } + + pDevice->SendRing[Idx] = 0; + + } /* for */ + if (pDevice->Flags & TX_4G_WORKAROUND_FLAG) + { + if (LM_Test4GBoundary(pDevice, pPacket, pTmpSendBd) == + LM_STATUS_SUCCESS) + { + if (MM_CoalesceTxBuffer(pDevice, pPacket) != LM_STATUS_SUCCESS) + { + QQ_PushHead(&pDevice->TxPacketFreeQ.Container, pPacket); + return LM_STATUS_FAILURE; + } + continue; + } + } + break; + } + /* Put the packet descriptor in the ActiveQ. */ + pDevice->SendRing[StartIdx] = pPacket; + +#ifdef BCM_NIC_SEND_BD + if (pDevice->Flags & NIC_SEND_BD_FLAG) + { + pSendBd = &pDevice->pSendBdVirt[StartIdx]; + pShadowSendBd = &pDevice->ShadowSendBd[StartIdx]; + + while (StartIdx != Idx) + { + LM_UINT32 Value32; + + if ((Value32 = pTmpSendBd->HostAddr.High) != + pShadowSendBd->HostAddr.High) + { + MM_MEMWRITEL(&(pSendBd->HostAddr.High), Value32); + pShadowSendBd->HostAddr.High = Value32; + } + + MM_MEMWRITEL(&(pSendBd->HostAddr.Low), pTmpSendBd->HostAddr.Low); + + if ((Value32 = pTmpSendBd->u1.Len_Flags) != + pShadowSendBd->u1.Len_Flags) + { + MM_MEMWRITEL(&(pSendBd->u1.Len_Flags), Value32); + pShadowSendBd->u1.Len_Flags = Value32; + } + + if (pPacket->Flags & SND_BD_FLAG_VLAN_TAG) + { + MM_MEMWRITEL(&(pSendBd->u2.VlanTag), pTmpSendBd->u2.VlanTag); + } + + StartIdx = (StartIdx + 1) & T3_SEND_RCB_ENTRY_COUNT_MASK; + if (StartIdx == 0) + { + pSendBd = &pDevice->pSendBdVirt[0]; + pShadowSendBd = &pDevice->ShadowSendBd[0]; + } + else + { + pSendBd++; + pShadowSendBd++; + } + pTmpSendBd++; + } + MM_WMB(); + MB_REG_WR(pDevice, Mailbox.SendNicProdIdx[0].Low, Idx); + + if(T3_CHIP_REV(pDevice->ChipRevId) == T3_CHIP_REV_5700_BX) + { + MB_REG_WR(pDevice, Mailbox.SendNicProdIdx[0].Low, Idx); + } + if (pDevice->Flags & FLUSH_POSTED_WRITE_FLAG) + { + MB_REG_RD(pDevice, Mailbox.SendNicProdIdx[0].Low); + } + else + { + MM_MMIOWB(); + } + } + else +#endif + { + MM_WMB(); + MB_REG_WR(pDevice, Mailbox.SendHostProdIdx[0].Low, Idx); + + if(T3_CHIP_REV(pDevice->ChipRevId) == T3_CHIP_REV_5700_BX) + { + MB_REG_WR(pDevice, Mailbox.SendHostProdIdx[0].Low, Idx); + } + if (pDevice->Flags & FLUSH_POSTED_WRITE_FLAG) + { + MB_REG_RD(pDevice, Mailbox.SendHostProdIdx[0].Low); + } + else + { + MM_MMIOWB(); + } + } + + /* Update the SendBdLeft count. */ + MM_ATOMIC_SUB(&pDevice->SendBdLeft, pPacket->u.Tx.FragCount); + + /* Update the producer index. */ + pDevice->SendProdIdx = Idx; + + return LM_STATUS_SUCCESS; +} + +STATIC LM_STATUS +LM_Test4GBoundary(PLM_DEVICE_BLOCK pDevice, PLM_PACKET pPacket, + PT3_SND_BD pSendBd) +{ + int FragCount; + LM_UINT32 Idx, Base, Len; + + Idx = pDevice->SendProdIdx; + for(FragCount = 0; ; ) + { + Len = pSendBd->u1.Len_Flags >> 16; + if (((Base = pSendBd->HostAddr.Low) > 0xffffdcc0) && + ((Base + 8 + Len) < Base)) + { + return LM_STATUS_SUCCESS; + } + FragCount++; + if (FragCount >= pPacket->u.Tx.FragCount) + { + break; + } + pSendBd++; + if (!(pDevice->Flags & NIC_SEND_BD_FLAG)) + { + Idx = (Idx + 1) & T3_SEND_RCB_ENTRY_COUNT_MASK; + if (Idx == 0) + { + pSendBd = &pDevice->pSendBdVirt[0]; + } + } + } + return LM_STATUS_FAILURE; +} + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_UINT32 +ComputeCrc32(LM_UINT8 *pBuffer, LM_UINT32 BufferSize) +{ + LM_UINT32 Reg; + LM_UINT32 Tmp; + int j, k; + + Reg = 0xffffffff; + + for(j = 0; j < BufferSize; j++) + { + Reg ^= pBuffer[j]; + + for(k = 0; k < 8; k++) + { + Tmp = Reg & 0x01; + + Reg >>= 1; + + if(Tmp) + { + Reg ^= 0xedb88320; + } + } + } + + return ~Reg; +} /* ComputeCrc32 */ + + + +/******************************************************************************/ +/* Description: */ +/* This routine sets the receive control register according to ReceiveMask */ +/* */ +/* Return: */ +/* LM_STATUS_SUCCESS */ +/******************************************************************************/ +LM_STATUS +LM_SetReceiveMask(PLM_DEVICE_BLOCK pDevice, LM_UINT32 Mask) +{ + LM_UINT32 ReceiveMask; + LM_UINT32 RxMode; + LM_UINT32 j, k; + + ReceiveMask = Mask; + + RxMode = pDevice->RxMode; + + if(Mask & LM_ACCEPT_UNICAST) + { + Mask &= ~LM_ACCEPT_UNICAST; + } + + if(Mask & LM_ACCEPT_MULTICAST) + { + Mask &= ~LM_ACCEPT_MULTICAST; + } + + if(Mask & LM_ACCEPT_ALL_MULTICAST) + { + Mask &= ~LM_ACCEPT_ALL_MULTICAST; + } + + if(Mask & LM_ACCEPT_BROADCAST) + { + Mask &= ~LM_ACCEPT_BROADCAST; + } + + RxMode &= ~RX_MODE_KEEP_VLAN_TAG; + if (Mask & LM_KEEP_VLAN_TAG) + { + RxMode |= RX_MODE_KEEP_VLAN_TAG; + Mask &= ~LM_KEEP_VLAN_TAG; + } + + RxMode &= ~RX_MODE_PROMISCUOUS_MODE; + if(Mask & LM_PROMISCUOUS_MODE) + { + RxMode |= RX_MODE_PROMISCUOUS_MODE; + Mask &= ~LM_PROMISCUOUS_MODE; + } + + RxMode &= ~(RX_MODE_ACCEPT_RUNTS | RX_MODE_ACCEPT_OVERSIZED); + if(Mask & LM_ACCEPT_ERROR_PACKET) + { + RxMode |= RX_MODE_ACCEPT_RUNTS | RX_MODE_ACCEPT_OVERSIZED; + Mask &= ~LM_ACCEPT_ERROR_PACKET; + } + + /* Make sure all the bits are valid before committing changes. */ + if(Mask) + { + return LM_STATUS_FAILURE; + } + + /* Commit the new filter. */ + pDevice->ReceiveMask = ReceiveMask; + + pDevice->RxMode = RxMode; + + if (pDevice->PowerLevel != LM_POWER_STATE_D0) + { + return LM_STATUS_SUCCESS; + } + + REG_WR(pDevice, MacCtrl.RxMode, RxMode); + + /* Set up the MC hash table. */ + if(ReceiveMask & LM_ACCEPT_ALL_MULTICAST) + { + for(k = 0; k < 4; k++) + { + REG_WR(pDevice, MacCtrl.HashReg[k], 0xffffffff); + } + } + else if(ReceiveMask & LM_ACCEPT_MULTICAST) + { + for(k = 0; k < 4; k++) + { + REG_WR(pDevice, MacCtrl.HashReg[k], pDevice->MulticastHash[k]); + } + } + else + { + /* Reject all multicast frames. */ + for(j = 0; j < 4; j++) + { + REG_WR(pDevice, MacCtrl.HashReg[j], 0); + } + } + + /* By default, Tigon3 will accept broadcast frames. We need to setup */ + if(ReceiveMask & LM_ACCEPT_BROADCAST) + { + REG_WR(pDevice, MacCtrl.RcvRules[RCV_RULE1_REJECT_BROADCAST_IDX].Rule, + REJECT_BROADCAST_RULE1_RULE & RCV_DISABLE_RULE_MASK); + REG_WR(pDevice, MacCtrl.RcvRules[RCV_RULE1_REJECT_BROADCAST_IDX].Value, + REJECT_BROADCAST_RULE1_VALUE & RCV_DISABLE_RULE_MASK); + REG_WR(pDevice, MacCtrl.RcvRules[RCV_RULE2_REJECT_BROADCAST_IDX].Rule, + REJECT_BROADCAST_RULE1_RULE & RCV_DISABLE_RULE_MASK); + REG_WR(pDevice, MacCtrl.RcvRules[RCV_RULE2_REJECT_BROADCAST_IDX].Value, + REJECT_BROADCAST_RULE1_VALUE & RCV_DISABLE_RULE_MASK); + } + else + { + REG_WR(pDevice, MacCtrl.RcvRules[RCV_RULE1_REJECT_BROADCAST_IDX].Rule, + REJECT_BROADCAST_RULE1_RULE); + REG_WR(pDevice, MacCtrl.RcvRules[RCV_RULE1_REJECT_BROADCAST_IDX].Value, + REJECT_BROADCAST_RULE1_VALUE); + REG_WR(pDevice, MacCtrl.RcvRules[RCV_RULE2_REJECT_BROADCAST_IDX].Rule, + REJECT_BROADCAST_RULE2_RULE); + REG_WR(pDevice, MacCtrl.RcvRules[RCV_RULE2_REJECT_BROADCAST_IDX].Value, + REJECT_BROADCAST_RULE2_VALUE); + } + + if(T3_ASIC_5714_FAMILY(pDevice->ChipRevId)) + { + k = 16; + } + else if (!T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) + { + k = 16; + } + else + { + k = 8; + } +#ifdef BCM_ASF + if (pDevice->AsfFlags & ASF_ENABLED) + { + k -= 4; + } +#endif + + /* disable the rest of the rules. */ + for(j = RCV_LAST_RULE_IDX; j < k; j++) + { + REG_WR(pDevice, MacCtrl.RcvRules[j].Rule, 0); + REG_WR(pDevice, MacCtrl.RcvRules[j].Value, 0); + } + + return LM_STATUS_SUCCESS; +} /* LM_SetReceiveMask */ + + + +/******************************************************************************/ +/* Description: */ +/* Disable the interrupt and put the transmitter and receiver engines in */ +/* an idle state. Also aborts all pending send requests and receive */ +/* buffers. */ +/* */ +/* Return: */ +/* LM_STATUS_SUCCESS */ +/******************************************************************************/ +LM_STATUS +LM_Abort( +PLM_DEVICE_BLOCK pDevice) +{ + PLM_PACKET pPacket; + LM_UINT Idx; + + LM_DisableInterrupt(pDevice); + + LM_DisableChip(pDevice); + + /* + * If we do not have a status block pointer, then + * the device hasn't really been opened. Do not + * attempt to clean up packets. + */ + if (pDevice->pStatusBlkVirt == NULL) + return LM_STATUS_SUCCESS; + + /* Abort packets that have already queued to go out. */ + Idx = pDevice->SendConIdx; + for ( ; ; ) + { + if ((pPacket = pDevice->SendRing[Idx])) + { + pDevice->SendRing[Idx] = 0; + pPacket->PacketStatus = LM_STATUS_TRANSMIT_ABORTED; + pDevice->TxCounters.TxPacketAbortedCnt++; + + MM_ATOMIC_ADD(&pDevice->SendBdLeft, pPacket->u.Tx.FragCount); + Idx = (Idx + pPacket->u.Tx.FragCount) & + T3_SEND_RCB_ENTRY_COUNT_MASK; + + QQ_PushTail(&pDevice->TxPacketXmittedQ.Container, pPacket); + } + else + { + break; + } + } + + /* Cleanup the receive return rings. */ +#ifdef BCM_NAPI_RXPOLL + LM_ServiceRxPoll(pDevice, T3_RCV_RETURN_RCB_ENTRY_COUNT); +#else + LM_ServiceRxInterrupt(pDevice); +#endif + + /* Indicate packets to the protocol. */ + MM_IndicateTxPackets(pDevice); + +#ifdef BCM_NAPI_RXPOLL + + /* Move the receive packet descriptors in the ReceivedQ to the */ + /* free queue. */ + for(; ;) + { + pPacket = (PLM_PACKET) QQ_PopHead( + &pDevice->RxPacketReceivedQ.Container); + if(pPacket == NULL) + { + break; + } + MM_UnmapRxDma(pDevice, pPacket); + QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket); + } +#else + /* Indicate received packets to the protocols. */ + MM_IndicateRxPackets(pDevice); +#endif + + /* Clean up the Std Receive Producer ring. */ + /* Don't always trust the consumer idx in the status block in case of */ + /* hw failure */ + Idx = 0; + + while(Idx < T3_STD_RCV_RCB_ENTRY_COUNT) + { + if ((pPacket = pDevice->RxStdRing[Idx])) + { + MM_UnmapRxDma(pDevice, pPacket); + QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket); + pDevice->RxStdRing[Idx] = 0; + } + + Idx++; + } /* while */ + + /* Reinitialize our copy of the indices. */ + pDevice->RxStdProdIdx = 0; + +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + /* Clean up the Jumbo Receive Producer ring. */ + Idx = 0; + + while(Idx < T3_JUMBO_RCV_RCB_ENTRY_COUNT) + { + if ((pPacket = pDevice->RxJumboRing[Idx])) + { + MM_UnmapRxDma(pDevice, pPacket); + QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket); + pDevice->RxJumboRing[Idx] = 0; + } + Idx++; + } /* while */ + + /* Reinitialize our copy of the indices. */ + pDevice->RxJumboProdIdx = 0; +#endif /* T3_JUMBO_RCV_RCB_ENTRY_COUNT */ + + /* Initialize the statistis Block */ + pDevice->pStatusBlkVirt->Status = 0; + pDevice->pStatusBlkVirt->RcvStdConIdx = 0; + pDevice->pStatusBlkVirt->RcvJumboConIdx = 0; + pDevice->pStatusBlkVirt->RcvMiniConIdx = 0; + + return LM_STATUS_SUCCESS; +} /* LM_Abort */ + + + +/******************************************************************************/ +/* Description: */ +/* Disable the interrupt and put the transmitter and receiver engines in */ +/* an idle state. Aborts all pending send requests and receive buffers. */ +/* Also free all the receive buffers. */ +/* */ +/* Return: */ +/* LM_STATUS_SUCCESS */ +/******************************************************************************/ +LM_STATUS +LM_DoHalt(LM_DEVICE_BLOCK *pDevice) +{ + PLM_PACKET pPacket; + LM_UINT32 EntryCnt; + + LM_DisableFW(pDevice); + + LM_WritePreResetSignatures(pDevice, LM_SHUTDOWN_RESET); + LM_Abort(pDevice); + + if((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5461_PHY_ID) + LM_WritePhy(pDevice, BCM546X_1c_SHADOW_REG, + (BCM546X_1c_SPR_CTRL_1 | BCM546X_1c_WR_EN)); + + /* Get the number of entries in the queue. */ + EntryCnt = QQ_GetEntryCnt(&pDevice->RxPacketFreeQ.Container); + + /* Make sure all the packets have been accounted for. */ + for(EntryCnt = 0; EntryCnt < pDevice->RxPacketDescCnt; EntryCnt++) + { + pPacket = (PLM_PACKET) QQ_PopHead(&pDevice->RxPacketFreeQ.Container); + if (pPacket == 0) + break; + + MM_FreeRxBuffer(pDevice, pPacket); + + QQ_PushTail(&pDevice->RxPacketFreeQ.Container, pPacket); + } + + LM_ResetChip(pDevice); + LM_WriteLegacySignatures(pDevice, LM_SHUTDOWN_RESET); + + /* Restore PCI configuration registers. */ + MM_WriteConfig32(pDevice, PCI_CACHE_LINE_SIZE_REG, + pDevice->SavedCacheLineReg); + LM_RegWrInd(pDevice, PCI_SUBSYSTEM_VENDOR_ID_REG, + (pDevice->SubsystemId << 16) | pDevice->SubsystemVendorId); + + /* Reprogram the MAC address. */ + LM_SetMacAddress(pDevice, pDevice->NodeAddress); + + return LM_STATUS_SUCCESS; +} /* LM_DoHalt */ + + +LM_STATUS +LM_Halt(LM_DEVICE_BLOCK *pDevice) +{ + LM_STATUS status; + + status = LM_DoHalt(pDevice); + LM_WritePostResetSignatures(pDevice, LM_SHUTDOWN_RESET); + return status; +} + + +STATIC LM_VOID +LM_WritePreResetSignatures(LM_DEVICE_BLOCK *pDevice, LM_RESET_TYPE Mode) +{ + MEM_WR_OFFSET(pDevice, T3_FIRMWARE_MAILBOX,T3_MAGIC_NUM_FIRMWARE_INIT_DONE); +#ifdef BCM_ASF + if (pDevice->AsfFlags & ASF_NEW_HANDSHAKE) + { + if (Mode == LM_INIT_RESET) + { + MEM_WR_OFFSET(pDevice, T3_DRV_STATE_MAILBOX, T3_DRV_STATE_START); + } + else if (Mode == LM_SHUTDOWN_RESET) + { + MEM_WR_OFFSET(pDevice, T3_DRV_STATE_MAILBOX, T3_DRV_STATE_UNLOAD); + } + else if (Mode == LM_SUSPEND_RESET) + { + MEM_WR_OFFSET(pDevice, T3_DRV_STATE_MAILBOX, T3_DRV_STATE_SUSPEND); + } + } +#endif +} + +STATIC LM_VOID +LM_WritePostResetSignatures(LM_DEVICE_BLOCK *pDevice, LM_RESET_TYPE Mode) +{ +#ifdef BCM_ASF + if (pDevice->AsfFlags & ASF_NEW_HANDSHAKE) + { + if (Mode == LM_INIT_RESET) + { + MEM_WR_OFFSET(pDevice, T3_DRV_STATE_MAILBOX, + T3_DRV_STATE_START_DONE); + } + else if (Mode == LM_SHUTDOWN_RESET) + { + MEM_WR_OFFSET(pDevice, T3_DRV_STATE_MAILBOX, + T3_DRV_STATE_UNLOAD_DONE); + } + } +#endif +} + +STATIC LM_VOID +LM_WriteLegacySignatures(LM_DEVICE_BLOCK *pDevice, LM_RESET_TYPE Mode) +{ +#ifdef BCM_ASF + if (pDevice->AsfFlags & ASF_ENABLED) + { + if (Mode == LM_INIT_RESET) + { + MEM_WR_OFFSET(pDevice, T3_DRV_STATE_MAILBOX, T3_DRV_STATE_START); + } + else if (Mode == LM_SHUTDOWN_RESET) + { + MEM_WR_OFFSET(pDevice, T3_DRV_STATE_MAILBOX, T3_DRV_STATE_UNLOAD); + } + else if (Mode == LM_SUSPEND_RESET) + { + MEM_WR_OFFSET(pDevice, T3_DRV_STATE_MAILBOX, T3_DRV_STATE_SUSPEND); + } + } +#endif +} + +STATIC LM_STATUS +LM_ResetChip(PLM_DEVICE_BLOCK pDevice) +{ + LM_UINT32 Value32; + LM_UINT32 j, tmp1 = 0, tmp2 = 0; + + /* Wait for access to the nvram interface before resetting. This is */ + if(T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5700 && + T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5701) + { + /* Request access to the flash interface. */ + LM_NVRAM_AcquireLock(pDevice); + } + + Value32 = GRC_MISC_CFG_CORE_CLOCK_RESET; + if (pDevice->Flags & PCI_EXPRESS_FLAG) + { + if (REG_RD_OFFSET(pDevice, 0x7e2c) == 0x60) /* PCIE 1.0 system */ + { + REG_WR_OFFSET(pDevice, 0x7e2c, 0x20); + } + if (pDevice->ChipRevId != T3_CHIP_ID_5750_A0) + { + /* This bit prevents PCIE link training during GRC reset */ + REG_WR(pDevice, Grc.MiscCfg, BIT_29); /* Write bit 29 first */ + Value32 |= BIT_29; /* and keep bit 29 set during GRC reset */ + } + } + if (T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) + { + Value32 |= GRC_MISC_GPHY_KEEP_POWER_DURING_RESET; + } + + if(T3_ASIC_5714_FAMILY(pDevice->ChipRevId) ) + { + /* Save the MSI ENABLE bit (may need to save the message as well) */ + tmp1 = LM_RegRd( pDevice, T3_PCI_MSI_ENABLE ); + } + + /* Global reset. */ + RAW_REG_WR(pDevice, Grc.MiscCfg, Value32); + MM_Wait(120); + + MM_ReadConfig32(pDevice, PCI_COMMAND_REG, &Value32); + + MM_Wait(120); + + /* make sure we re-enable indirect accesses */ + MM_WriteConfig32(pDevice, T3_PCI_MISC_HOST_CTRL_REG, + pDevice->MiscHostCtrl); + + /* Set MAX PCI retry to zero. */ + Value32 = T3_PCI_STATE_PCI_ROM_ENABLE | T3_PCI_STATE_PCI_ROM_RETRY_ENABLE; + if (pDevice->ChipRevId == T3_CHIP_ID_5704_A0) + { + if (!(pDevice->PciState & T3_PCI_STATE_CONVENTIONAL_PCI_MODE)) + { + Value32 |= T3_PCI_STATE_RETRY_SAME_DMA; + } + } + MM_WriteConfig32(pDevice, T3_PCI_STATE_REG, Value32); + + /* Restore PCI command register. */ + MM_WriteConfig32(pDevice, PCI_COMMAND_REG, + pDevice->PciCommandStatusWords); + + /* Disable PCI-X relaxed ordering bit. */ + MM_ReadConfig32(pDevice, PCIX_CAP_REG, &Value32); + Value32 &= ~PCIX_ENABLE_RELAXED_ORDERING; + MM_WriteConfig32(pDevice, PCIX_CAP_REG, Value32); + + /* Enable memory arbiter */ + if(T3_ASIC_5714_FAMILY(pDevice->ChipRevId) ) + { + Value32 = REG_RD(pDevice,MemArbiter.Mode); + REG_WR(pDevice, MemArbiter.Mode, T3_MEM_ARBITER_MODE_ENABLE | Value32); + } + else + { + REG_WR(pDevice, MemArbiter.Mode, T3_MEM_ARBITER_MODE_ENABLE); + } + + if(T3_ASIC_5714_FAMILY(pDevice->ChipRevId)) + { + /* restore the MSI ENABLE bit (may need to restore the message also) */ + tmp2 = LM_RegRd( pDevice, T3_PCI_MSI_ENABLE ); + tmp2 |= (tmp1 & (1 << 16)); + LM_RegWr( pDevice, T3_PCI_MSI_ENABLE, tmp2, TRUE ); + tmp2 = LM_RegRd( pDevice, T3_PCI_MSI_ENABLE ); + } + + + if (pDevice->ChipRevId == T3_CHIP_ID_5750_A3) + { + /* Because of chip bug on A3, we need to kill the CPU */ + LM_DisableFW(pDevice); + REG_WR_OFFSET(pDevice, 0x5000, 0x400); + } + + /* + * BCM4785: In order to avoid repercussions from using potentially + * defective internal ROM, stop the Rx RISC CPU, which is not + * required. + */ + if (pDevice->Flags & SB_CORE_FLAG) { + LM_DisableFW(pDevice); + LM_HaltCpu(pDevice, T3_RX_CPU_ID); + } + +#ifdef BIG_ENDIAN_HOST + /* Reconfigure the mode register. */ + Value32 = GRC_MODE_BYTE_SWAP_NON_FRAME_DATA | + GRC_MODE_WORD_SWAP_NON_FRAME_DATA | + GRC_MODE_BYTE_SWAP_DATA | + GRC_MODE_WORD_SWAP_DATA; +#else + /* Reconfigure the mode register. */ + Value32 = GRC_MODE_BYTE_SWAP_NON_FRAME_DATA | GRC_MODE_BYTE_SWAP_DATA; +#endif + REG_WR(pDevice, Grc.Mode, Value32); + + if ((pDevice->Flags & MINI_PCI_FLAG) && + (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5705)) + { + pDevice->ClockCtrl |= T3_PCI_CLKRUN_OUTPUT_EN; + if (pDevice->ChipRevId == T3_CHIP_ID_5705_A0) + { + pDevice->ClockCtrl |= T3_PCI_FORCE_CLKRUN; + } + REG_WR(pDevice, PciCfg.ClockCtrl, pDevice->ClockCtrl); + } + + if (pDevice->TbiFlags & ENABLE_TBI_FLAG) + { + pDevice->MacMode = MAC_MODE_PORT_MODE_TBI; + } + else if(pDevice->PhyFlags & PHY_IS_FIBER) + { + pDevice->MacMode = MAC_MODE_PORT_MODE_GMII; + } + else + { + pDevice->MacMode = 0; + } + + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode); + REG_RD_BACK(pDevice, MacCtrl.Mode); + MM_Wait(40); + + /* BCM4785: Don't use any firmware, so don't wait */ + if (!pDevice->Flags & SB_CORE_FLAG) { + /* Wait for the firmware to finish initialization. */ + for(j = 0; j < 100000; j++) { + MM_Wait(10); + + if (j < 100) + continue; + + Value32 = MEM_RD_OFFSET(pDevice, T3_FIRMWARE_MAILBOX); + if(Value32 == ~T3_MAGIC_NUM_FIRMWARE_INIT_DONE) { + break; + } + } + if ((j >= 0x100000) && (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5704)) { + /* if the boot code is not running */ + if (LM_NVRAM_AcquireLock(pDevice) != LM_STATUS_SUCCESS) { + LM_DEVICE_BLOCK *pDevice2; + + REG_WR(pDevice, Nvram.Cmd, NVRAM_CMD_RESET); + pDevice2 = MM_FindPeerDev(pDevice); + if (pDevice2 && !pDevice2->InitDone) + REG_WR(pDevice2, Nvram.Cmd, NVRAM_CMD_RESET); + } else { + LM_NVRAM_ReleaseLock(pDevice); + } + } + } + + if ((pDevice->Flags & PCI_EXPRESS_FLAG) && + (pDevice->ChipRevId != T3_CHIP_ID_5750_A0)) + { + /* Enable PCIE bug fix */ + Value32 = REG_RD_OFFSET(pDevice, 0x7c00); + REG_WR_OFFSET(pDevice, 0x7c00, Value32 | BIT_25 | BIT_29); + } + +#ifdef BCM_ASF + pDevice->AsfFlags = 0; + Value32 = MEM_RD_OFFSET(pDevice, T3_NIC_DATA_SIG_ADDR); + + if (Value32 == T3_NIC_DATA_SIG) + { + Value32 = MEM_RD_OFFSET(pDevice, T3_NIC_DATA_NIC_CFG_ADDR); + if (Value32 & T3_NIC_CFG_ENABLE_ASF) + { + pDevice->AsfFlags = ASF_ENABLED; + if (T3_ASIC_IS_575X_PLUS(pDevice->ChipRevId)) + { + pDevice->AsfFlags |= ASF_NEW_HANDSHAKE; + } + } + } +#endif + + return LM_STATUS_SUCCESS; +} + + +LM_STATUS +LM_ShutdownChip(PLM_DEVICE_BLOCK pDevice, LM_RESET_TYPE Mode) +{ + LM_DisableFW(pDevice); + LM_WritePreResetSignatures(pDevice, Mode); + if (pDevice->InitDone) + { + LM_Abort(pDevice); + } + else + { + LM_DisableChip(pDevice); + } + LM_ResetChip(pDevice); + LM_WriteLegacySignatures(pDevice, Mode); + LM_WritePostResetSignatures(pDevice, Mode); + return LM_STATUS_SUCCESS; +} + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +void +LM_ServiceTxInterrupt( +PLM_DEVICE_BLOCK pDevice) { + PLM_PACKET pPacket; + LM_UINT32 HwConIdx; + LM_UINT32 SwConIdx; + + HwConIdx = pDevice->pStatusBlkVirt->Idx[0].SendConIdx; + + /* Get our copy of the consumer index. The buffer descriptors */ + /* that are in between the consumer indices are freed. */ + SwConIdx = pDevice->SendConIdx; + + /* Move the packets from the TxPacketActiveQ that are sent out to */ + /* the TxPacketXmittedQ. Packets that are sent use the */ + /* descriptors that are between SwConIdx and HwConIdx. */ + while(SwConIdx != HwConIdx) + { + pPacket = pDevice->SendRing[SwConIdx]; + pDevice->SendRing[SwConIdx] = 0; + + /* Set the return status. */ + pPacket->PacketStatus = LM_STATUS_SUCCESS; + + /* Put the packet in the TxPacketXmittedQ for indication later. */ + QQ_PushTail(&pDevice->TxPacketXmittedQ.Container, pPacket); + + /* Move to the next packet's BD. */ + SwConIdx = (SwConIdx + pPacket->u.Tx.FragCount) & + T3_SEND_RCB_ENTRY_COUNT_MASK; + + /* Update the number of unused BDs. */ + MM_ATOMIC_ADD(&pDevice->SendBdLeft, pPacket->u.Tx.FragCount); + + /* Get the new updated HwConIdx. */ + HwConIdx = pDevice->pStatusBlkVirt->Idx[0].SendConIdx; + } /* while */ + + /* Save the new SwConIdx. */ + pDevice->SendConIdx = SwConIdx; + +} /* LM_ServiceTxInterrupt */ + + +#ifdef BCM_NAPI_RXPOLL +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +int +LM_ServiceRxPoll(PLM_DEVICE_BLOCK pDevice, int limit) +{ + PLM_PACKET pPacket=NULL; + PT3_RCV_BD pRcvBd; + LM_UINT32 HwRcvRetProdIdx; + LM_UINT32 SwRcvRetConIdx; + int received = 0; + + /* Loop thru the receive return rings for received packets. */ + HwRcvRetProdIdx = pDevice->pStatusBlkVirt->Idx[0].RcvProdIdx; + + SwRcvRetConIdx = pDevice->RcvRetConIdx; + MM_RMB(); + while (SwRcvRetConIdx != HwRcvRetProdIdx) + { + pRcvBd = &pDevice->pRcvRetBdVirt[SwRcvRetConIdx]; + + /* Get the received packet descriptor. */ + pPacket = (PLM_PACKET) (MM_UINT_PTR(pDevice->pPacketDescBase) + + MM_UINT_PTR(pRcvBd->Opaque)); + + switch(pPacket->u.Rx.RcvProdRing) { +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + case T3_JUMBO_RCV_PROD_RING: /* Jumbo Receive Ring. */ + pDevice->RxJumboRing[pPacket->u.Rx.RcvRingProdIdx] = 0; + break; +#endif + case T3_STD_RCV_PROD_RING: /* Standard Receive Ring. */ + pDevice->RxStdRing[pPacket->u.Rx.RcvRingProdIdx] = 0; + break; + } + + /* Check the error flag. */ + if(pRcvBd->ErrorFlag && + pRcvBd->ErrorFlag != RCV_BD_ERR_ODD_NIBBLED_RCVD_MII) + { + pPacket->PacketStatus = LM_STATUS_FAILURE; + + pDevice->RxCounters.RxPacketErrCnt++; + + if(pRcvBd->ErrorFlag & RCV_BD_ERR_BAD_CRC) + { + pDevice->RxCounters.RxErrCrcCnt++; + } + + if(pRcvBd->ErrorFlag & RCV_BD_ERR_COLL_DETECT) + { + pDevice->RxCounters.RxErrCollCnt++; + } + + if(pRcvBd->ErrorFlag & RCV_BD_ERR_LINK_LOST_DURING_PKT) + { + pDevice->RxCounters.RxErrLinkLostCnt++; + } + + if(pRcvBd->ErrorFlag & RCV_BD_ERR_PHY_DECODE_ERR) + { + pDevice->RxCounters.RxErrPhyDecodeCnt++; + } + + if(pRcvBd->ErrorFlag & RCV_BD_ERR_ODD_NIBBLED_RCVD_MII) + { + pDevice->RxCounters.RxErrOddNibbleCnt++; + } + + if(pRcvBd->ErrorFlag & RCV_BD_ERR_MAC_ABORT) + { + pDevice->RxCounters.RxErrMacAbortCnt++; + } + + if(pRcvBd->ErrorFlag & RCV_BD_ERR_LEN_LT_64) + { + pDevice->RxCounters.RxErrShortPacketCnt++; + } + + if(pRcvBd->ErrorFlag & RCV_BD_ERR_TRUNC_NO_RESOURCES) + { + pDevice->RxCounters.RxErrNoResourceCnt++; + } + + if(pRcvBd->ErrorFlag & RCV_BD_ERR_GIANT_FRAME_RCVD) + { + pDevice->RxCounters.RxErrLargePacketCnt++; + } + } + else + { + pPacket->PacketStatus = LM_STATUS_SUCCESS; + pPacket->PacketSize = pRcvBd->Len - 4; + + pPacket->Flags = pRcvBd->Flags; + if(pRcvBd->Flags & RCV_BD_FLAG_VLAN_TAG) + { + pPacket->VlanTag = pRcvBd->VlanTag; + } + + pPacket->u.Rx.TcpUdpChecksum = pRcvBd->TcpUdpCksum; + } + + /* Put the packet descriptor containing the received packet */ + /* buffer in the RxPacketReceivedQ for indication later. */ + QQ_PushTail(&pDevice->RxPacketReceivedQ.Container, pPacket); + + /* Go to the next buffer descriptor. */ + SwRcvRetConIdx = (SwRcvRetConIdx + 1) & + pDevice->RcvRetRcbEntryCountMask; + + if (++received >= limit) + { + break; + } + } /* while */ + + pDevice->RcvRetConIdx = SwRcvRetConIdx; + + /* Update the receive return ring consumer index. */ + MB_REG_WR(pDevice, Mailbox.RcvRetConIdx[0].Low, SwRcvRetConIdx); + if (pDevice->Flags & FLUSH_POSTED_WRITE_FLAG) + { + MB_REG_RD(pDevice, Mailbox.RcvRetConIdx[0].Low); + } + else + { + MM_MMIOWB(); + } + return received; +} /* LM_ServiceRxPoll */ +#endif /* BCM_NAPI_RXPOLL */ + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +void +LM_ServiceRxInterrupt(PLM_DEVICE_BLOCK pDevice) +{ +#ifndef BCM_NAPI_RXPOLL + PLM_PACKET pPacket; + PT3_RCV_BD pRcvBd; +#endif + LM_UINT32 HwRcvRetProdIdx; + LM_UINT32 SwRcvRetConIdx; + + /* Loop thru the receive return rings for received packets. */ + HwRcvRetProdIdx = pDevice->pStatusBlkVirt->Idx[0].RcvProdIdx; + + SwRcvRetConIdx = pDevice->RcvRetConIdx; +#ifdef BCM_NAPI_RXPOLL + if (!pDevice->RxPoll) + { + if (SwRcvRetConIdx != HwRcvRetProdIdx) + { + if (MM_ScheduleRxPoll(pDevice) == LM_STATUS_SUCCESS) + { + pDevice->RxPoll = TRUE; + REG_WR(pDevice, Grc.Mode, + pDevice->GrcMode | GRC_MODE_NO_INTERRUPT_ON_RECEIVE); + } + } + } +#else + MM_RMB(); + while(SwRcvRetConIdx != HwRcvRetProdIdx) + { + pRcvBd = &pDevice->pRcvRetBdVirt[SwRcvRetConIdx]; + + /* Get the received packet descriptor. */ + pPacket = (PLM_PACKET) (MM_UINT_PTR(pDevice->pPacketDescBase) + + MM_UINT_PTR(pRcvBd->Opaque)); + + switch(pPacket->u.Rx.RcvProdRing) { +#if T3_JUMBO_RCV_RCB_ENTRY_COUNT + case T3_JUMBO_RCV_PROD_RING: /* Jumbo Receive Ring. */ + pDevice->RxJumboRing[pPacket->u.Rx.RcvRingProdIdx] = 0; + break; +#endif + case T3_STD_RCV_PROD_RING: /* Standard Receive Ring. */ + pDevice->RxStdRing[pPacket->u.Rx.RcvRingProdIdx] = 0; + break; + } + + /* Check the error flag. */ + if(pRcvBd->ErrorFlag && + pRcvBd->ErrorFlag != RCV_BD_ERR_ODD_NIBBLED_RCVD_MII) + { + pPacket->PacketStatus = LM_STATUS_FAILURE; + + pDevice->RxCounters.RxPacketErrCnt++; + + if(pRcvBd->ErrorFlag & RCV_BD_ERR_BAD_CRC) + { + pDevice->RxCounters.RxErrCrcCnt++; + } + + if(pRcvBd->ErrorFlag & RCV_BD_ERR_COLL_DETECT) + { + pDevice->RxCounters.RxErrCollCnt++; + } + + if(pRcvBd->ErrorFlag & RCV_BD_ERR_LINK_LOST_DURING_PKT) + { + pDevice->RxCounters.RxErrLinkLostCnt++; + } + + if(pRcvBd->ErrorFlag & RCV_BD_ERR_PHY_DECODE_ERR) + { + pDevice->RxCounters.RxErrPhyDecodeCnt++; + } + + if(pRcvBd->ErrorFlag & RCV_BD_ERR_ODD_NIBBLED_RCVD_MII) + { + pDevice->RxCounters.RxErrOddNibbleCnt++; + } + + if(pRcvBd->ErrorFlag & RCV_BD_ERR_MAC_ABORT) + { + pDevice->RxCounters.RxErrMacAbortCnt++; + } + + if(pRcvBd->ErrorFlag & RCV_BD_ERR_LEN_LT_64) + { + pDevice->RxCounters.RxErrShortPacketCnt++; + } + + if(pRcvBd->ErrorFlag & RCV_BD_ERR_TRUNC_NO_RESOURCES) + { + pDevice->RxCounters.RxErrNoResourceCnt++; + } + + if(pRcvBd->ErrorFlag & RCV_BD_ERR_GIANT_FRAME_RCVD) + { + pDevice->RxCounters.RxErrLargePacketCnt++; + } + } + else + { + pPacket->PacketStatus = LM_STATUS_SUCCESS; + pPacket->PacketSize = pRcvBd->Len - 4; + + pPacket->Flags = pRcvBd->Flags; + if(pRcvBd->Flags & RCV_BD_FLAG_VLAN_TAG) + { + pPacket->VlanTag = pRcvBd->VlanTag; + } + + pPacket->u.Rx.TcpUdpChecksum = pRcvBd->TcpUdpCksum; + } + + /* Put the packet descriptor containing the received packet */ + /* buffer in the RxPacketReceivedQ for indication later. */ + QQ_PushTail(&pDevice->RxPacketReceivedQ.Container, pPacket); + + /* Go to the next buffer descriptor. */ + SwRcvRetConIdx = (SwRcvRetConIdx + 1) & + pDevice->RcvRetRcbEntryCountMask; + + } /* while */ + + pDevice->RcvRetConIdx = SwRcvRetConIdx; + + /* Update the receive return ring consumer index. */ + MB_REG_WR(pDevice, Mailbox.RcvRetConIdx[0].Low, SwRcvRetConIdx); + if (pDevice->Flags & FLUSH_POSTED_WRITE_FLAG) + { + MB_REG_RD(pDevice, Mailbox.RcvRetConIdx[0].Low); + } + else + { + MM_MMIOWB(); + } + +#endif +} /* LM_ServiceRxInterrupt */ + + + +/******************************************************************************/ +/* Description: */ +/* This is the interrupt event handler routine. It acknowledges all */ +/* pending interrupts and process all pending events. */ +/* */ +/* Return: */ +/* LM_STATUS_SUCCESS */ +/******************************************************************************/ +LM_STATUS +LM_ServiceInterrupts( + PLM_DEVICE_BLOCK pDevice) +{ + LM_UINT32 Value32; + int ServicePhyInt = FALSE; + + /* Setup the phy chip whenever the link status changes. */ + if(pDevice->LinkChngMode == T3_LINK_CHNG_MODE_USE_STATUS_REG) + { + Value32 = REG_RD(pDevice, MacCtrl.Status); + if(pDevice->PhyIntMode == T3_PHY_INT_MODE_MI_INTERRUPT) + { + if (Value32 & MAC_STATUS_MI_INTERRUPT) + { + ServicePhyInt = TRUE; + } + } + else if(Value32 & MAC_STATUS_LINK_STATE_CHANGED) + { + ServicePhyInt = TRUE; + } + } + else + { + if(pDevice->pStatusBlkVirt->Status & STATUS_BLOCK_LINK_CHANGED_STATUS) + { + pDevice->pStatusBlkVirt->Status = STATUS_BLOCK_UPDATED | + (pDevice->pStatusBlkVirt->Status & ~STATUS_BLOCK_LINK_CHANGED_STATUS); + ServicePhyInt = TRUE; + } + } +#ifdef INCLUDE_TBI_SUPPORT + if (pDevice->IgnoreTbiLinkChange == TRUE) + { + ServicePhyInt = FALSE; + } +#endif + if (ServicePhyInt == TRUE) + { + MM_ACQUIRE_PHY_LOCK_IN_IRQ(pDevice); + LM_SetupPhy(pDevice); + MM_RELEASE_PHY_LOCK_IN_IRQ(pDevice); + } + + /* Service receive and transmit interrupts. */ + LM_ServiceRxInterrupt(pDevice); + LM_ServiceTxInterrupt(pDevice); + +#ifndef BCM_NAPI_RXPOLL + /* No spinlock for this queue since this routine is serialized. */ + if(!QQ_Empty(&pDevice->RxPacketReceivedQ.Container)) + { + /* Indicate receive packets. */ + MM_IndicateRxPackets(pDevice); + } +#endif + + /* No spinlock for this queue since this routine is serialized. */ + if(!QQ_Empty(&pDevice->TxPacketXmittedQ.Container)) + { + MM_IndicateTxPackets(pDevice); + } + + return LM_STATUS_SUCCESS; +} /* LM_ServiceInterrupts */ + + +/******************************************************************************/ +/* Description: Add a Multicast address. Note that MC addresses, once added, */ +/* cannot be individually deleted. All addresses must be */ +/* cleared. */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_STATUS +LM_MulticastAdd(LM_DEVICE_BLOCK *pDevice, PLM_UINT8 pMcAddress) +{ + + LM_UINT32 RegIndex; + LM_UINT32 Bitpos; + LM_UINT32 Crc32; + + Crc32 = ComputeCrc32(pMcAddress, ETHERNET_ADDRESS_SIZE); + + /* The most significant 7 bits of the CRC32 (no inversion), */ + /* are used to index into one of the possible 128 bit positions. */ + Bitpos = ~Crc32 & 0x7f; + + /* Hash register index. */ + RegIndex = (Bitpos & 0x60) >> 5; + + /* Bit to turn on within a hash register. */ + Bitpos &= 0x1f; + + /* Enable the multicast bit. */ + pDevice->MulticastHash[RegIndex] |= (1 << Bitpos); + + LM_SetReceiveMask(pDevice, pDevice->ReceiveMask | LM_ACCEPT_MULTICAST); + + return LM_STATUS_SUCCESS; +} + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_STATUS +LM_MulticastDel(LM_DEVICE_BLOCK *pDevice, PLM_UINT8 pMcAddress) +{ + return LM_STATUS_FAILURE; +} /* LM_MulticastDel */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_STATUS +LM_MulticastClear(LM_DEVICE_BLOCK *pDevice) +{ + int i; + + for (i = 0; i < 4; i++) + { + pDevice->MulticastHash[i] = 0; + } + LM_SetReceiveMask(pDevice, pDevice->ReceiveMask & ~LM_ACCEPT_MULTICAST); + + return LM_STATUS_SUCCESS; +} /* LM_MulticastClear */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_STATUS +LM_SetMacAddress( + PLM_DEVICE_BLOCK pDevice, + PLM_UINT8 pMacAddress) +{ + LM_UINT32 j; + + for(j = 0; j < 4; j++) + { + REG_WR(pDevice, MacCtrl.MacAddr[j].High, + (pMacAddress[0] << 8) | pMacAddress[1]); + REG_WR(pDevice, MacCtrl.MacAddr[j].Low, + (pMacAddress[2] << 24) | (pMacAddress[3] << 16) | + (pMacAddress[4] << 8) | pMacAddress[5]); + } + + if ((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5703) || + (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5704)) + { + for (j = 0; j < 12; j++) + { + REG_WR(pDevice, MacCtrl.MacAddrExt[j].High, + (pMacAddress[0] << 8) | pMacAddress[1]); + REG_WR(pDevice, MacCtrl.MacAddrExt[j].Low, + (pMacAddress[2] << 24) | (pMacAddress[3] << 16) | + (pMacAddress[4] << 8) | pMacAddress[5]); + } + } + return LM_STATUS_SUCCESS; +} + +LM_VOID +LM_PhyTapPowerMgmt(LM_DEVICE_BLOCK *pDevice) +{ + /* Turn off tap power management. */ + if((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5401_PHY_ID) + { + LM_WritePhy(pDevice, BCM5401_AUX_CTRL, 0x4c20); + LM_WritePhy(pDevice, BCM540X_DSP_ADDRESS_REG, 0x0012); + LM_WritePhy(pDevice, BCM540X_DSP_RW_PORT, 0x1804); + LM_WritePhy(pDevice, BCM540X_DSP_ADDRESS_REG, 0x0013); + LM_WritePhy(pDevice, BCM540X_DSP_RW_PORT, 0x1204); + LM_WritePhy(pDevice, BCM540X_DSP_ADDRESS_REG, 0x8006); + LM_WritePhy(pDevice, BCM540X_DSP_RW_PORT, 0x0132); + LM_WritePhy(pDevice, BCM540X_DSP_ADDRESS_REG, 0x8006); + LM_WritePhy(pDevice, BCM540X_DSP_RW_PORT, 0x0232); + LM_WritePhy(pDevice, BCM540X_DSP_ADDRESS_REG, 0x201f); + LM_WritePhy(pDevice, BCM540X_DSP_RW_PORT, 0x0a20); + + MM_Wait(40); + } +} + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/* LM_STATUS_LINK_ACTIVE */ +/* LM_STATUS_LINK_DOWN */ +/******************************************************************************/ +static LM_STATUS +LM_InitBcm540xPhy( +PLM_DEVICE_BLOCK pDevice) +{ + LM_LINE_SPEED CurrentLineSpeed; + LM_DUPLEX_MODE CurrentDuplexMode; + LM_STATUS CurrentLinkStatus; + LM_UINT32 Value32; + LM_UINT32 j; + robo_info_t *robo; + + LM_WritePhy(pDevice, BCM5401_AUX_CTRL, 0x02); + + if ((pDevice->PhyFlags & PHY_RESET_ON_LINKDOWN) && + (pDevice->LinkStatus == LM_STATUS_LINK_ACTIVE)) + { + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + if(!(Value32 & PHY_STATUS_LINK_PASS)) + { + LM_ResetPhy(pDevice); + } + } + if((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5401_PHY_ID) + { + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + + if(!pDevice->InitDone) + { + Value32 = 0; + } + + if(!(Value32 & PHY_STATUS_LINK_PASS)) + { + LM_PhyTapPowerMgmt(pDevice); + + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + for(j = 0; j < 1000; j++) + { + MM_Wait(10); + + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + if(Value32 & PHY_STATUS_LINK_PASS) + { + MM_Wait(40); + break; + } + } + + if((pDevice->PhyId & PHY_ID_REV_MASK) == PHY_BCM5401_B0_REV) + { + if(!(Value32 & PHY_STATUS_LINK_PASS) && + (pDevice->OldLineSpeed == LM_LINE_SPEED_1000MBPS)) + { + LM_ResetPhy(pDevice); + } + } + } + } + else if(pDevice->ChipRevId == T3_CHIP_ID_5701_A0 || + pDevice->ChipRevId == T3_CHIP_ID_5701_B0) + { + LM_WritePhy(pDevice, 0x15, 0x0a75); + LM_WritePhy(pDevice, 0x1c, 0x8c68); + LM_WritePhy(pDevice, 0x1c, 0x8d68); + LM_WritePhy(pDevice, 0x1c, 0x8c68); + } + + /* Acknowledge interrupts. */ + LM_ReadPhy(pDevice, BCM540X_INT_STATUS_REG, &Value32); + LM_ReadPhy(pDevice, BCM540X_INT_STATUS_REG, &Value32); + + /* Configure the interrupt mask. */ + if(pDevice->PhyIntMode == T3_PHY_INT_MODE_MI_INTERRUPT) + { + LM_WritePhy(pDevice, BCM540X_INT_MASK_REG, ~BCM540X_INT_LINK_CHANGE); + } + + /* Configure PHY led mode. */ + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701 || + (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700)) + { + if(pDevice->LedCtrl == LED_CTRL_PHY_MODE_1) + { + LM_WritePhy(pDevice, BCM540X_EXT_CTRL_REG, + BCM540X_EXT_CTRL_LINK3_LED_MODE); + } + else + { + LM_WritePhy(pDevice, BCM540X_EXT_CTRL_REG, 0); + } + } + else if((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5461_PHY_ID) + { + /* + ** Set up the 'link' LED for the 4785+5461 combo, + ** using the INTR/ENERGYDET pin (on the BCM4785 bringup board). + */ + LM_WritePhy( pDevice, + BCM546X_1c_SHADOW_REG, + (BCM546X_1c_SPR_CTRL_2 | BCM546X_1c_WR_EN | BCM546X_1c_SP2_NRG_DET) ); + + /* + ** Set up the LINK LED mode for the 4785+5461 combo, + ** using the 5461 SLAVE/ANEN pin (on the BCM4785 bringup board) as + ** active low link status (phy ready) feedback to the 4785 + */ + LM_WritePhy( pDevice, + BCM546X_1c_SHADOW_REG, + (BCM546X_1c_SPR_CTRL_1 | BCM546X_1c_WR_EN | BCM546X_1c_SP1_LINK_LED) ); + } + + if (pDevice->PhyFlags & PHY_CAPACITIVE_COUPLING) + { + LM_WritePhy(pDevice, BCM5401_AUX_CTRL, 0x4007); + LM_ReadPhy(pDevice, BCM5401_AUX_CTRL, &Value32); + if (!(Value32 & BIT_10)) + { + /* set the bit and re-link */ + LM_WritePhy(pDevice, BCM5401_AUX_CTRL, Value32 | BIT_10); + return LM_STATUS_LINK_SETTING_MISMATCH; + } + } + + CurrentLinkStatus = LM_STATUS_LINK_DOWN; + + if(UNKNOWN_PHY_ID(pDevice->PhyId) && (pDevice->Flags & ROBO_SWITCH_FLAG)) { + B57_INFO(("Force to active link of 1000 MBPS and full duplex mod.\n")); + CurrentLinkStatus = LM_STATUS_LINK_ACTIVE; + + /* Set the line speed based on the robo switch type */ + robo = ((PUM_DEVICE_BLOCK)pDevice)->robo; + if (robo->devid == DEVID5325) + { + CurrentLineSpeed = LM_LINE_SPEED_100MBPS; + } + else + { + CurrentLineSpeed = LM_LINE_SPEED_1000MBPS; + } + CurrentDuplexMode = LM_DUPLEX_MODE_FULL; + + /* Save line settings. */ + pDevice->LineSpeed = CurrentLineSpeed; + pDevice->DuplexMode = CurrentDuplexMode; + } else { + + /* Get current link and duplex mode. */ + for(j = 0; j < 100; j++) + { + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + + if(Value32 & PHY_STATUS_LINK_PASS) + { + break; + } + MM_Wait(40); + } + + if(Value32 & PHY_STATUS_LINK_PASS) + { + + /* Determine the current line and duplex settings. */ + LM_ReadPhy(pDevice, BCM540X_AUX_STATUS_REG, &Value32); + for(j = 0; j < 2000; j++) + { + MM_Wait(10); + + LM_ReadPhy(pDevice, BCM540X_AUX_STATUS_REG, &Value32); + if(Value32) + { + break; + } + } + + switch(Value32 & BCM540X_AUX_SPEED_MASK) + { + case BCM540X_AUX_10BASET_HD: + CurrentLineSpeed = LM_LINE_SPEED_10MBPS; + CurrentDuplexMode = LM_DUPLEX_MODE_HALF; + break; + + case BCM540X_AUX_10BASET_FD: + CurrentLineSpeed = LM_LINE_SPEED_10MBPS; + CurrentDuplexMode = LM_DUPLEX_MODE_FULL; + break; + + case BCM540X_AUX_100BASETX_HD: + CurrentLineSpeed = LM_LINE_SPEED_100MBPS; + CurrentDuplexMode = LM_DUPLEX_MODE_HALF; + break; + + case BCM540X_AUX_100BASETX_FD: + CurrentLineSpeed = LM_LINE_SPEED_100MBPS; + CurrentDuplexMode = LM_DUPLEX_MODE_FULL; + break; + + case BCM540X_AUX_100BASET_HD: + CurrentLineSpeed = LM_LINE_SPEED_1000MBPS; + CurrentDuplexMode = LM_DUPLEX_MODE_HALF; + break; + + case BCM540X_AUX_100BASET_FD: + CurrentLineSpeed = LM_LINE_SPEED_1000MBPS; + CurrentDuplexMode = LM_DUPLEX_MODE_FULL; + break; + + default: + + CurrentLineSpeed = LM_LINE_SPEED_UNKNOWN; + CurrentDuplexMode = LM_DUPLEX_MODE_UNKNOWN; + break; + } + + /* Make sure we are in auto-neg mode. */ + for (j = 0; j < 200; j++) + { + LM_ReadPhy(pDevice, PHY_CTRL_REG, &Value32); + if(Value32 && Value32 != 0x7fff) + { + break; + } + + if(Value32 == 0 && + pDevice->RequestedLineSpeed == LM_LINE_SPEED_10MBPS && + pDevice->RequestedDuplexMode == LM_DUPLEX_MODE_HALF) + { + break; + } + + MM_Wait(10); + } + + /* Use the current line settings for "auto" mode. */ + if(pDevice->RequestedLineSpeed == LM_LINE_SPEED_AUTO) + { + if(Value32 & PHY_CTRL_AUTO_NEG_ENABLE) + { + CurrentLinkStatus = LM_STATUS_LINK_ACTIVE; + + /* We may be exiting low power mode and the link is in */ + /* 10mb. In this case, we need to restart autoneg. */ + + if (LM_PhyAdvertiseAll(pDevice) != LM_STATUS_SUCCESS) + { + CurrentLinkStatus = LM_STATUS_LINK_SETTING_MISMATCH; + } + } + else + { + CurrentLinkStatus = LM_STATUS_LINK_SETTING_MISMATCH; + } + } + else + { + /* Force line settings. */ + /* Use the current setting if it matches the user's requested */ + /* setting. */ + LM_ReadPhy(pDevice, PHY_CTRL_REG, &Value32); + if((pDevice->LineSpeed == CurrentLineSpeed) && + (pDevice->DuplexMode == CurrentDuplexMode)) + { + if ((pDevice->DisableAutoNeg && + !(Value32 & PHY_CTRL_AUTO_NEG_ENABLE)) || + (!pDevice->DisableAutoNeg && + (Value32 & PHY_CTRL_AUTO_NEG_ENABLE))) + { + CurrentLinkStatus = LM_STATUS_LINK_ACTIVE; + } + else + { + CurrentLinkStatus = LM_STATUS_LINK_SETTING_MISMATCH; + } + } + else + { + CurrentLinkStatus = LM_STATUS_LINK_SETTING_MISMATCH; + } + } + + /* Save line settings. */ + pDevice->LineSpeed = CurrentLineSpeed; + pDevice->DuplexMode = CurrentDuplexMode; + } +} + + return CurrentLinkStatus; +} /* LM_InitBcm540xPhy */ + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_STATUS +LM_SetFlowControl( + PLM_DEVICE_BLOCK pDevice, + LM_UINT32 LocalPhyAd, + LM_UINT32 RemotePhyAd) +{ + LM_FLOW_CONTROL FlowCap; + + /* Resolve flow control. */ + FlowCap = LM_FLOW_CONTROL_NONE; + + /* See Table 28B-3 of 802.3ab-1999 spec. */ + if(pDevice->FlowControlCap & LM_FLOW_CONTROL_AUTO_PAUSE) + { + if(pDevice->PhyFlags & PHY_IS_FIBER){ + LocalPhyAd &= ~(PHY_AN_AD_ASYM_PAUSE | + PHY_AN_AD_PAUSE_CAPABLE); + RemotePhyAd &= ~(PHY_AN_AD_ASYM_PAUSE | + PHY_AN_AD_PAUSE_CAPABLE); + + if (LocalPhyAd & PHY_AN_AD_1000XPAUSE) + LocalPhyAd |= PHY_AN_AD_PAUSE_CAPABLE; + if (LocalPhyAd & PHY_AN_AD_1000XPSE_ASYM) + LocalPhyAd |= PHY_AN_AD_ASYM_PAUSE; + if (RemotePhyAd & PHY_AN_AD_1000XPAUSE) + RemotePhyAd |= PHY_LINK_PARTNER_PAUSE_CAPABLE; + if (RemotePhyAd & PHY_AN_AD_1000XPSE_ASYM) + RemotePhyAd |= PHY_LINK_PARTNER_ASYM_PAUSE; + } + + if(LocalPhyAd & PHY_AN_AD_PAUSE_CAPABLE) + { + if(LocalPhyAd & PHY_AN_AD_ASYM_PAUSE) + { + if(RemotePhyAd & PHY_LINK_PARTNER_PAUSE_CAPABLE) + { + FlowCap = LM_FLOW_CONTROL_TRANSMIT_PAUSE | + LM_FLOW_CONTROL_RECEIVE_PAUSE; + } + else if(RemotePhyAd & PHY_LINK_PARTNER_ASYM_PAUSE) + { + FlowCap = LM_FLOW_CONTROL_RECEIVE_PAUSE; + } + } + else + { + if(RemotePhyAd & PHY_LINK_PARTNER_PAUSE_CAPABLE) + { + FlowCap = LM_FLOW_CONTROL_TRANSMIT_PAUSE | + LM_FLOW_CONTROL_RECEIVE_PAUSE; + } + } + } + else if(LocalPhyAd & PHY_AN_AD_ASYM_PAUSE) + { + if((RemotePhyAd & PHY_LINK_PARTNER_PAUSE_CAPABLE) && + (RemotePhyAd & PHY_LINK_PARTNER_ASYM_PAUSE)) + { + FlowCap = LM_FLOW_CONTROL_TRANSMIT_PAUSE; + } + } + } + else + { + FlowCap = pDevice->FlowControlCap; + } + + pDevice->FlowControl = LM_FLOW_CONTROL_NONE; + + /* Enable/disable rx PAUSE. */ + pDevice->RxMode &= ~RX_MODE_ENABLE_FLOW_CONTROL; + if(FlowCap & LM_FLOW_CONTROL_RECEIVE_PAUSE && + (pDevice->FlowControlCap == LM_FLOW_CONTROL_AUTO_PAUSE || + pDevice->FlowControlCap & LM_FLOW_CONTROL_RECEIVE_PAUSE)) + { + pDevice->FlowControl |= LM_FLOW_CONTROL_RECEIVE_PAUSE; + pDevice->RxMode |= RX_MODE_ENABLE_FLOW_CONTROL; + + } + REG_WR(pDevice, MacCtrl.RxMode, pDevice->RxMode); + + /* Enable/disable tx PAUSE. */ + pDevice->TxMode &= ~TX_MODE_ENABLE_FLOW_CONTROL; + if(FlowCap & LM_FLOW_CONTROL_TRANSMIT_PAUSE && + (pDevice->FlowControlCap == LM_FLOW_CONTROL_AUTO_PAUSE || + pDevice->FlowControlCap & LM_FLOW_CONTROL_TRANSMIT_PAUSE)) + { + pDevice->FlowControl |= LM_FLOW_CONTROL_TRANSMIT_PAUSE; + pDevice->TxMode |= TX_MODE_ENABLE_FLOW_CONTROL; + + } + REG_WR(pDevice, MacCtrl.TxMode, pDevice->TxMode); + + return LM_STATUS_SUCCESS; +} + + +#ifdef INCLUDE_TBI_SUPPORT +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +STATIC LM_STATUS +LM_InitBcm800xPhy( + PLM_DEVICE_BLOCK pDevice) +{ + LM_UINT32 Value32; + LM_UINT32 j; + + + Value32 = REG_RD(pDevice, MacCtrl.Status); + + /* Reset the SERDES during init and when we have link. */ + if(!pDevice->InitDone || Value32 & MAC_STATUS_PCS_SYNCED) + { + /* Set PLL lock range. */ + LM_WritePhy(pDevice, 0x16, 0x8007); + + /* Software reset. */ + LM_WritePhy(pDevice, 0x00, 0x8000); + + /* Wait for reset to complete. */ + for(j = 0; j < 500; j++) + { + MM_Wait(10); + } + + /* Config mode; seletct PMA/Ch 1 regs. */ + LM_WritePhy(pDevice, 0x10, 0x8411); + + /* Enable auto-lock and comdet, select txclk for tx. */ + LM_WritePhy(pDevice, 0x11, 0x0a10); + + LM_WritePhy(pDevice, 0x18, 0x00a0); + LM_WritePhy(pDevice, 0x16, 0x41ff); + + /* Assert and deassert POR. */ + LM_WritePhy(pDevice, 0x13, 0x0400); + MM_Wait(40); + LM_WritePhy(pDevice, 0x13, 0x0000); + + LM_WritePhy(pDevice, 0x11, 0x0a50); + MM_Wait(40); + LM_WritePhy(pDevice, 0x11, 0x0a10); + + /* Delay for signal to stabilize. */ + for(j = 0; j < 15000; j++) + { + MM_Wait(10); + } + + /* Deselect the channel register so we can read the PHY id later. */ + LM_WritePhy(pDevice, 0x10, 0x8011); + } + + return LM_STATUS_SUCCESS; +} + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +STATIC LM_STATUS +LM_SetupFiberPhy( + PLM_DEVICE_BLOCK pDevice) +{ + LM_STATUS CurrentLinkStatus; + AUTONEG_STATUS AnStatus = 0; + LM_UINT32 Value32; + LM_UINT32 Cnt; + LM_UINT32 j, k; + LM_UINT32 MacStatus, RemotePhyAd, LocalPhyAd; + LM_FLOW_CONTROL PreviousFlowControl = pDevice->FlowControl; + + + if (pDevice->LoopBackMode == LM_MAC_LOOP_BACK_MODE) + { + pDevice->LinkStatus = LM_STATUS_LINK_ACTIVE; + MM_IndicateStatus(pDevice, LM_STATUS_LINK_ACTIVE); + return LM_STATUS_SUCCESS; + } + + + if ((T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5704) && + (pDevice->LinkStatus == LM_STATUS_LINK_ACTIVE) && pDevice->InitDone) + { + MacStatus = REG_RD(pDevice, MacCtrl.Status); + if ((MacStatus & (MAC_STATUS_PCS_SYNCED | MAC_STATUS_SIGNAL_DETECTED | + MAC_STATUS_CFG_CHANGED | MAC_STATUS_RECEIVING_CFG)) + == (MAC_STATUS_PCS_SYNCED | MAC_STATUS_SIGNAL_DETECTED)) + { + + REG_WR(pDevice, MacCtrl.Status, MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED); + return LM_STATUS_SUCCESS; + } + } + pDevice->MacMode &= ~(MAC_MODE_HALF_DUPLEX | MAC_MODE_PORT_MODE_MASK); + + /* Initialize the send_config register. */ + REG_WR(pDevice, MacCtrl.TxAutoNeg, 0); + + pDevice->MacMode |= MAC_MODE_PORT_MODE_TBI; + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode); + MM_Wait(10); + + /* Initialize the BCM8002 SERDES PHY. */ + switch(pDevice->PhyId & PHY_ID_MASK) + { + case PHY_BCM8002_PHY_ID: + LM_InitBcm800xPhy(pDevice); + break; + + default: + break; + } + + /* Enable link change interrupt. */ + REG_WR(pDevice, MacCtrl.MacEvent, MAC_EVENT_ENABLE_LINK_STATE_CHANGED_ATTN); + + /* Default to link down. */ + CurrentLinkStatus = LM_STATUS_LINK_DOWN; + + /* Get the link status. */ + MacStatus = REG_RD(pDevice, MacCtrl.Status); + + if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5704) + { + LM_UINT32 SgDigCtrl, SgDigStatus; + LM_UINT32 SerdesCfg = 0; + LM_UINT32 ExpectedSgDigCtrl = 0; + LM_UINT32 WorkAround = 0; + LM_UINT32 PortA = 1; + + if ((pDevice->ChipRevId != T3_CHIP_ID_5704_A0) && + (pDevice->ChipRevId != T3_CHIP_ID_5704_A1)) + { + WorkAround = 1; + if (REG_RD(pDevice, PciCfg.DualMacCtrl) & T3_DUAL_MAC_ID) + { + PortA = 0; + } + + if(pDevice->TbiFlags & TBI_DO_PREEMPHASIS) + { + /* Save voltage reg bits & bits 14:0 */ + SerdesCfg = REG_RD(pDevice, MacCtrl.SerdesCfg) & + (BIT_23 | BIT_22 | BIT_21 | BIT_20 | 0x7fff ); + + } + else + { + /* preserve the voltage regulator bits */ + SerdesCfg = REG_RD(pDevice, MacCtrl.SerdesCfg) & + (BIT_23 | BIT_22 | BIT_21 | BIT_20); + } + } + SgDigCtrl = REG_RD(pDevice, MacCtrl.SgDigControl); + if((pDevice->RequestedLineSpeed == LM_LINE_SPEED_AUTO) || + (pDevice->DisableAutoNeg == FALSE)) + { + + ExpectedSgDigCtrl = 0x81388400; + LocalPhyAd = GetPhyAdFlowCntrlSettings(pDevice); + if(LocalPhyAd & PHY_AN_AD_PAUSE_CAPABLE) + { + ExpectedSgDigCtrl |= BIT_11; + } + if(LocalPhyAd & PHY_AN_AD_ASYM_PAUSE) + { + ExpectedSgDigCtrl |= BIT_12; + } + if (SgDigCtrl != ExpectedSgDigCtrl) + { + if (WorkAround) + { + if(pDevice->TbiFlags & TBI_DO_PREEMPHASIS) + { + REG_WR(pDevice, MacCtrl.SerdesCfg, 0xc011000 | SerdesCfg); + } + else + { + REG_WR(pDevice, MacCtrl.SerdesCfg, 0xc011880 | SerdesCfg); + } + } + REG_WR(pDevice, MacCtrl.SgDigControl, ExpectedSgDigCtrl | + BIT_30); + REG_RD_BACK(pDevice, MacCtrl.SgDigControl); + MM_Wait(5); + REG_WR(pDevice, MacCtrl.SgDigControl, ExpectedSgDigCtrl); + pDevice->AutoNegJustInited = TRUE; + } + /* If autoneg is off, you only get SD when link is up */ + else if(MacStatus & (MAC_STATUS_PCS_SYNCED | + MAC_STATUS_SIGNAL_DETECTED)) + { + SgDigStatus = REG_RD(pDevice, MacCtrl.SgDigStatus); + if ((SgDigStatus & BIT_1) && + (MacStatus & MAC_STATUS_PCS_SYNCED)) + { + /* autoneg. completed */ + RemotePhyAd = 0; + if(SgDigStatus & BIT_19) + { + RemotePhyAd |= PHY_LINK_PARTNER_PAUSE_CAPABLE; + } + + if(SgDigStatus & BIT_20) + { + RemotePhyAd |= PHY_LINK_PARTNER_ASYM_PAUSE; + } + + LM_SetFlowControl(pDevice, LocalPhyAd, RemotePhyAd); + CurrentLinkStatus = LM_STATUS_LINK_ACTIVE; + pDevice->AutoNegJustInited = FALSE; + } + else if (!(SgDigStatus & BIT_1)) + { + if (pDevice->AutoNegJustInited == TRUE) + { + /* we may be checking too soon, so check again */ + /* at the next poll interval */ + pDevice->AutoNegJustInited = FALSE; + } + else + { + /* autoneg. failed */ + if (WorkAround) + { + if (PortA) + { + if(pDevice->TbiFlags & TBI_DO_PREEMPHASIS) + { + REG_WR(pDevice, MacCtrl.SerdesCfg, + 0xc010000 | (SerdesCfg & ~0x00001000)); + } + else + { + REG_WR(pDevice, MacCtrl.SerdesCfg, + 0xc010880 | SerdesCfg); + } + } + else + { + if(pDevice->TbiFlags & TBI_DO_PREEMPHASIS) + { + REG_WR(pDevice, MacCtrl.SerdesCfg, + 0x4010000 | (SerdesCfg & ~0x00001000)); + } + else + { + REG_WR(pDevice, MacCtrl.SerdesCfg, + 0x4010880 | SerdesCfg); + } + } + } + /* turn off autoneg. to allow traffic to pass */ + REG_WR(pDevice, MacCtrl.SgDigControl, 0x01388400); + REG_RD_BACK(pDevice, MacCtrl.SgDigControl); + MM_Wait(40); + MacStatus = REG_RD(pDevice, MacCtrl.Status); + if ((MacStatus & MAC_STATUS_PCS_SYNCED) && !(MacStatus & MAC_STATUS_RECEIVING_CFG)) + { + LM_SetFlowControl(pDevice, 0, 0); + CurrentLinkStatus = LM_STATUS_LINK_ACTIVE; + } + } + } + } + } + else + { + if (SgDigCtrl & BIT_31) { + if (WorkAround) + { + if (PortA) + { + + if(pDevice->TbiFlags & TBI_DO_PREEMPHASIS) + { + REG_WR(pDevice, MacCtrl.SerdesCfg, + 0xc010000 | (SerdesCfg & ~0x00001000)); + } + else + { + REG_WR(pDevice, MacCtrl.SerdesCfg, + 0xc010880 | SerdesCfg); + } + } + else + { + if(pDevice->TbiFlags & TBI_DO_PREEMPHASIS) + { + REG_WR(pDevice, MacCtrl.SerdesCfg, + 0x4010000 | (SerdesCfg & ~0x00001000)); + } + else + { + REG_WR(pDevice, MacCtrl.SerdesCfg, + 0x4010880 | SerdesCfg); + } + } + } + REG_WR(pDevice, MacCtrl.SgDigControl, 0x01388400); + } + if(MacStatus & MAC_STATUS_PCS_SYNCED) + { + LM_SetFlowControl(pDevice, 0, 0); + CurrentLinkStatus = LM_STATUS_LINK_ACTIVE; + } + } + } + else if(MacStatus & MAC_STATUS_PCS_SYNCED) + { + if((pDevice->RequestedLineSpeed == LM_LINE_SPEED_AUTO) || + (pDevice->DisableAutoNeg == FALSE)) + { + /* auto-negotiation mode. */ + /* Initialize the autoneg default capaiblities. */ + AutonegInit(&pDevice->AnInfo); + + /* Set the context pointer to point to the main device structure. */ + pDevice->AnInfo.pContext = pDevice; + + /* Setup flow control advertisement register. */ + Value32 = GetPhyAdFlowCntrlSettings(pDevice); + if(Value32 & PHY_AN_AD_PAUSE_CAPABLE) + { + pDevice->AnInfo.mr_adv_sym_pause = 1; + } + else + { + pDevice->AnInfo.mr_adv_sym_pause = 0; + } + + if(Value32 & PHY_AN_AD_ASYM_PAUSE) + { + pDevice->AnInfo.mr_adv_asym_pause = 1; + } + else + { + pDevice->AnInfo.mr_adv_asym_pause = 0; + } + + /* Try to autoneg up to six times. */ + if (pDevice->IgnoreTbiLinkChange) + { + Cnt = 1; + } + else + { + Cnt = 6; + } + for (j = 0; j < Cnt; j++) + { + REG_WR(pDevice, MacCtrl.TxAutoNeg, 0); + + Value32 = pDevice->MacMode & ~MAC_MODE_PORT_MODE_MASK; + REG_WR(pDevice, MacCtrl.Mode, Value32); + REG_RD_BACK(pDevice, MacCtrl.Mode); + MM_Wait(20); + + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode | + MAC_MODE_SEND_CONFIGS); + REG_RD_BACK(pDevice, MacCtrl.Mode); + + MM_Wait(20); + + pDevice->AnInfo.State = AN_STATE_UNKNOWN; + pDevice->AnInfo.CurrentTime_us = 0; + + REG_WR(pDevice, Grc.Timer, 0); + for(k = 0; (pDevice->AnInfo.CurrentTime_us < 75000) && + (k < 75000); k++) + { + AnStatus = Autoneg8023z(&pDevice->AnInfo); + + if((AnStatus == AUTONEG_STATUS_DONE) || + (AnStatus == AUTONEG_STATUS_FAILED)) + { + break; + } + + pDevice->AnInfo.CurrentTime_us = REG_RD(pDevice, Grc.Timer); + + } + if((AnStatus == AUTONEG_STATUS_DONE) || + (AnStatus == AUTONEG_STATUS_FAILED)) + { + break; + } + if (j >= 1) + { + if (!(REG_RD(pDevice, MacCtrl.Status) & + MAC_STATUS_PCS_SYNCED)) { + break; + } + } + } + + /* Stop sending configs. */ + MM_AnTxIdle(&pDevice->AnInfo); + + /* Resolve flow control settings. */ + if((AnStatus == AUTONEG_STATUS_DONE) && + pDevice->AnInfo.mr_an_complete && pDevice->AnInfo.mr_link_ok && + pDevice->AnInfo.mr_lp_adv_full_duplex) + { + LM_UINT32 RemotePhyAd; + LM_UINT32 LocalPhyAd; + + LocalPhyAd = 0; + if(pDevice->AnInfo.mr_adv_sym_pause) + { + LocalPhyAd |= PHY_AN_AD_PAUSE_CAPABLE; + } + + if(pDevice->AnInfo.mr_adv_asym_pause) + { + LocalPhyAd |= PHY_AN_AD_ASYM_PAUSE; + } + + RemotePhyAd = 0; + if(pDevice->AnInfo.mr_lp_adv_sym_pause) + { + RemotePhyAd |= PHY_LINK_PARTNER_PAUSE_CAPABLE; + } + + if(pDevice->AnInfo.mr_lp_adv_asym_pause) + { + RemotePhyAd |= PHY_LINK_PARTNER_ASYM_PAUSE; + } + + LM_SetFlowControl(pDevice, LocalPhyAd, RemotePhyAd); + + CurrentLinkStatus = LM_STATUS_LINK_ACTIVE; + } + else + { + LM_SetFlowControl(pDevice, 0, 0); + } + for (j = 0; j < 30; j++) + { + MM_Wait(20); + REG_WR(pDevice, MacCtrl.Status, MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED); + REG_RD_BACK(pDevice, MacCtrl.Status); + MM_Wait(20); + if ((REG_RD(pDevice, MacCtrl.Status) & + (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED)) == 0) + break; + } + if (pDevice->TbiFlags & TBI_POLLING_FLAGS) + { + Value32 = REG_RD(pDevice, MacCtrl.Status); + if (Value32 & MAC_STATUS_RECEIVING_CFG) + { + pDevice->IgnoreTbiLinkChange = TRUE; + } + else if (pDevice->TbiFlags & TBI_POLLING_INTR_FLAG) + { + pDevice->IgnoreTbiLinkChange = FALSE; + } + } + Value32 = REG_RD(pDevice, MacCtrl.Status); + if (CurrentLinkStatus == LM_STATUS_LINK_DOWN && + (Value32 & MAC_STATUS_PCS_SYNCED) && + ((Value32 & MAC_STATUS_RECEIVING_CFG) == 0)) + { + CurrentLinkStatus = LM_STATUS_LINK_ACTIVE; + } + } + else + { + /* We are forcing line speed. */ + pDevice->FlowControlCap &= ~LM_FLOW_CONTROL_AUTO_PAUSE; + LM_SetFlowControl(pDevice, 0, 0); + + CurrentLinkStatus = LM_STATUS_LINK_ACTIVE; + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode | + MAC_MODE_SEND_CONFIGS); + } + } + /* Set the link polarity bit. */ + pDevice->MacMode &= ~MAC_MODE_LINK_POLARITY; + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode); + + pDevice->pStatusBlkVirt->Status = STATUS_BLOCK_UPDATED | + (pDevice->pStatusBlkVirt->Status & ~STATUS_BLOCK_LINK_CHANGED_STATUS); + + for (j = 0; j < 100; j++) + { + REG_WR(pDevice, MacCtrl.Status, MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED); + REG_RD_BACK(pDevice, MacCtrl.Status); + MM_Wait(5); + if ((REG_RD(pDevice, MacCtrl.Status) & + (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED)) == 0) + break; + } + + Value32 = REG_RD(pDevice, MacCtrl.Status); + if((Value32 & MAC_STATUS_PCS_SYNCED) == 0) + { + CurrentLinkStatus = LM_STATUS_LINK_DOWN; + if (pDevice->DisableAutoNeg == FALSE) + { + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode | + MAC_MODE_SEND_CONFIGS); + REG_RD_BACK(pDevice, MacCtrl.Mode); + MM_Wait(1); + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode); + } + } + + /* Initialize the current link status. */ + if(CurrentLinkStatus == LM_STATUS_LINK_ACTIVE) + { + pDevice->LineSpeed = LM_LINE_SPEED_1000MBPS; + pDevice->DuplexMode = LM_DUPLEX_MODE_FULL; + REG_WR(pDevice, MacCtrl.LedCtrl, pDevice->LedCtrl | + LED_CTRL_OVERRIDE_LINK_LED | + LED_CTRL_1000MBPS_LED_ON); + } + else + { + pDevice->LineSpeed = LM_LINE_SPEED_UNKNOWN; + pDevice->DuplexMode = LM_DUPLEX_MODE_UNKNOWN; + REG_WR(pDevice, MacCtrl.LedCtrl, pDevice->LedCtrl | + LED_CTRL_OVERRIDE_LINK_LED | + LED_CTRL_OVERRIDE_TRAFFIC_LED); + } + + /* Indicate link status. */ + if ((pDevice->LinkStatus != CurrentLinkStatus) || + ((CurrentLinkStatus == LM_STATUS_LINK_ACTIVE) && + (PreviousFlowControl != pDevice->FlowControl))) + { + pDevice->LinkStatus = CurrentLinkStatus; + MM_IndicateStatus(pDevice, CurrentLinkStatus); + } + + return LM_STATUS_SUCCESS; +} +#endif /* INCLUDE_TBI_SUPPORT */ + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_STATUS +LM_SetupCopperPhy( + PLM_DEVICE_BLOCK pDevice) +{ + LM_STATUS CurrentLinkStatus; + LM_UINT32 Value32; + + /* Assume there is not link first. */ + CurrentLinkStatus = LM_STATUS_LINK_DOWN; + + /* Disable phy link change attention. */ + REG_WR(pDevice, MacCtrl.MacEvent, 0); + + /* Clear link change attention. */ + REG_WR(pDevice, MacCtrl.Status, MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED | MAC_STATUS_MI_COMPLETION | + MAC_STATUS_LINK_STATE_CHANGED); + + /* Disable auto-polling for the moment. */ + pDevice->MiMode = 0xc0000; + REG_WR(pDevice, MacCtrl.MiMode, pDevice->MiMode); + REG_RD_BACK(pDevice, MacCtrl.MiMode); + MM_Wait(40); + + /* Determine the requested line speed and duplex. */ + pDevice->OldLineSpeed = pDevice->LineSpeed; + /* Set line and duplex only if we don't have a Robo switch */ + if (!(pDevice->Flags & ROBO_SWITCH_FLAG)) { + pDevice->LineSpeed = pDevice->RequestedLineSpeed; + pDevice->DuplexMode = pDevice->RequestedDuplexMode; + } + + /* Set the phy to loopback mode. */ + if ((pDevice->LoopBackMode == LM_PHY_LOOP_BACK_MODE) || + (pDevice->LoopBackMode == LM_MAC_LOOP_BACK_MODE)) + { + LM_ReadPhy(pDevice, PHY_CTRL_REG, &Value32); + if(!(Value32 & PHY_CTRL_LOOPBACK_MODE) && + (pDevice->LoopBackMode == LM_PHY_LOOP_BACK_MODE)) + { + /* Disable link change and PHY interrupts. */ + REG_WR(pDevice, MacCtrl.MacEvent, 0); + + /* Clear link change attention. */ + REG_WR(pDevice, MacCtrl.Status, MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED); + + LM_WritePhy(pDevice, PHY_CTRL_REG, 0x4140); + MM_Wait(40); + + pDevice->MacMode &= ~MAC_MODE_LINK_POLARITY; + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701 || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5703 || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5704 || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5705 || + (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700 && + (pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5411_PHY_ID)) + { + pDevice->MacMode |= MAC_MODE_LINK_POLARITY; + } + + /* Prevent the interrupt handling from being called. */ + pDevice->pStatusBlkVirt->Status = STATUS_BLOCK_UPDATED | + (pDevice->pStatusBlkVirt->Status & + ~STATUS_BLOCK_LINK_CHANGED_STATUS); + + /* GMII interface. */ + pDevice->MacMode &= ~MAC_MODE_PORT_MODE_MASK; + pDevice->MacMode |= MAC_MODE_PORT_MODE_GMII; + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode); + REG_RD_BACK(pDevice, MacCtrl.Mode); + MM_Wait(40); + + /* Configure PHY led mode. */ + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701 || + (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700)) + { + LM_WritePhy(pDevice, BCM540X_EXT_CTRL_REG, + BCM540X_EXT_CTRL_LINK3_LED_MODE); + MM_Wait(40); + } + + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700) + { + int j = 0; + + while (REG_RD(pDevice, DmaWrite.Mode) & DMA_WRITE_MODE_ENABLE) + { + MM_Wait(40); + j++; + if (j > 20) + break; + } + + Value32 = DMA_WRITE_MODE_ENABLE | + DMA_WRITE_MODE_TARGET_ABORT_ATTN_ENABLE | + DMA_WRITE_MODE_MASTER_ABORT_ATTN_ENABLE | + DMA_WRITE_MODE_PARITY_ERROR_ATTN_ENABLE | + DMA_WRITE_MODE_ADDR_OVERFLOW_ATTN_ENABLE | + DMA_WRITE_MODE_FIFO_OVERRUN_ATTN_ENABLE | + DMA_WRITE_MODE_FIFO_UNDERRUN_ATTN_ENABLE | + DMA_WRITE_MODE_FIFO_OVERREAD_ATTN_ENABLE | + DMA_WRITE_MODE_LONG_READ_ATTN_ENABLE; + REG_WR(pDevice, DmaWrite.Mode, Value32); + } + } + + pDevice->LinkStatus = LM_STATUS_LINK_ACTIVE; + MM_IndicateStatus(pDevice, LM_STATUS_LINK_ACTIVE); + + return LM_STATUS_SUCCESS; + } + + /* For Robo switch read PHY_CTRL_REG value as zero */ + if (pDevice->Flags & ROBO_SWITCH_FLAG) + Value32 = 0; + else + LM_ReadPhy(pDevice, PHY_CTRL_REG, &Value32); + + if(Value32 & PHY_CTRL_LOOPBACK_MODE) + { + CurrentLinkStatus = LM_STATUS_LINK_DOWN; + + /* Re-enable link change interrupt. This was disabled when we */ + /* enter loopback mode. */ + if(pDevice->PhyIntMode == T3_PHY_INT_MODE_MI_INTERRUPT) + { + REG_WR(pDevice, MacCtrl.MacEvent, MAC_EVENT_ENABLE_MI_INTERRUPT); + } + else + { + REG_WR(pDevice, MacCtrl.MacEvent, + MAC_EVENT_ENABLE_LINK_STATE_CHANGED_ATTN); + } + } + else + { + /* Initialize the phy chip. */ + CurrentLinkStatus = LM_InitBcm540xPhy(pDevice); + } + + if(CurrentLinkStatus == LM_STATUS_LINK_SETTING_MISMATCH) + { + CurrentLinkStatus = LM_STATUS_LINK_DOWN; + } + + /* Setup flow control. */ + pDevice->FlowControl = LM_FLOW_CONTROL_NONE; + if(CurrentLinkStatus == LM_STATUS_LINK_ACTIVE) + { + LM_FLOW_CONTROL FlowCap; /* Flow control capability. */ + + FlowCap = LM_FLOW_CONTROL_NONE; + + if(pDevice->DuplexMode == LM_DUPLEX_MODE_FULL) + { + if(pDevice->DisableAutoNeg == FALSE || + pDevice->RequestedLineSpeed == LM_LINE_SPEED_AUTO) + { + LM_UINT32 ExpectedPhyAd; + LM_UINT32 LocalPhyAd; + LM_UINT32 RemotePhyAd; + + LM_ReadPhy(pDevice, PHY_AN_AD_REG, &LocalPhyAd); + pDevice->advertising = LocalPhyAd; + LocalPhyAd &= (PHY_AN_AD_ASYM_PAUSE | PHY_AN_AD_PAUSE_CAPABLE); + + ExpectedPhyAd = GetPhyAdFlowCntrlSettings(pDevice); + + if(LocalPhyAd != ExpectedPhyAd) + { + CurrentLinkStatus = LM_STATUS_LINK_DOWN; + } + else + { + LM_ReadPhy(pDevice, PHY_LINK_PARTNER_ABILITY_REG, + &RemotePhyAd); + + LM_SetFlowControl(pDevice, LocalPhyAd, RemotePhyAd); + } + } + else + { + pDevice->FlowControlCap &= ~LM_FLOW_CONTROL_AUTO_PAUSE; + LM_SetFlowControl(pDevice, 0, 0); + } + } + } + + if(CurrentLinkStatus == LM_STATUS_LINK_DOWN) + { + LM_ForceAutoNeg(pDevice); + + /* If we force line speed, we make get link right away. */ + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + if(Value32 & PHY_STATUS_LINK_PASS) + { + CurrentLinkStatus = LM_STATUS_LINK_ACTIVE; + } + } + + /* GMII interface. */ + pDevice->MacMode &= ~MAC_MODE_PORT_MODE_MASK; + if(CurrentLinkStatus == LM_STATUS_LINK_ACTIVE) + { + if(pDevice->LineSpeed == LM_LINE_SPEED_100MBPS || + pDevice->LineSpeed == LM_LINE_SPEED_10MBPS) + { + pDevice->MacMode |= MAC_MODE_PORT_MODE_MII; + } + else + { + pDevice->MacMode |= MAC_MODE_PORT_MODE_GMII; + } + } + else { + pDevice->MacMode |= MAC_MODE_PORT_MODE_GMII; + } + + /* In order for the 5750 core in BCM4785 chip to work properly + * in RGMII mode, the Led Control Register must be set up. + */ + if (pDevice->Flags & RGMII_MODE_FLAG) + { + LM_UINT32 LedCtrl_Reg; + + LedCtrl_Reg = REG_RD(pDevice, MacCtrl.LedCtrl); + LedCtrl_Reg &= ~(LED_CTRL_1000MBPS_LED_ON | LED_CTRL_100MBPS_LED_ON); + + if(pDevice->LineSpeed == LM_LINE_SPEED_10MBPS) + LedCtrl_Reg |= LED_CTRL_OVERRIDE_LINK_LED; + else if (pDevice->LineSpeed == LM_LINE_SPEED_100MBPS) + LedCtrl_Reg |= (LED_CTRL_OVERRIDE_LINK_LED | LED_CTRL_100MBPS_LED_ON); + else /* LM_LINE_SPEED_1000MBPS */ + LedCtrl_Reg |= (LED_CTRL_OVERRIDE_LINK_LED | LED_CTRL_1000MBPS_LED_ON); + + REG_WR(pDevice, MacCtrl.LedCtrl, LedCtrl_Reg); + + MM_Wait(40); + } + + /* Set the MAC to operate in the appropriate duplex mode. */ + pDevice->MacMode &= ~MAC_MODE_HALF_DUPLEX; + if(pDevice->DuplexMode == LM_DUPLEX_MODE_HALF) + { + pDevice->MacMode |= MAC_MODE_HALF_DUPLEX; + } + + /* Set the link polarity bit. */ + pDevice->MacMode &= ~MAC_MODE_LINK_POLARITY; + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700) + { + if((pDevice->LedCtrl == LED_CTRL_PHY_MODE_2) || + (CurrentLinkStatus == LM_STATUS_LINK_ACTIVE && + pDevice->LineSpeed == LM_LINE_SPEED_10MBPS)) + { + pDevice->MacMode |= MAC_MODE_LINK_POLARITY; + } + } + else + { + if (CurrentLinkStatus == LM_STATUS_LINK_ACTIVE) + { + pDevice->MacMode |= MAC_MODE_LINK_POLARITY; + } + } + + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode); + + /* Enable auto polling. */ + if(pDevice->PhyIntMode == T3_PHY_INT_MODE_AUTO_POLLING) + { + pDevice->MiMode |= MI_MODE_AUTO_POLLING_ENABLE; + REG_WR(pDevice, MacCtrl.MiMode, pDevice->MiMode); + } + /* if using MAC led mode and not using auto polling, need to configure */ + /* mi status register */ + else if ((pDevice->LedCtrl & + (LED_CTRL_PHY_MODE_1 | LED_CTRL_PHY_MODE_2)) == 0) + { + if (CurrentLinkStatus != LM_STATUS_LINK_ACTIVE) + { + REG_WR(pDevice, MacCtrl.MiStatus, 0); + } + else if (pDevice->LineSpeed == LM_LINE_SPEED_10MBPS) + { + REG_WR(pDevice, MacCtrl.MiStatus, + MI_STATUS_ENABLE_LINK_STATUS_ATTN | MI_STATUS_10MBPS); + } + else + { + REG_WR(pDevice, MacCtrl.MiStatus, + MI_STATUS_ENABLE_LINK_STATUS_ATTN); + } + } + + /* Enable phy link change attention. */ + if(pDevice->PhyIntMode == T3_PHY_INT_MODE_MI_INTERRUPT) + { + REG_WR(pDevice, MacCtrl.MacEvent, MAC_EVENT_ENABLE_MI_INTERRUPT); + } + else + { + REG_WR(pDevice, MacCtrl.MacEvent, + MAC_EVENT_ENABLE_LINK_STATE_CHANGED_ATTN); + } + if ((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700) && + (CurrentLinkStatus == LM_STATUS_LINK_ACTIVE) && + (pDevice->LineSpeed == LM_LINE_SPEED_1000MBPS) && + (((pDevice->PciState & T3_PCI_STATE_CONVENTIONAL_PCI_MODE) && + (pDevice->PciState & T3_PCI_STATE_BUS_SPEED_HIGH)) || + !(pDevice->PciState & T3_PCI_STATE_CONVENTIONAL_PCI_MODE))) + { + MM_Wait(120); + REG_WR(pDevice, MacCtrl.Status, MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED); + MEM_WR_OFFSET(pDevice, T3_FIRMWARE_MAILBOX, + T3_MAGIC_NUM_DISABLE_DMAW_ON_LINK_CHANGE); + } + + /* Indicate link status. */ + if (pDevice->LinkStatus != CurrentLinkStatus) { + pDevice->LinkStatus = CurrentLinkStatus; + MM_IndicateStatus(pDevice, CurrentLinkStatus); + } + + return LM_STATUS_SUCCESS; +} /* LM_SetupCopperPhy */ + + +void +LM_5714_FamForceFiber( + PLM_DEVICE_BLOCK pDevice) +{ + LM_UINT32 Creg, new_bmcr; + LM_ReadPhy(pDevice, PHY_CTRL_REG, &Creg); + + new_bmcr = Creg & ~PHY_CTRL_AUTO_NEG_ENABLE; + + if ( pDevice->RequestedDuplexMode == 0 || + pDevice->RequestedDuplexMode == LM_DUPLEX_MODE_FULL){ + + new_bmcr |= PHY_CTRL_FULL_DUPLEX_MODE; + } + + if(Creg == new_bmcr) + return; + + new_bmcr |= PHY_CTRL_SPEED_SELECT_1000MBPS; /* Reserve bit */ + + /* Force a linkdown */ + LM_WritePhy(pDevice, PHY_AN_AD_REG, 0); + LM_WritePhy(pDevice, PHY_CTRL_REG, new_bmcr | + PHY_CTRL_RESTART_AUTO_NEG | + PHY_CTRL_AUTO_NEG_ENABLE | + PHY_CTRL_SPEED_SELECT_1000MBPS); + MM_Wait(10); + + /* Force it */ + LM_WritePhy(pDevice, PHY_CTRL_REG, new_bmcr); + MM_Wait(10); + + return; + +}/* LM_5714_FamForceFiber */ + + +void +LM_5714_FamGoFiberAutoNeg( + PLM_DEVICE_BLOCK pDevice) +{ + LM_UINT32 adv,Creg,new; + + LM_ReadPhy(pDevice, PHY_CTRL_REG, &Creg); + LM_ReadPhy(pDevice,PHY_AN_AD_REG, &adv); + + new = adv & ~( PHY_AN_AD_1000XFULL | + PHY_AN_AD_1000XHALF | + PHY_AN_AD_1000XPAUSE | + PHY_AN_AD_1000XPSE_ASYM | + 0x1f); + + new |= PHY_AN_AD_1000XPAUSE; + + new |= PHY_AN_AD_1000XFULL; + new |= PHY_AN_AD_1000XHALF; + + if ((new != adv) || !(Creg & PHY_CTRL_AUTO_NEG_ENABLE)){ + LM_WritePhy(pDevice, PHY_AN_AD_REG, new); + MM_Wait(5); + pDevice->AutoNegJustInited=1; + LM_WritePhy(pDevice, PHY_CTRL_REG, (Creg | + PHY_CTRL_RESTART_AUTO_NEG | + PHY_CTRL_SPEED_SELECT_1000MBPS | + PHY_CTRL_AUTO_NEG_ENABLE) ); + } + + return; +} /* 5714_FamGoFiberAutoNeg */ + + +void +LM_5714_FamDoFiberLoopback(PLM_DEVICE_BLOCK pDevice) +{ + LM_UINT32 Value32; + + LM_ReadPhy(pDevice, PHY_CTRL_REG, &Value32); + + if( !(Value32 & PHY_CTRL_LOOPBACK_MODE) ) + { + LM_WritePhy(pDevice, PHY_CTRL_REG, 0x4140); + + /* Prevent the interrupt handling from being called. */ + pDevice->pStatusBlkVirt->Status = STATUS_BLOCK_UPDATED | + (pDevice->pStatusBlkVirt->Status & + ~STATUS_BLOCK_LINK_CHANGED_STATUS); + } + + pDevice->LinkStatus = LM_STATUS_LINK_ACTIVE; + MM_IndicateStatus(pDevice, LM_STATUS_LINK_ACTIVE); + + return; + +}/* 5714_FamDoFiberLoopBack */ + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ + +LM_STATUS +LM_SetupNewFiberPhy( + PLM_DEVICE_BLOCK pDevice) +{ + LM_STATUS LmStatus = LM_STATUS_SUCCESS; + LM_UINT32 Creg,Sreg,rsav; + + rsav = pDevice->LinkStatus; + + pDevice->MacMode |= MAC_MODE_PORT_MODE_GMII; + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode); + MM_Wait(40); + + /* Disable phy link change attention. */ + REG_WR(pDevice, MacCtrl.MacEvent, 0); + + /* Clear link change attention. */ + REG_WR(pDevice, MacCtrl.Status, MAC_STATUS_SYNC_CHANGED | + MAC_STATUS_CFG_CHANGED | MAC_STATUS_MI_COMPLETION | + MAC_STATUS_LINK_STATE_CHANGED); + + + if( (pDevice->PhyFlags & PHY_FIBER_FALLBACK) && + ( pDevice->RequestedLineSpeed == LM_LINE_SPEED_AUTO) ){ + + /* do nothing */ + }else if ( pDevice->LoopBackMode == LM_MAC_LOOP_BACK_MODE){ + + LM_5714_FamDoFiberLoopback(pDevice); + goto fiberloopbackreturn; + + } else if( pDevice->RequestedLineSpeed == LM_LINE_SPEED_AUTO) { + + LM_5714_FamGoFiberAutoNeg(pDevice); + + + }else { + + LM_5714_FamForceFiber(pDevice); + } + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Sreg); + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Sreg); + + if(Sreg & PHY_STATUS_LINK_PASS){ + + pDevice->LinkStatus = LM_STATUS_LINK_ACTIVE; + pDevice->LineSpeed = LM_LINE_SPEED_1000MBPS; + + LM_ReadPhy(pDevice, PHY_CTRL_REG, &Creg); + + if(Creg & PHY_CTRL_FULL_DUPLEX_MODE) { + pDevice->DuplexMode = LM_DUPLEX_MODE_FULL; + }else{ + pDevice->DuplexMode = LM_DUPLEX_MODE_HALF; + pDevice->MacMode |= MAC_MODE_HALF_DUPLEX; + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode); + } + + if(Creg & PHY_CTRL_AUTO_NEG_ENABLE){ + LM_UINT32 ours,partner; + + LM_ReadPhy(pDevice,PHY_AN_AD_REG, &ours); + LM_ReadPhy(pDevice,PHY_LINK_PARTNER_ABILITY_REG, &partner); + LM_SetFlowControl(pDevice, ours, partner); + } + + }else{ + pDevice->LinkStatus = LM_STATUS_LINK_DOWN; + pDevice->LineSpeed = 0; + } + + if(rsav != pDevice->LinkStatus) + MM_IndicateStatus(pDevice, pDevice->LinkStatus); + +fiberloopbackreturn: + pDevice->MacMode |= MAC_MODE_PORT_MODE_GMII; + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode); + MM_Wait(40); + /* Enable link change interrupt. */ + REG_WR(pDevice, MacCtrl.MacEvent, MAC_EVENT_ENABLE_LINK_STATE_CHANGED_ATTN); + + return LmStatus; +} /* Setup New phy */ + +void +LM_5714_FamFiberCheckLink( + PLM_DEVICE_BLOCK pDevice) +{ + + if(pDevice->AutoNegJustInited){ + pDevice->AutoNegJustInited=0; + return; + } + + if ((pDevice->LinkStatus != LM_STATUS_LINK_ACTIVE) && + (pDevice->RequestedLineSpeed == LM_LINE_SPEED_AUTO) && + !(pDevice->PhyFlags & PHY_FIBER_FALLBACK)){ + LM_UINT32 bmcr; + + LM_ReadPhy(pDevice, PHY_CTRL_REG, &bmcr); + if (bmcr & PHY_CTRL_AUTO_NEG_ENABLE) { + LM_UINT32 phy1, phy2; + + LM_WritePhy(pDevice, 0x1c, 0x7c00); + LM_ReadPhy(pDevice, 0x1c, &phy1); + + LM_WritePhy(pDevice, 0x17, 0x0f01); + LM_ReadPhy(pDevice, 0x15, &phy2); + LM_ReadPhy(pDevice, 0x15, &phy2); + + if ((phy1 & 0x10) && !(phy2 & 0x20)) { + + /* We have signal detect and not receiving + * configs. + */ + + pDevice->PhyFlags |= PHY_FIBER_FALLBACK; + LM_5714_FamForceFiber(pDevice); + } + } + } + else if ( (pDevice->PhyFlags & PHY_FIBER_FALLBACK) && + (pDevice->RequestedLineSpeed == LM_LINE_SPEED_AUTO)) { + LM_UINT32 phy2; + + LM_WritePhy(pDevice, 0x17, 0x0f01); + LM_ReadPhy(pDevice, 0x15, &phy2); + if (phy2 & 0x20) { + /* Receiving configs. */ + + pDevice->PhyFlags &= ~PHY_FIBER_FALLBACK; + LM_5714_FamGoFiberAutoNeg(pDevice); + } + } + +} /* LM_5714_FamFiberCheckLink */ + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_STATUS +LM_SetupPhy( + PLM_DEVICE_BLOCK pDevice) +{ + LM_STATUS LmStatus; + LM_UINT32 Value32; + + if(pDevice->PhyFlags & PHY_IS_FIBER) + { + LmStatus = LM_SetupNewFiberPhy(pDevice); + }else +#ifdef INCLUDE_TBI_SUPPORT + if (pDevice->TbiFlags & ENABLE_TBI_FLAG) + { + LmStatus = LM_SetupFiberPhy(pDevice); + } + else +#endif /* INCLUDE_TBI_SUPPORT */ + { + LmStatus = LM_SetupCopperPhy(pDevice); + } + if (pDevice->ChipRevId == T3_CHIP_ID_5704_A0) + { + if (!(pDevice->PciState & T3_PCI_STATE_CONVENTIONAL_PCI_MODE)) + { + Value32 = REG_RD(pDevice, PciCfg.PciState); + REG_WR(pDevice, PciCfg.PciState, + Value32 | T3_PCI_STATE_RETRY_SAME_DMA); + } + } + if ((pDevice->LineSpeed == LM_LINE_SPEED_1000MBPS) && + (pDevice->DuplexMode == LM_DUPLEX_MODE_HALF)) + { + REG_WR(pDevice, MacCtrl.TxLengths, 0x26ff); + } + else + { + REG_WR(pDevice, MacCtrl.TxLengths, 0x2620); + } + if(!T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) + { + if (pDevice->LinkStatus == LM_STATUS_LINK_DOWN) + { + REG_WR(pDevice, HostCoalesce.StatsCoalescingTicks, 0); + } + else + { + REG_WR(pDevice, HostCoalesce.StatsCoalescingTicks, + pDevice->StatsCoalescingTicks); + } + } + + return LmStatus; +} + + +/* test data pattern */ +static LM_UINT32 pattern[4][6] = { + /* For 5703/04, each DFE TAP has 21-bits (low word 15, hi word 6) + For 5705 , each DFE TAP has 19-bits (low word 15, hi word 4) + For simplicity, we check only 19-bits, so we don't have to + distinguish which chip it is. + the LO word contains 15 bits, make sure pattern data is < 0x7fff + the HI word contains 6 bits, make sure pattern data is < 0x003f */ + {0x00005555, 0x00000005, /* ch0, TAP 0, LO/HI pattern */ + 0x00002aaa, 0x0000000a, /* ch0, TAP 1, LO/HI pattern */ + 0x00003456, 0x00000003}, /* ch0, TAP 2, LO/HI pattern */ + + {0x00002aaa, 0x0000000a, /* ch1, TAP 0, LO/HI pattern */ + 0x00003333, 0x00000003, /* ch1, TAP 1, LO/HI pattern */ + 0x0000789a, 0x00000005}, /* ch1, TAP 2, LO/HI pattern */ + + {0x00005a5a, 0x00000005, /* ch2, TAP 0, LO/HI pattern */ + 0x00002a6a, 0x0000000a, /* ch2, TAP 1, LO/HI pattern */ + 0x00001bcd, 0x00000003}, /* ch2, TAP 2, LO/HI pattern */ + + {0x00002a5a, 0x0000000a, /* ch3, TAP 0, LO/HI pattern */ + 0x000033c3, 0x00000003, /* ch3, TAP 1, LO/HI pattern */ + 0x00002ef1, 0x00000005}, /* ch3, TAP 2, LO/HI pattern */ +}; + +/********************************************************/ +/* Routine to wait for PHY Macro Command to complete */ +/* */ +/* If PHY's Macro operation keeps stay busy, nothing we */ +/* can do anyway. The timeout is there so we won't */ +/* stay in this routine indefinitly. */ +/********************************************************/ +static LM_UINT32 LM_wait_macro_done(LM_DEVICE_BLOCK *pDevice); + +static LM_UINT32 +LM_wait_macro_done(LM_DEVICE_BLOCK *pDevice) +{ + LM_UINT32 timeout; + LM_UINT32 val32; + + timeout = 100; + while (timeout--) + { + /* make sure the MACRO operation is complete */ + LM_ReadPhy(pDevice, 0x16, &val32); + if ((val32 & 0x1000) == 0) break; + } + + return( timeout > 0 ); +} + +/********************************************************/ +/* This routine resets the PHY on following chips: */ +/* 5703, 04, CIOB-E and 5705 */ +/* */ +/* This routine will issue PHY_RESET and check if */ +/* the reset is sucessful. If not, another PHY RESET */ +/* will be issued, until max "retry" reaches */ +/* */ +/* Input: */ +/* pDevice - device's context */ +/* retry - number of retries */ +/* reset - TRUE=will cause a PHY reset initially */ +/* FALSE = will not issue a PHY reset */ +/* unless TAP lockup detected */ +/* */ +/* Output: */ +/* TRUE - PHY Reset is done sucessfully */ +/* FALSE - PHY Reset had failed, after "retry" */ +/* has reached */ +/* */ +/* Dependencies: */ +/* void LM_wait_macro_done() */ +/* LM_UINT32 pattern[] */ +/* */ +/* Usage: */ +/* a. Before calling this routine, caller must */ +/* determine if the chip is a 5702/03/04 or */ +/* CIOB-E, and only call this routine if the */ +/* is one of these. */ +/* or its derivatives. */ +/* b. Instead of using MII register write to reset */ +/* the PHY, call this routine instead */ +/* c. Upon return from this routine, check return */ +/* value (TRUE/FALSE) to determine if PHY reset */ +/* is successful of not and "optionally" take */ +/* appropriate action (such as: event log) */ +/* d. Regardless of the return TRUE or FALSE, */ +/* proceed with PHY setup as you normally would */ +/* after a PHY_RESET. */ +/* e. It is recommended that the caller will give */ +/* 10 "retry", however, caller can change to a */ +/* different number, depending on you code. */ +/* */ +/********************************************************/ +LM_STATUS LM_ResetPhy_5703_4_5(LM_DEVICE_BLOCK *pDevice, int retry, int reset); + +LM_STATUS +LM_ResetPhy_5703_4_5(LM_DEVICE_BLOCK *pDevice, int retry, int reset) +{ + LM_UINT32 val32, save9; + LM_UINT32 dataLo, dataHi; + int i, channel; + int reset_success = LM_STATUS_FAILURE; + int force_reset; + + /* to actually do a PHY_RESET or not is dictated by the caller */ + force_reset = reset; + + while (retry-- && (reset_success != LM_STATUS_SUCCESS)) + { + if (force_reset) + { + /* issue a phy reset, and wait for reset to complete */ + LM_WritePhy(pDevice, PHY_CTRL_REG, PHY_CTRL_PHY_RESET); + for(i = 0; i < 100; i++) + { + MM_Wait(10); + + LM_ReadPhy(pDevice, PHY_CTRL_REG, &val32); + if(val32 && !(val32 & PHY_CTRL_PHY_RESET)) + { + MM_Wait(20); + break; + } + } + + /* no more phy reset unless lockup detected */ + force_reset = FALSE; + } + + /* assuming reset is successful first */ + reset_success = LM_STATUS_SUCCESS; + + /* now go check the DFE TAPs to see if locked up, but + first, we need to set up PHY so we can read DFE TAPs */ + + /* Disable Transmitter and Interrupt, while we play with + the PHY registers, so the link partner won't see any + strange data and the Driver won't see any interrupts. */ + LM_ReadPhy(pDevice, 0x10, &val32); + LM_WritePhy(pDevice, 0x10, val32 | 0x3000); + + /* Setup Full-Duplex, 1000 mbps */ + LM_WritePhy(pDevice, 0x0, 0x0140); + + /* Set to Master mode */ + LM_ReadPhy(pDevice, 0x9, &save9); + LM_WritePhy(pDevice, 0x9, 0x1800); + + /* Enable SM_DSP_CLOCK & 6dB */ + LM_WritePhy(pDevice, 0x18, 0x0c00); + + /* blocks the PHY control access */ + LM_WritePhy(pDevice, 0x17, 0x8005); + LM_WritePhy(pDevice, 0x15, 0x0800); + + /* check TAPs for all 4 channels, as soon + as we see a lockup we'll stop checking */ + for (channel=0; (channel<4) && (reset_success == LM_STATUS_SUCCESS); + channel++) + { + /* select channel and set TAP index to 0 */ + LM_WritePhy(pDevice, 0x17, (channel * 0x2000) | 0x0200); + /* freeze filter again just to be safe */ + LM_WritePhy(pDevice, 0x16, 0x0002); + + /* write fixed pattern to the RAM, 3 TAPs for + each channel, each TAP have 2 WORDs (LO/HI) */ + for (i=0; i<6; i++) + LM_WritePhy(pDevice, 0x15, pattern[channel][i]); + + /* Activate PHY's Macro operation to write DFE TAP from RAM, + and wait for Macro to complete */ + LM_WritePhy(pDevice, 0x16, 0x0202); + if (!LM_wait_macro_done(pDevice)) + { + reset_success = LM_STATUS_FAILURE; + force_reset = TRUE; + break; + } + + /* --- done with write phase, now begin read phase --- */ + + /* select channel and set TAP index to 0 */ + LM_WritePhy(pDevice, 0x17, (channel * 0x2000) | 0x0200); + + /* Active PHY's Macro operation to load DFE TAP to RAM, + and wait for Macro to complete */ + LM_WritePhy(pDevice, 0x16, 0x0082); + if (!LM_wait_macro_done(pDevice)) + { + reset_success = LM_STATUS_FAILURE; + force_reset = TRUE; + break; + } + + /* enable "pre-fetch" */ + LM_WritePhy(pDevice, 0x16, 0x0802); + if (!LM_wait_macro_done(pDevice)) + { + reset_success = LM_STATUS_FAILURE; + force_reset = TRUE; + break; + } + + /* read back the TAP values. + 3 TAPs for each channel, each TAP have 2 WORDs (LO/HI) */ + for (i=0; i<6; i+=2) + { + /* read Lo/Hi then wait for 'done' is faster */ + LM_ReadPhy(pDevice, 0x15, &dataLo); + LM_ReadPhy(pDevice, 0x15, &dataHi); + if (!LM_wait_macro_done(pDevice)) + { + reset_success = LM_STATUS_FAILURE; + force_reset = TRUE; + break; + } + + /* For 5703/04, each DFE TAP has 21-bits (low word 15, + * hi word 6) For 5705, each DFE TAP pas 19-bits (low word 15, + * hi word 4) For simplicity, we check only 19-bits, so we + * don't have to distinguish which chip it is. */ + dataLo &= 0x7fff; + dataHi &= 0x000f; + + /* check if what we wrote is what we read back */ + if ( (dataLo != pattern[channel][i]) || (dataHi != pattern[channel][i+1]) ) + { + /* if failed, then the PHY is locked up, + we need to do PHY reset again */ + reset_success = LM_STATUS_FAILURE; + force_reset = TRUE; + /* 04/25/2003. sb. do these writes before issueing a reset. */ + /* these steps will reduce the chance of back-to-back + * phy lockup after reset */ + LM_WritePhy(pDevice, 0x17, 0x000B); + LM_WritePhy(pDevice, 0x15, 0x4001); + LM_WritePhy(pDevice, 0x15, 0x4005); + break; + } + } /* for i */ + } /* for channel */ + } /* while */ + + /* restore dfe coeff back to zeros */ + for (channel=0; channel<4 ; channel++) + { + LM_WritePhy(pDevice, 0x17, (channel * 0x2000) | 0x0200); + LM_WritePhy(pDevice, 0x16, 0x0002); + for (i=0; i<6; i++) + LM_WritePhy(pDevice, 0x15, 0x0000); + LM_WritePhy(pDevice, 0x16, 0x0202); + if (!LM_wait_macro_done(pDevice)) + { + reset_success = LM_STATUS_FAILURE; + break; + } + } + + /* remove block phy control */ + LM_WritePhy(pDevice, 0x17, 0x8005); + LM_WritePhy(pDevice, 0x15, 0x0000); + + /* unfreeze DFE TAP filter for all channels */ + LM_WritePhy(pDevice, 0x17, 0x8200); + LM_WritePhy(pDevice, 0x16, 0x0000); + + /* Restore PHY back to operating state */ + LM_WritePhy(pDevice, 0x18, 0x0400); + + /* Restore register 9 */ + LM_WritePhy(pDevice, 0x9, save9); + + /* enable transmitter and interrupt */ + LM_ReadPhy(pDevice, 0x10, &val32); + LM_WritePhy(pDevice, 0x10, (val32 & ~0x3000)); + + return reset_success; +} + +LM_VOID +LM_ResetPhy(LM_DEVICE_BLOCK *pDevice) +{ + int j; + LM_UINT32 miireg; + + if (pDevice->PhyFlags & PHY_CHECK_TAPS_AFTER_RESET) + { + LM_ResetPhy_5703_4_5(pDevice, 5, 1); + } + else + { + int wait_val = 100; + LM_WritePhy(pDevice, PHY_CTRL_REG, PHY_CTRL_PHY_RESET); + + if( pDevice->PhyFlags & PHY_IS_FIBER ) + wait_val = 5000; + + for(j = 0; j < wait_val; j++) + { + MM_Wait(10); + + LM_ReadPhy(pDevice, PHY_CTRL_REG, &miireg); + if(miireg && !(miireg & PHY_CTRL_PHY_RESET)) + { + MM_Wait(20); + break; + } + } + + LM_PhyTapPowerMgmt(pDevice); + } + if ( (pDevice->PhyFlags & PHY_ADC_FIX) && + !( pDevice->PhyFlags & PHY_IS_FIBER) ) + { + LM_WritePhy(pDevice, 0x18, 0x0c00); + LM_WritePhy(pDevice, 0x17, 0x201f); + LM_WritePhy(pDevice, 0x15, 0x2aaa); + LM_WritePhy(pDevice, 0x17, 0x000a); + LM_WritePhy(pDevice, 0x15, 0x0323); + LM_WritePhy(pDevice, 0x18, 0x0400); + } + if ( (pDevice->PhyFlags & PHY_5705_5750_FIX) && + !( pDevice->PhyFlags & PHY_IS_FIBER) ) + { + LM_WritePhy(pDevice, 0x18, 0x0c00); + LM_WritePhy(pDevice, 0x17, 0x000a); + LM_WritePhy(pDevice, 0x15, 0x310b); + LM_WritePhy(pDevice, 0x17, 0x201f); + LM_WritePhy(pDevice, 0x15, 0x9506); + LM_WritePhy(pDevice, 0x17, 0x401f); + LM_WritePhy(pDevice, 0x15, 0x14e2); + LM_WritePhy(pDevice, 0x18, 0x0400); + } + if ( (pDevice->PhyFlags & PHY_5704_A0_FIX) && + !( pDevice->PhyFlags & PHY_IS_FIBER) ) + { + LM_WritePhy(pDevice, 0x1c, 0x8d68); + LM_WritePhy(pDevice, 0x1c, 0x8d68); + } + if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5401_PHY_ID) + { + LM_ReadPhy(pDevice, BCM540X_EXT_CTRL_REG, &miireg); + miireg |= 1; /* set tx elastic fifo */ + LM_WritePhy(pDevice, BCM540X_EXT_CTRL_REG, miireg); + + LM_WritePhy(pDevice, BCM5401_AUX_CTRL, 0x4c20); + } + else if (pDevice->Flags & JUMBO_CAPABLE_FLAG) + { + LM_WritePhy(pDevice, BCM5401_AUX_CTRL, 0x0007); + LM_ReadPhy(pDevice, BCM5401_AUX_CTRL, &miireg); + miireg |= 0x4000; /* set rx extended packet length */ + LM_WritePhy(pDevice, BCM5401_AUX_CTRL, miireg); + + LM_ReadPhy(pDevice, BCM540X_EXT_CTRL_REG, &miireg); + miireg |= 1; /* set tx elastic fifo */ + LM_WritePhy(pDevice, BCM540X_EXT_CTRL_REG, miireg); + + } + + LM_SetEthWireSpeed(pDevice); + pDevice->PhyFlags &= ~PHY_FIBER_FALLBACK; +} + +STATIC LM_VOID +LM_SetEthWireSpeed(LM_DEVICE_BLOCK *pDevice) +{ + LM_UINT32 Value32; + + if( pDevice->PhyFlags & PHY_IS_FIBER) + return; + + /* Enable Ethernet@WireSpeed. */ + if (pDevice->PhyFlags & PHY_ETHERNET_WIRESPEED) + { + LM_WritePhy(pDevice, 0x18, 0x7007); + LM_ReadPhy(pDevice, 0x18, &Value32); + LM_WritePhy(pDevice, 0x18, Value32 | BIT_15 | BIT_4); + } +} + +STATIC LM_STATUS +LM_PhyAdvertiseAll(LM_DEVICE_BLOCK *pDevice) +{ + LM_UINT32 miireg; + + LM_ReadPhy(pDevice, PHY_AN_AD_REG, &miireg); + pDevice->advertising = miireg; + if ((miireg & PHY_AN_AD_ALL_SPEEDS) != PHY_AN_AD_ALL_SPEEDS) + { + return LM_STATUS_FAILURE; + } + + LM_ReadPhy(pDevice, BCM540X_1000BASET_CTRL_REG, &miireg); + pDevice->advertising1000 = miireg; + + if (!(pDevice->PhyFlags & PHY_NO_GIGABIT)) + { + if ((miireg & BCM540X_AN_AD_ALL_1G_SPEEDS) != + BCM540X_AN_AD_ALL_1G_SPEEDS) + { + return LM_STATUS_FAILURE; + } + }else{ + + if(miireg) + { + return LM_STATUS_FAILURE; + } + } + return LM_STATUS_SUCCESS; +} + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_VOID +LM_ReadPhy( +PLM_DEVICE_BLOCK pDevice, +LM_UINT32 PhyReg, +PLM_UINT32 pData32) { + LM_UINT32 Value32; + LM_UINT32 j; + + if(pDevice->PhyIntMode == T3_PHY_INT_MODE_AUTO_POLLING) + { + REG_WR(pDevice, MacCtrl.MiMode, pDevice->MiMode & + ~MI_MODE_AUTO_POLLING_ENABLE); + REG_RD_BACK(pDevice, MacCtrl.MiMode); + MM_Wait(40); + } + + Value32 = (pDevice->PhyAddr << MI_COM_FIRST_PHY_ADDR_BIT) | + ((PhyReg & MI_COM_PHY_REG_ADDR_MASK) << MI_COM_FIRST_PHY_REG_ADDR_BIT) | + MI_COM_CMD_READ | MI_COM_START; + + REG_WR(pDevice, MacCtrl.MiCom, Value32); + + for(j = 0; j < 200; j++) + { + MM_Wait(1); + + Value32 = REG_RD(pDevice, MacCtrl.MiCom); + + if(!(Value32 & MI_COM_BUSY)) + { + MM_Wait(5); + Value32 = REG_RD(pDevice, MacCtrl.MiCom); + Value32 &= MI_COM_PHY_DATA_MASK; + break; + } + } + + if(Value32 & MI_COM_BUSY) + { + Value32 = 0; + } + + *pData32 = Value32; + + if(pDevice->PhyIntMode == T3_PHY_INT_MODE_AUTO_POLLING) + { + REG_WR(pDevice, MacCtrl.MiMode, pDevice->MiMode); + REG_RD_BACK(pDevice, MacCtrl.MiMode); + MM_Wait(40); + } +} /* LM_ReadPhy */ + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_VOID +LM_WritePhy( +PLM_DEVICE_BLOCK pDevice, +LM_UINT32 PhyReg, +LM_UINT32 Data32) { + LM_UINT32 Value32; + LM_UINT32 j; + + if(pDevice->PhyIntMode == T3_PHY_INT_MODE_AUTO_POLLING) + { + REG_WR(pDevice, MacCtrl.MiMode, pDevice->MiMode & + ~MI_MODE_AUTO_POLLING_ENABLE); + REG_RD_BACK(pDevice, MacCtrl.MiMode); + MM_Wait(40); + } + + Value32 = (pDevice->PhyAddr << MI_COM_FIRST_PHY_ADDR_BIT) | + ((PhyReg & MI_COM_PHY_REG_ADDR_MASK) << MI_COM_FIRST_PHY_REG_ADDR_BIT) | + (Data32 & MI_COM_PHY_DATA_MASK) | MI_COM_CMD_WRITE | MI_COM_START; + + REG_WR(pDevice, MacCtrl.MiCom, Value32); + + for(j = 0; j < 200; j++) + { + MM_Wait(1); + + Value32 = REG_RD(pDevice, MacCtrl.MiCom); + + if(!(Value32 & MI_COM_BUSY)) + { + MM_Wait(5); + break; + } + } + + if(pDevice->PhyIntMode == T3_PHY_INT_MODE_AUTO_POLLING) + { + REG_WR(pDevice, MacCtrl.MiMode, pDevice->MiMode); + REG_RD_BACK(pDevice, MacCtrl.MiMode); + MM_Wait(40); + } +} /* LM_WritePhy */ + +/* MII read/write functions to export to the robo support code */ +LM_UINT16 +robo_miird(void *h, int phyadd, int regoff) +{ + PLM_DEVICE_BLOCK pdev = h; + LM_UINT32 savephyaddr, val32; + + savephyaddr = pdev->PhyAddr; + pdev->PhyAddr = phyadd; + + LM_ReadPhy(pdev, regoff, &val32); + + pdev->PhyAddr = savephyaddr; + + return ((LM_UINT16)(val32 & 0xffff)); +} + +void +robo_miiwr(void *h, int phyadd, int regoff, LM_UINT16 value) +{ + PLM_DEVICE_BLOCK pdev = h; + LM_UINT32 val32, savephyaddr; + + savephyaddr = pdev->PhyAddr; + pdev->PhyAddr = phyadd; + + val32 = (LM_UINT32)value; + LM_WritePhy(pdev, regoff, val32); + + pdev->PhyAddr = savephyaddr; +} + +STATIC void +LM_GetPhyId(LM_DEVICE_BLOCK *pDevice) +{ + LM_UINT32 Value32; + + LM_ReadPhy(pDevice, PHY_ID1_REG, &Value32); + pDevice->PhyId = (Value32 & PHY_ID1_OUI_MASK) << 10; + + LM_ReadPhy(pDevice, PHY_ID2_REG, &Value32); + pDevice->PhyId |= ((Value32 & PHY_ID2_OUI_MASK) << 16) | + (Value32 & PHY_ID2_MODEL_MASK) | (Value32 & PHY_ID2_REV_MASK); + +} + +LM_STATUS +LM_EnableMacLoopBack(PLM_DEVICE_BLOCK pDevice) +{ + pDevice->LoopBackMode = LM_MAC_LOOP_BACK_MODE; + pDevice->MacMode &= ~MAC_MODE_PORT_MODE_MASK; + pDevice->MacMode |= (MAC_MODE_PORT_INTERNAL_LOOPBACK | + MAC_MODE_LINK_POLARITY | MAC_MODE_PORT_MODE_GMII); + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode); + MM_Wait(40); + LM_SetupPhy(pDevice); + return LM_STATUS_SUCCESS; +} + +LM_STATUS +LM_DisableMacLoopBack(PLM_DEVICE_BLOCK pDevice) +{ + pDevice->LoopBackMode = 0; + + pDevice->MacMode &= ~(MAC_MODE_PORT_INTERNAL_LOOPBACK | + MAC_MODE_LINK_POLARITY | MAC_MODE_PORT_MODE_MASK); + REG_WR(pDevice, MacCtrl.Mode, pDevice->MacMode); + MM_Wait(40); + if(pDevice->PhyFlags & PHY_IS_FIBER) + LM_ResetPhy(pDevice); + + LM_SetupPhy(pDevice); + return LM_STATUS_SUCCESS; +} + +LM_STATUS +LM_EnablePhyLoopBack(PLM_DEVICE_BLOCK pDevice) +{ + pDevice->LoopBackMode = LM_PHY_LOOP_BACK_MODE; + LM_SetupPhy(pDevice); + return LM_STATUS_SUCCESS; +} + +LM_STATUS +LM_DisablePhyLoopBack(PLM_DEVICE_BLOCK pDevice) +{ + pDevice->LoopBackMode = 0; + LM_SetupPhy(pDevice); + return LM_STATUS_SUCCESS; +} + +LM_STATUS +LM_EnableExtLoopBack(PLM_DEVICE_BLOCK pDevice, LM_LINE_SPEED LineSpeed) +{ + pDevice->LoopBackMode = LM_EXT_LOOP_BACK_MODE; + + pDevice->SavedDisableAutoNeg = pDevice->DisableAutoNeg; + pDevice->SavedRequestedLineSpeed = pDevice->RequestedLineSpeed; + pDevice->SavedRequestedDuplexMode = pDevice->RequestedDuplexMode; + + pDevice->DisableAutoNeg = TRUE; + pDevice->RequestedLineSpeed = LineSpeed; + pDevice->RequestedDuplexMode = LM_DUPLEX_MODE_FULL; + LM_SetupPhy(pDevice); + return LM_STATUS_SUCCESS; +} + +LM_STATUS +LM_DisableExtLoopBack(PLM_DEVICE_BLOCK pDevice) +{ + pDevice->LoopBackMode = 0; + + pDevice->DisableAutoNeg = pDevice->SavedDisableAutoNeg; + pDevice->RequestedLineSpeed = pDevice->SavedRequestedLineSpeed; + pDevice->RequestedDuplexMode = pDevice->SavedRequestedDuplexMode; + + LM_SetupPhy(pDevice); + return LM_STATUS_SUCCESS; +} + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_STATUS +LM_SetPowerState( +PLM_DEVICE_BLOCK pDevice, +LM_POWER_STATE PowerLevel) +{ +#ifdef BCM_WOL + LM_UINT32 PmeSupport; + PLM_DEVICE_BLOCK pDevice2 = 0; + int j; +#endif + LM_UINT32 Value32; + LM_UINT32 PmCtrl; + + /* make sureindirect accesses are enabled*/ + MM_WriteConfig32(pDevice, T3_PCI_MISC_HOST_CTRL_REG, pDevice->MiscHostCtrl); + + /* Clear the PME_ASSERT bit and the power state bits. Also enable */ + /* the PME bit. */ + MM_ReadConfig32(pDevice, T3_PCI_PM_STATUS_CTRL_REG, &PmCtrl); + + PmCtrl |= T3_PM_PME_ASSERTED; + PmCtrl &= ~T3_PM_POWER_STATE_MASK; + + /* Set the appropriate power state. */ + if(PowerLevel == LM_POWER_STATE_D0) + { + /* Bring the card out of low power mode. */ + PmCtrl |= T3_PM_POWER_STATE_D0; + MM_WriteConfig32(pDevice, T3_PCI_PM_STATUS_CTRL_REG, PmCtrl); + + Value32 = REG_RD(pDevice, Grc.LocalCtrl); + + if(T3_ASIC_5752(pDevice->ChipRevId)){ + Value32 |= (GRC_MISC_LOCAL_CTRL_GPIO_OE3 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT3 | + GRC_MISC_LOCAL_CTRL_GPIO_OE0 | + GRC_MISC_LOCAL_CTRL_GPIO_OE1 | + GRC_MISC_LOCAL_CTRL_GPIO_OE2 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT0 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT2); + } + else + { + Value32 &= ~(GRC_MISC_LOCAL_CTRL_GPIO_OE0 | + GRC_MISC_LOCAL_CTRL_GPIO_OE1 | + GRC_MISC_LOCAL_CTRL_GPIO_OE2 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT0 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT2); + } + + RAW_REG_WR(pDevice, Grc.LocalCtrl, Value32); + + MM_Wait(40); /* Required delay is about 20us. */ + + pDevice->PowerLevel = PowerLevel; + return LM_STATUS_SUCCESS; + } +#ifdef BCM_WOL + else if(PowerLevel == LM_POWER_STATE_D1) + { + PmCtrl |= T3_PM_POWER_STATE_D1; + } + else if(PowerLevel == LM_POWER_STATE_D2) + { + PmCtrl |= T3_PM_POWER_STATE_D2; + } + else if(PowerLevel == LM_POWER_STATE_D3) + { + PmCtrl |= T3_PM_POWER_STATE_D3; + } + else + { + return LM_STATUS_FAILURE; + } + PmCtrl |= T3_PM_PME_ENABLE; + + /* Mask out all interrupts so LM_SetupPhy won't be called while we are */ + /* setting new line speed. */ + Value32 = REG_RD(pDevice, PciCfg.MiscHostCtrl); + REG_WR(pDevice, PciCfg.MiscHostCtrl, Value32 | MISC_HOST_CTRL_MASK_PCI_INT); + + if(!pDevice->RestoreOnWakeUp) + { + pDevice->RestoreOnWakeUp = TRUE; + pDevice->WakeUpDisableAutoNeg = pDevice->DisableAutoNeg; + pDevice->WakeUpRequestedLineSpeed = pDevice->RequestedLineSpeed; + pDevice->WakeUpRequestedDuplexMode = pDevice->RequestedDuplexMode; + } + + /* Force auto-negotiation to 10 line speed. */ + pDevice->DisableAutoNeg = FALSE; + + if (!(pDevice->TbiFlags & ENABLE_TBI_FLAG)) + { + pDevice->RequestedLineSpeed = LM_LINE_SPEED_10MBPS; + LM_SetupPhy(pDevice); + } + + /* Put the driver in the initial state, and go through the power down */ + /* sequence. */ + LM_DoHalt(pDevice); + + if (!(pDevice->AsfFlags & ASF_ENABLED)) + { + for(j = 0; j < 20000; j++) + { + MM_Wait(10); + + Value32 = MEM_RD_OFFSET(pDevice, T3_ASF_FW_STATUS_MAILBOX); + if(Value32 == ~T3_MAGIC_NUM_FIRMWARE_INIT_DONE) + { + break; + } + } + } + + MEM_WR_OFFSET(pDevice, DRV_WOL_MAILBOX, DRV_WOL_SIGNATURE | + DRV_DOWN_STATE_SHUTDOWN | 0x2 | DRV_WOL_SET_MAGIC_PKT); + + MM_ReadConfig32(pDevice, T3_PCI_PM_CAP_REG, &PmeSupport); + + if (pDevice->WakeUpModeCap != LM_WAKE_UP_MODE_NONE) + { + + /* Enable WOL. */ + if (!(pDevice->TbiFlags & ENABLE_TBI_FLAG)) + { + LM_WritePhy(pDevice, BCM5401_AUX_CTRL, 0x5a); + MM_Wait(40); + } + + if (! T3_ASIC_IS_575X_PLUS(pDevice->ChipRevId)) + { + /* Let boot code deal with LED mode on shasta */ + REG_WR(pDevice, MacCtrl.LedCtrl, pDevice->LedCtrl); + } + + if (pDevice->TbiFlags & ENABLE_TBI_FLAG) + { + Value32 = MAC_MODE_PORT_MODE_TBI; + } + else + { + Value32 = MAC_MODE_PORT_MODE_MII; + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700) + { + if(pDevice->LedCtrl == LED_CTRL_PHY_MODE_2 || + pDevice->WolSpeed == WOL_SPEED_10MB) + { + Value32 |= MAC_MODE_LINK_POLARITY; + } + } + else + { + Value32 |= MAC_MODE_LINK_POLARITY; + } + } + REG_WR(pDevice, MacCtrl.Mode, Value32); + REG_RD_BACK(pDevice, MacCtrl.Mode); + MM_Wait(40); MM_Wait(40); MM_Wait(40); + + /* Always enable magic packet wake-up if we have vaux. */ + if((PmeSupport & T3_PCI_PM_CAP_PME_D3COLD) && + (pDevice->WakeUpModeCap & LM_WAKE_UP_MODE_MAGIC_PACKET)) + { + Value32 |= MAC_MODE_DETECT_MAGIC_PACKET_ENABLE; + } + +#ifdef BCM_ASF + if (pDevice->AsfFlags & ASF_ENABLED) + { + Value32 &= ~MAC_MODE_ACPI_POWER_ON_ENABLE; + } +#endif + REG_WR(pDevice, MacCtrl.Mode, Value32); + + /* Enable the receiver. */ + REG_WR(pDevice, MacCtrl.RxMode, RX_MODE_ENABLE); + } + else if (!(pDevice->AsfFlags & ASF_ENABLED)) + { + if (pDevice->TbiFlags & ENABLE_TBI_FLAG) + { + REG_WR(pDevice, MacCtrl.LedCtrl, LED_CTRL_OVERRIDE_LINK_LED | + LED_CTRL_OVERRIDE_TRAFFIC_LED); + } + else + { + LM_WritePhy(pDevice, BCM540X_EXT_CTRL_REG, + BCM540X_EXT_CTRL_FORCE_LED_OFF); + LM_WritePhy(pDevice, 0x18, 0x01b2); + if ((T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5700) && + (T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5704) && + !T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId) ) + { + LM_WritePhy(pDevice, PHY_CTRL_REG, PHY_CTRL_LOWER_POWER_MODE); + } + } + } + + /* Disable tx/rx clocks, and select an alternate clock. */ + if (T3_ASIC_5714_FAMILY(pDevice->ChipRevId)){ + /* Do nothing */ + } + else if ((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700) || + ((T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) && + (pDevice->WolSpeed == WOL_SPEED_10MB))) + { + Value32 = T3_PCI_DISABLE_RX_CLOCK | T3_PCI_DISABLE_TX_CLOCK | + T3_PCI_SELECT_ALTERNATE_CLOCK | + T3_PCI_POWER_DOWN_PCI_PLL133; + + REG_WR(pDevice, PciCfg.ClockCtrl, pDevice->ClockCtrl | Value32); + } + /* ASF on 5750 will not run properly on slow core clock */ + else if( !(T3_ASIC_IS_575X_PLUS(pDevice->ChipRevId) && + (pDevice->AsfFlags & ASF_ENABLED) )) + { + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) + { + Value32 = T3_PCI_DISABLE_RX_CLOCK | T3_PCI_DISABLE_TX_CLOCK | + T3_PCI_SELECT_ALTERNATE_CLOCK; + } + else if(T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId) ) + { + Value32 = T3_PCI_625_CORE_CLOCK; + } + else + { + Value32 = T3_PCI_SELECT_ALTERNATE_CLOCK; + } + RAW_REG_WR(pDevice, PciCfg.ClockCtrl, pDevice->ClockCtrl | Value32); + + MM_Wait(40); + + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700 || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) + { + Value32 = T3_PCI_DISABLE_RX_CLOCK | T3_PCI_DISABLE_TX_CLOCK | + T3_PCI_SELECT_ALTERNATE_CLOCK | T3_PCI_44MHZ_CORE_CLOCK; + } + else if(T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId) ) + { + Value32 = T3_PCI_SELECT_ALTERNATE_CLOCK | T3_PCI_625_CORE_CLOCK; + } + else if(!T3_ASIC_5714_FAMILY(pDevice->ChipRevId)) + { + Value32 = T3_PCI_SELECT_ALTERNATE_CLOCK | T3_PCI_44MHZ_CORE_CLOCK; + } + + RAW_REG_WR(pDevice, PciCfg.ClockCtrl, pDevice->ClockCtrl | Value32); + + if (!T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) + { + MM_Wait(40); + + if(T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700 || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) + { + Value32 = T3_PCI_DISABLE_RX_CLOCK | T3_PCI_DISABLE_TX_CLOCK | + T3_PCI_44MHZ_CORE_CLOCK; + } + else + { + Value32 = T3_PCI_44MHZ_CORE_CLOCK; + } + + RAW_REG_WR(pDevice, PciCfg.ClockCtrl, pDevice->ClockCtrl | Value32); + } + } + + MM_Wait(40); + + if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5704) + { + pDevice2 = MM_FindPeerDev(pDevice); + } + if (!(pDevice->Flags & EEPROM_WP_FLAG)) + { + LM_SwitchVaux(pDevice, pDevice2); + } + + LM_WritePostResetSignatures(pDevice, LM_SHUTDOWN_RESET); + + if((T3_CHIP_REV(pDevice->ChipRevId) == T3_CHIP_REV_5750_AX) || + (T3_CHIP_REV(pDevice->ChipRevId) == T3_CHIP_REV_5750_BX)) { + + Value32= REG_RD_OFFSET(pDevice, 0x7d00); + REG_WR_OFFSET(pDevice, 0x7d00,Value32 & ~(BIT_16 | BIT_4 | BIT_2 | BIT_1 | BIT_0)); + + if(!(pDevice->AsfFlags & ASF_ENABLED)) + LM_HaltCpu(pDevice, T3_RX_CPU_ID); + + } + + /* Put the the hardware in low power mode. */ + if (!(pDevice->Flags & DISABLE_D3HOT_FLAG)) + { + MM_WriteConfig32(pDevice, T3_PCI_PM_STATUS_CTRL_REG, PmCtrl); + MM_Wait(200); /* Wait 200us for state transition */ + } + + pDevice->PowerLevel = PowerLevel; + +#else + LM_WritePostResetSignatures(pDevice, LM_SHUTDOWN_RESET); +#endif /* BCM_WOL */ + + return LM_STATUS_SUCCESS; +} /* LM_SetPowerState */ + + +LM_VOID +LM_SwitchVaux(PLM_DEVICE_BLOCK pDevice, PLM_DEVICE_BLOCK pDevice2) +{ + if(T3_ASIC_5714_FAMILY(pDevice->ChipRevId)) + return; + + pDevice->GrcLocalCtrl &= ~(GRC_MISC_LOCAL_CTRL_GPIO_OE0 | + GRC_MISC_LOCAL_CTRL_GPIO_OE1 | + GRC_MISC_LOCAL_CTRL_GPIO_OE2 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT0 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT2); + + /* Switch adapter to auxilliary power if WOL enabled */ + if ((pDevice->WakeUpModeCap != LM_WAKE_UP_MODE_NONE) || + (pDevice->AsfFlags & ASF_ENABLED) || + (pDevice2 && ((pDevice2->WakeUpModeCap != LM_WAKE_UP_MODE_NONE) || + (pDevice2->AsfFlags & ASF_ENABLED)))) + { + if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5700 || + T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5701) + { + /* GPIO0 = 1, GPIO1 = 1, GPIO2 = 0. */ + RAW_REG_WR(pDevice, Grc.LocalCtrl, pDevice->GrcLocalCtrl | + GRC_MISC_LOCAL_CTRL_GPIO_OE0 | + GRC_MISC_LOCAL_CTRL_GPIO_OE1 | + GRC_MISC_LOCAL_CTRL_GPIO_OE2 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT0 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1); + MM_Wait(40); + } + else + { + if (pDevice2 && pDevice2->InitDone) + { + return; + } + + /* On NICs GPIOs are used for vaux. + The transition of GPIO0 from 0-1 causes vaux + to power up. Transition of GPIO1 from 1-0 turns vaux off. + GPIO2 transition from 1-0 enables a non-glitch vaux + transition from one state to another. + On certain designs we should not output GPIO2. + */ + if(pDevice->Flags & GPIO2_DONOT_OUTPUT) + { + /* GPIO0 = 0, GPIO1 = 1. */ + RAW_REG_WR(pDevice, Grc.LocalCtrl, pDevice->GrcLocalCtrl | + GRC_MISC_LOCAL_CTRL_GPIO_OE0 | + GRC_MISC_LOCAL_CTRL_GPIO_OE1 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1); + + MM_Wait(40); + + /* GPIO0 = 1, GPIO1 = 1. */ + RAW_REG_WR(pDevice, Grc.LocalCtrl, pDevice->GrcLocalCtrl | + GRC_MISC_LOCAL_CTRL_GPIO_OE0 | + GRC_MISC_LOCAL_CTRL_GPIO_OE1 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT0 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1); + + MM_Wait(40); + } + else + { + + /* GPIO0 = 0, GPIO1 = 1, GPIO2 = 1. */ + RAW_REG_WR(pDevice, Grc.LocalCtrl, pDevice->GrcLocalCtrl | + GRC_MISC_LOCAL_CTRL_GPIO_OE0 | + GRC_MISC_LOCAL_CTRL_GPIO_OE1 | + GRC_MISC_LOCAL_CTRL_GPIO_OE2 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT2); + + MM_Wait(40); + + /* GPIO0 = 1, GPIO1 = 1, GPIO2 = 1. */ + RAW_REG_WR(pDevice, Grc.LocalCtrl, pDevice->GrcLocalCtrl | + GRC_MISC_LOCAL_CTRL_GPIO_OE0 | + GRC_MISC_LOCAL_CTRL_GPIO_OE1 | + GRC_MISC_LOCAL_CTRL_GPIO_OE2 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT0 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT2); + MM_Wait(40); + + /* GPIO0 = 1, GPIO1 = 1, GPIO2 = 0. */ + RAW_REG_WR(pDevice, Grc.LocalCtrl, pDevice->GrcLocalCtrl | + GRC_MISC_LOCAL_CTRL_GPIO_OE0 | + GRC_MISC_LOCAL_CTRL_GPIO_OE1 | + GRC_MISC_LOCAL_CTRL_GPIO_OE2 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT0 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1); + MM_Wait(40); + } /* GPIO2 OK */ + } /* Not 5700||5701 */ + } /* WOL disabled */ + else + { + if ((T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5700) && + (T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5701)) + { + if (pDevice2 && pDevice2->InitDone) + { + return; + } + + /* GPIO1 = 1 */ + RAW_REG_WR(pDevice, Grc.LocalCtrl, pDevice->GrcLocalCtrl | + GRC_MISC_LOCAL_CTRL_GPIO_OE1 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1); + MM_Wait(40); + + /* GPIO1 = 0 */ + RAW_REG_WR(pDevice, Grc.LocalCtrl, pDevice->GrcLocalCtrl | + GRC_MISC_LOCAL_CTRL_GPIO_OE1); + MM_Wait(40); + + /* GPIO1 = 1 */ + RAW_REG_WR(pDevice, Grc.LocalCtrl, pDevice->GrcLocalCtrl | + GRC_MISC_LOCAL_CTRL_GPIO_OE1 | + GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1); + MM_Wait(40); + } + } +} + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +static LM_UINT32 +GetPhyAdFlowCntrlSettings( + PLM_DEVICE_BLOCK pDevice) +{ + LM_UINT32 Value32; + + Value32 = 0; + + /* Auto negotiation flow control only when autonegotiation is enabled. */ + if(pDevice->DisableAutoNeg == FALSE || + pDevice->RequestedLineSpeed == LM_LINE_SPEED_AUTO) + { + if (T3_ASIC_5714_FAMILY(pDevice->ChipRevId) && + (pDevice->PhyFlags & PHY_IS_FIBER)) { + + /* Please refer to Table 28B-3 of the 802.3ab-1999 spec. */ + if((pDevice->FlowControlCap == LM_FLOW_CONTROL_AUTO_PAUSE) || + ((pDevice->FlowControlCap & LM_FLOW_CONTROL_RECEIVE_PAUSE) && + (pDevice->FlowControlCap & LM_FLOW_CONTROL_TRANSMIT_PAUSE))) + { + Value32 |=PHY_AN_AD_1000XPAUSE; + } + else if(pDevice->FlowControlCap & LM_FLOW_CONTROL_TRANSMIT_PAUSE) + { + Value32 |= PHY_AN_AD_1000XPSE_ASYM; + } + else if(pDevice->FlowControlCap & LM_FLOW_CONTROL_RECEIVE_PAUSE) + { + Value32 |= (PHY_AN_AD_1000XPSE_ASYM | PHY_AN_AD_1000XPAUSE); + } + + }else{ + + /* Please refer to Table 28B-3 of the 802.3ab-1999 spec. */ + if((pDevice->FlowControlCap == LM_FLOW_CONTROL_AUTO_PAUSE) || + ((pDevice->FlowControlCap & LM_FLOW_CONTROL_RECEIVE_PAUSE) && + (pDevice->FlowControlCap & LM_FLOW_CONTROL_TRANSMIT_PAUSE))) + { + Value32 |= PHY_AN_AD_PAUSE_CAPABLE; + } + else if(pDevice->FlowControlCap & LM_FLOW_CONTROL_TRANSMIT_PAUSE) + { + Value32 |= PHY_AN_AD_ASYM_PAUSE; + } + else if(pDevice->FlowControlCap & LM_FLOW_CONTROL_RECEIVE_PAUSE) + { + Value32 |= PHY_AN_AD_PAUSE_CAPABLE | PHY_AN_AD_ASYM_PAUSE; + } + } + } + + return Value32; +} + + + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/* LM_STATUS_FAILURE */ +/* LM_STATUS_SUCCESS */ +/* */ +/******************************************************************************/ +static LM_STATUS +LM_ForceAutoNeg(PLM_DEVICE_BLOCK pDevice) +{ + LM_LINE_SPEED LineSpeed; + LM_DUPLEX_MODE DuplexMode; + LM_UINT32 NewPhyCtrl; + LM_UINT32 Value32, PhyReg18; + LM_UINT32 Cnt; + + /* Get the interface type, line speed, and duplex mode. */ + LineSpeed = pDevice->RequestedLineSpeed; + DuplexMode = pDevice->RequestedDuplexMode; + + /* Exit ext. loop back, in case it was in ext. loopback mode */ + /* Set Extended packet length bit on chips that support jumbo frames */ + if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5401_PHY_ID) + { + LM_WritePhy(pDevice, BCM5401_AUX_CTRL, 0x4c20); + + LM_ReadPhy(pDevice, BCM540X_EXT_CTRL_REG, &Value32); + Value32 |= 1; /* set tx elastic fifo */ + LM_WritePhy(pDevice, BCM540X_EXT_CTRL_REG, Value32); + + } + else + { + LM_WritePhy(pDevice, BCM5401_AUX_CTRL, 0x0007); + LM_ReadPhy(pDevice, BCM5401_AUX_CTRL, &PhyReg18); + PhyReg18 &= ~0x8000; /* clear external loop back */ + + if (pDevice->Flags & JUMBO_CAPABLE_FLAG) + { + PhyReg18 |= 0x4000; /* set extended packet length */ + LM_ReadPhy(pDevice, BCM540X_EXT_CTRL_REG, &Value32); + Value32 |= 1; /* set tx elastic fifo */ + LM_WritePhy(pDevice, BCM540X_EXT_CTRL_REG, Value32); + } + LM_WritePhy(pDevice, BCM5401_AUX_CTRL, PhyReg18); + } + +#ifdef BCM_WOL + if (pDevice->RestoreOnWakeUp) + { + LM_WritePhy(pDevice, BCM540X_1000BASET_CTRL_REG, 0); + pDevice->advertising1000 = 0; + Value32 = PHY_AN_AD_10BASET_FULL | PHY_AN_AD_10BASET_HALF; + if (pDevice->WolSpeed == WOL_SPEED_100MB) + { + Value32 |= PHY_AN_AD_100BASETX_FULL | PHY_AN_AD_100BASETX_HALF; + } + Value32 |= PHY_AN_AD_PROTOCOL_802_3_CSMA_CD; + Value32 |= GetPhyAdFlowCntrlSettings(pDevice); + LM_WritePhy(pDevice, PHY_AN_AD_REG, Value32); + pDevice->advertising = Value32; + } + /* Setup the auto-negotiation advertisement register. */ + else if(LineSpeed == LM_LINE_SPEED_UNKNOWN) +#else + /* Setup the auto-negotiation advertisement register. */ + if(LineSpeed == LM_LINE_SPEED_UNKNOWN) +#endif + { + /* Setup the 10/100 Mbps auto-negotiation advertisement register. */ + Value32 = PHY_AN_AD_PROTOCOL_802_3_CSMA_CD | PHY_AN_AD_ALL_SPEEDS; + Value32 |= GetPhyAdFlowCntrlSettings(pDevice); + + LM_WritePhy(pDevice, PHY_AN_AD_REG, Value32); + pDevice->advertising = Value32; + + /* Advertise 1000Mbps */ + if (!(pDevice->PhyFlags & PHY_NO_GIGABIT)) + { + Value32 = BCM540X_AN_AD_ALL_1G_SPEEDS; + +#ifdef INCLUDE_5701_AX_FIX + /* slave mode. This will force the PHY to operate in */ + /* master mode. */ + if(pDevice->ChipRevId == T3_CHIP_ID_5701_A0 || + pDevice->ChipRevId == T3_CHIP_ID_5701_B0) + { + Value32 |= BCM540X_CONFIG_AS_MASTER | + BCM540X_ENABLE_CONFIG_AS_MASTER; + } +#endif + + LM_WritePhy(pDevice, BCM540X_1000BASET_CTRL_REG, Value32); + pDevice->advertising1000 = Value32; + } + else + { + LM_WritePhy(pDevice, BCM540X_1000BASET_CTRL_REG, 0); + pDevice->advertising1000 = 0; + } + } + else + { + if ((pDevice->PhyFlags & PHY_NO_GIGABIT) && + (LineSpeed == LM_LINE_SPEED_1000MBPS)) + { + LineSpeed = LM_LINE_SPEED_100MBPS; + } + if(LineSpeed == LM_LINE_SPEED_1000MBPS) + { + Value32 = PHY_AN_AD_PROTOCOL_802_3_CSMA_CD; + Value32 |= GetPhyAdFlowCntrlSettings(pDevice); + + LM_WritePhy(pDevice, PHY_AN_AD_REG, Value32); + pDevice->advertising = Value32; + + if(DuplexMode != LM_DUPLEX_MODE_FULL) + { + Value32 = BCM540X_AN_AD_1000BASET_HALF; + } + else + { + Value32 = BCM540X_AN_AD_1000BASET_FULL; + } + +#ifdef INCLUDE_5701_AX_FIX + if ((pDevice->LoopBackMode == LM_EXT_LOOP_BACK_MODE) || + (pDevice->ChipRevId == T3_CHIP_ID_5701_A0 || + pDevice->ChipRevId == T3_CHIP_ID_5701_B0)) +#else + if (pDevice->LoopBackMode == LM_EXT_LOOP_BACK_MODE) +#endif + { + Value32 |= BCM540X_CONFIG_AS_MASTER | + BCM540X_ENABLE_CONFIG_AS_MASTER; + } + LM_WritePhy(pDevice, BCM540X_1000BASET_CTRL_REG, Value32); + pDevice->advertising1000 = Value32; + if (pDevice->LoopBackMode == LM_EXT_LOOP_BACK_MODE) + { + if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5401_PHY_ID) + { + LM_WritePhy(pDevice, BCM5401_AUX_CTRL, 0x8c20); + } + else + { + LM_WritePhy(pDevice, BCM5401_AUX_CTRL, 0x0007); + LM_ReadPhy(pDevice, BCM5401_AUX_CTRL, &PhyReg18); + PhyReg18 |= 0x8000; /* set loop back */ + LM_WritePhy(pDevice, BCM5401_AUX_CTRL, PhyReg18); + } + } + } + else if(LineSpeed == LM_LINE_SPEED_100MBPS) + { + LM_WritePhy(pDevice, BCM540X_1000BASET_CTRL_REG, 0); + pDevice->advertising1000 = 0; + + if(DuplexMode != LM_DUPLEX_MODE_FULL) + { + Value32 = PHY_AN_AD_100BASETX_HALF; + } + else + { + Value32 = PHY_AN_AD_100BASETX_FULL; + } + + Value32 |= PHY_AN_AD_PROTOCOL_802_3_CSMA_CD; + Value32 |= GetPhyAdFlowCntrlSettings(pDevice); + + LM_WritePhy(pDevice, PHY_AN_AD_REG, Value32); + pDevice->advertising = Value32; + } + else if(LineSpeed == LM_LINE_SPEED_10MBPS) + { + LM_WritePhy(pDevice, BCM540X_1000BASET_CTRL_REG, 0); + pDevice->advertising1000 = 0; + + if(DuplexMode != LM_DUPLEX_MODE_FULL) + { + Value32 = PHY_AN_AD_10BASET_HALF; + } + else + { + Value32 = PHY_AN_AD_10BASET_FULL; + } + + Value32 |= PHY_AN_AD_PROTOCOL_802_3_CSMA_CD; + Value32 |= GetPhyAdFlowCntrlSettings(pDevice); + + LM_WritePhy(pDevice, PHY_AN_AD_REG, Value32); + pDevice->advertising = Value32; + } + } + + /* Force line speed if auto-negotiation is disabled. */ + if(pDevice->DisableAutoNeg && LineSpeed != LM_LINE_SPEED_UNKNOWN) + { + /* This code path is executed only when there is link. */ + pDevice->LineSpeed = LineSpeed; + pDevice->DuplexMode = DuplexMode; + + /* Force line seepd. */ + NewPhyCtrl = 0; + switch(LineSpeed) + { + case LM_LINE_SPEED_10MBPS: + NewPhyCtrl |= PHY_CTRL_SPEED_SELECT_10MBPS; + break; + case LM_LINE_SPEED_100MBPS: + NewPhyCtrl |= PHY_CTRL_SPEED_SELECT_100MBPS; + break; + case LM_LINE_SPEED_1000MBPS: + NewPhyCtrl |= PHY_CTRL_SPEED_SELECT_1000MBPS; + break; + default: + NewPhyCtrl |= PHY_CTRL_SPEED_SELECT_1000MBPS; + break; + } + + if(DuplexMode == LM_DUPLEX_MODE_FULL) + { + NewPhyCtrl |= PHY_CTRL_FULL_DUPLEX_MODE; + } + + /* Don't do anything if the PHY_CTRL is already what we wanted. */ + LM_ReadPhy(pDevice, PHY_CTRL_REG, &Value32); + if(Value32 != NewPhyCtrl) + { + /* Temporary bring the link down before forcing line speed. */ + LM_WritePhy(pDevice, PHY_CTRL_REG, PHY_CTRL_LOOPBACK_MODE); + + /* Wait for link to go down. */ + for(Cnt = 0; Cnt < 1500; Cnt++) + { + MM_Wait(10); + + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + LM_ReadPhy(pDevice, PHY_STATUS_REG, &Value32); + + if(!(Value32 & PHY_STATUS_LINK_PASS)) + { + MM_Wait(40); + break; + } + } + + LM_WritePhy(pDevice, PHY_CTRL_REG, NewPhyCtrl); + MM_Wait(40); + } + } + else + { + LM_WritePhy(pDevice, PHY_CTRL_REG, PHY_CTRL_AUTO_NEG_ENABLE | + PHY_CTRL_RESTART_AUTO_NEG); + } + + return LM_STATUS_SUCCESS; +} /* LM_ForceAutoNegBcm540xPhy */ + +/******************************************************************************/ +/* Description: */ +/* */ +/* Return: */ +/******************************************************************************/ +LM_STATUS LM_LoadFirmware(PLM_DEVICE_BLOCK pDevice, + PT3_FWIMG_INFO pFwImg, + LM_UINT32 LoadCpu, + LM_UINT32 StartCpu) +{ + LM_UINT32 i; + LM_UINT32 address; + LM_VOID (*Wr_fn)(PLM_DEVICE_BLOCK pDevice,LM_UINT32 Register,LM_UINT32 Value32); + LM_UINT32 (*Rd_fn)(PLM_DEVICE_BLOCK pDevice,LM_UINT32 Register); + LM_UINT32 len; + LM_UINT32 base_addr; + + /* BCM4785: Avoid all use of firmware. */ + if (pDevice->Flags & SB_CORE_FLAG) + return LM_STATUS_FAILURE; + +#ifdef INCLUDE_TCP_SEG_SUPPORT + if (T3_ASIC_REV(pDevice->ChipRevId) == T3_ASIC_REV_5705) + { + Wr_fn = LM_MemWrInd; + Rd_fn = LM_MemRdInd; + len = LM_GetStkOffLdFirmwareSize(pDevice); + base_addr = T3_NIC_BCM5705_MBUF_POOL_ADDR; + } + else +#endif + { + Wr_fn = LM_RegWrInd; + Rd_fn = LM_RegRdInd; + len = T3_RX_CPU_SPAD_SIZE; + base_addr = T3_RX_CPU_SPAD_ADDR; + } + + if (LoadCpu & T3_RX_CPU_ID) + { + if (LM_HaltCpu(pDevice,T3_RX_CPU_ID) != LM_STATUS_SUCCESS) + { + return LM_STATUS_FAILURE; + } + + /* First of all clear scrach pad memory */ + for (i = 0; i < len; i+=4) + { + Wr_fn(pDevice,base_addr+i,0); + } + + /* Copy code first */ + address = base_addr + (pFwImg->Text.Offset & 0xffff); + for (i = 0; i <= pFwImg->Text.Length; i+=4) + { + Wr_fn(pDevice,address+i, + ((LM_UINT32 *)pFwImg->Text.Buffer)[i/4]); + } + + address = base_addr + (pFwImg->ROnlyData.Offset & 0xffff); + for (i = 0; i <= pFwImg->ROnlyData.Length; i+=4) + { + Wr_fn(pDevice,address+i, + ((LM_UINT32 *)pFwImg->ROnlyData.Buffer)[i/4]); + } + + address = base_addr + (pFwImg->Data.Offset & 0xffff); + for (i= 0; i <= pFwImg->Data.Length; i+=4) + { + Wr_fn(pDevice,address+i, + ((LM_UINT32 *)pFwImg->Data.Buffer)[i/4]); + } + } + + if ((LoadCpu & T3_TX_CPU_ID) && + (T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5705)) + { + if (LM_HaltCpu(pDevice,T3_TX_CPU_ID) != LM_STATUS_SUCCESS) + { + return LM_STATUS_FAILURE; + } + + /* First of all clear scrach pad memory */ + for (i = 0; i < T3_TX_CPU_SPAD_SIZE; i+=4) + { + Wr_fn(pDevice,T3_TX_CPU_SPAD_ADDR+i,0); + } + + /* Copy code first */ + address = T3_TX_CPU_SPAD_ADDR + (pFwImg->Text.Offset & 0xffff); + for (i= 0; i <= pFwImg->Text.Length; i+=4) + { + Wr_fn(pDevice,address+i, + ((LM_UINT32 *)pFwImg->Text.Buffer)[i/4]); + } + + address = T3_TX_CPU_SPAD_ADDR + (pFwImg->ROnlyData.Offset & 0xffff); + for (i= 0; i <= pFwImg->ROnlyData.Length; i+=4) + { + Wr_fn(pDevice,address+i, + ((LM_UINT32 *)pFwImg->ROnlyData.Buffer)[i/4]); + } + + address = T3_TX_CPU_SPAD_ADDR + (pFwImg->Data.Offset & 0xffff); + for (i= 0; i <= pFwImg->Data.Length; i+=4) + { + Wr_fn(pDevice,address+i, + ((LM_UINT32 *)pFwImg->Data.Buffer)[i/4]); + } + } + + if (StartCpu & T3_RX_CPU_ID) + { + /* Start Rx CPU */ + REG_WR(pDevice,rxCpu.reg.state, 0xffffffff); + REG_WR(pDevice,rxCpu.reg.PC,pFwImg->StartAddress); + for (i = 0 ; i < 5; i++) + { + if (pFwImg->StartAddress == REG_RD(pDevice,rxCpu.reg.PC)) + break; + + REG_WR(pDevice,rxCpu.reg.state, 0xffffffff); + REG_WR(pDevice,rxCpu.reg.mode,CPU_MODE_HALT); + REG_WR(pDevice,rxCpu.reg.PC,pFwImg->StartAddress); + REG_RD_BACK(pDevice,rxCpu.reg.PC); + MM_Wait(1000); + } + + REG_WR(pDevice,rxCpu.reg.state, 0xffffffff); + REG_WR(pDevice,rxCpu.reg.mode, 0); + } + + if ((StartCpu & T3_TX_CPU_ID) && + (T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5705)) + { + /* Start Tx CPU */ + REG_WR(pDevice,txCpu.reg.state, 0xffffffff); + REG_WR(pDevice,txCpu.reg.PC,pFwImg->StartAddress); + for (i = 0 ; i < 5; i++) + { + if (pFwImg->StartAddress == REG_RD(pDevice,txCpu.reg.PC)) + break; + + REG_WR(pDevice,txCpu.reg.state, 0xffffffff); + REG_WR(pDevice,txCpu.reg.mode,CPU_MODE_HALT); + REG_WR(pDevice,txCpu.reg.PC,pFwImg->StartAddress); + REG_RD_BACK(pDevice,txCpu.reg.PC); + MM_Wait(1000); + } + + REG_WR(pDevice,txCpu.reg.state, 0xffffffff); + REG_WR(pDevice,txCpu.reg.mode, 0); + } + + return LM_STATUS_SUCCESS; +} + +LM_STATUS LM_HaltCpu(PLM_DEVICE_BLOCK pDevice,LM_UINT32 cpu_number) +{ + LM_UINT32 i; + LM_STATUS status; + + status = LM_STATUS_SUCCESS; + + if (T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId) && + !(cpu_number & T3_RX_CPU_ID)) + { + return status; + } + + if ((T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5700) && + (T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5701)) + { + status = LM_NVRAM_AcquireLock(pDevice); + } + + if (cpu_number & T3_RX_CPU_ID) + { + for (i = 0 ; i < 10000; i++) + { + REG_WR(pDevice,rxCpu.reg.state, 0xffffffff); + REG_WR(pDevice,rxCpu.reg.mode,CPU_MODE_HALT); + + if (REG_RD(pDevice,rxCpu.reg.mode) & CPU_MODE_HALT) + break; + } + + REG_WR(pDevice,rxCpu.reg.state, 0xffffffff); + REG_WR(pDevice,rxCpu.reg.mode,CPU_MODE_HALT); + REG_RD_BACK(pDevice,rxCpu.reg.mode); + MM_Wait(10); + + if (i == 10000) + status = LM_STATUS_FAILURE; + } + + /* + * BCM4785: There is only an Rx CPU for the 5750 derivative in + * the 4785. Don't go any further in this code in order to + * avoid access to the NVRAM arbitration register. + */ + if (pDevice->Flags & SB_CORE_FLAG) + return status; + + if ((pDevice->Flags & T3_HAS_TWO_CPUS) && + (cpu_number & T3_TX_CPU_ID)) + { + for (i = 0 ; i < 10000; i++) + { + REG_WR(pDevice,txCpu.reg.state, 0xffffffff); + REG_WR(pDevice,txCpu.reg.mode,CPU_MODE_HALT); + + if (REG_RD(pDevice,txCpu.reg.mode) & CPU_MODE_HALT) + break; + } + + if (i == 10000) + status = LM_STATUS_FAILURE; + } + + if ((T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5700) && + (T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5701)) + { + if (status != LM_STATUS_SUCCESS) + { + /* + * Some part of this operation failed. + * Just undo our own actions. + */ + LM_NVRAM_ReleaseLock(pDevice); + } + else if (!(pDevice->Flags & T3_HAS_TWO_CPUS) || + cpu_number == (T3_TX_CPU_ID | T3_RX_CPU_ID)) + { + /* + * Release our NVRAM arbitration grant along + * with the firmware's arbitration request bit. + */ + REG_WR(pDevice, Nvram.SwArb, SW_ARB_REQ_CLR1 | SW_ARB_REQ_CLR0); + REG_RD_BACK(pDevice, Nvram.SwArb); + } + else + { + LM_NVRAM_ReleaseLock(pDevice); + + if (LM_NVRAM_AcquireLock(pDevice) == LM_STATUS_SUCCESS) + { + /* All is well. Release the arbitration and continue. */ + LM_NVRAM_ReleaseLock(pDevice); + } + else + { + /* + * We've timed out while attempting to get the + * NVRAM arbitration. Assume the cause is that + * the NVRAM has requested arbitration after we + * acquired arbitration the first time, but before + * the CPU was actually halted. + */ + + /* + * Release our NVRAM arbitration grant along + * with the firmware's arbitration request bit. + */ + REG_WR(pDevice, Nvram.SwArb, SW_ARB_REQ_CLR1 | SW_ARB_REQ_CLR0); + REG_RD_BACK(pDevice, Nvram.SwArb); + } + } + } + + return status; +} + + +LM_STATUS +LM_BlinkLED(PLM_DEVICE_BLOCK pDevice, LM_UINT32 BlinkDurationSec) +{ + int j; + int ret = LM_STATUS_SUCCESS; + + if(BlinkDurationSec == 0) + { + BlinkDurationSec = 1; + } + if(BlinkDurationSec > 120) + { + BlinkDurationSec = 120; + } + + for(j = 0; j < BlinkDurationSec * 2; j++) + { + if(j % 2) + { + // Turn on the LEDs. + REG_WR(pDevice, MacCtrl.LedCtrl, + LED_CTRL_OVERRIDE_LINK_LED | + LED_CTRL_1000MBPS_LED_ON | + LED_CTRL_100MBPS_LED_ON | + LED_CTRL_10MBPS_LED_ON | + LED_CTRL_OVERRIDE_TRAFFIC_LED | + LED_CTRL_BLINK_TRAFFIC_LED | + LED_CTRL_TRAFFIC_LED); + } + else + { + // Turn off the LEDs. + REG_WR(pDevice, MacCtrl.LedCtrl, + LED_CTRL_OVERRIDE_LINK_LED | + LED_CTRL_OVERRIDE_TRAFFIC_LED); + } + if (MM_Sleep(pDevice, 500) != LM_STATUS_SUCCESS)/* 0.5 second */ + { + ret = LM_STATUS_FAILURE; + break; + } + } + REG_WR(pDevice, MacCtrl.LedCtrl, pDevice->LedCtrl); + return ret; +} + +LM_STATUS +LM_SwitchClocks(PLM_DEVICE_BLOCK pDevice) +{ + LM_UINT32 ClockCtrl; + + if(T3_ASIC_5714_FAMILY(pDevice->ChipRevId)) + return LM_STATUS_SUCCESS; + + ClockCtrl = REG_RD(pDevice, PciCfg.ClockCtrl); + pDevice->ClockCtrl = ClockCtrl & (T3_PCI_FORCE_CLKRUN | + T3_PCI_CLKRUN_OUTPUT_EN | 0x1f); + if (T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) + { + if (ClockCtrl & T3_PCI_625_CORE_CLOCK) + { + /* clear ALT clock first */ + RAW_REG_WR(pDevice, PciCfg.ClockCtrl, pDevice->ClockCtrl | + T3_PCI_625_CORE_CLOCK); + MM_Wait(40); /* required delay is 27usec */ + } + } + else + { + if (ClockCtrl & T3_PCI_44MHZ_CORE_CLOCK) + { + RAW_REG_WR(pDevice, PciCfg.ClockCtrl, pDevice->ClockCtrl | + T3_PCI_44MHZ_CORE_CLOCK | T3_PCI_SELECT_ALTERNATE_CLOCK); + MM_Wait(40); /* required delay is 27usec */ + RAW_REG_WR(pDevice, PciCfg.ClockCtrl, pDevice->ClockCtrl | + T3_PCI_SELECT_ALTERNATE_CLOCK); + MM_Wait(40); /* required delay is 27usec */ + } + } + + RAW_REG_WR(pDevice, PciCfg.ClockCtrl, pDevice->ClockCtrl); + MM_Wait(40); /* required delay is 27usec */ + return LM_STATUS_SUCCESS; +} + +int t3_do_dma(PLM_DEVICE_BLOCK pDevice, + LM_PHYSICAL_ADDRESS host_addr_phy, int length, + int dma_read) +{ + T3_DMA_DESC dma_desc; + int i; + LM_UINT32 dma_desc_addr; + LM_UINT32 value32; + + REG_WR(pDevice, BufMgr.Mode, 0); + REG_WR(pDevice, Ftq.Reset, 0); + + dma_desc.host_addr.High = host_addr_phy.High; + dma_desc.host_addr.Low = host_addr_phy.Low; + dma_desc.nic_mbuf = 0x2100; + dma_desc.len = length; + dma_desc.flags = 0x00000005; /* Generate Rx-CPU event */ + + if (dma_read) + { + dma_desc.cqid_sqid = (T3_QID_RX_BD_COMP << 8) | + T3_QID_DMA_HIGH_PRI_READ; + REG_WR(pDevice, DmaRead.Mode, DMA_READ_MODE_ENABLE); + } + else + { + dma_desc.cqid_sqid = (T3_QID_RX_DATA_COMP << 8) | + T3_QID_DMA_HIGH_PRI_WRITE; + REG_WR(pDevice, DmaWrite.Mode, DMA_WRITE_MODE_ENABLE); + } + + dma_desc_addr = T3_NIC_DMA_DESC_POOL_ADDR; + + /* Writing this DMA descriptor to DMA memory */ + for (i = 0; i < sizeof(T3_DMA_DESC); i += 4) + { + value32 = *((PLM_UINT32) (((PLM_UINT8) &dma_desc) + i)); + MM_WriteConfig32(pDevice, T3_PCI_MEM_WIN_ADDR_REG, dma_desc_addr+i); + MM_WriteConfig32(pDevice, T3_PCI_MEM_WIN_DATA_REG, + MM_SWAP_LE32(value32)); + } + MM_WriteConfig32(pDevice, T3_PCI_MEM_WIN_ADDR_REG, 0); + + if (dma_read) + REG_WR(pDevice, Ftq.DmaHighReadFtqFifoEnqueueDequeue, dma_desc_addr); + else + REG_WR(pDevice, Ftq.DmaHighWriteFtqFifoEnqueueDequeue, dma_desc_addr); + + for (i = 0; i < 40; i++) + { + if (dma_read) + value32 = REG_RD(pDevice, Ftq.RcvBdCompFtqFifoEnqueueDequeue); + else + value32 = REG_RD(pDevice, Ftq.RcvDataCompFtqFifoEnqueueDequeue); + + if ((value32 & 0xffff) == dma_desc_addr) + break; + + MM_Wait(10); + } + + return LM_STATUS_SUCCESS; +} + +STATIC LM_STATUS +LM_DmaTest(PLM_DEVICE_BLOCK pDevice, PLM_UINT8 pBufferVirt, + LM_PHYSICAL_ADDRESS BufferPhy, LM_UINT32 BufferSize) +{ + int j; + LM_UINT32 *ptr; + int dma_success = 0; + LM_STATUS ret = LM_STATUS_FAILURE; + + if(T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5700 && + T3_ASIC_REV(pDevice->ChipRevId) != T3_ASIC_REV_5701) + { + return LM_STATUS_SUCCESS; + } + while (!dma_success) + { + /* Fill data with incremental patterns */ + ptr = (LM_UINT32 *)pBufferVirt; + for (j = 0; j < BufferSize/4; j++) + *ptr++ = j; + + if (t3_do_dma(pDevice,BufferPhy,BufferSize, 1) == LM_STATUS_FAILURE) + { + goto LM_DmaTestDone; + } + + MM_Wait(40); + ptr = (LM_UINT32 *)pBufferVirt; + /* Fill data with zero */ + for (j = 0; j < BufferSize/4; j++) + *ptr++ = 0; + + if (t3_do_dma(pDevice,BufferPhy,BufferSize, 0) == LM_STATUS_FAILURE) + { + goto LM_DmaTestDone; + } + + MM_Wait(40); + /* Check for data */ + ptr = (LM_UINT32 *)pBufferVirt; + for (j = 0; j < BufferSize/4; j++) + { + if (*ptr++ != j) + { + if ((pDevice->DmaReadWriteCtrl & DMA_CTRL_WRITE_BOUNDARY_MASK) + != DMA_CTRL_WRITE_BOUNDARY_16) + { + pDevice->DmaReadWriteCtrl = (pDevice->DmaReadWriteCtrl & + ~DMA_CTRL_WRITE_BOUNDARY_MASK) | + DMA_CTRL_WRITE_BOUNDARY_16; + REG_WR(pDevice, PciCfg.DmaReadWriteCtrl, + pDevice->DmaReadWriteCtrl); + break; + } + else + { + goto LM_DmaTestDone; + } + } + } + if (j == (BufferSize/4)) + dma_success = 1; + } + ret = LM_STATUS_SUCCESS; +LM_DmaTestDone: + memset(pBufferVirt, 0, BufferSize); + return ret; +} + +void +LM_Add32To64Counter(LM_UINT32 Counter32, T3_64BIT_REGISTER *Counter64) +{ + Counter64->Low += Counter32; + if (Counter64->Low < Counter32) + { + Counter64->High++; + } +} + +LM_STATUS +LM_GetStats(PLM_DEVICE_BLOCK pDevice) +{ + PT3_STATS_BLOCK pStats = (PT3_STATS_BLOCK) pDevice->pStatsBlkVirt; + + if(!T3_ASIC_IS_5705_BEYOND(pDevice->ChipRevId)) + { + return LM_STATUS_FAILURE; + } + + if (pStats == 0) + { + return LM_STATUS_FAILURE; + } + LM_Add32To64Counter(REG_RD(pDevice, MacCtrl.ifHCOutOctets), + &pStats->ifHCOutOctets); + LM_Add32To64Counter(REG_RD(pDevice, MacCtrl.etherStatsCollisions), + &pStats->etherStatsCollisions); + LM_Add32To64Counter(REG_RD(pDevice, MacCtrl.outXonSent), + &pStats->outXonSent); + LM_Add32To64Counter(REG_RD(pDevice, MacCtrl.outXoffSent), + &pStats->outXoffSent); + LM_Add32To64Counter(REG_RD(pDevice, + MacCtrl.dot3StatsInternalMacTransmitErrors), + &pStats->dot3StatsInternalMacTransmitErrors); + LM_Add32To64Counter(REG_RD(pDevice, MacCtrl.dot3StatsSingleCollisionFrames), + &pStats->dot3StatsSingleCollisionFrames); + LM_Add32To64Counter(REG_RD(pDevice, + MacCtrl.dot3StatsMultipleCollisionFrames), + &pStats->dot3StatsMultipleCollisionFrames); + LM_Add32To64Counter(REG_RD(pDevice, MacCtrl.dot3StatsDeferredTransmissions), + &pStats->dot3StatsDeferredTransmissions); + LM_Add32To64Counter(REG_RD(pDevice, MacCtrl.dot3StatsExcessiveCollisions), + &pStats->dot3StatsExcessiveCollisions); + LM_Add32To64Counter(REG_RD(pDevice, MacCtrl.dot3StatsLateCollisions), + &pStats->dot3StatsLateCollisions); + LM_Add32To64Counter(REG_RD(pDevice, MacCtrl.ifHCOutUcastPkts), + &pStats->ifHCOutUcastPkts); + LM_Add32To64Counter(REG_RD(pDevice, MacCtrl.ifHCOutMulticastPkts), + &pStats->ifHCOutMulticastPkts); + LM_Add32To64Counter(REG_RD(pDevice, MacCtrl.ifHCOutBroadcastPkts), + &pStats->ifHCOutBroadcastPkts); + LM_Add32To64Counter(REG_RD(pDevice, MacCtrl.ifHCInOctets), + &pStats->ifHCInOctets); + LM_Add32To64Counter(REG_RD(pDevice, MacCtrl.etherStatsFragments), + &pStats->etherStatsFragments); + LM_Add32To64Counter(REG_RD(pDevice, MacCtrl.ifHCInUcastPkts), + &pStats->ifHCInUcastPkts); + LM_Add32To64Counter(REG_RD(pDevice, MacCtrl.ifHCInMulticastPkts), + &pStats->ifHCInMulticastPkts); + LM_Add32To64Counter(REG_RD(pDevice, MacCtrl.ifHCInBroadcastPkts), + &pStats->ifHCInBroadcastPkts); + LM_Add32To64Counter(REG_RD(pDevice, MacCtrl.dot3StatsFCSErrors), + &pStats->dot3StatsFCSErrors); + LM_Add32To64Counter(REG_RD(pDevice, MacCtrl.dot3StatsAlignmentErrors), + &pStats->dot3StatsAlignmentErrors); + LM_Add32To64Counter(REG_RD(pDevice, MacCtrl.xonPauseFramesReceived), + &pStats->xonPauseFramesReceived); + LM_Add32To64Counter(REG_RD(pDevice, MacCtrl.xoffPauseFramesReceived), + &pStats->xoffPauseFramesReceived); + LM_Add32To64Counter(REG_RD(pDevice, MacCtrl.macControlFramesReceived), + &pStats->macControlFramesReceived); + LM_Add32To64Counter(REG_RD(pDevice, MacCtrl.xoffStateEntered), + &pStats->xoffStateEntered); + LM_Add32To64Counter(REG_RD(pDevice, MacCtrl.dot3StatsFramesTooLong), + &pStats->dot3StatsFramesTooLong); + LM_Add32To64Counter(REG_RD(pDevice, MacCtrl.etherStatsJabbers), + &pStats->etherStatsJabbers); + LM_Add32To64Counter(REG_RD(pDevice, MacCtrl.etherStatsUndersizePkts), + &pStats->etherStatsUndersizePkts); + + return LM_STATUS_SUCCESS; +} diff --git a/package/broadcom-57xx/src/tigon3.h b/package/broadcom-57xx/src/tigon3.h new file mode 100644 index 0000000000..2860ab16d6 --- /dev/null +++ b/package/broadcom-57xx/src/tigon3.h @@ -0,0 +1,3882 @@ +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 - 2005 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* History: */ +/* */ +/******************************************************************************/ + +#ifndef TIGON3_H +#define TIGON3_H + +#include "lm.h" +#ifdef INCLUDE_TBI_SUPPORT +#include "autoneg.h" +#endif + + + +/******************************************************************************/ +/* Constants. */ +/******************************************************************************/ + +#ifndef TIGON3_DEBUG +#define TIGON3_DEBUG 0 +#endif /* TIGON3_DEBUG */ + +/* Number of entries in the Jumbo Receive RCB. This value must 256 or 0. */ +/* Currently, Jumbo Receive RCB is disabled. */ +#ifndef T3_JUMBO_RCV_RCB_ENTRY_COUNT +#define T3_JUMBO_RCV_RCB_ENTRY_COUNT 0 +#endif /* T3_JUMBO_RCV_RCB_ENTRY_COUNT */ + +#ifndef T3_JUMBO_RCV_ENTRY_COUNT +#define T3_JUMBO_RCV_ENTRY_COUNT 0 +#endif /* T3_JUMBO_RCV_ENTRY_COUNT */ + +#ifndef T3_JUMBO_RCB_ENTRY_COUNT +#define T3_JUMBO_RCB_ENTRY_COUNT 0 +#endif /* T3_JUMBO_RCB_ENTRY_COUNT */ + +/* Maxim number of packet descriptors used for sending packets. */ +#define MAX_TX_PACKET_DESC_COUNT T3_SEND_RCB_ENTRY_COUNT +#define DEFAULT_TX_PACKET_DESC_COUNT 120 + +/* Maximum number of packet descriptors used for receiving packets. */ +#if T3_JUMBO_RCB_ENTRY_COUNT +#define MAX_RX_PACKET_DESC_COUNT \ + (T3_STD_RCV_RCB_ENTRY_COUNT + T3_JUMBO_RCV_RCB_ENTRY_COUNT) +#else +#define MAX_RX_PACKET_DESC_COUNT T3_STD_RCV_RCB_ENTRY_COUNT +#endif +#define DEFAULT_RX_PACKET_DESC_COUNT 200 + +/* Threshhold for double copying small tx packets. 0 will disable double */ +/* copying of small Tx packets. */ +#define DEFAULT_TX_COPY_BUFFER_SIZE 0 +#define MIN_TX_COPY_BUFFER_SIZE 64 +#define MAX_TX_COPY_BUFFER_SIZE 512 + +/* Cache line. */ +#define COMMON_CACHE_LINE_SIZE 0x20 +#define COMMON_CACHE_LINE_MASK (COMMON_CACHE_LINE_SIZE-1) + +/* Maximum number of fragment we can handle. */ +#ifndef MAX_FRAGMENT_COUNT +#define MAX_FRAGMENT_COUNT 32 +#endif + +/* B0 bug. */ +#define BCM5700_BX_MIN_FRAG_SIZE 10 +#define BCM5700_BX_MIN_FRAG_BUF_SIZE 16 /* nice aligned size. */ +#define BCM5700_BX_MIN_FRAG_BUF_SIZE_MASK (BCM5700_BX_MIN_FRAG_BUF_SIZE-1) +#define BCM5700_BX_TX_COPY_BUF_SIZE (BCM5700_BX_MIN_FRAG_BUF_SIZE * \ + MAX_FRAGMENT_COUNT) + +/* MAGIC number. */ +//#define T3_MAGIC_NUM 'KevT' +#define T3_FIRMWARE_MAILBOX 0x0b50 +#define T3_MAGIC_NUM_FIRMWARE_INIT_DONE 0x4B657654 +#define T3_MAGIC_NUM_DISABLE_DMAW_ON_LINK_CHANGE 0x4861764b + +#define T3_NIC_DATA_SIG_ADDR 0x0b54 +#define T3_NIC_DATA_SIG 0x4b657654 + +#define T3_NIC_DATA_NIC_CFG_ADDR 0x0b58 +#define T3_NIC_CFG_LED_MAC_MODE BIT_NONE +#define T3_NIC_CFG_LED_PHY_MODE_1 BIT_2 +#define T3_NIC_CFG_LED_PHY_MODE_2 BIT_3 +#define T3_NIC_CFG_LED_MODE_MASK (BIT_2 | BIT_3) +#define T3_NIC_CFG_PHY_TYPE_UNKNOWN BIT_NONE +#define T3_NIC_CFG_PHY_TYPE_COPPER BIT_4 +#define T3_NIC_CFG_PHY_TYPE_FIBER BIT_5 +#define T3_NIC_CFG_PHY_TYPE_MASK (BIT_4 | BIT_5) +#define T3_NIC_CFG_ENABLE_WOL BIT_6 +#define T3_NIC_CFG_ENABLE_ASF BIT_7 +#define T3_NIC_EEPROM_WP BIT_8 +#define T3_NIC_WOL_LIMIT_10 BIT_10 +#define T3_NIC_MINI_PCI BIT_12 +#define T3_NIC_FIBER_WOL_CAPABLE BIT_14 +#define T3_NIC_BOTH_PORT_100MB_WOL_CAPABLE BIT_15 +#define T3_NIC_GPIO2_NOT_AVAILABLE BIT_20 + +#define T3_NIC_DATA_VER 0x0b5c +#define T3_NIC_DATA_VER_SHIFT 16 + +#define T3_NIC_DATA_PHY_ID_ADDR 0x0b74 +#define T3_NIC_PHY_ID1_MASK 0xffff0000 +#define T3_NIC_PHY_ID2_MASK 0x0000ffff + +#define T3_CMD_MAILBOX 0x0b78 +#define T3_CMD_NICDRV_ALIVE 0x01 +#define T3_CMD_NICDRV_PAUSE_FW 0x02 +#define T3_CMD_NICDRV_IPV4ADDR_CHANGE 0x03 +#define T3_CMD_NICDRV_IPV6ADDR_CHANGE 0x04 +#define T3_CMD_5703A0_FIX_DMAFW_DMAR 0x05 +#define T3_CMD_5703A0_FIX_DMAFW_DMAW 0x06 + +#define T3_CMD_NICDRV_ALIVE2 0x0d + +#define T3_CMD_LENGTH_MAILBOX 0x0b7c +#define T3_CMD_DATA_MAILBOX 0x0b80 + +#define T3_ASF_FW_STATUS_MAILBOX 0x0c00 + +#define T3_DRV_STATE_MAILBOX 0x0c04 +#define T3_DRV_STATE_START 0x01 +#define T3_DRV_STATE_START_DONE 0x80000001 +#define T3_DRV_STATE_UNLOAD 0x02 +#define T3_DRV_STATE_UNLOAD_DONE 0x80000002 +#define T3_DRV_STATE_WOL 0x03 +#define T3_DRV_STATE_SUSPEND 0x04 + +#define T3_FW_RESET_TYPE_MAILBOX 0x0c08 + +#define T3_MAC_ADDR_HIGH_MAILBOX 0x0c14 +#define T3_MAC_ADDR_LOW_MAILBOX 0x0c18 + +#define DRV_WOL_MAILBOX 0xd30 +#define DRV_WOL_SIGNATURE 0x474c0000 + +#define DRV_DOWN_STATE_SHUTDOWN 0x1 + +#define DRV_WOL_SET_MAGIC_PKT BIT_2 + +#define T3_NIC_DATA_NIC_CFG_ADDR2 0x0d38 /* bit 2-3 are same as in */ + /* 0xb58 */ +#define T3_SHASTA_EXT_LED_MODE_MASK (BIT_15 | BIT_16) +#define T3_SHASTA_EXT_LED_LEGACY_MODE BIT_NONE +#define T3_SHASTA_EXT_LED_SHARED_TRAFFIC_LINK_MODE BIT_15 +#define T3_SHASTA_EXT_LED_MAC_MODE BIT_16 +#define T3_SHASTA_EXT_LED_WIRELESS_COMBO_MODE (BIT_15 | BIT_16) +#define T3_NIC_CFG_CAPACITIVE_COUPLING BIT_17 +#define T3_NIC_CFG_PRESERVE_PREEMPHASIS BIT_18 + +/******************************************************************************/ +/* Hardware constants. */ +/******************************************************************************/ + +/* Number of entries in the send ring: must be 512. */ +#define T3_SEND_RCB_ENTRY_COUNT 512 +#define T3_SEND_RCB_ENTRY_COUNT_MASK (T3_SEND_RCB_ENTRY_COUNT-1) + +/* Number of send RCBs. May be 1-16 but for now, only support one. */ +#define T3_MAX_SEND_RCB_COUNT 16 + +/* Number of entries in the Standard Receive RCB. Must be 512 entries. */ +#define T3_STD_RCV_RCB_ENTRY_COUNT 512 +#define T3_STD_RCV_RCB_ENTRY_COUNT_MASK (T3_STD_RCV_RCB_ENTRY_COUNT-1) +#define DEFAULT_STD_RCV_DESC_COUNT 200 /* Must be < 512. */ +#define MAX_STD_RCV_BUFFER_SIZE 0x600 + +/* Number of entries in the Mini Receive RCB. This value can either be */ +/* 0, 1024. Currently Mini Receive RCB is disabled. */ +#ifndef T3_MINI_RCV_RCB_ENTRY_COUNT +#define T3_MINI_RCV_RCB_ENTRY_COUNT 0 +#endif /* T3_MINI_RCV_RCB_ENTRY_COUNT */ +#define T3_MINI_RCV_RCB_ENTRY_COUNT_MASK (T3_MINI_RCV_RCB_ENTRY_COUNT-1) +#define MAX_MINI_RCV_BUFFER_SIZE 512 +#define DEFAULT_MINI_RCV_BUFFER_SIZE 64 +#define DEFAULT_MINI_RCV_DESC_COUNT 100 /* Must be < 1024. */ + +#define T3_JUMBO_RCV_RCB_ENTRY_COUNT_MASK (T3_JUMBO_RCV_RCB_ENTRY_COUNT-1) + +#define MAX_JUMBO_RCV_BUFFER_SIZE (10 * 1024) /* > 1514 */ +#define DEFAULT_JUMBO_RCV_BUFFER_SIZE (4 * 1024) /* > 1514 */ +#define DEFAULT_JUMBO_RCV_DESC_COUNT 128 /* Must be < 256. */ + +#define MAX_JUMBO_TX_BUFFER_SIZE (8 * 1024) /* > 1514 */ +#define DEFAULT_JUMBO_TX_BUFFER_SIZE (4 * 1024) /* > 1514 */ + +/* Number of receive return RCBs. Maybe 1-16 but for now, only support one. */ +#define T3_MAX_RCV_RETURN_RCB_COUNT 16 + +/* Number of entries in a Receive Return ring. This value is either 1024 */ +/* or 2048. */ +#ifndef T3_RCV_RETURN_RCB_ENTRY_COUNT +#define T3_RCV_RETURN_RCB_ENTRY_COUNT 1024 +#endif /* T3_RCV_RETURN_RCB_ENTRY_COUNT */ +#define T3_RCV_RETURN_RCB_ENTRY_COUNT_MASK (T3_RCV_RETURN_RCB_ENTRY_COUNT-1) + + +/* Default coalescing parameters. */ +#ifdef BCM_NAPI_RXPOLL +#define DEFAULT_RX_COALESCING_TICKS 18 +#define DEFAULT_RX_MAX_COALESCED_FRAMES 6 +#else +#define DEFAULT_RX_COALESCING_TICKS 60 +#define DEFAULT_RX_MAX_COALESCED_FRAMES 15 +#endif + +#define DEFAULT_TX_COALESCING_TICKS 200 +#define DEFAULT_TX_MAX_COALESCED_FRAMES 35 + +#define MAX_RX_COALESCING_TICKS 500 +#define MAX_TX_COALESCING_TICKS 500 +#define MAX_RX_MAX_COALESCED_FRAMES 100 +#define MAX_TX_MAX_COALESCED_FRAMES 100 + +#define ADAPTIVE_LO_RX_MAX_COALESCED_FRAMES 5 +#define ADAPTIVE_HI_RX_MAX_COALESCED_FRAMES 48 +#define ADAPTIVE_LO_RX_COALESCING_TICKS 25 +#define ADAPTIVE_HI_RX_COALESCING_TICKS 120 +#define ADAPTIVE_LO_PKT_THRESH 52000 +#define ADAPTIVE_HI_PKT_THRESH 112000 +#define ADAPTIVE_LO_TX_MAX_COALESCED_FRAMES 20 +#define ADAPTIVE_HI_TX_MAX_COALESCED_FRAMES 75 + +#ifdef BCM_NAPI_RXPOLL +#define DEFAULT_RX_COALESCING_TICKS_DURING_INT 18 +#define DEFAULT_RX_MAX_COALESCED_FRAMES_DURING_INT 6 +#else +#define DEFAULT_RX_COALESCING_TICKS_DURING_INT 25 +#define DEFAULT_RX_MAX_COALESCED_FRAMES_DURING_INT 2 +#endif +#define DEFAULT_TX_COALESCING_TICKS_DURING_INT 25 +#define ADAPTIVE_LO_RX_MAX_COALESCED_FRAMES_DURING_INT 1 +#define ADAPTIVE_HI_RX_MAX_COALESCED_FRAMES_DURING_INT 5 +#define DEFAULT_TX_MAX_COALESCED_FRAMES_DURING_INT 5 + +#define BAD_DEFAULT_VALUE 0xffffffff + +#define DEFAULT_STATS_COALESCING_TICKS 1000000 +#define MIN_STATS_COALESCING_TICKS 100 +#define MAX_STATS_COALESCING_TICKS 3600000000U + + +/* Receive BD Replenish thresholds. */ +#define DEFAULT_RCV_STD_BD_REPLENISH_THRESHOLD 4 +#define DEFAULT_RCV_JUMBO_BD_REPLENISH_THRESHOLD 4 + +/* Maximum physical fragment size. */ +#define MAX_FRAGMENT_SIZE (64 * 1024) + + +/* Standard view. */ +#define T3_STD_VIEW_SIZE (64 * 1024) +#define T3_FLAT_VIEW_SIZE (32 * 1024 * 1024) + + +/* Buffer descriptor base address on the NIC's memory. */ + +#define T3_NIC_SND_BUFFER_DESC_ADDR 0x4000 +#define T3_NIC_STD_RCV_BUFFER_DESC_ADDR 0x6000 +#define T3_NIC_JUMBO_RCV_BUFFER_DESC_ADDR 0x7000 + +#define T3_NIC_STD_RCV_BUFFER_DESC_ADDR_EXT_MEM 0xc000 +#define T3_NIC_JUMBO_RCV_BUFFER_DESC_ADDR_EXT_MEM 0xd000 +#define T3_NIC_MINI_RCV_BUFFER_DESC_ADDR_EXT_MEM 0xe000 + +#define T3_NIC_SND_BUFFER_DESC_SIZE (T3_SEND_RCB_ENTRY_COUNT * \ + sizeof(T3_SND_BD) / 4) + +#define T3_NIC_STD_RCV_BUFFER_DESC_SIZE (T3_STD_RCV_RCB_ENTRY_COUNT * \ + sizeof(T3_RCV_BD) / 4) + +#define T3_NIC_JUMBO_RCV_BUFFER_DESC_SIZE (T3_JUMBO_RCV_RCB_ENTRY_COUNT * \ + sizeof(T3_EXT_RCV_BD) / 4) + + +/* MBUF pool. */ +#define T3_NIC_MBUF_POOL_ADDR 0x8000 +#define T3_NIC_MBUF_POOL_SIZE32 0x8000 +#define T3_NIC_MBUF_POOL_SIZE96 0x18000 +#define T3_NIC_MBUF_POOL_SIZE64 0x10000 + +#define T3_NIC_MBUF_POOL_ADDR_EXT_MEM 0x20000 + +#define T3_NIC_BCM5705_MBUF_POOL_ADDR 0x10000 +#define T3_NIC_BCM5705_MBUF_POOL_SIZE 0xe000 + +/* DMA descriptor pool */ +#define T3_NIC_DMA_DESC_POOL_ADDR 0x2000 +#define T3_NIC_DMA_DESC_POOL_SIZE 0x2000 /* 8KB. */ + +#define T3_DEF_DMA_MBUF_LOW_WMARK 0x50 +#define T3_DEF_RX_MAC_MBUF_LOW_WMARK 0x20 +#define T3_DEF_MBUF_HIGH_WMARK 0x60 + +#define T3_DEF_DMA_MBUF_LOW_WMARK_5705 0x0 +#define T3_DEF_RX_MAC_MBUF_LOW_WMARK_5705 0x10 +#define T3_DEF_MBUF_HIGH_WMARK_5705 0x60 + +#define T3_DEF_DMA_MBUF_LOW_WMARK_JUMBO 304 +#define T3_DEF_RX_MAC_MBUF_LOW_WMARK_JUMBO 152 +#define T3_DEF_MBUF_HIGH_WMARK_JUMBO 380 + +#define T3_DEF_DMA_DESC_LOW_WMARK 5 +#define T3_DEF_DMA_DESC_HIGH_WMARK 10 + +/* Maximum size of giant TCP packet can be sent */ +#define T3_TCP_SEG_MAX_OFFLOAD_SIZE 64*1000 +#define T3_TCP_SEG_MIN_NUM_SEG 20 + +#define T3_RX_CPU_ID 0x1 +#define T3_TX_CPU_ID 0x2 +#define T3_RX_CPU_SPAD_ADDR 0x30000 +#define T3_RX_CPU_SPAD_SIZE 0x4000 +#define T3_TX_CPU_SPAD_ADDR 0x34000 +#define T3_TX_CPU_SPAD_SIZE 0x4000 + +typedef struct T3_DIR_ENTRY +{ + PLM_UINT8 Buffer; + LM_UINT32 Offset; + LM_UINT32 Length; +} T3_DIR_ENTRY,*PT3_DIR_ENTRY; + +typedef struct T3_FWIMG_INFO +{ + LM_UINT32 StartAddress; + T3_DIR_ENTRY Text; + T3_DIR_ENTRY ROnlyData; + T3_DIR_ENTRY Data; + T3_DIR_ENTRY Sbss; + T3_DIR_ENTRY Bss; +} T3_FWIMG_INFO, *PT3_FWIMG_INFO; + + + +/******************************************************************************/ +/* Tigon3 PCI Registers. */ +/******************************************************************************/ +/* MSI ENABLE bit is located at this offset */ +#define T3_PCI_MSI_ENABLE 0x58 + +#define T3_PCI_ID_BCM5700 0x164414e4 +#define T3_PCI_ID_BCM5701 0x164514e4 +#define T3_PCI_ID_BCM5702 0x164614e4 +#define T3_PCI_ID_BCM5702x 0x16A614e4 +#define T3_PCI_ID_BCM5703 0x164714e4 +#define T3_PCI_ID_BCM5703x 0x16A714e4 +#define T3_PCI_ID_BCM5702FE 0x164D14e4 +#define T3_PCI_ID_BCM5704 0x164814e4 +#define T3_PCI_ID_BCM5705 0x165314e4 +#define T3_PCI_ID_BCM5705M 0x165D14e4 +#define T3_PCI_ID_BCM5705F 0x166E14e4 +#define T3_PCI_ID_BCM5901 0x170D14e4 +#define T3_PCI_ID_BCM5901A2 0x170E14e4 +#define T3_PCI_ID_BCM5751F 0x167E14e4 + +#define T3_PCI_ID_BCM471F 0x471f14e4 + +#define T3_PCI_ID_BCM5753 0x16f714e4 +#define T3_PCI_ID_BCM5753M 0x16fd14e4 +#define T3_PCI_ID_BCM5753F 0x16fe14e4 +#define T3_PCI_ID_BCM5781 0x16dd14e4 + +#define T3_PCI_ID_BCM5903M 0x16ff14e4 + +#define T3_PCI_VENDOR_ID(x) ((x) & 0xffff) +#define T3_PCI_DEVICE_ID(x) ((x) >> 16) + +#define T3_PCI_MISC_HOST_CTRL_REG 0x68 + +/* The most significant 16bit of register 0x68. */ +/* ChipId:4, ChipRev:4, MetalRev:8 */ +#define T3_CHIP_ID_5700_A0 0x7000 +#define T3_CHIP_ID_5700_A1 0x7001 +#define T3_CHIP_ID_5700_B0 0x7100 +#define T3_CHIP_ID_5700_B1 0x7101 +#define T3_CHIP_ID_5700_C0 0x7200 + +#define T3_CHIP_ID_5701_A0 0x0000 +#define T3_CHIP_ID_5701_B0 0x0100 +#define T3_CHIP_ID_5701_B2 0x0102 +#define T3_CHIP_ID_5701_B5 0x0105 + +#define T3_CHIP_ID_5703_A0 0x1000 +#define T3_CHIP_ID_5703_A1 0x1001 +#define T3_CHIP_ID_5703_A2 0x1002 +#define T3_CHIP_ID_5703_A3 0x1003 + +#define T3_CHIP_ID_5704_A0 0x2000 +#define T3_CHIP_ID_5704_A1 0x2001 +#define T3_CHIP_ID_5704_A2 0x2002 + +#define T3_CHIP_ID_5705_A0 0x3000 +#define T3_CHIP_ID_5705_A1 0x3001 +#define T3_CHIP_ID_5705_A2 0x3002 +#define T3_CHIP_ID_5705_A3 0x3003 + +#define T3_CHIP_ID_5750_A0 0x4000 +#define T3_CHIP_ID_5750_A1 0x4001 +#define T3_CHIP_ID_5750_A3 0x4003 +#define T3_CHIP_ID_5750_B0 0x4010 +#define T3_CHIP_ID_5750_C0 0x4200 + +#define T3_CHIP_ID_5714_A0 0x5000 +#define T3_CHIP_ID_5752_A0 0x6000 +#define T3_CHIP_ID_5714 0x8000 + + +/* Chip Id. */ +#define T3_ASIC_REV(_ChipRevId) ((_ChipRevId) >> 12) +#define T3_ASIC_REV_5700 0x07 +#define T3_ASIC_REV_5701 0x00 +#define T3_ASIC_REV_5703 0x01 +#define T3_ASIC_REV_5704 0x02 +#define T3_ASIC_REV_5705 0x03 +#define T3_ASIC_REV_5750 0x04 +#define T3_ASIC_REV_5714_A0 0x05 /*5714,5715*/ +#define T3_ASIC_REV_5752 0x06 +#define T3_ASIC_REV_5780 0x08 /* 5780 previously htle */ +#define T3_ASIC_REV_5714 0x09 /*5714,5715*/ + +#define T3_ASIC_IS_5705_BEYOND(_ChipRevId) \ + ((T3_ASIC_REV(_ChipRevId) == T3_ASIC_REV_5705) || \ + (T3_ASIC_REV(_ChipRevId) == T3_ASIC_REV_5750) || \ + (T3_ASIC_REV(_ChipRevId) == T3_ASIC_REV_5714_A0) || \ + (T3_ASIC_REV(_ChipRevId) == T3_ASIC_REV_5780) || \ + (T3_ASIC_REV(_ChipRevId) == T3_ASIC_REV_5714) || \ + (T3_ASIC_REV(_ChipRevId) == T3_ASIC_REV_5752)) + +#define T3_ASIC_IS_575X_PLUS(_ChipRevId) \ + ((T3_ASIC_REV(_ChipRevId) == T3_ASIC_REV_5750) || \ + (T3_ASIC_REV(_ChipRevId) == T3_ASIC_REV_5714_A0) || \ + (T3_ASIC_REV(_ChipRevId) == T3_ASIC_REV_5780) || \ + (T3_ASIC_REV(_ChipRevId) == T3_ASIC_REV_5714) || \ + (T3_ASIC_REV(_ChipRevId) == T3_ASIC_REV_5752)) + +#define T3_ASIC_5714_FAMILY(_ChipRevId) \ + ((T3_ASIC_REV(_ChipRevId) == T3_ASIC_REV_5714_A0) || \ + (T3_ASIC_REV(_ChipRevId) == T3_ASIC_REV_5780) || \ + (T3_ASIC_REV(_ChipRevId) == T3_ASIC_REV_5714)) + +#define T3_ASIC_IS_JUMBO_CAPABLE(_ChipRevId) \ + ((T3_ASIC_REV(_ChipRevId) == T3_ASIC_REV_5700) || \ + (T3_ASIC_REV(_ChipRevId) == T3_ASIC_REV_5701) || \ + (T3_ASIC_REV(_ChipRevId) == T3_ASIC_REV_5703) || \ + (T3_ASIC_REV(_ChipRevId) == T3_ASIC_REV_5714_A0) || \ + (T3_ASIC_REV(_ChipRevId) == T3_ASIC_REV_5780) || \ + (T3_ASIC_REV(_ChipRevId) == T3_ASIC_REV_5714) || \ + (T3_ASIC_REV(_ChipRevId) == T3_ASIC_REV_5704)) + +#define T3_ASIC_5752(_ChipRevId) \ + (T3_ASIC_REV(_ChipRevId) == T3_ASIC_REV_5752) + +#define T3_ASIC_5705_OR_5750(_ChipRevId) \ + ((T3_ASIC_REV(_ChipRevId) == T3_ASIC_REV_5705) || \ + (T3_ASIC_REV(_ChipRevId) == T3_ASIC_REV_5750)) + +/* Chip id and revision. */ +#define T3_CHIP_REV(_ChipRevId) ((_ChipRevId) >> 8) +#define T3_CHIP_REV_5700_AX 0x70 +#define T3_CHIP_REV_5700_BX 0x71 +#define T3_CHIP_REV_5700_CX 0x72 +#define T3_CHIP_REV_5701_AX 0x00 +#define T3_CHIP_REV_5703_AX 0x10 +#define T3_CHIP_REV_5704_AX 0x20 +#define T3_CHIP_REV_5704_BX 0x21 + +#define T3_CHIP_REV_5750_AX 0x40 +#define T3_CHIP_REV_5750_BX 0x41 + +/* Metal revision. */ +#define T3_METAL_REV(_ChipRevId) ((_ChipRevId) & 0xff) +#define T3_METAL_REV_A0 0x00 +#define T3_METAL_REV_A1 0x01 +#define T3_METAL_REV_B0 0x00 +#define T3_METAL_REV_B1 0x01 +#define T3_METAL_REV_B2 0x02 + +#define T3_PCI_REG_CLOCK_CTRL 0x74 + +#define T3_PCI_DISABLE_RX_CLOCK BIT_10 +#define T3_PCI_DISABLE_TX_CLOCK BIT_11 +#define T3_PCI_SELECT_ALTERNATE_CLOCK BIT_12 +#define T3_PCI_POWER_DOWN_PCI_PLL133 BIT_15 +#define T3_PCI_44MHZ_CORE_CLOCK BIT_18 +#define T3_PCI_625_CORE_CLOCK BIT_20 +#define T3_PCI_FORCE_CLKRUN BIT_21 +#define T3_PCI_CLKRUN_OUTPUT_EN BIT_22 + + +#define T3_PCI_REG_ADDR_REG 0x78 +#define T3_PCI_REG_DATA_REG 0x80 + +#define T3_PCI_MEM_WIN_ADDR_REG 0x7c +#define T3_PCI_MEM_WIN_DATA_REG 0x84 + +#define T3_PCI_PM_CAP_REG 0x48 + +#define T3_PCI_PM_CAP_PME_D3COLD BIT_31 +#define T3_PCI_PM_CAP_PME_D3HOT BIT_30 + +#define T3_PCI_PM_STATUS_CTRL_REG 0x4c + +#define T3_PM_POWER_STATE_MASK (BIT_0 | BIT_1) +#define T3_PM_POWER_STATE_D0 BIT_NONE +#define T3_PM_POWER_STATE_D1 BIT_0 +#define T3_PM_POWER_STATE_D2 BIT_1 +#define T3_PM_POWER_STATE_D3 (BIT_0 | BIT_1) + +#define T3_PM_PME_ENABLE BIT_8 +#define T3_PM_PME_ASSERTED BIT_15 + +#define T3_MSI_CAPABILITY_ID_REG 0x58 +#define T3_MSI_NEXT_CAPABILITY_PTR 0x59 + +/* PCI state register. */ +#define T3_PCI_STATE_REG 0x70 + +#define T3_PCI_STATE_FORCE_RESET BIT_0 +#define T3_PCI_STATE_INT_NOT_ACTIVE BIT_1 +#define T3_PCI_STATE_CONVENTIONAL_PCI_MODE BIT_2 +#define T3_PCI_STATE_BUS_SPEED_HIGH BIT_3 +#define T3_PCI_STATE_32BIT_PCI_BUS BIT_4 + + +/* Broadcom subsystem/subvendor IDs. */ +#define T3_SVID_BROADCOM 0x14e4 + +#define T3_SSID_BROADCOM_BCM95700A6 0x1644 +#define T3_SSID_BROADCOM_BCM95701A5 0x0001 +#define T3_SSID_BROADCOM_BCM95700T6 0x0002 /* BCM8002 */ +#define T3_SSID_BROADCOM_BCM95700A9 0x0003 /* Agilent */ +#define T3_SSID_BROADCOM_BCM95701T1 0x0005 +#define T3_SSID_BROADCOM_BCM95701T8 0x0006 +#define T3_SSID_BROADCOM_BCM95701A7 0x0007 /* Agilent */ +#define T3_SSID_BROADCOM_BCM95701A10 0x0008 +#define T3_SSID_BROADCOM_BCM95701A12 0x8008 +#define T3_SSID_BROADCOM_BCM95703Ax1 0x0009 +#define T3_SSID_BROADCOM_BCM95703Ax2 0x8009 + +/* 3COM subsystem/subvendor IDs. */ +#define T3_SVID_3COM 0x10b7 + +#define T3_SSID_3COM_3C996T 0x1000 +#define T3_SSID_3COM_3C996BT 0x1006 +#define T3_SSID_3COM_3C996CT 0x1002 +#define T3_SSID_3COM_3C997T 0x1003 +#define T3_SSID_3COM_3C1000T 0x1007 +#define T3_SSID_3COM_3C940BR01 0x1008 + +/* Fiber boards. */ +#define T3_SSID_3COM_3C996SX 0x1004 +#define T3_SSID_3COM_3C997SX 0x1005 + + +/* Dell subsystem/subvendor IDs. */ + +#define T3_SVID_DELL 0x1028 + +#define T3_SSID_DELL_VIPER 0x00d1 +#define T3_SSID_DELL_JAGUAR 0x0106 +#define T3_SSID_DELL_MERLOT 0x0109 +#define T3_SSID_DELL_SLIM_MERLOT 0x010a + +/* Compaq subsystem/subvendor IDs */ + +#define T3_SVID_COMPAQ 0x0e11 + +#define T3_SSID_COMPAQ_BANSHEE 0x007c +#define T3_SSID_COMPAQ_BANSHEE_2 0x009a +#define T3_SSID_COMPAQ_CHANGELING 0x007d +#define T3_SSID_COMPAQ_NC7780 0x0085 +#define T3_SSID_COMPAQ_NC7780_2 0x0099 + +#define T3_PCIE_CAPABILITY_ID_REG 0xD0 +#define T3_PCIE_CAPABILITY_ID 0x10 + +#define T3_PCIE_CAPABILITY_REG 0xD2 + +/******************************************************************************/ +/* MII registers. */ +/******************************************************************************/ + +/* Control register. */ +#define PHY_CTRL_REG 0x00 + +#define PHY_CTRL_SPEED_MASK (BIT_6 | BIT_13) +#define PHY_CTRL_SPEED_SELECT_10MBPS BIT_NONE +#define PHY_CTRL_SPEED_SELECT_100MBPS BIT_13 +#define PHY_CTRL_SPEED_SELECT_1000MBPS BIT_6 +#define PHY_CTRL_COLLISION_TEST_ENABLE BIT_7 +#define PHY_CTRL_FULL_DUPLEX_MODE BIT_8 +#define PHY_CTRL_RESTART_AUTO_NEG BIT_9 +#define PHY_CTRL_ISOLATE_PHY BIT_10 +#define PHY_CTRL_LOWER_POWER_MODE BIT_11 +#define PHY_CTRL_AUTO_NEG_ENABLE BIT_12 +#define PHY_CTRL_LOOPBACK_MODE BIT_14 +#define PHY_CTRL_PHY_RESET BIT_15 + + +/* Status register. */ +#define PHY_STATUS_REG 0x01 + +#define PHY_STATUS_LINK_PASS BIT_2 +#define PHY_STATUS_AUTO_NEG_COMPLETE BIT_5 + + +/* Phy Id registers. */ +#define PHY_ID1_REG 0x02 +#define PHY_ID1_OUI_MASK 0xffff + +#define PHY_ID2_REG 0x03 +#define PHY_ID2_REV_MASK 0x000f +#define PHY_ID2_MODEL_MASK 0x03f0 +#define PHY_ID2_OUI_MASK 0xfc00 + + +/* Auto-negotiation advertisement register. */ +#define PHY_AN_AD_REG 0x04 + +#define PHY_AN_AD_ASYM_PAUSE BIT_11 +#define PHY_AN_AD_PAUSE_CAPABLE BIT_10 +#define PHY_AN_AD_10BASET_HALF BIT_5 +#define PHY_AN_AD_10BASET_FULL BIT_6 +#define PHY_AN_AD_100BASETX_HALF BIT_7 +#define PHY_AN_AD_100BASETX_FULL BIT_8 +#define PHY_AN_AD_PROTOCOL_802_3_CSMA_CD 0x01 + +/* Defines for 5714 family fiber on the 546x phy*/ + +#define PHY_AN_AD_1000XFULL 0x20 +#define PHY_AN_AD_1000XHALF 0x40 +#define PHY_AN_AD_1000XPAUSE 0x80 +#define PHY_AN_AD_1000XPSE_ASYM 0x100 +#define PHY_AN_AD_1000XREM_FAULT_OFFLINE 0x2000 +#define PHY_AN_AD_1000XREM_FAULT_AN_ERROR 0x3000 + +#define PHY_AN_AD_ALL_SPEEDS (PHY_AN_AD_10BASET_HALF | PHY_AN_AD_10BASET_FULL |\ + PHY_AN_AD_100BASETX_HALF | PHY_AN_AD_100BASETX_FULL) + +/* Auto-negotiation Link Partner Ability register. */ +#define PHY_LINK_PARTNER_ABILITY_REG 0x05 + +#define PHY_LINK_PARTNER_ASYM_PAUSE BIT_11 +#define PHY_LINK_PARTNER_PAUSE_CAPABLE BIT_10 + + +/* Auto-negotiation expansion register. */ +#define PHY_AN_EXPANSION_REG 0x06 + + + +/******************************************************************************/ +/* BCM5400 and BCM5401 phy info. */ +/******************************************************************************/ + +#define PHY_DEVICE_ID 1 + +/* OUI: bit 31-10; Model#: bit 9-4; Rev# bit 3-0. */ +#define PHY_UNKNOWN_PHY 0x00000000 +#define PHY_BCM5400_PHY_ID 0x60008040 +#define PHY_BCM5401_PHY_ID 0x60008050 +#define PHY_BCM5411_PHY_ID 0x60008070 +#define PHY_BCM5461_PHY_ID 0x600080c0 +#define PHY_BCM5701_PHY_ID 0x60008110 +#define PHY_BCM5703_PHY_ID 0x60008160 +#define PHY_BCM5704_PHY_ID 0x60008190 +#define PHY_BCM5705_PHY_ID 0x600081a0 +#define PHY_BCM5750_PHY_ID 0x60008180 +#define PHY_BCM8002_PHY_ID 0x60010140 +#define PHY_BCM5714_PHY_ID 0x60008340 +#define PHY_BCM5780_PHY_ID 0x60008350 +#define PHY_BCM5752_PHY_ID 0x60008100 + +#define PHY_BCM5401_B0_REV 0x1 +#define PHY_BCM5401_B2_REV 0x3 +#define PHY_BCM5401_C0_REV 0x6 + +#define PHY_ID_OUI_MASK 0xfffffc00 +#define PHY_ID_MODEL_MASK 0x000003f0 +#define PHY_ID_REV_MASK 0x0000000f +#define PHY_ID_MASK (PHY_ID_OUI_MASK | \ + PHY_ID_MODEL_MASK) + +#define UNKNOWN_PHY_ID(x) ((((x) & PHY_ID_MASK) != PHY_BCM5400_PHY_ID) && \ + (((x) & PHY_ID_MASK) != PHY_BCM5401_PHY_ID) && \ + (((x) & PHY_ID_MASK) != PHY_BCM5411_PHY_ID) && \ + (((x) & PHY_ID_MASK) != PHY_BCM5701_PHY_ID) && \ + (((x) & PHY_ID_MASK) != PHY_BCM5703_PHY_ID) && \ + (((x) & PHY_ID_MASK) != PHY_BCM5704_PHY_ID) && \ + (((x) & PHY_ID_MASK) != PHY_BCM5705_PHY_ID) && \ + (((x) & PHY_ID_MASK) != PHY_BCM5750_PHY_ID) && \ + (((x) & PHY_ID_MASK) != PHY_BCM8002_PHY_ID) && \ + (((x) & PHY_ID_MASK) != PHY_BCM5714_PHY_ID) && \ + (((x) & PHY_ID_MASK) != PHY_BCM5780_PHY_ID) && \ + (((x) & PHY_ID_MASK) != PHY_BCM5752_PHY_ID) && \ + (((x) & PHY_ID_MASK) != PHY_BCM5461_PHY_ID)) + +/* 1000Base-T control register. */ +#define BCM540X_1000BASET_CTRL_REG 0x09 + +#define BCM540X_AN_AD_1000BASET_HALF BIT_8 +#define BCM540X_AN_AD_1000BASET_FULL BIT_9 +#define BCM540X_CONFIG_AS_MASTER BIT_11 +#define BCM540X_ENABLE_CONFIG_AS_MASTER BIT_12 + +#define BCM540X_AN_AD_ALL_1G_SPEEDS (BCM540X_AN_AD_1000BASET_HALF | \ + BCM540X_AN_AD_1000BASET_FULL) + +/* Extended control register. */ +#define BCM540X_EXT_CTRL_REG 0x10 + +#define BCM540X_EXT_CTRL_LINK3_LED_MODE BIT_1 +#define BCM540X_EXT_CTRL_FORCE_LED_OFF BIT_3 +#define BCM540X_EXT_CTRL_TBI BIT_15 + +/* PHY extended status register. */ +#define BCM540X_EXT_STATUS_REG 0x11 + +#define BCM540X_EXT_STATUS_LINK_PASS BIT_8 + + +/* DSP Coefficient Read/Write Port. */ +#define BCM540X_DSP_RW_PORT 0x15 + + +/* DSP Coeficient Address Register. */ +#define BCM540X_DSP_ADDRESS_REG 0x17 + +#define BCM540X_DSP_TAP_NUMBER_MASK 0x00 +#define BCM540X_DSP_AGC_A 0x00 +#define BCM540X_DSP_AGC_B 0x01 +#define BCM540X_DSP_MSE_PAIR_STATUS 0x02 +#define BCM540X_DSP_SOFT_DECISION 0x03 +#define BCM540X_DSP_PHASE_REG 0x04 +#define BCM540X_DSP_SKEW 0x05 +#define BCM540X_DSP_POWER_SAVER_UPPER_BOUND 0x06 +#define BCM540X_DSP_POWER_SAVER_LOWER_BOUND 0x07 +#define BCM540X_DSP_LAST_ECHO 0x08 +#define BCM540X_DSP_FREQUENCY 0x09 +#define BCM540X_DSP_PLL_BANDWIDTH 0x0a +#define BCM540X_DSP_PLL_PHASE_OFFSET 0x0b + +#define BCM540X_DSP_FILTER_DCOFFSET (BIT_10 | BIT_11) +#define BCM540X_DSP_FILTER_FEXT3 (BIT_8 | BIT_9 | BIT_11) +#define BCM540X_DSP_FILTER_FEXT2 (BIT_9 | BIT_11) +#define BCM540X_DSP_FILTER_FEXT1 (BIT_8 | BIT_11) +#define BCM540X_DSP_FILTER_FEXT0 BIT_11 +#define BCM540X_DSP_FILTER_NEXT3 (BIT_8 | BIT_9 | BIT_10) +#define BCM540X_DSP_FILTER_NEXT2 (BIT_9 | BIT_10) +#define BCM540X_DSP_FILTER_NEXT1 (BIT_8 | BIT_10) +#define BCM540X_DSP_FILTER_NEXT0 BIT_10 +#define BCM540X_DSP_FILTER_ECHO (BIT_8 | BIT_9) +#define BCM540X_DSP_FILTER_DFE BIT_9 +#define BCM540X_DSP_FILTER_FFE BIT_8 + +#define BCM540X_DSP_CONTROL_ALL_FILTERS BIT_12 + +#define BCM540X_DSP_SEL_CH_0 BIT_NONE +#define BCM540X_DSP_SEL_CH_1 BIT_13 +#define BCM540X_DSP_SEL_CH_2 BIT_14 +#define BCM540X_DSP_SEL_CH_3 (BIT_13 | BIT_14) + +#define BCM540X_CONTROL_ALL_CHANNELS BIT_15 + + +/* Auxilliary Control Register (Shadow Register) */ +#define BCM5401_AUX_CTRL 0x18 + +#define BCM5401_SHADOW_SEL_MASK 0x7 +#define BCM5401_SHADOW_SEL_NORMAL 0x00 +#define BCM5401_SHADOW_SEL_10BASET 0x01 +#define BCM5401_SHADOW_SEL_POWER_CONTROL 0x02 +#define BCM5401_SHADOW_SEL_IP_PHONE 0x03 +#define BCM5401_SHADOW_SEL_MISC_TEST1 0x04 +#define BCM5401_SHADOW_SEL_MISC_TEST2 0x05 +#define BCM5401_SHADOW_SEL_IP_PHONE_SEED 0x06 + + +/* Shadow register selector == '000' */ +#define BCM5401_SHDW_NORMAL_DIAG_MODE BIT_3 +#define BCM5401_SHDW_NORMAL_DISABLE_MBP BIT_4 +#define BCM5401_SHDW_NORMAL_DISABLE_LOW_PWR BIT_5 +#define BCM5401_SHDW_NORMAL_DISABLE_INV_PRF BIT_6 +#define BCM5401_SHDW_NORMAL_DISABLE_PRF BIT_7 +#define BCM5401_SHDW_NORMAL_RX_SLICING_NORMAL BIT_NONE +#define BCM5401_SHDW_NORMAL_RX_SLICING_4D BIT_8 +#define BCM5401_SHDW_NORMAL_RX_SLICING_3LVL_1D BIT_9 +#define BCM5401_SHDW_NORMAL_RX_SLICING_5LVL_1D (BIT_8 | BIT_9) +#define BCM5401_SHDW_NORMAL_TX_6DB_CODING BIT_10 +#define BCM5401_SHDW_NORMAL_ENABLE_SM_DSP_CLOCK BIT_11 +#define BCM5401_SHDW_NORMAL_EDGERATE_CTRL_4NS BIT_NONE +#define BCM5401_SHDW_NORMAL_EDGERATE_CTRL_5NS BIT_12 +#define BCM5401_SHDW_NORMAL_EDGERATE_CTRL_3NS BIT_13 +#define BCM5401_SHDW_NORMAL_EDGERATE_CTRL_0NS (BIT_12 | BIT_13) +#define BCM5401_SHDW_NORMAL_EXT_PACKET_LENGTH BIT_14 +#define BCM5401_SHDW_NORMAL_EXTERNAL_LOOPBACK BIT_15 + + +/* Auxilliary status summary. */ +#define BCM540X_AUX_STATUS_REG 0x19 + +#define BCM540X_AUX_LINK_PASS BIT_2 +#define BCM540X_AUX_SPEED_MASK (BIT_8 | BIT_9 | BIT_10) +#define BCM540X_AUX_10BASET_HD BIT_8 +#define BCM540X_AUX_10BASET_FD BIT_9 +#define BCM540X_AUX_100BASETX_HD (BIT_8 | BIT_9) +#define BCM540X_AUX_100BASET4 BIT_10 +#define BCM540X_AUX_100BASETX_FD (BIT_8 | BIT_10) +#define BCM540X_AUX_100BASET_HD (BIT_9 | BIT_10) +#define BCM540X_AUX_100BASET_FD (BIT_8 | BIT_9 | BIT_10) + + +/* Interrupt status. */ +#define BCM540X_INT_STATUS_REG 0x1a + +#define BCM540X_INT_LINK_CHANGE BIT_1 +#define BCM540X_INT_SPEED_CHANGE BIT_2 +#define BCM540X_INT_DUPLEX_CHANGE BIT_3 +#define BCM540X_INT_AUTO_NEG_PAGE_RX BIT_10 + + +/* Interrupt mask register. */ +#define BCM540X_INT_MASK_REG 0x1b + +/* BCM5461 x1c Shadow Control register */ +#define BCM546X_1c_SHADOW_REG 0x1c + +#define BCM546X_1c_WR_EN 0x8000 /* shadow (1c) write enable bit mask */ + +#define BCM546X_1c_SPR_CTRL_1 0x0800 /* shadow (1c) reg 00010 addr */ +#define BCM546X_1c_SP1_LINK_LED 0x0001 /* shadow (1c) reg 00010 link LED mode mask */ + +#define BCM546X_1c_SPR_CTRL_2 0x100C /* shadow (1c) reg 00100 addr */ +#define BCM546X_1c_SP2_NRG_DET 0x0002 /* shadow (1c) reg 00100 energy detect bit mask */ + + + +/******************************************************************************/ +/* Register definitions. */ +/******************************************************************************/ + +typedef volatile LM_UINT8 T3_8BIT_REGISTER, *PT3_8BIT_REGISTER; +typedef volatile LM_UINT16 T3_16BIT_REGISTER, *PT3_16BIT_REGISTER; +typedef volatile LM_UINT32 T3_32BIT_REGISTER, *PT3_32BIT_REGISTER; + +typedef struct { + /* Big endian format. */ + T3_32BIT_REGISTER High; + T3_32BIT_REGISTER Low; +} T3_64BIT_REGISTER, *PT3_64BIT_REGISTER; + +typedef T3_64BIT_REGISTER T3_64BIT_HOST_ADDR, *PT3_64BIT_HOST_ADDR; + +#define T3_NUM_OF_DMA_DESC 256 +#define T3_NUM_OF_MBUF 768 + +typedef struct +{ + T3_64BIT_REGISTER host_addr; + T3_32BIT_REGISTER nic_mbuf; + T3_16BIT_REGISTER len; + T3_16BIT_REGISTER cqid_sqid; + T3_32BIT_REGISTER flags; + T3_32BIT_REGISTER opaque1; + T3_32BIT_REGISTER opaque2; + T3_32BIT_REGISTER opaque3; +}T3_DMA_DESC, *PT3_DMA_DESC; + + + +/******************************************************************************/ +/* Ring control block. */ +/******************************************************************************/ + +typedef struct { + T3_64BIT_REGISTER HostRingAddr; + + union { + struct { +#ifdef BIG_ENDIAN_HOST + T3_16BIT_REGISTER MaxLen; + T3_16BIT_REGISTER Flags; +#else /* BIG_ENDIAN_HOST */ + T3_16BIT_REGISTER Flags; + T3_16BIT_REGISTER MaxLen; +#endif + } s; + + T3_32BIT_REGISTER MaxLen_Flags; + } u; + + T3_32BIT_REGISTER NicRingAddr; +} T3_RCB, *PT3_RCB; + +#define T3_RCB_FLAG_USE_EXT_RECV_BD BIT_0 +#define T3_RCB_FLAG_RING_DISABLED BIT_1 + + + +/******************************************************************************/ +/* Status block. */ +/******************************************************************************/ + +/* + * Size of status block is actually 0x50 bytes. Use 0x80 bytes for + * cache line alignment. + */ +#define T3_STATUS_BLOCK_SIZE 0x80 + +typedef struct { + volatile LM_UINT32 Status; + #define STATUS_BLOCK_UPDATED BIT_0 + #define STATUS_BLOCK_LINK_CHANGED_STATUS BIT_1 + #define STATUS_BLOCK_ERROR BIT_2 + + volatile LM_UINT32 StatusTag; + +#ifdef BIG_ENDIAN_HOST + volatile LM_UINT16 RcvStdConIdx; + volatile LM_UINT16 RcvJumboConIdx; + + volatile LM_UINT16 Reserved2; + volatile LM_UINT16 RcvMiniConIdx; + + struct { + volatile LM_UINT16 SendConIdx; /* Send consumer index. */ + volatile LM_UINT16 RcvProdIdx; /* Receive producer index. */ + } Idx[16]; +#else /* BIG_ENDIAN_HOST */ + volatile LM_UINT16 RcvJumboConIdx; + volatile LM_UINT16 RcvStdConIdx; + + volatile LM_UINT16 RcvMiniConIdx; + volatile LM_UINT16 Reserved2; + + struct { + volatile LM_UINT16 RcvProdIdx; /* Receive producer index. */ + volatile LM_UINT16 SendConIdx; /* Send consumer index. */ + } Idx[16]; +#endif +} T3_STATUS_BLOCK, *PT3_STATUS_BLOCK; + + + +/******************************************************************************/ +/* Receive buffer descriptors. */ +/******************************************************************************/ + +typedef struct { + T3_64BIT_HOST_ADDR HostAddr; + +#ifdef BIG_ENDIAN_HOST + volatile LM_UINT16 Index; + volatile LM_UINT16 Len; + + volatile LM_UINT16 Type; + volatile LM_UINT16 Flags; + + volatile LM_UINT16 IpCksum; + volatile LM_UINT16 TcpUdpCksum; + + volatile LM_UINT16 ErrorFlag; + volatile LM_UINT16 VlanTag; +#else /* BIG_ENDIAN_HOST */ + volatile LM_UINT16 Len; + volatile LM_UINT16 Index; + + volatile LM_UINT16 Flags; + volatile LM_UINT16 Type; + + volatile LM_UINT16 TcpUdpCksum; + volatile LM_UINT16 IpCksum; + + volatile LM_UINT16 VlanTag; + volatile LM_UINT16 ErrorFlag; +#endif + + volatile LM_UINT32 Reserved; + volatile LM_UINT32 Opaque; +} T3_RCV_BD, *PT3_RCV_BD; + + +typedef struct { + T3_64BIT_HOST_ADDR HostAddr[3]; + +#ifdef BIG_ENDIAN_HOST + LM_UINT16 Len1; + LM_UINT16 Len2; + + LM_UINT16 Len3; + LM_UINT16 Reserved1; +#else /* BIG_ENDIAN_HOST */ + LM_UINT16 Len2; + LM_UINT16 Len1; + + LM_UINT16 Reserved1; + LM_UINT16 Len3; +#endif + + T3_RCV_BD StdRcvBd; +} T3_EXT_RCV_BD, *PT3_EXT_RCV_BD; + + +/* Error flags. */ +#define RCV_BD_ERR_BAD_CRC 0x0001 +#define RCV_BD_ERR_COLL_DETECT 0x0002 +#define RCV_BD_ERR_LINK_LOST_DURING_PKT 0x0004 +#define RCV_BD_ERR_PHY_DECODE_ERR 0x0008 +#define RCV_BD_ERR_ODD_NIBBLED_RCVD_MII 0x0010 +#define RCV_BD_ERR_MAC_ABORT 0x0020 +#define RCV_BD_ERR_LEN_LT_64 0x0040 +#define RCV_BD_ERR_TRUNC_NO_RESOURCES 0x0080 +#define RCV_BD_ERR_GIANT_FRAME_RCVD 0x0100 + + +/* Buffer descriptor flags. */ +#define RCV_BD_FLAG_END 0x0004 +#define RCV_BD_FLAG_JUMBO_RING 0x0020 +#define RCV_BD_FLAG_VLAN_TAG 0x0040 +#define RCV_BD_FLAG_FRAME_HAS_ERROR 0x0400 +#define RCV_BD_FLAG_MINI_RING 0x0800 +#define RCV_BD_FLAG_IP_CHKSUM_FIELD 0x1000 +#define RCV_BD_FLAG_TCP_UDP_CHKSUM_FIELD 0x2000 +#define RCV_BD_FLAG_TCP_PACKET 0x4000 + + + +/******************************************************************************/ +/* Send buffer descriptor. */ +/******************************************************************************/ + +typedef struct { + T3_64BIT_HOST_ADDR HostAddr; + + union { + struct { +#ifdef BIG_ENDIAN_HOST + LM_UINT16 Len; + LM_UINT16 Flags; +#else /* BIG_ENDIAN_HOST */ + LM_UINT16 Flags; + LM_UINT16 Len; +#endif + } s1; + + LM_UINT32 Len_Flags; + } u1; + + union { + struct { +#ifdef BIG_ENDIAN_HOST + LM_UINT16 Reserved; + LM_UINT16 VlanTag; +#else /* BIG_ENDIAN_HOST */ + LM_UINT16 VlanTag; + LM_UINT16 Reserved; +#endif + } s2; + + LM_UINT32 VlanTag; + } u2; +} T3_SND_BD, *PT3_SND_BD; + + +/* Send buffer descriptor flags. */ +#define SND_BD_FLAG_TCP_UDP_CKSUM 0x0001 +#define SND_BD_FLAG_IP_CKSUM 0x0002 +#define SND_BD_FLAG_END 0x0004 +#define SND_BD_FLAG_IP_FRAG 0x0008 +#define SND_BD_FLAG_IP_FRAG_END 0x0010 +#define SND_BD_FLAG_VLAN_TAG 0x0040 +#define SND_BD_FLAG_COAL_NOW 0x0080 +#define SND_BD_FLAG_CPU_PRE_DMA 0x0100 +#define SND_BD_FLAG_CPU_POST_DMA 0x0200 +#define SND_BD_FLAG_INSERT_SRC_ADDR 0x1000 +#define SND_BD_FLAG_CHOOSE_SRC_ADDR 0x6000 +#define SND_BD_FLAG_DONT_GEN_CRC 0x8000 + +/* MBUFs */ +typedef struct T3_MBUF_FRAME_DESC { +#ifdef BIG_ENDIAN_HOST + LM_UINT32 status_control; + union { + struct { + LM_UINT8 cqid; + LM_UINT8 reserved1; + LM_UINT16 length; + }s1; + LM_UINT32 word; + }u1; + union { + struct + { + LM_UINT16 ip_hdr_start; + LM_UINT16 tcp_udp_hdr_start; + }s2; + + LM_UINT32 word; + }u2; + + union { + struct { + LM_UINT16 data_start; + LM_UINT16 vlan_id; + }s3; + + LM_UINT32 word; + }u3; + + union { + struct { + LM_UINT16 ip_checksum; + LM_UINT16 tcp_udp_checksum; + }s4; + + LM_UINT32 word; + }u4; + + union { + struct { + LM_UINT16 pseudo_checksum; + LM_UINT16 checksum_status; + }s5; + + LM_UINT32 word; + }u5; + + union { + struct { + LM_UINT16 rule_match; + LM_UINT8 class; + LM_UINT8 rupt; + }s6; + + LM_UINT32 word; + }u6; + + union { + struct { + LM_UINT16 reserved2; + LM_UINT16 mbuf_num; + }s7; + + LM_UINT32 word; + }u7; + + LM_UINT32 reserved3; + LM_UINT32 reserved4; +#else + LM_UINT32 status_control; + union { + struct { + LM_UINT16 length; + LM_UINT8 reserved1; + LM_UINT8 cqid; + }s1; + LM_UINT32 word; + }u1; + union { + struct + { + LM_UINT16 tcp_udp_hdr_start; + LM_UINT16 ip_hdr_start; + }s2; + + LM_UINT32 word; + }u2; + + union { + struct { + LM_UINT16 vlan_id; + LM_UINT16 data_start; + }s3; + + LM_UINT32 word; + }u3; + + union { + struct { + LM_UINT16 tcp_udp_checksum; + LM_UINT16 ip_checksum; + }s4; + + LM_UINT32 word; + }u4; + + union { + struct { + LM_UINT16 checksum_status; + LM_UINT16 pseudo_checksum; + }s5; + + LM_UINT32 word; + }u5; + + union { + struct { + LM_UINT8 rupt; + LM_UINT8 class; + LM_UINT16 rule_match; + }s6; + + LM_UINT32 word; + }u6; + + union { + struct { + LM_UINT16 mbuf_num; + LM_UINT16 reserved2; + }s7; + + LM_UINT32 word; + }u7; + + LM_UINT32 reserved3; + LM_UINT32 reserved4; +#endif +}T3_MBUF_FRAME_DESC,*PT3_MBUF_FRAME_DESC; + +typedef struct T3_MBUF_HDR { + union { + struct { + unsigned int C:1; + unsigned int F:1; + unsigned int reserved1:7; + unsigned int next_mbuf:16; + unsigned int length:7; + }s1; + + LM_UINT32 word; + }u1; + + LM_UINT32 next_frame_ptr; +}T3_MBUF_HDR, *PT3_MBUF_HDR; + +typedef struct T3_MBUF +{ + T3_MBUF_HDR hdr; + union + { + struct { + T3_MBUF_FRAME_DESC frame_hdr; + LM_UINT32 data[20]; + }s1; + + struct { + LM_UINT32 data[30]; + }s2; + }body; +}T3_MBUF, *PT3_MBUF; + +#define T3_MBUF_BASE (T3_NIC_MBUF_POOL_ADDR >> 7) +#define T3_MBUF_END ((T3_NIC_MBUF_POOL_ADDR + T3_NIC_MBUF_POOL_SIZE) >> 7) + + + +/******************************************************************************/ +/* Statistics block. */ +/******************************************************************************/ + +typedef struct { + LM_UINT8 Reserved0[0x400-0x300]; + + /* Statistics maintained by Receive MAC. */ + T3_64BIT_REGISTER ifHCInOctets; + T3_64BIT_REGISTER Reserved1; + T3_64BIT_REGISTER etherStatsFragments; + T3_64BIT_REGISTER ifHCInUcastPkts; + T3_64BIT_REGISTER ifHCInMulticastPkts; + T3_64BIT_REGISTER ifHCInBroadcastPkts; + T3_64BIT_REGISTER dot3StatsFCSErrors; + T3_64BIT_REGISTER dot3StatsAlignmentErrors; + T3_64BIT_REGISTER xonPauseFramesReceived; + T3_64BIT_REGISTER xoffPauseFramesReceived; + T3_64BIT_REGISTER macControlFramesReceived; + T3_64BIT_REGISTER xoffStateEntered; + T3_64BIT_REGISTER dot3StatsFramesTooLong; + T3_64BIT_REGISTER etherStatsJabbers; + T3_64BIT_REGISTER etherStatsUndersizePkts; + T3_64BIT_REGISTER inRangeLengthError; + T3_64BIT_REGISTER outRangeLengthError; + T3_64BIT_REGISTER etherStatsPkts64Octets; + T3_64BIT_REGISTER etherStatsPkts65Octetsto127Octets; + T3_64BIT_REGISTER etherStatsPkts128Octetsto255Octets; + T3_64BIT_REGISTER etherStatsPkts256Octetsto511Octets; + T3_64BIT_REGISTER etherStatsPkts512Octetsto1023Octets; + T3_64BIT_REGISTER etherStatsPkts1024Octetsto1522Octets; + T3_64BIT_REGISTER etherStatsPkts1523Octetsto2047Octets; + T3_64BIT_REGISTER etherStatsPkts2048Octetsto4095Octets; + T3_64BIT_REGISTER etherStatsPkts4096Octetsto8191Octets; + T3_64BIT_REGISTER etherStatsPkts8192Octetsto9022Octets; + + T3_64BIT_REGISTER Unused1[37]; + + /* Statistics maintained by Transmit MAC. */ + T3_64BIT_REGISTER ifHCOutOctets; + T3_64BIT_REGISTER Reserved2; + T3_64BIT_REGISTER etherStatsCollisions; + T3_64BIT_REGISTER outXonSent; + T3_64BIT_REGISTER outXoffSent; + T3_64BIT_REGISTER flowControlDone; + T3_64BIT_REGISTER dot3StatsInternalMacTransmitErrors; + T3_64BIT_REGISTER dot3StatsSingleCollisionFrames; + T3_64BIT_REGISTER dot3StatsMultipleCollisionFrames; + T3_64BIT_REGISTER dot3StatsDeferredTransmissions; + T3_64BIT_REGISTER Reserved3; + T3_64BIT_REGISTER dot3StatsExcessiveCollisions; + T3_64BIT_REGISTER dot3StatsLateCollisions; + T3_64BIT_REGISTER dot3Collided2Times; + T3_64BIT_REGISTER dot3Collided3Times; + T3_64BIT_REGISTER dot3Collided4Times; + T3_64BIT_REGISTER dot3Collided5Times; + T3_64BIT_REGISTER dot3Collided6Times; + T3_64BIT_REGISTER dot3Collided7Times; + T3_64BIT_REGISTER dot3Collided8Times; + T3_64BIT_REGISTER dot3Collided9Times; + T3_64BIT_REGISTER dot3Collided10Times; + T3_64BIT_REGISTER dot3Collided11Times; + T3_64BIT_REGISTER dot3Collided12Times; + T3_64BIT_REGISTER dot3Collided13Times; + T3_64BIT_REGISTER dot3Collided14Times; + T3_64BIT_REGISTER dot3Collided15Times; + T3_64BIT_REGISTER ifHCOutUcastPkts; + T3_64BIT_REGISTER ifHCOutMulticastPkts; + T3_64BIT_REGISTER ifHCOutBroadcastPkts; + T3_64BIT_REGISTER dot3StatsCarrierSenseErrors; + T3_64BIT_REGISTER ifOutDiscards; + T3_64BIT_REGISTER ifOutErrors; + + T3_64BIT_REGISTER Unused2[31]; + + /* Statistics maintained by Receive List Placement. */ + T3_64BIT_REGISTER COSIfHCInPkts[16]; + T3_64BIT_REGISTER COSFramesDroppedDueToFilters; + T3_64BIT_REGISTER nicDmaWriteQueueFull; + T3_64BIT_REGISTER nicDmaWriteHighPriQueueFull; + T3_64BIT_REGISTER nicNoMoreRxBDs; + T3_64BIT_REGISTER ifInDiscards; + T3_64BIT_REGISTER ifInErrors; + T3_64BIT_REGISTER nicRecvThresholdHit; + + T3_64BIT_REGISTER Unused3[9]; + + /* Statistics maintained by Send Data Initiator. */ + T3_64BIT_REGISTER COSIfHCOutPkts[16]; + T3_64BIT_REGISTER nicDmaReadQueueFull; + T3_64BIT_REGISTER nicDmaReadHighPriQueueFull; + T3_64BIT_REGISTER nicSendDataCompQueueFull; + + /* Statistics maintained by Host Coalescing. */ + T3_64BIT_REGISTER nicRingSetSendProdIndex; + T3_64BIT_REGISTER nicRingStatusUpdate; + T3_64BIT_REGISTER nicInterrupts; + T3_64BIT_REGISTER nicAvoidedInterrupts; + T3_64BIT_REGISTER nicSendThresholdHit; + + LM_UINT8 Reserved4[0xb00-0x9c0]; +} T3_STATS_BLOCK, *PT3_STATS_BLOCK; + + + +/******************************************************************************/ +/* PCI configuration registers. */ +/******************************************************************************/ + +typedef struct { + T3_16BIT_REGISTER VendorId; + T3_16BIT_REGISTER DeviceId; + + T3_16BIT_REGISTER Command; + T3_16BIT_REGISTER Status; + + T3_32BIT_REGISTER ClassCodeRevId; + + T3_8BIT_REGISTER CacheLineSize; + T3_8BIT_REGISTER LatencyTimer; + T3_8BIT_REGISTER HeaderType; + T3_8BIT_REGISTER Bist; + + T3_32BIT_REGISTER MemBaseAddrLow; + T3_32BIT_REGISTER MemBaseAddrHigh; + + LM_UINT8 Unused1[20]; + + T3_16BIT_REGISTER SubsystemVendorId; + T3_16BIT_REGISTER SubsystemId; + + T3_32BIT_REGISTER RomBaseAddr; + + T3_8BIT_REGISTER PciXCapiblityPtr; + LM_UINT8 Unused2[7]; + + T3_8BIT_REGISTER IntLine; + T3_8BIT_REGISTER IntPin; + T3_8BIT_REGISTER MinGnt; + T3_8BIT_REGISTER MaxLat; + + T3_8BIT_REGISTER PciXCapabilities; + T3_8BIT_REGISTER PmCapabilityPtr; + T3_16BIT_REGISTER PciXCommand; + #define PXC_MAX_READ_BYTE_COUNT_MASK (BIT_3 | BIT_2) + #define PXC_MAX_READ_BYTE_COUNT_512 (0) + #define PXC_MAX_READ_BYTE_COUNT_1024 (BIT_2) + #define PXC_MAX_READ_BYTE_COUNT_2048 (BIT_3) + #define PXC_MAX_READ_BYTE_COUNT_4096 (BIT_3 | BIT_2) + + T3_32BIT_REGISTER PciXStatus; + + T3_8BIT_REGISTER PmCapabilityId; + T3_8BIT_REGISTER VpdCapabilityPtr; + T3_16BIT_REGISTER PmCapabilities; + + T3_16BIT_REGISTER PmCtrlStatus; + #define PM_CTRL_PME_STATUS BIT_15 + #define PM_CTRL_PME_ENABLE BIT_8 + #define PM_CTRL_PME_POWER_STATE_D0 0 + #define PM_CTRL_PME_POWER_STATE_D1 1 + #define PM_CTRL_PME_POWER_STATE_D2 2 + #define PM_CTRL_PME_POWER_STATE_D3H 3 + + T3_8BIT_REGISTER BridgeSupportExt; + T3_8BIT_REGISTER PmData; + + T3_8BIT_REGISTER VpdCapabilityId; + T3_8BIT_REGISTER MsiCapabilityPtr; + T3_16BIT_REGISTER VpdAddrFlag; + #define VPD_FLAG_WRITE (1 << 15) + #define VPD_FLAG_RW_MASK (1 << 15) + #define VPD_FLAG_READ 0 + + + T3_32BIT_REGISTER VpdData; + + T3_8BIT_REGISTER MsiCapabilityId; + T3_8BIT_REGISTER NextCapabilityPtr; + T3_16BIT_REGISTER MsiCtrl; + #define MSI_CTRL_64BIT_CAP (1 << 7) + #define MSI_CTRL_MSG_ENABLE(x) (x << 4) + #define MSI_CTRL_MSG_CAP(x) (x << 1) + #define MSI_CTRL_ENABLE (1 << 0) + + + T3_32BIT_REGISTER MsiAddrLow; + T3_32BIT_REGISTER MsiAddrHigh; + + T3_16BIT_REGISTER MsiData; + T3_16BIT_REGISTER Unused3; + + T3_32BIT_REGISTER MiscHostCtrl; + #define MISC_HOST_CTRL_CLEAR_INT BIT_0 + #define MISC_HOST_CTRL_MASK_PCI_INT BIT_1 + #define MISC_HOST_CTRL_ENABLE_ENDIAN_BYTE_SWAP BIT_2 + #define MISC_HOST_CTRL_ENABLE_ENDIAN_WORD_SWAP BIT_3 + #define MISC_HOST_CTRL_ENABLE_PCI_STATE_REG_RW BIT_4 + #define MISC_HOST_CTRL_ENABLE_CLK_REG_RW BIT_5 + #define MISC_HOST_CTRL_ENABLE_REG_WORD_SWAP BIT_6 + #define MISC_HOST_CTRL_ENABLE_INDIRECT_ACCESS BIT_7 + #define MISC_HOST_CTRL_ENABLE_INT_MASK_MODE BIT_8 + #define MISC_HOST_CTRL_ENABLE_TAGGED_STATUS_MODE BIT_9 + + T3_32BIT_REGISTER DmaReadWriteCtrl; + #define DMA_CTRL_WRITE_CMD 0x70000000 + #define DMA_CTRL_WRITE_BOUNDARY_64_PCIE 0x10000000 + #define DMA_CTRL_WRITE_BOUNDARY_128_PCIE 0x30000000 + #define DMA_CTRL_WRITE_BOUNDARY_DISABLE_PCIE 0x70000000 + #define DMA_CTRL_READ_CMD 0x06000000 + + /* bits 21:19 */ + #define DMA_CTRL_WRITE_PCIE_H20MARK_128 0x00180000 + #define DMA_CTRL_WRITE_PCIE_H20MARK_256 0x00380000 + + #define DMA_CTRL_PCIX_READ_WATERMARK_MASK (BIT_18 | BIT_17 | BIT_16) + #define DMA_CTRL_PCIX_READ_WATERMARK_64 (0) + #define DMA_CTRL_PCIX_READ_WATERMARK_128 (BIT_16) + #define DMA_CTRL_PCIX_READ_WATERMARK_256 (BIT_17) + #define DMA_CTRL_PCIX_READ_WATERMARK_384 (BIT_17 | BIT_16) + #define DMA_CTRL_PCIX_READ_WATERMARK_512 (BIT_18) + #define DMA_CTRL_PCIX_READ_WATERMARK_1024 (BIT_18 | BIT_16) + #define DMA_CTRL_PCIX_READ_WATERMARK_1536X (BIT_18 | BIT_17) + #define DMA_CTRL_PCIX_READ_WATERMARK_1536 (BIT_18 | BIT_17 | BIT_16) + + #define DMA_CTRL_WRITE_BOUNDARY_MASK (BIT_11 | BIT_12 | BIT_13) + #define DMA_CTRL_WRITE_BOUNDARY_DISABLE 0 + #define DMA_CTRL_WRITE_BOUNDARY_16 BIT_11 + #define DMA_CTRL_WRITE_BOUNDARY_128_PCIX BIT_11 + #define DMA_CTRL_WRITE_BOUNDARY_32 BIT_12 + #define DMA_CTRL_WRITE_BOUNDARY_256_PCIX BIT_12 + #define DMA_CTRL_WRITE_BOUNDARY_64 (BIT_12 | BIT_11) + #define DMA_CTRL_WRITE_BOUNDARY_384_PCIX (BIT_12 | BIT_11) + #define DMA_CTRL_WRITE_BOUNDARY_128 BIT_13 + #define DMA_CTRL_WRITE_BOUNDARY_256 (BIT_13 | BIT_11) + #define DMA_CTRL_WRITE_BOUNDARY_512 (BIT_13 | BIT_12) + #define DMA_CTRL_WRITE_BOUNDARY_1024 (BIT_13 | BIT_12 | BIT_11) + #define DMA_CTRL_WRITE_ONE_DMA_AT_ONCE BIT_14 + + #define DMA_CTRL_READ_BOUNDARY_MASK (BIT_10 | BIT_9 | BIT_8) + #define DMA_CTRL_READ_BOUNDARY_DISABLE 0 + #define DMA_CTRL_READ_BOUNDARY_16 BIT_8 + #define DMA_CTRL_READ_BOUNDARY_128_PCIX BIT_8 + #define DMA_CTRL_READ_BOUNDARY_32 BIT_9 + #define DMA_CTRL_READ_BOUNDARY_256_PCIX BIT_9 + #define DMA_CTRL_READ_BOUNDARY_64 (BIT_9 | BIT_8) + #define DMA_CTRL_READ_BOUNDARY_384_PCIX (BIT_9 | BIT_8) + #define DMA_CTRL_READ_BOUNDARY_128 BIT_10 + #define DMA_CTRL_READ_BOUNDARY_256 (BIT_10 | BIT_8) + #define DMA_CTRL_READ_BOUNDARY_512 (BIT_10 | BIT_9) + #define DMA_CTRL_READ_BOUNDARY_1024 (BIT_10 | BIT_9 | BIT_8) + + T3_32BIT_REGISTER PciState; + #define T3_PCI_STATE_FORCE_PCI_RESET BIT_0 + #define T3_PCI_STATE_INTERRUPT_NOT_ACTIVE BIT_1 + #define T3_PCI_STATE_NOT_PCI_X_BUS BIT_2 + #define T3_PCI_STATE_HIGH_BUS_SPEED BIT_3 + #define T3_PCI_STATE_32BIT_PCI_BUS BIT_4 + #define T3_PCI_STATE_PCI_ROM_ENABLE BIT_5 + #define T3_PCI_STATE_PCI_ROM_RETRY_ENABLE BIT_6 + #define T3_PCI_STATE_FLAT_VIEW BIT_8 + #define T3_PCI_STATE_RETRY_SAME_DMA BIT_13 + + T3_32BIT_REGISTER ClockCtrl; + #define T3_PCI_CLKCTRL_TXCPU_CLK_DISABLE BIT_11 + #define T3_PCI_CLKCTRL_RXCPU_CLK_DISABLE BIT_10 + #define T3_PCI_CLKCTRL_CORE_CLK_DISABLE BIT_9 + + T3_32BIT_REGISTER RegBaseAddr; + + T3_32BIT_REGISTER MemWindowBaseAddr; + +#ifdef NIC_CPU_VIEW + /* These registers are ONLY visible to NIC CPU */ + T3_32BIT_REGISTER PowerConsumed; + T3_32BIT_REGISTER PowerDissipated; +#else /* NIC_CPU_VIEW */ + T3_32BIT_REGISTER RegData; + T3_32BIT_REGISTER MemWindowData; +#endif /* !NIC_CPU_VIEW */ + + T3_32BIT_REGISTER ModeCtrl; + + T3_32BIT_REGISTER MiscCfg; + + T3_32BIT_REGISTER MiscLocalCtrl; + + T3_32BIT_REGISTER Unused4; + + /* NOTE: Big/Little-endian clarification needed. Are these register */ + /* in big or little endian formate. */ + T3_64BIT_REGISTER StdRingProdIdx; + T3_64BIT_REGISTER RcvRetRingConIdx; + T3_64BIT_REGISTER SndProdIdx; + + T3_32BIT_REGISTER Unused5[2]; /* 0xb0-0xb7 */ + + T3_32BIT_REGISTER DualMacCtrl; /* 0xb8 */ + #define T3_DUAL_MAC_CH_CTRL_MASK (BIT_1 | BIT_0) + #define T3_DUAL_MAC_ID BIT_2 + + T3_32BIT_REGISTER MacMessageExchangeOutput; /* 0xbc */ + T3_32BIT_REGISTER MacMessageExchangeInput; /* 0xc0 */ + + T3_32BIT_REGISTER FunctionEventMask; /* 0xc4 */ + + T3_32BIT_REGISTER Unused6[4]; /* 0xc8-0xd7 */ + + T3_32BIT_REGISTER DeviceCtrl; /* 0xd8 */ + #define MAX_PAYLOAD_SIZE_MASK 0x0e0 + + LM_UINT8 Unused7[36]; + +} T3_PCI_CONFIGURATION, *PT3_PCI_CONFIGURATION; + +#define PCIX_CMD_MAX_SPLIT_MASK 0x00700000 +#define PCIX_CMD_MAX_SPLIT_SHL 20 +#define PCIX_CMD_MAX_BURST_MASK 0x000c0000 +#define PCIX_CMD_MAX_BURST_SHL 18 +#define PCIX_CMD_MAX_BURST_CPIOB 2 + +/******************************************************************************/ +/* Mac control registers. */ +/******************************************************************************/ + +typedef struct { + /* MAC mode control. */ + T3_32BIT_REGISTER Mode; + #define MAC_MODE_GLOBAL_RESET BIT_0 + #define MAC_MODE_HALF_DUPLEX BIT_1 + #define MAC_MODE_PORT_MODE_MASK (BIT_2 | BIT_3) + #define MAC_MODE_PORT_MODE_TBI (BIT_2 | BIT_3) + #define MAC_MODE_PORT_MODE_GMII BIT_3 + #define MAC_MODE_PORT_MODE_MII BIT_2 + #define MAC_MODE_PORT_MODE_NONE BIT_NONE + #define MAC_MODE_PORT_INTERNAL_LOOPBACK BIT_4 + #define MAC_MODE_TAGGED_MAC_CONTROL BIT_7 + #define MAC_MODE_TX_BURSTING BIT_8 + #define MAC_MODE_MAX_DEFER BIT_9 + #define MAC_MODE_LINK_POLARITY BIT_10 + #define MAC_MODE_ENABLE_RX_STATISTICS BIT_11 + #define MAC_MODE_CLEAR_RX_STATISTICS BIT_12 + #define MAC_MODE_FLUSH_RX_STATISTICS BIT_13 + #define MAC_MODE_ENABLE_TX_STATISTICS BIT_14 + #define MAC_MODE_CLEAR_TX_STATISTICS BIT_15 + #define MAC_MODE_FLUSH_TX_STATISTICS BIT_16 + #define MAC_MODE_SEND_CONFIGS BIT_17 + #define MAC_MODE_DETECT_MAGIC_PACKET_ENABLE BIT_18 + #define MAC_MODE_ACPI_POWER_ON_ENABLE BIT_19 + #define MAC_MODE_ENABLE_MIP BIT_20 + #define MAC_MODE_ENABLE_TDE BIT_21 + #define MAC_MODE_ENABLE_RDE BIT_22 + #define MAC_MODE_ENABLE_FHDE BIT_23 + + /* MAC status */ + T3_32BIT_REGISTER Status; + #define MAC_STATUS_PCS_SYNCED BIT_0 + #define MAC_STATUS_SIGNAL_DETECTED BIT_1 + #define MAC_STATUS_RECEIVING_CFG BIT_2 + #define MAC_STATUS_CFG_CHANGED BIT_3 + #define MAC_STATUS_SYNC_CHANGED BIT_4 + #define MAC_STATUS_PORT_DECODE_ERROR BIT_10 + #define MAC_STATUS_LINK_STATE_CHANGED BIT_12 + #define MAC_STATUS_MI_COMPLETION BIT_22 + #define MAC_STATUS_MI_INTERRUPT BIT_23 + #define MAC_STATUS_AP_ERROR BIT_24 + #define MAC_STATUS_ODI_ERROR BIT_25 + #define MAC_STATUS_RX_STATS_OVERRUN BIT_26 + #define MAC_STATUS_TX_STATS_OVERRUN BIT_27 + + /* Event Enable */ + T3_32BIT_REGISTER MacEvent; + #define MAC_EVENT_ENABLE_PORT_DECODE_ERR BIT_10 + #define MAC_EVENT_ENABLE_LINK_STATE_CHANGED_ATTN BIT_12 + #define MAC_EVENT_ENABLE_MI_COMPLETION BIT_22 + #define MAC_EVENT_ENABLE_MI_INTERRUPT BIT_23 + #define MAC_EVENT_ENABLE_AP_ERROR BIT_24 + #define MAC_EVENT_ENABLE_ODI_ERROR BIT_25 + #define MAC_EVENT_ENABLE_RX_STATS_OVERRUN BIT_26 + #define MAC_EVENT_ENABLE_TX_STATS_OVERRUN BIT_27 + + /* Led control. */ + T3_32BIT_REGISTER LedCtrl; + #define LED_CTRL_OVERRIDE_LINK_LED BIT_0 + #define LED_CTRL_1000MBPS_LED_ON BIT_1 + #define LED_CTRL_100MBPS_LED_ON BIT_2 + #define LED_CTRL_10MBPS_LED_ON BIT_3 + #define LED_CTRL_OVERRIDE_TRAFFIC_LED BIT_4 + #define LED_CTRL_BLINK_TRAFFIC_LED BIT_5 + #define LED_CTRL_TRAFFIC_LED BIT_6 + #define LED_CTRL_1000MBPS_LED_STATUS BIT_7 + #define LED_CTRL_100MBPS_LED_STATUS BIT_8 + #define LED_CTRL_10MBPS_LED_STATUS BIT_9 + #define LED_CTRL_TRAFFIC_LED_STATUS BIT_10 + #define LED_CTRL_MAC_MODE BIT_NONE + #define LED_CTRL_PHY_MODE_1 BIT_11 + #define LED_CTRL_PHY_MODE_2 BIT_12 + #define LED_CTRL_SHASTA_MAC_MODE BIT_13 + #define LED_CTRL_SHARED_TRAFFIC_LINK BIT_14 + #define LED_CTRL_WIRELESS_COMBO BIT_15 + #define LED_CTRL_BLINK_RATE_MASK 0x7ff80000 + #define LED_CTRL_OVERRIDE_BLINK_PERIOD BIT_19 + #define LED_CTRL_OVERRIDE_BLINK_RATE BIT_31 + + /* MAC addresses. */ + struct { + T3_32BIT_REGISTER High; /* Upper 2 bytes. */ + T3_32BIT_REGISTER Low; /* Lower 4 bytes. */ + } MacAddr[4]; + + /* ACPI Mbuf pointer. */ + T3_32BIT_REGISTER AcpiMbufPtr; + + /* ACPI Length and Offset. */ + T3_32BIT_REGISTER AcpiLengthOffset; + #define ACPI_LENGTH_MASK 0xffff + #define ACPI_OFFSET_MASK 0x0fff0000 + #define ACPI_LENGTH(x) x + #define ACPI_OFFSET(x) ((x) << 16) + + /* Transmit random backoff. */ + T3_32BIT_REGISTER TxBackoffSeed; + #define MAC_TX_BACKOFF_SEED_MASK 0x3ff + + /* Receive MTU */ + T3_32BIT_REGISTER MtuSize; + #define MAC_RX_MTU_MASK 0xffff + + /* Gigabit PCS Test. */ + T3_32BIT_REGISTER PcsTest; + #define MAC_PCS_TEST_DATA_PATTERN_MASK 0x0fffff + #define MAC_PCS_TEST_ENABLE BIT_20 + + /* Transmit Gigabit Auto-Negotiation. */ + T3_32BIT_REGISTER TxAutoNeg; + #define MAC_AN_TX_AN_DATA_MASK 0xffff + + /* Receive Gigabit Auto-Negotiation. */ + T3_32BIT_REGISTER RxAutoNeg; + #define MAC_AN_RX_AN_DATA_MASK 0xffff + + /* MI Communication. */ + T3_32BIT_REGISTER MiCom; + #define MI_COM_CMD_MASK (BIT_26 | BIT_27) + #define MI_COM_CMD_WRITE BIT_26 + #define MI_COM_CMD_READ BIT_27 + #define MI_COM_READ_FAILED BIT_28 + #define MI_COM_START BIT_29 + #define MI_COM_BUSY BIT_29 + + #define MI_COM_PHY_ADDR_MASK 0x1f + #define MI_COM_FIRST_PHY_ADDR_BIT 21 + + #define MI_COM_PHY_REG_ADDR_MASK 0x1f + #define MI_COM_FIRST_PHY_REG_ADDR_BIT 16 + + #define MI_COM_PHY_DATA_MASK 0xffff + + /* MI Status. */ + T3_32BIT_REGISTER MiStatus; + #define MI_STATUS_ENABLE_LINK_STATUS_ATTN BIT_0 + #define MI_STATUS_10MBPS BIT_1 + + /* MI Mode. */ + T3_32BIT_REGISTER MiMode; + #define MI_MODE_CLOCK_SPEED_10MHZ BIT_0 + #define MI_MODE_USE_SHORT_PREAMBLE BIT_1 + #define MI_MODE_AUTO_POLLING_ENABLE BIT_4 + #define MI_MODE_CORE_CLOCK_SPEED_62MHZ BIT_15 + + /* Auto-polling status. */ + T3_32BIT_REGISTER AutoPollStatus; + #define AUTO_POLL_ERROR BIT_0 + + /* Transmit MAC mode. */ + T3_32BIT_REGISTER TxMode; + #define TX_MODE_RESET BIT_0 + #define TX_MODE_ENABLE BIT_1 + #define TX_MODE_ENABLE_FLOW_CONTROL BIT_4 + #define TX_MODE_ENABLE_BIG_BACKOFF BIT_5 + #define TX_MODE_ENABLE_LONG_PAUSE BIT_6 + + /* Transmit MAC status. */ + T3_32BIT_REGISTER TxStatus; + #define TX_STATUS_RX_CURRENTLY_XOFFED BIT_0 + #define TX_STATUS_SENT_XOFF BIT_1 + #define TX_STATUS_SENT_XON BIT_2 + #define TX_STATUS_LINK_UP BIT_3 + #define TX_STATUS_ODI_UNDERRUN BIT_4 + #define TX_STATUS_ODI_OVERRUN BIT_5 + + /* Transmit MAC length. */ + T3_32BIT_REGISTER TxLengths; + #define TX_LEN_SLOT_TIME_MASK 0xff + #define TX_LEN_IPG_MASK 0x0f00 + #define TX_LEN_IPG_CRS_MASK (BIT_12 | BIT_13) + + /* Receive MAC mode. */ + T3_32BIT_REGISTER RxMode; + #define RX_MODE_RESET BIT_0 + #define RX_MODE_ENABLE BIT_1 + #define RX_MODE_ENABLE_FLOW_CONTROL BIT_2 + #define RX_MODE_KEEP_MAC_CONTROL BIT_3 + #define RX_MODE_KEEP_PAUSE BIT_4 + #define RX_MODE_ACCEPT_OVERSIZED BIT_5 + #define RX_MODE_ACCEPT_RUNTS BIT_6 + #define RX_MODE_LENGTH_CHECK BIT_7 + #define RX_MODE_PROMISCUOUS_MODE BIT_8 + #define RX_MODE_NO_CRC_CHECK BIT_9 + #define RX_MODE_KEEP_VLAN_TAG BIT_10 + + /* Receive MAC status. */ + T3_32BIT_REGISTER RxStatus; + #define RX_STATUS_REMOTE_TRANSMITTER_XOFFED BIT_0 + #define RX_STATUS_XOFF_RECEIVED BIT_1 + #define RX_STATUS_XON_RECEIVED BIT_2 + + /* Hash registers. */ + T3_32BIT_REGISTER HashReg[4]; + + /* Receive placement rules registers. */ + struct { + T3_32BIT_REGISTER Rule; + T3_32BIT_REGISTER Value; + } RcvRules[16]; + + #define RCV_DISABLE_RULE_MASK 0x7fffffff + + #define RCV_RULE1_REJECT_BROADCAST_IDX 0x00 + #define REJECT_BROADCAST_RULE1_RULE 0xc2000000 + #define REJECT_BROADCAST_RULE1_VALUE 0xffffffff + + #define RCV_RULE2_REJECT_BROADCAST_IDX 0x01 + #define REJECT_BROADCAST_RULE2_RULE 0x86000004 + #define REJECT_BROADCAST_RULE2_VALUE 0xffffffff + +#if INCLUDE_5701_AX_FIX + #define RCV_LAST_RULE_IDX 0x04 +#else + #define RCV_LAST_RULE_IDX 0x02 +#endif + + T3_32BIT_REGISTER RcvRuleCfg; + #define RX_RULE_DEFAULT_CLASS (1 << 3) + + T3_32BIT_REGISTER LowWaterMarkMaxRxFrame; + + LM_UINT8 Reserved1[24]; + + T3_32BIT_REGISTER HashRegU[4]; + + struct { + T3_32BIT_REGISTER High; + T3_32BIT_REGISTER Low; + } MacAddrExt[12]; + + T3_32BIT_REGISTER SerdesCfg; + T3_32BIT_REGISTER SerdesStatus; + + LM_UINT8 Reserved2[24]; + + T3_32BIT_REGISTER SgDigControl; + T3_32BIT_REGISTER SgDigStatus; + + LM_UINT8 Reserved3[72]; + + volatile LM_UINT8 TxMacState[16]; + volatile LM_UINT8 RxMacState[20]; + + LM_UINT8 Reserved4[476]; + + T3_32BIT_REGISTER ifHCOutOctets; + T3_32BIT_REGISTER Reserved5; + T3_32BIT_REGISTER etherStatsCollisions; + T3_32BIT_REGISTER outXonSent; + T3_32BIT_REGISTER outXoffSent; + T3_32BIT_REGISTER Reserved6; + T3_32BIT_REGISTER dot3StatsInternalMacTransmitErrors; + T3_32BIT_REGISTER dot3StatsSingleCollisionFrames; + T3_32BIT_REGISTER dot3StatsMultipleCollisionFrames; + T3_32BIT_REGISTER dot3StatsDeferredTransmissions; + T3_32BIT_REGISTER Reserved7; + T3_32BIT_REGISTER dot3StatsExcessiveCollisions; + T3_32BIT_REGISTER dot3StatsLateCollisions; + T3_32BIT_REGISTER Reserved8[14]; + T3_32BIT_REGISTER ifHCOutUcastPkts; + T3_32BIT_REGISTER ifHCOutMulticastPkts; + T3_32BIT_REGISTER ifHCOutBroadcastPkts; + T3_32BIT_REGISTER Reserved9[2]; + T3_32BIT_REGISTER ifHCInOctets; + T3_32BIT_REGISTER Reserved10; + T3_32BIT_REGISTER etherStatsFragments; + T3_32BIT_REGISTER ifHCInUcastPkts; + T3_32BIT_REGISTER ifHCInMulticastPkts; + T3_32BIT_REGISTER ifHCInBroadcastPkts; + T3_32BIT_REGISTER dot3StatsFCSErrors; + T3_32BIT_REGISTER dot3StatsAlignmentErrors; + T3_32BIT_REGISTER xonPauseFramesReceived; + T3_32BIT_REGISTER xoffPauseFramesReceived; + T3_32BIT_REGISTER macControlFramesReceived; + T3_32BIT_REGISTER xoffStateEntered; + T3_32BIT_REGISTER dot3StatsFramesTooLong; + T3_32BIT_REGISTER etherStatsJabbers; + T3_32BIT_REGISTER etherStatsUndersizePkts; + + T3_32BIT_REGISTER Reserved11[209]; + +} T3_MAC_CONTROL, *PT3_MAC_CONTROL; + + + +/******************************************************************************/ +/* Send data initiator control registers. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; + #define T3_SND_DATA_IN_MODE_RESET BIT_0 + #define T3_SND_DATA_IN_MODE_ENABLE BIT_1 + #define T3_SND_DATA_IN_MODE_STATS_OFLW_ATTN_ENABLE BIT_2 + + T3_32BIT_REGISTER Status; + #define T3_SND_DATA_IN_STATUS_STATS_OFLW_ATTN BIT_2 + + T3_32BIT_REGISTER StatsCtrl; + #define T3_SND_DATA_IN_STATS_CTRL_ENABLE BIT_0 + #define T3_SND_DATA_IN_STATS_CTRL_FASTER_UPDATE BIT_1 + #define T3_SND_DATA_IN_STATS_CTRL_CLEAR BIT_2 + #define T3_SND_DATA_IN_STATS_CTRL_FLUSH BIT_3 + #define T3_SND_DATA_IN_STATS_CTRL_FORCE_ZERO BIT_4 + + T3_32BIT_REGISTER StatsEnableMask; + + T3_32BIT_REGISTER StatsIncMask; + + LM_UINT8 Reserved[108]; + + T3_32BIT_REGISTER ClassOfServCnt[16]; + T3_32BIT_REGISTER DmaReadQFullCnt; + T3_32BIT_REGISTER DmaPriorityReadQFullCnt; + T3_32BIT_REGISTER SdcQFullCnt; + + T3_32BIT_REGISTER NicRingSetSendProdIdxCnt; + T3_32BIT_REGISTER StatusUpdatedCnt; + T3_32BIT_REGISTER InterruptsCnt; + T3_32BIT_REGISTER AvoidInterruptsCnt; + T3_32BIT_REGISTER SendThresholdHitCnt; + + /* Unused space. */ + LM_UINT8 Unused[800]; +} T3_SEND_DATA_INITIATOR, *PT3_SEND_DATA_INITIATOR; + + + +/******************************************************************************/ +/* Send data completion control registers. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; + #define SND_DATA_COMP_MODE_RESET BIT_0 + #define SND_DATA_COMP_MODE_ENABLE BIT_1 + + /* Unused space. */ + LM_UINT8 Unused[1020]; +} T3_SEND_DATA_COMPLETION, *PT3_SEND_DATA_COMPLETION; + + + +/******************************************************************************/ +/* Send BD Ring Selector Control Registers. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; + #define SND_BD_SEL_MODE_RESET BIT_0 + #define SND_BD_SEL_MODE_ENABLE BIT_1 + #define SND_BD_SEL_MODE_ATTN_ENABLE BIT_2 + + T3_32BIT_REGISTER Status; + #define SND_BD_SEL_STATUS_ERROR_ATTN BIT_2 + + T3_32BIT_REGISTER HwDiag; + + /* Unused space. */ + LM_UINT8 Unused1[52]; + + /* Send BD Ring Selector Local NIC Send BD Consumer Index. */ + T3_32BIT_REGISTER NicSendBdSelConIdx[16]; + + /* Unused space. */ + LM_UINT8 Unused2[896]; +} T3_SEND_BD_SELECTOR, *PT3_SEND_BD_SELECTOR; + + + +/******************************************************************************/ +/* Send BD initiator control registers. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; + #define SND_BD_IN_MODE_RESET BIT_0 + #define SND_BD_IN_MODE_ENABLE BIT_1 + #define SND_BD_IN_MODE_ATTN_ENABLE BIT_2 + + T3_32BIT_REGISTER Status; + #define SND_BD_IN_STATUS_ERROR_ATTN BIT_2 + + /* Send BD initiator local NIC send BD producer index. */ + T3_32BIT_REGISTER NicSendBdInProdIdx[16]; + + /* Unused space. */ + LM_UINT8 Unused2[952]; +} T3_SEND_BD_INITIATOR, *PT3_SEND_BD_INITIATOR; + + + +/******************************************************************************/ +/* Send BD Completion Control. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; + #define SND_BD_COMP_MODE_RESET BIT_0 + #define SND_BD_COMP_MODE_ENABLE BIT_1 + #define SND_BD_COMP_MODE_ATTN_ENABLE BIT_2 + + /* Unused space. */ + LM_UINT8 Unused2[1020]; +} T3_SEND_BD_COMPLETION, *PT3_SEND_BD_COMPLETION; + + + +/******************************************************************************/ +/* Receive list placement control registers. */ +/******************************************************************************/ + +typedef struct { + /* Mode. */ + T3_32BIT_REGISTER Mode; + #define RCV_LIST_PLMT_MODE_RESET BIT_0 + #define RCV_LIST_PLMT_MODE_ENABLE BIT_1 + #define RCV_LIST_PLMT_MODE_CLASS0_ATTN_ENABLE BIT_2 + #define RCV_LIST_PLMT_MODE_MAPPING_OOR_ATTN_ENABLE BIT_3 + #define RCV_LIST_PLMT_MODE_STATS_OFLOW_ATTN_ENABLE BIT_4 + + /* Status. */ + T3_32BIT_REGISTER Status; + #define RCV_LIST_PLMT_STATUS_CLASS0_ATTN BIT_2 + #define RCV_LIST_PLMT_STATUS_MAPPING_ATTN BIT_3 + #define RCV_LIST_PLMT_STATUS_STATS_OFLOW_ATTN BIT_4 + + /* Receive selector list lock register. */ + T3_32BIT_REGISTER Lock; + #define RCV_LIST_SEL_LOCK_REQUEST_MASK 0xffff + #define RCV_LIST_SEL_LOCK_GRANT_MASK 0xffff0000 + + /* Selector non-empty bits. */ + T3_32BIT_REGISTER NonEmptyBits; + #define RCV_LIST_SEL_NON_EMPTY_MASK 0xffff + + /* Receive list placement configuration register. */ + T3_32BIT_REGISTER Config; + + /* Receive List Placement statistics Control. */ + T3_32BIT_REGISTER StatsCtrl; +#define RCV_LIST_STATS_ENABLE BIT_0 +#define RCV_LIST_STATS_FAST_UPDATE BIT_1 + + /* Receive List Placement statistics Enable Mask. */ + T3_32BIT_REGISTER StatsEnableMask; + #define T3_DISABLE_LONG_BURST_READ_DYN_FIX BIT_22 + + /* Receive List Placement statistics Increment Mask. */ + T3_32BIT_REGISTER StatsIncMask; + + /* Unused space. */ + LM_UINT8 Unused1[224]; + + struct { + T3_32BIT_REGISTER Head; + T3_32BIT_REGISTER Tail; + T3_32BIT_REGISTER Count; + + /* Unused space. */ + LM_UINT8 Unused[4]; + } RcvSelectorList[16]; + + /* Local statistics counter. */ + T3_32BIT_REGISTER ClassOfServCnt[16]; + + T3_32BIT_REGISTER DropDueToFilterCnt; + T3_32BIT_REGISTER DmaWriteQFullCnt; + T3_32BIT_REGISTER DmaHighPriorityWriteQFullCnt; + T3_32BIT_REGISTER NoMoreReceiveBdCnt; + T3_32BIT_REGISTER IfInDiscardsCnt; + T3_32BIT_REGISTER IfInErrorsCnt; + T3_32BIT_REGISTER RcvThresholdHitCnt; + + /* Another unused space. */ + LM_UINT8 Unused2[420]; +} T3_RCV_LIST_PLACEMENT, *PT3_RCV_LIST_PLACEMENT; + + + +/******************************************************************************/ +/* Receive Data and Receive BD Initiator Control. */ +/******************************************************************************/ + +typedef struct { + /* Mode. */ + T3_32BIT_REGISTER Mode; + #define RCV_DATA_BD_IN_MODE_RESET BIT_0 + #define RCV_DATA_BD_IN_MODE_ENABLE BIT_1 + #define RCV_DATA_BD_IN_MODE_JUMBO_BD_NEEDED BIT_2 + #define RCV_DATA_BD_IN_MODE_FRAME_TOO_BIG BIT_3 + #define RCV_DATA_BD_IN_MODE_INVALID_RING_SIZE BIT_4 + + /* Status. */ + T3_32BIT_REGISTER Status; + #define RCV_DATA_BD_IN_STATUS_JUMBO_BD_NEEDED BIT_2 + #define RCV_DATA_BD_IN_STATUS_FRAME_TOO_BIG BIT_3 + #define RCV_DATA_BD_IN_STATUS_INVALID_RING_SIZE BIT_4 + + /* Split frame minium size. */ + T3_32BIT_REGISTER SplitFrameMinSize; + + /* Unused space. */ + LM_UINT8 Unused1[0x2440-0x240c]; + + /* Receive RCBs. */ + T3_RCB JumboRcvRcb; + T3_RCB StdRcvRcb; + T3_RCB MiniRcvRcb; + + /* Receive Data and Receive BD Ring Initiator Local NIC Receive */ + /* BD Consumber Index. */ + T3_32BIT_REGISTER NicJumboConIdx; + T3_32BIT_REGISTER NicStdConIdx; + T3_32BIT_REGISTER NicMiniConIdx; + + /* Unused space. */ + LM_UINT8 Unused2[4]; + + /* Receive Data and Receive BD Initiator Local Receive Return ProdIdx. */ + T3_32BIT_REGISTER RcvDataBdProdIdx[16]; + + /* Receive Data and Receive BD Initiator Hardware Diagnostic. */ + T3_32BIT_REGISTER HwDiag; + + /* Unused space. */ + LM_UINT8 Unused3[828]; +} T3_RCV_DATA_BD_INITIATOR, *PT3_RCV_DATA_BD_INITIATOR; + + + +/******************************************************************************/ +/* Receive Data Completion Control Registes. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; + #define RCV_DATA_COMP_MODE_RESET BIT_0 + #define RCV_DATA_COMP_MODE_ENABLE BIT_1 + #define RCV_DATA_COMP_MODE_ATTN_ENABLE BIT_2 + + /* Unused spaced. */ + LM_UINT8 Unused[1020]; +} T3_RCV_DATA_COMPLETION, *PT3_RCV_DATA_COMPLETION; + + + +/******************************************************************************/ +/* Receive BD Initiator Control. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; + #define RCV_BD_IN_MODE_RESET BIT_0 + #define RCV_BD_IN_MODE_ENABLE BIT_1 + #define RCV_BD_IN_MODE_BD_IN_DIABLED_RCB_ATTN_ENABLE BIT_2 + + T3_32BIT_REGISTER Status; + #define RCV_BD_IN_STATUS_BD_IN_DIABLED_RCB_ATTN BIT_2 + + T3_32BIT_REGISTER NicJumboRcvProdIdx; + T3_32BIT_REGISTER NicStdRcvProdIdx; + T3_32BIT_REGISTER NicMiniRcvProdIdx; + + T3_32BIT_REGISTER MiniRcvThreshold; + T3_32BIT_REGISTER StdRcvThreshold; + T3_32BIT_REGISTER JumboRcvThreshold; + + /* Unused space. */ + LM_UINT8 Unused[992]; +} T3_RCV_BD_INITIATOR, *PT3_RCV_BD_INITIATOR; + + + +/******************************************************************************/ +/* Receive BD Completion Control Registers. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; + #define RCV_BD_COMP_MODE_RESET BIT_0 + #define RCV_BD_COMP_MODE_ENABLE BIT_1 + #define RCV_BD_COMP_MODE_ATTN_ENABLE BIT_2 + + T3_32BIT_REGISTER Status; + #define RCV_BD_COMP_STATUS_ERROR_ATTN BIT_2 + + T3_32BIT_REGISTER NicJumboRcvBdProdIdx; + T3_32BIT_REGISTER NicStdRcvBdProdIdx; + T3_32BIT_REGISTER NicMiniRcvBdProdIdx; + + /* Unused space. */ + LM_UINT8 Unused[1004]; +} T3_RCV_BD_COMPLETION, *PT3_RCV_BD_COMPLETION; + + + +/******************************************************************************/ +/* Receive list selector control register. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; + #define RCV_LIST_SEL_MODE_RESET BIT_0 + #define RCV_LIST_SEL_MODE_ENABLE BIT_1 + #define RCV_LIST_SEL_MODE_ATTN_ENABLE BIT_2 + + T3_32BIT_REGISTER Status; + #define RCV_LIST_SEL_STATUS_ERROR_ATTN BIT_2 + + /* Unused space. */ + LM_UINT8 Unused[1016]; +} T3_RCV_LIST_SELECTOR, *PT3_RCV_LIST_SELECTOR; + + + +/******************************************************************************/ +/* Mbuf cluster free registers. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; +#define MBUF_CLUSTER_FREE_MODE_RESET BIT_0 +#define MBUF_CLUSTER_FREE_MODE_ENABLE BIT_1 + + T3_32BIT_REGISTER Status; + + /* Unused space. */ + LM_UINT8 Unused[1016]; +} T3_MBUF_CLUSTER_FREE, *PT3_MBUF_CLUSTER_FREE; + + + +/******************************************************************************/ +/* Host coalescing control registers. */ +/******************************************************************************/ + +typedef struct { + /* Mode. */ + T3_32BIT_REGISTER Mode; + #define HOST_COALESCE_RESET BIT_0 + #define HOST_COALESCE_ENABLE BIT_1 + #define HOST_COALESCE_ATTN BIT_2 + #define HOST_COALESCE_NOW BIT_3 + #define HOST_COALESCE_FULL_STATUS_MODE BIT_NONE + #define HOST_COALESCE_64_BYTE_STATUS_MODE BIT_7 + #define HOST_COALESCE_32_BYTE_STATUS_MODE BIT_8 + #define HOST_COALESCE_CLEAR_TICKS_ON_RX_BD_EVENT BIT_9 + #define HOST_COALESCE_CLEAR_TICKS_ON_TX_BD_EVENT BIT_10 + #define HOST_COALESCE_NO_INT_ON_COALESCE_NOW_MODE BIT_11 + #define HOST_COALESCE_NO_INT_ON_FORCE_DMAD_MODE BIT_12 + + /* Status. */ + T3_32BIT_REGISTER Status; + #define HOST_COALESCE_ERROR_ATTN BIT_2 + + /* Receive coalescing ticks. */ + T3_32BIT_REGISTER RxCoalescingTicks; + + /* Send coalescing ticks. */ + T3_32BIT_REGISTER TxCoalescingTicks; + + /* Receive max coalesced frames. */ + T3_32BIT_REGISTER RxMaxCoalescedFrames; + + /* Send max coalesced frames. */ + T3_32BIT_REGISTER TxMaxCoalescedFrames; + + /* Receive coalescing ticks during interrupt. */ + T3_32BIT_REGISTER RxCoalescedTickDuringInt; + + /* Send coalescing ticks during interrupt. */ + T3_32BIT_REGISTER TxCoalescedTickDuringInt; + + /* Receive max coalesced frames during interrupt. */ + T3_32BIT_REGISTER RxMaxCoalescedFramesDuringInt; + + /* Send max coalesced frames during interrupt. */ + T3_32BIT_REGISTER TxMaxCoalescedFramesDuringInt; + + /* Statistics tick. */ + T3_32BIT_REGISTER StatsCoalescingTicks; + + /* Unused space. */ + LM_UINT8 Unused2[4]; + + /* Statistics host address. */ + T3_64BIT_REGISTER StatsBlkHostAddr; + + /* Status block host address.*/ + T3_64BIT_REGISTER StatusBlkHostAddr; + + /* Statistics NIC address. */ + T3_32BIT_REGISTER StatsBlkNicAddr; + + /* Statust block NIC address. */ + T3_32BIT_REGISTER StatusBlkNicAddr; + + /* Flow attention registers. */ + T3_32BIT_REGISTER FlowAttn; + + /* Unused space. */ + LM_UINT8 Unused3[4]; + + T3_32BIT_REGISTER NicJumboRcvBdConIdx; + T3_32BIT_REGISTER NicStdRcvBdConIdx; + T3_32BIT_REGISTER NicMiniRcvBdConIdx; + + /* Unused space. */ + LM_UINT8 Unused4[36]; + + T3_32BIT_REGISTER NicRetProdIdx[16]; + T3_32BIT_REGISTER NicSndBdConIdx[16]; + + /* Unused space. */ + LM_UINT8 Unused5[768]; +} T3_HOST_COALESCING, *PT3_HOST_COALESCING; + + + +/******************************************************************************/ +/* Memory arbiter registers. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; +#define T3_MEM_ARBITER_MODE_RESET BIT_0 +#define T3_MEM_ARBITER_MODE_ENABLE BIT_1 + + T3_32BIT_REGISTER Status; + + T3_32BIT_REGISTER ArbTrapAddrLow; + T3_32BIT_REGISTER ArbTrapAddrHigh; + + /* Unused space. */ + LM_UINT8 Unused[1008]; +} T3_MEM_ARBITER, *PT3_MEM_ARBITER; + + + +/******************************************************************************/ +/* Buffer manager control register. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; + #define BUFMGR_MODE_RESET BIT_0 + #define BUFMGR_MODE_ENABLE BIT_1 + #define BUFMGR_MODE_ATTN_ENABLE BIT_2 + #define BUFMGR_MODE_BM_TEST BIT_3 + #define BUFMGR_MODE_MBUF_LOW_ATTN_ENABLE BIT_4 + + T3_32BIT_REGISTER Status; + #define BUFMGR_STATUS_ERROR BIT_2 + #define BUFMGR_STATUS_MBUF_LOW BIT_4 + + T3_32BIT_REGISTER MbufPoolAddr; + T3_32BIT_REGISTER MbufPoolSize; + T3_32BIT_REGISTER MbufReadDmaLowWaterMark; + T3_32BIT_REGISTER MbufMacRxLowWaterMark; + T3_32BIT_REGISTER MbufHighWaterMark; + + T3_32BIT_REGISTER RxCpuMbufAllocReq; + #define BUFMGR_MBUF_ALLOC_BIT BIT_31 + T3_32BIT_REGISTER RxCpuMbufAllocResp; + T3_32BIT_REGISTER TxCpuMbufAllocReq; + T3_32BIT_REGISTER TxCpuMbufAllocResp; + + T3_32BIT_REGISTER DmaDescPoolAddr; + T3_32BIT_REGISTER DmaDescPoolSize; + T3_32BIT_REGISTER DmaLowWaterMark; + T3_32BIT_REGISTER DmaHighWaterMark; + + T3_32BIT_REGISTER RxCpuDmaAllocReq; + T3_32BIT_REGISTER RxCpuDmaAllocResp; + T3_32BIT_REGISTER TxCpuDmaAllocReq; + T3_32BIT_REGISTER TxCpuDmaAllocResp; + + T3_32BIT_REGISTER Hwdiag[3]; + + /* Unused space. */ + LM_UINT8 Unused[936]; +} T3_BUFFER_MANAGER, *PT3_BUFFER_MANAGER; + + + +/******************************************************************************/ +/* Read DMA control registers. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; + #define DMA_READ_MODE_RESET BIT_0 + #define DMA_READ_MODE_ENABLE BIT_1 + #define DMA_READ_MODE_TARGET_ABORT_ATTN_ENABLE BIT_2 + #define DMA_READ_MODE_MASTER_ABORT_ATTN_ENABLE BIT_3 + #define DMA_READ_MODE_PARITY_ERROR_ATTN_ENABLE BIT_4 + #define DMA_READ_MODE_ADDR_OVERFLOW_ATTN_ENABLE BIT_5 + #define DMA_READ_MODE_FIFO_OVERRUN_ATTN_ENABLE BIT_6 + #define DMA_READ_MODE_FIFO_UNDERRUN_ATTN_ENABLE BIT_7 + #define DMA_READ_MODE_FIFO_OVERREAD_ATTN_ENABLE BIT_8 + #define DMA_READ_MODE_LONG_READ_ATTN_ENABLE BIT_9 + #define DMA_READ_MODE_MULTI_SPLIT_ENABLE BIT_11 + #define DMA_READ_MODE_MULTI_SPLIT_RESET BIT_12 + #define DMA_READ_MODE_FIFO_SIZE_128 BIT_17 + #define DMA_READ_MODE_FIFO_LONG_BURST (BIT_16 | BIT_17) + + T3_32BIT_REGISTER Status; + #define DMA_READ_STATUS_TARGET_ABORT_ATTN BIT_2 + #define DMA_READ_STATUS_MASTER_ABORT_ATTN BIT_3 + #define DMA_READ_STATUS_PARITY_ERROR_ATTN BIT_4 + #define DMA_READ_STATUS_ADDR_OVERFLOW_ATTN BIT_5 + #define DMA_READ_STATUS_FIFO_OVERRUN_ATTN BIT_6 + #define DMA_READ_STATUS_FIFO_UNDERRUN_ATTN BIT_7 + #define DMA_READ_STATUS_FIFO_OVERREAD_ATTN BIT_8 + #define DMA_READ_STATUS_LONG_READ_ATTN BIT_9 + + /* Unused space. */ + LM_UINT8 Unused[1016]; +} T3_DMA_READ, *PT3_DMA_READ; + +#if defined(PC) +#undef PC +#define PC pc +#endif + +typedef union T3_CPU +{ + struct + { + T3_32BIT_REGISTER mode; + #define CPU_MODE_HALT BIT_10 + #define CPU_MODE_RESET BIT_0 + T3_32BIT_REGISTER state; + T3_32BIT_REGISTER EventMask; + T3_32BIT_REGISTER reserved1[4]; + T3_32BIT_REGISTER PC; + T3_32BIT_REGISTER Instruction; + T3_32BIT_REGISTER SpadUnderflow; + T3_32BIT_REGISTER WatchdogClear; + T3_32BIT_REGISTER WatchdogVector; + T3_32BIT_REGISTER WatchdogSavedPC; + T3_32BIT_REGISTER HardwareBp; + T3_32BIT_REGISTER reserved2[3]; + T3_32BIT_REGISTER WatchdogSavedState; + T3_32BIT_REGISTER LastBrchAddr; + T3_32BIT_REGISTER SpadUnderflowSet; + T3_32BIT_REGISTER reserved3[(0x200-0x50)/4]; + T3_32BIT_REGISTER Regs[32]; + T3_32BIT_REGISTER reserved4[(0x400-0x280)/4]; + }reg; +}T3_CPU, *PT3_CPU; + +/******************************************************************************/ +/* Write DMA control registers. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; + #define DMA_WRITE_MODE_RESET BIT_0 + #define DMA_WRITE_MODE_ENABLE BIT_1 + #define DMA_WRITE_MODE_TARGET_ABORT_ATTN_ENABLE BIT_2 + #define DMA_WRITE_MODE_MASTER_ABORT_ATTN_ENABLE BIT_3 + #define DMA_WRITE_MODE_PARITY_ERROR_ATTN_ENABLE BIT_4 + #define DMA_WRITE_MODE_ADDR_OVERFLOW_ATTN_ENABLE BIT_5 + #define DMA_WRITE_MODE_FIFO_OVERRUN_ATTN_ENABLE BIT_6 + #define DMA_WRITE_MODE_FIFO_UNDERRUN_ATTN_ENABLE BIT_7 + #define DMA_WRITE_MODE_FIFO_OVERREAD_ATTN_ENABLE BIT_8 + #define DMA_WRITE_MODE_LONG_READ_ATTN_ENABLE BIT_9 + #define DMA_WRITE_MODE_RECEIVE_ACCELERATE BIT_10 + + T3_32BIT_REGISTER Status; + #define DMA_WRITE_STATUS_TARGET_ABORT_ATTN BIT_2 + #define DMA_WRITE_STATUS_MASTER_ABORT_ATTN BIT_3 + #define DMA_WRITE_STATUS_PARITY_ERROR_ATTN BIT_4 + #define DMA_WRITE_STATUS_ADDR_OVERFLOW_ATTN BIT_5 + #define DMA_WRITE_STATUS_FIFO_OVERRUN_ATTN BIT_6 + #define DMA_WRITE_STATUS_FIFO_UNDERRUN_ATTN BIT_7 + #define DMA_WRITE_STATUS_FIFO_OVERREAD_ATTN BIT_8 + #define DMA_WRITE_STATUS_LONG_READ_ATTN BIT_9 + + /* Unused space. */ + LM_UINT8 Unused[1016]; +} T3_DMA_WRITE, *PT3_DMA_WRITE; + + + +/******************************************************************************/ +/* Mailbox registers. */ +/******************************************************************************/ + +typedef struct { + /* Interrupt mailbox registers. */ + T3_64BIT_REGISTER Interrupt[4]; + + /* General mailbox registers. */ + T3_64BIT_REGISTER General[8]; + + /* Reload statistics mailbox. */ + T3_64BIT_REGISTER ReloadStat; + + /* Receive BD ring producer index registers. */ + T3_64BIT_REGISTER RcvStdProdIdx; + T3_64BIT_REGISTER RcvJumboProdIdx; + T3_64BIT_REGISTER RcvMiniProdIdx; + + /* Receive return ring consumer index registers. */ + T3_64BIT_REGISTER RcvRetConIdx[16]; + + /* Send BD ring host producer index registers. */ + T3_64BIT_REGISTER SendHostProdIdx[16]; + + /* Send BD ring nic producer index registers. */ + T3_64BIT_REGISTER SendNicProdIdx[16]; +}T3_MAILBOX, *PT3_MAILBOX; + +typedef struct { + T3_MAILBOX Mailbox; + + /* Priority mailbox registers. */ + T3_32BIT_REGISTER HighPriorityEventVector; + T3_32BIT_REGISTER HighPriorityEventMask; + T3_32BIT_REGISTER LowPriorityEventVector; + T3_32BIT_REGISTER LowPriorityEventMask; + + /* Unused space. */ + LM_UINT8 Unused[496]; +} T3_GRC_MAILBOX, *PT3_GRC_MAILBOX; + + +/******************************************************************************/ +/* Flow through queues. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Reset; + + LM_UINT8 Unused[12]; + + T3_32BIT_REGISTER DmaNormalReadFtqCtrl; + T3_32BIT_REGISTER DmaNormalReadFtqFullCnt; + T3_32BIT_REGISTER DmaNormalReadFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER DmaNormalReadFtqFifoWritePeek; + + T3_32BIT_REGISTER DmaHighReadFtqCtrl; + T3_32BIT_REGISTER DmaHighReadFtqFullCnt; + T3_32BIT_REGISTER DmaHighReadFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER DmaHighReadFtqFifoWritePeek; + + T3_32BIT_REGISTER DmaCompDiscardFtqCtrl; + T3_32BIT_REGISTER DmaCompDiscardFtqFullCnt; + T3_32BIT_REGISTER DmaCompDiscardFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER DmaCompDiscardFtqFifoWritePeek; + + T3_32BIT_REGISTER SendBdCompFtqCtrl; + T3_32BIT_REGISTER SendBdCompFtqFullCnt; + T3_32BIT_REGISTER SendBdCompFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER SendBdCompFtqFifoWritePeek; + + T3_32BIT_REGISTER SendDataInitiatorFtqCtrl; + T3_32BIT_REGISTER SendDataInitiatorFtqFullCnt; + T3_32BIT_REGISTER SendDataInitiatorFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER SendDataInitiatorFtqFifoWritePeek; + + T3_32BIT_REGISTER DmaNormalWriteFtqCtrl; + T3_32BIT_REGISTER DmaNormalWriteFtqFullCnt; + T3_32BIT_REGISTER DmaNormalWriteFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER DmaNormalWriteFtqFifoWritePeek; + + T3_32BIT_REGISTER DmaHighWriteFtqCtrl; + T3_32BIT_REGISTER DmaHighWriteFtqFullCnt; + T3_32BIT_REGISTER DmaHighWriteFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER DmaHighWriteFtqFifoWritePeek; + + T3_32BIT_REGISTER SwType1FtqCtrl; + T3_32BIT_REGISTER SwType1FtqFullCnt; + T3_32BIT_REGISTER SwType1FtqFifoEnqueueDequeue; + T3_32BIT_REGISTER SwType1FtqFifoWritePeek; + + T3_32BIT_REGISTER SendDataCompFtqCtrl; + T3_32BIT_REGISTER SendDataCompFtqFullCnt; + T3_32BIT_REGISTER SendDataCompFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER SendDataCompFtqFifoWritePeek; + + T3_32BIT_REGISTER HostCoalesceFtqCtrl; + T3_32BIT_REGISTER HostCoalesceFtqFullCnt; + T3_32BIT_REGISTER HostCoalesceFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER HostCoalesceFtqFifoWritePeek; + + T3_32BIT_REGISTER MacTxFtqCtrl; + T3_32BIT_REGISTER MacTxFtqFullCnt; + T3_32BIT_REGISTER MacTxFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER MacTxFtqFifoWritePeek; + + T3_32BIT_REGISTER MbufClustFreeFtqCtrl; + T3_32BIT_REGISTER MbufClustFreeFtqFullCnt; + T3_32BIT_REGISTER MbufClustFreeFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER MbufClustFreeFtqFifoWritePeek; + + T3_32BIT_REGISTER RcvBdCompFtqCtrl; + T3_32BIT_REGISTER RcvBdCompFtqFullCnt; + T3_32BIT_REGISTER RcvBdCompFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER RcvBdCompFtqFifoWritePeek; + + T3_32BIT_REGISTER RcvListPlmtFtqCtrl; + T3_32BIT_REGISTER RcvListPlmtFtqFullCnt; + T3_32BIT_REGISTER RcvListPlmtFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER RcvListPlmtFtqFifoWritePeek; + + T3_32BIT_REGISTER RcvDataBdInitiatorFtqCtrl; + T3_32BIT_REGISTER RcvDataBdInitiatorFtqFullCnt; + T3_32BIT_REGISTER RcvDataBdInitiatorFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER RcvDataBdInitiatorFtqFifoWritePeek; + + T3_32BIT_REGISTER RcvDataCompFtqCtrl; + T3_32BIT_REGISTER RcvDataCompFtqFullCnt; + T3_32BIT_REGISTER RcvDataCompFtqFifoEnqueueDequeue; + T3_32BIT_REGISTER RcvDataCompFtqFifoWritePeek; + + T3_32BIT_REGISTER SwType2FtqCtrl; + T3_32BIT_REGISTER SwType2FtqFullCnt; + T3_32BIT_REGISTER SwType2FtqFifoEnqueueDequeue; + T3_32BIT_REGISTER SwType2FtqFifoWritePeek; + + /* Unused space. */ + LM_UINT8 Unused2[736]; +} T3_FTQ, *PT3_FTQ; + + + +/******************************************************************************/ +/* Message signaled interrupt registers. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; +#define MSI_MODE_RESET BIT_0 +#define MSI_MODE_ENABLE BIT_1 + T3_32BIT_REGISTER Status; + + T3_32BIT_REGISTER MsiFifoAccess; + + /* Unused space. */ + LM_UINT8 Unused[1012]; +} T3_MSG_SIGNALED_INT, *PT3_MSG_SIGNALED_INT; + + + +/******************************************************************************/ +/* DMA Completion registes. */ +/******************************************************************************/ + +typedef struct { + T3_32BIT_REGISTER Mode; + #define DMA_COMP_MODE_RESET BIT_0 + #define DMA_COMP_MODE_ENABLE BIT_1 + + /* Unused space. */ + LM_UINT8 Unused[1020]; +} T3_DMA_COMPLETION, *PT3_DMA_COMPLETION; + + + +/******************************************************************************/ +/* GRC registers. */ +/******************************************************************************/ + +typedef struct { + /* Mode control register. */ + T3_32BIT_REGISTER Mode; + #define GRC_MODE_UPDATE_ON_COALESCING BIT_0 + #define GRC_MODE_BYTE_SWAP_NON_FRAME_DATA BIT_1 + #define GRC_MODE_WORD_SWAP_NON_FRAME_DATA BIT_2 + #define GRC_MODE_BYTE_SWAP_DATA BIT_4 + #define GRC_MODE_WORD_SWAP_DATA BIT_5 + #define GRC_MODE_SPLIT_HEADER_MODE BIT_8 + #define GRC_MODE_NO_FRAME_CRACKING BIT_9 + #define GRC_MODE_INCLUDE_CRC BIT_10 + #define GRC_MODE_ALLOW_BAD_FRAMES BIT_11 + #define GRC_MODE_NO_INTERRUPT_ON_SENDS BIT_13 + #define GRC_MODE_NO_INTERRUPT_ON_RECEIVE BIT_14 + #define GRC_MODE_FORCE_32BIT_PCI_BUS_MODE BIT_15 + #define GRC_MODE_HOST_STACK_UP BIT_16 + #define GRC_MODE_HOST_SEND_BDS BIT_17 + #define GRC_MODE_TX_NO_PSEUDO_HEADER_CHKSUM BIT_20 + #define GRC_MODE_NVRAM_WRITE_ENABLE BIT_21 + #define GRC_MODE_RX_NO_PSEUDO_HEADER_CHKSUM BIT_23 + #define GRC_MODE_INT_ON_TX_CPU_ATTN BIT_24 + #define GRC_MODE_INT_ON_RX_CPU_ATTN BIT_25 + #define GRC_MODE_INT_ON_MAC_ATTN BIT_26 + #define GRC_MODE_INT_ON_DMA_ATTN BIT_27 + #define GRC_MODE_INT_ON_FLOW_ATTN BIT_28 + #define GRC_MODE_4X_NIC_BASED_SEND_RINGS BIT_29 + #define GRC_MODE_MULTICAST_FRAME_ENABLE BIT_30 + + /* Misc configuration register. */ + T3_32BIT_REGISTER MiscCfg; + #define GRC_MISC_CFG_CORE_CLOCK_RESET BIT_0 + #define GRC_MISC_PRESCALAR_TIMER_MASK 0xfe + #define GRC_MISC_BD_ID_MASK 0x0001e000 + #define GRC_MISC_BD_ID_5700 0x0001e000 + #define GRC_MISC_BD_ID_5701 0x00000000 + #define GRC_MISC_BD_ID_5703 0x00000000 + #define GRC_MISC_BD_ID_5703S 0x00002000 + #define GRC_MISC_BD_ID_5702FE 0x00004000 + #define GRC_MISC_BD_ID_5704 0x00000000 + #define GRC_MISC_BD_ID_5704CIOBE 0x00004000 + #define GRC_MISC_BD_ID_5788 0x00010000 + #define GRC_MISC_BD_ID_5788M 0x00018000 + #define GRC_MISC_GPHY_KEEP_POWER_DURING_RESET BIT_26 + + /* Miscellaneous local control register. */ + T3_32BIT_REGISTER LocalCtrl; + #define GRC_MISC_LOCAL_CTRL_INT_ACTIVE BIT_0 + #define GRC_MISC_LOCAL_CTRL_CLEAR_INT BIT_1 + #define GRC_MISC_LOCAL_CTRL_SET_INT BIT_2 + #define GRC_MISC_LOCAL_CTRL_INT_ON_ATTN BIT_3 + + #define GRC_MISC_LOCAL_CTRL_GPIO_INPUT3 BIT_5 + #define GRC_MISC_LOCAL_CTRL_GPIO_OE3 BIT_6 + #define GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT3 BIT_7 + + #define GRC_MISC_LOCAL_CTRL_GPIO_INPUT0 BIT_8 + #define GRC_MISC_LOCAL_CTRL_GPIO_INPUT1 BIT_9 + #define GRC_MISC_LOCAL_CTRL_GPIO_INPUT2 BIT_10 + #define GRC_MISC_LOCAL_CTRL_GPIO_OE0 BIT_11 + #define GRC_MISC_LOCAL_CTRL_GPIO_OE1 BIT_12 + #define GRC_MISC_LOCAL_CTRL_GPIO_OE2 BIT_13 + #define GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT0 BIT_14 + #define GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT1 BIT_15 + #define GRC_MISC_LOCAL_CTRL_GPIO_OUTPUT2 BIT_16 + #define GRC_MISC_LOCAL_CTRL_ENABLE_EXT_MEMORY BIT_17 + #define GRC_MISC_LOCAL_CTRL_BANK_SELECT BIT_21 + #define GRC_MISC_LOCAL_CTRL_SSRAM_TYPE BIT_22 + + #define GRC_MISC_MEMSIZE_256K 0 + #define GRC_MISC_MEMSIZE_512K (1 << 18) + #define GRC_MISC_MEMSIZE_1024K (2 << 18) + #define GRC_MISC_MEMSIZE_2048K (3 << 18) + #define GRC_MISC_MEMSIZE_4096K (4 << 18) + #define GRC_MISC_MEMSIZE_8192K (5 << 18) + #define GRC_MISC_MEMSIZE_16M (6 << 18) + #define GRC_MISC_LOCAL_CTRL_AUTO_SEEPROM BIT_24 + + + T3_32BIT_REGISTER Timer; + + T3_32BIT_REGISTER RxCpuEvent; + T3_32BIT_REGISTER RxTimerRef; + T3_32BIT_REGISTER RxCpuSemaphore; + T3_32BIT_REGISTER RemoteRxCpuAttn; + + T3_32BIT_REGISTER TxCpuEvent; + T3_32BIT_REGISTER TxTimerRef; + T3_32BIT_REGISTER TxCpuSemaphore; + T3_32BIT_REGISTER RemoteTxCpuAttn; + + T3_64BIT_REGISTER MemoryPowerUp; + + T3_32BIT_REGISTER EepromAddr; + #define SEEPROM_ADDR_WRITE 0 + #define SEEPROM_ADDR_READ (1 << 31) + #define SEEPROM_ADDR_RW_MASK 0x80000000 + #define SEEPROM_ADDR_COMPLETE (1 << 30) + #define SEEPROM_ADDR_FSM_RESET (1 << 29) + #define SEEPROM_ADDR_DEV_ID(x) (x << 26) + #define SEEPROM_ADDR_DEV_ID_MASK 0x1c000000 + #define SEEPROM_ADDR_START (1 << 25) + #define SEEPROM_ADDR_CLK_PERD(x) (x << 16) + #define SEEPROM_ADDR_ADDRESS(x) (x & 0xfffc) + #define SEEPROM_ADDR_ADDRESS_MASK 0x0000ffff + + #define SEEPROM_CLOCK_PERIOD 60 + #define SEEPROM_CHIP_SIZE (64 * 1024) + + T3_32BIT_REGISTER EepromData; + T3_32BIT_REGISTER EepromCtrl; + + T3_32BIT_REGISTER MdiCtrl; + T3_32BIT_REGISTER SepromDelay; + + /* Unused space. */ + LM_UINT8 Unused[948]; +} T3_GRC, *PT3_GRC; + + +/******************************************************************************/ +/* NVRAM control registers. */ +/******************************************************************************/ + +typedef struct +{ + T3_32BIT_REGISTER Cmd; + #define NVRAM_CMD_RESET BIT_0 + #define NVRAM_CMD_DONE BIT_3 + #define NVRAM_CMD_DO_IT BIT_4 + #define NVRAM_CMD_WR BIT_5 + #define NVRAM_CMD_RD BIT_NONE + #define NVRAM_CMD_ERASE BIT_6 + #define NVRAM_CMD_FIRST BIT_7 + #define NVRAM_CMD_LAST BIT_8 + #define NVRAM_CMD_WRITE_ENABLE BIT_16 + #define NVRAM_CMD_WRITE_DISABLE BIT_17 + #define NVRAM_CMD_EN_WR_SR BIT_18 + #define NVRAM_CMD_DO_WR_SR BIT_19 + + T3_32BIT_REGISTER Status; + T3_32BIT_REGISTER WriteData; + + T3_32BIT_REGISTER Addr; + #define NVRAM_ADDRESS_MASK 0xffffff + + T3_32BIT_REGISTER ReadData; + + /* Flash config 1 register. */ + T3_32BIT_REGISTER Config1; + #define FLASH_INTERFACE_ENABLE BIT_0 + #define FLASH_SSRAM_BUFFERED_MODE BIT_1 + #define FLASH_PASS_THRU_MODE BIT_2 + #define FLASH_BIT_BANG_MODE BIT_3 + #define FLASH_STATUS_BITS_MASK (BIT_4 | BIT_5 | BIT_6) + #define FLASH_SIZE BIT_25 + #define FLASH_COMPAT_BYPASS BIT_31 + #define FLASH_VENDOR_MASK (BIT_25 | BIT_24 | BIT_1 | BIT_0) + #define FLASH_VENDOR_ATMEL_EEPROM BIT_25 + #define FLASH_VENDOR_ATMEL_FLASH_BUFFERED (BIT_25 | BIT_1 | BIT_0) + #define FLASH_VENDOR_ATMEL_FLASH_UNBUFFERED (BIT_1 | BIT_0) + #define FLASH_VENDOR_ST (BIT_25 | BIT_24 | BIT_0) + #define FLASH_VENDOR_SAIFUN (BIT_24 | BIT_1 | BIT_0) + #define FLASH_VENDOR_SST_SMALL BIT_0 + #define FLASH_VENDOR_SST_LARGE (BIT_25 | BIT_0) + + #define BUFFERED_FLASH (FLASH_INTERFACE_ENABLE | FLASH_SSRAM_BUFFERED_MODE) + + /* Buffered flash (Atmel: AT45DB011B) specific information */ + #define BUFFERED_FLASH_PAGE_POS 9 + #define BUFFERED_FLASH_BYTE_ADDR_MASK ((1<Flags & UNDI_FIX_FLAG) ? \ + LM_RegWrInd(pDevice, OFFSETOF(T3_STD_MEM_MAP, OffsetName)+0x5600, \ + Value32) : \ + (void) MM_MEMWRITEL(&((pDevice)->pMemView->OffsetName), Value32) + +#define MB_REG_RD(pDevice, OffsetName) \ + (((pDevice)->Flags & UNDI_FIX_FLAG) ? \ + LM_RegRdInd(pDevice, OFFSETOF(T3_STD_MEM_MAP, OffsetName)+0x5600) : \ + MM_MEMREADL(&((pDevice)->pMemView->OffsetName))) + +#define REG_RD(pDevice, OffsetName) \ + LM_RegRd(pDevice, OFFSETOF(T3_STD_MEM_MAP, OffsetName)) + +#define REG_RD_BACK(pDevice, OffsetName) \ + LM_RegRdBack(pDevice, OFFSETOF(T3_STD_MEM_MAP, OffsetName)) + +#define REG_WR(pDevice, OffsetName, Value32) \ + LM_RegWr(pDevice, OFFSETOF(T3_STD_MEM_MAP, OffsetName), Value32, TRUE) + +#define RAW_REG_WR(pDevice, OffsetName, Value32) \ + LM_RegWr(pDevice, OFFSETOF(T3_STD_MEM_MAP, OffsetName), Value32, FALSE) + +#define REG_RD_OFFSET(pDevice, Offset) \ + MM_MEMREADL(((LM_UINT8 *) (pDevice)->pMemView + Offset)) + +#define REG_WR_OFFSET(pDevice, Offset, Value32) \ + MM_MEMWRITEL(((LM_UINT8 *) (pDevice)->pMemView + Offset), Value32) + +#define MEM_RD(pDevice, AddrName) \ + LM_MemRdInd(pDevice, OFFSETOF(T3_FIRST_32K_SRAM, AddrName)) +#define MEM_WR(pDevice, AddrName, Value32) \ + LM_MemWrInd(pDevice, OFFSETOF(T3_FIRST_32K_SRAM, AddrName), Value32) + +#define MEM_RD_OFFSET(pDevice, Offset) \ + LM_MemRdInd(pDevice, Offset) +#define MEM_WR_OFFSET(pDevice, Offset, Value32) \ + LM_MemWrInd(pDevice, Offset, Value32) + + +#endif /* TIGON3_H */ +