This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "IPFire 2.x development tree".
The branch, master has been updated via 69c59a9e29c03b9ededdadfeef4372d7a6a970e9 (commit) via c7337ce5ed48add3c80455796e0e1a954a462f6f (commit) from fac293969ade08b669efc32ad05892f0bc537165 (commit)
Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below.
- Log ----------------------------------------------------------------- commit 69c59a9e29c03b9ededdadfeef4372d7a6a970e9 Author: Arne Fitzenreiter arne_f@ipfire.org Date: Mon Feb 8 12:05:23 2010 +0100
Fix watchdog backup include.
commit c7337ce5ed48add3c80455796e0e1a954a462f6f Author: Arne Fitzenreiter arne_f@ipfire.org Date: Mon Feb 8 12:03:51 2010 +0100
Add ET131x ethernet driver.
-----------------------------------------------------------------------
Summary of changes: config/backup/includes/watchdog | 2 +- config/rootfiles/core/37/filelists/files | 2 + lfs/{atl1c => et131x} | 4 +- lfs/watchdog | 2 +- make.sh | 2 + src/et131x/Kconfig | 18 + src/et131x/Makefile | 25 + src/et131x/README | 25 + src/et131x/et1310_address_map.h | 2399 ++++++++++++++++++++++++++++++ src/et131x/et1310_eeprom.c | 480 ++++++ src/et131x/et1310_eeprom.h | 89 ++ src/et131x/et1310_jagcore.c | 220 +++ src/et131x/et1310_jagcore.h | 112 ++ src/et131x/et1310_mac.c | 792 ++++++++++ src/et131x/et1310_mac.h | 93 ++ src/et131x/et1310_phy.c | 1281 ++++++++++++++++ src/et131x/et1310_phy.h | 910 +++++++++++ src/et131x/et1310_pm.c | 207 +++ src/et131x/et1310_pm.h | 125 ++ src/et131x/et1310_rx.c | 1391 +++++++++++++++++ src/et131x/et1310_rx.h | 373 +++++ src/et131x/et1310_tx.c | 1525 +++++++++++++++++++ src/et131x/et1310_tx.h | 242 +++ src/et131x/et131x_adapter.h | 347 +++++ src/et131x/et131x_config.c | 325 ++++ src/et131x/et131x_config.h | 67 + src/et131x/et131x_debug.c | 218 +++ src/et131x/et131x_debug.h | 201 +++ src/et131x/et131x_defs.h | 128 ++ src/et131x/et131x_initpci.c | 1046 +++++++++++++ src/et131x/et131x_initpci.h | 73 + src/et131x/et131x_isr.c | 488 ++++++ src/et131x/et131x_isr.h | 65 + src/et131x/et131x_netdev.c | 856 +++++++++++ src/et131x/et131x_netdev.h | 64 + src/et131x/et131x_version.h | 81 + 36 files changed, 14274 insertions(+), 4 deletions(-) copy lfs/{atl1c => et131x} (96%) create mode 100644 src/et131x/Kconfig create mode 100644 src/et131x/Makefile create mode 100644 src/et131x/README create mode 100644 src/et131x/et1310_address_map.h create mode 100644 src/et131x/et1310_eeprom.c create mode 100644 src/et131x/et1310_eeprom.h create mode 100644 src/et131x/et1310_jagcore.c create mode 100644 src/et131x/et1310_jagcore.h create mode 100644 src/et131x/et1310_mac.c create mode 100644 src/et131x/et1310_mac.h create mode 100644 src/et131x/et1310_phy.c create mode 100644 src/et131x/et1310_phy.h create mode 100644 src/et131x/et1310_pm.c create mode 100644 src/et131x/et1310_pm.h create mode 100644 src/et131x/et1310_rx.c create mode 100644 src/et131x/et1310_rx.h create mode 100644 src/et131x/et1310_tx.c create mode 100644 src/et131x/et1310_tx.h create mode 100644 src/et131x/et131x_adapter.h create mode 100644 src/et131x/et131x_config.c create mode 100644 src/et131x/et131x_config.h create mode 100644 src/et131x/et131x_debug.c create mode 100644 src/et131x/et131x_debug.h create mode 100644 src/et131x/et131x_defs.h create mode 100644 src/et131x/et131x_initpci.c create mode 100644 src/et131x/et131x_initpci.h create mode 100644 src/et131x/et131x_isr.c create mode 100644 src/et131x/et131x_isr.h create mode 100644 src/et131x/et131x_netdev.c create mode 100644 src/et131x/et131x_netdev.h create mode 100644 src/et131x/et131x_version.h
Difference in files: diff --git a/config/backup/includes/watchdog b/config/backup/includes/watchdog index a708771..3ef1359 100644 --- a/config/backup/includes/watchdog +++ b/config/backup/includes/watchdog @@ -1 +1 @@ -etc/watchdog.conf +/etc/watchdog.conf diff --git a/config/rootfiles/core/37/filelists/files b/config/rootfiles/core/37/filelists/files index f981e83..e275dd3 100644 --- a/config/rootfiles/core/37/filelists/files +++ b/config/rootfiles/core/37/filelists/files @@ -5,4 +5,6 @@ lib/modules/2.6.27.42-ipfire/mISDN/hfcsusb.ko lib/modules/2.6.27.42-ipfire-xen/mISDN/hfcsusb.ko lib/modules/2.6.27.42-ipfire/kernel/driver/hwmon/coretemp.ko lib/modules/2.6.27.42-ipfire-xen/kernel/driver/hwmon/coretemp.ko +lib/modules/2.6.27.42-ipfire/kernel/driver/net/e131x.ko +lib/modules/2.6.27.42-ipfire-xen/kernel/driver/net/e131x.ko srv/web/ipfire/cgi-bin/urlfilter.cgi diff --git a/lfs/et131x b/lfs/et131x new file mode 100644 index 0000000..f23701b --- /dev/null +++ b/lfs/et131x @@ -0,0 +1,61 @@ +############################################################################### +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2009 Michael Tremer & Christian Schmidt # +# # +# 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 3 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. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see http://www.gnu.org/licenses/. # +# # +############################################################################### + +############################################################################### +# Definitions +############################################################################### + +include Config + +ifeq "$(XEN)" "1" + VERSUFIX = ipfire-xen +else + VERSUFIX = ipfire +endif + +VER = ipfire-1 + +THISAPP = et131x +DIR_APP = $(DIR_SRC)/$(THISAPP) +TARGET = $(DIR_INFO)/$(THISAPP)-kmod-$(KVER)-$(VERSUFIX) + +############################################################################### +# Top-level Rules +############################################################################### + +install : $(TARGET) + +check : + +download : + +md5 : + +############################################################################### +# Installation Details +############################################################################### + +$(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects)) + @$(PREBUILD) + @rm -rf $(DIR_APP) && cp -r $(DIR_SRC)/src/$(THISAPP) $(DIR_APP) + cd $(DIR_APP) && make -C /lib/modules/$(KVER)-$(VERSUFIX)/build/ SUBDIRS=$(DIR_APP) modules + cd $(DIR_APP) && install -m 644 et131x.ko /lib/modules/$(KVER)-$(VERSUFIX)/kernel/drivers/net + @rm -rf $(DIR_APP) + @$(POSTBUILD) diff --git a/lfs/watchdog b/lfs/watchdog index c8b0b45..fbdb82a 100644 --- a/lfs/watchdog +++ b/lfs/watchdog @@ -32,7 +32,7 @@ DL_FROM = $(URL_IPFIRE) DIR_APP = $(DIR_SRC)/$(THISAPP) TARGET = $(DIR_INFO)/$(THISAPP) PROG = watchdog -PAK_VER = 1 +PAK_VER = 2
DEPS = ""
diff --git a/make.sh b/make.sh index 99ab986..6229cd1 100755 --- a/make.sh +++ b/make.sh @@ -345,6 +345,7 @@ buildipfire() { ipfiremake atl2 XEN=1 ipfiremake hso XEN=1 ipfiremake e1000e XEN=1 + ipfiremake et131x XEN=1 ipfiremake r8101 XEN=1 ipfiremake r8169 XEN=1 ipfiremake r8168 XEN=1 @@ -362,6 +363,7 @@ buildipfire() { ipfiremake atl2 ipfiremake hso ipfiremake e1000e + ipfiremake et131x ipfiremake r8101 ipfiremake r8169 ipfiremake r8168 diff --git a/src/et131x/Kconfig b/src/et131x/Kconfig new file mode 100644 index 0000000..e11cf34 --- /dev/null +++ b/src/et131x/Kconfig @@ -0,0 +1,18 @@ +config ET131X + tristate "Agere ET-1310 Gigabit Ethernet support" + depends on NETDEV_1000 && PCI + default n + ---help--- + This driver supports Agere ET-1310 ethernet adapters. + + To compile this driver as a module, choose M here. The module + will be called et131x. + +config ET131X_DEBUG + bool "Enable et131x debugging" + depends on ET131X + default n + ---help--- + Say Y for detailed debug information. + + If in doubt, say N. diff --git a/src/et131x/Makefile b/src/et131x/Makefile new file mode 100644 index 0000000..71640ff --- /dev/null +++ b/src/et131x/Makefile @@ -0,0 +1,25 @@ +KSRC ?= /lib/modules/$(shell uname -r)/build + +obj-m = et131x.o + +et131x-objs := et1310_eeprom.o \ + et1310_jagcore.o \ + et1310_mac.o \ + et1310_phy.o \ + et1310_pm.o \ + et1310_rx.o \ + et1310_tx.o \ + et131x_config.o \ + et131x_debug.o \ + et131x_initpci.o \ + et131x_isr.o \ + et131x_netdev.o + +all: + $(MAKE) -C $(KSRC) SUBDIRS=$(PWD) modules + +clean: + rm -rf *.ko *.mod.* *.o .*.cmd .tmp_versions Module.symvers + +distclean: clean + rm -rf cscope.* *~ diff --git a/src/et131x/README b/src/et131x/README new file mode 100644 index 0000000..28752a5 --- /dev/null +++ b/src/et131x/README @@ -0,0 +1,25 @@ +This is a driver for the ET1310 network device. + +Based on the driver found at https://sourceforge.net/projects/et131x/ + +Cleaned up immensely by Olaf Hartman o.hartmann@telovital.com and Christoph +Hellwig hch@infradead.org + +Note, the powermanagement options were removed from the vendor provided +driver as they did not build properly at the time. + +TODO: + - kernel coding style cleanups + - forward port for latest network driver changes + - kill useless typecasts (e.g. in et1310_phy.c) + - alloc_etherdev is initializing memory with zero?!? + - add_timer call in et131x_netdev.c is correct? + - Add power saving functionality (suspend, sleep, resume) + - Implement a few more kernel Parameter (set mac ) + +Please send patches to: + Greg Kroah-Hartman gregkh@suse.de + +And Cc: Olaf Hartmann o.hartmann@telovital.com as he has this device and can +test any changes. + diff --git a/src/et131x/et1310_address_map.h b/src/et131x/et1310_address_map.h new file mode 100644 index 0000000..3c85999 --- /dev/null +++ b/src/et131x/et1310_address_map.h @@ -0,0 +1,2399 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et1310_address_map.h - Contains the register mapping for the ET1310 + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#ifndef _ET1310_ADDRESS_MAP_H_ +#define _ET1310_ADDRESS_MAP_H_ + + +/* START OF GLOBAL REGISTER ADDRESS MAP */ + +typedef union _Q_ADDR_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused:22; // bits 10-31 + u32 addr:10; // bits 0-9 +#else + u32 addr:10; // bits 0-9 + u32 unused:22; // bits 10-31 +#endif + } bits; +} Q_ADDR_t, *PQ_ADDR_t; + +/* + * structure for tx queue start address reg in global address map + * located at address 0x0000 + * Defined earlier (Q_ADDR_t) + */ + +/* + * structure for tx queue end address reg in global address map + * located at address 0x0004 + * Defined earlier (Q_ADDR_t) + */ + +/* + * structure for rx queue start address reg in global address map + * located at address 0x0008 + * Defined earlier (Q_ADDR_t) + */ + +/* + * structure for rx queue end address reg in global address map + * located at address 0x000C + * Defined earlier (Q_ADDR_t) + */ + +/* + * structure for power management control status reg in global address map + * located at address 0x0010 + */ +typedef union _PM_CSR_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused:22; // bits 10-31 + u32 pm_jagcore_rx_rdy:1; // bit 9 + u32 pm_jagcore_tx_rdy:1; // bit 8 + u32 pm_phy_lped_en:1; // bit 7 + u32 pm_phy_sw_coma:1; // bit 6 + u32 pm_rxclk_gate:1; // bit 5 + u32 pm_txclk_gate:1; // bit 4 + u32 pm_sysclk_gate:1; // bit 3 + u32 pm_jagcore_rx_en:1; // bit 2 + u32 pm_jagcore_tx_en:1; // bit 1 + u32 pm_gigephy_en:1; // bit 0 +#else + u32 pm_gigephy_en:1; // bit 0 + u32 pm_jagcore_tx_en:1; // bit 1 + u32 pm_jagcore_rx_en:1; // bit 2 + u32 pm_sysclk_gate:1; // bit 3 + u32 pm_txclk_gate:1; // bit 4 + u32 pm_rxclk_gate:1; // bit 5 + u32 pm_phy_sw_coma:1; // bit 6 + u32 pm_phy_lped_en:1; // bit 7 + u32 pm_jagcore_tx_rdy:1; // bit 8 + u32 pm_jagcore_rx_rdy:1; // bit 9 + u32 unused:22; // bits 10-31 +#endif + } bits; +} PM_CSR_t, *PPM_CSR_t; + +/* + * structure for interrupt status reg in global address map + * located at address 0x0018 + */ +typedef union _INTERRUPT_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused5:11; // bits 21-31 + u32 slv_timeout:1; // bit 20 + u32 mac_stat_interrupt:1; // bit 19 + u32 rxmac_interrupt:1; // bit 18 + u32 txmac_interrupt:1; // bit 17 + u32 phy_interrupt:1; // bit 16 + u32 wake_on_lan:1; // bit 15 + u32 watchdog_interrupt:1; // bit 14 + u32 unused4:4; // bits 10-13 + u32 rxdma_err:1; // bit 9 + u32 rxdma_pkt_stat_ring_low:1; // bit 8 + u32 rxdma_fb_ring1_low:1; // bit 7 + u32 rxdma_fb_ring0_low:1; // bit 6 + u32 rxdma_xfr_done:1; // bit 5 + u32 txdma_err:1; // bit 4 + u32 txdma_isr:1; // bit 3 + u32 unused3:1; // bit 2 + u32 unused2:1; // bit 1 + u32 unused1:1; // bit 0 +#else + u32 unused1:1; // bit 0 + u32 unused2:1; // bit 1 + u32 unused3:1; // bit 2 + u32 txdma_isr:1; // bit 3 + u32 txdma_err:1; // bit 4 + u32 rxdma_xfr_done:1; // bit 5 + u32 rxdma_fb_ring0_low:1; // bit 6 + u32 rxdma_fb_ring1_low:1; // bit 7 + u32 rxdma_pkt_stat_ring_low:1; // bit 8 + u32 rxdma_err:1; // bit 9 + u32 unused4:4; // bits 10-13 + u32 watchdog_interrupt:1; // bit 14 + u32 wake_on_lan:1; // bit 15 + u32 phy_interrupt:1; // bit 16 + u32 txmac_interrupt:1; // bit 17 + u32 rxmac_interrupt:1; // bit 18 + u32 mac_stat_interrupt:1; // bit 19 + u32 slv_timeout:1; // bit 20 + u32 unused5:11; // bits 21-31 +#endif + } bits; +} INTERRUPT_t, *PINTERRUPT_t; + +/* + * structure for interrupt mask reg in global address map + * located at address 0x001C + * Defined earlier (INTERRUPT_t), but 'watchdog_interrupt' is not used. + */ + +/* + * structure for interrupt alias clear mask reg in global address map + * located at address 0x0020 + * Defined earlier (INTERRUPT_t) + */ + +/* + * structure for interrupt status alias reg in global address map + * located at address 0x0024 + * Defined earlier (INTERRUPT_t) + */ + +/* + * structure for software reset reg in global address map + * located at address 0x0028 + */ +typedef union _SW_RESET_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 selfclr_disable:1; // bit 31 + u32 unused:24; // bits 7-30 + u32 mmc_sw_reset:1; // bit 6 + u32 mac_stat_sw_reset:1; // bit 5 + u32 mac_sw_reset:1; // bit 4 + u32 rxmac_sw_reset:1; // bit 3 + u32 txmac_sw_reset:1; // bit 2 + u32 rxdma_sw_reset:1; // bit 1 + u32 txdma_sw_reset:1; // bit 0 +#else + u32 txdma_sw_reset:1; // bit 0 + u32 rxdma_sw_reset:1; // bit 1 + u32 txmac_sw_reset:1; // bit 2 + u32 rxmac_sw_reset:1; // bit 3 + u32 mac_sw_reset:1; // bit 4 + u32 mac_stat_sw_reset:1; // bit 5 + u32 mmc_sw_reset:1; // bit 6 + u32 unused:24; // bits 7-30 + u32 selfclr_disable:1; // bit 31 +#endif + } bits; +} SW_RESET_t, *PSW_RESET_t; + +/* + * structure for SLV Timer reg in global address map + * located at address 0x002C + */ +typedef union _SLV_TIMER_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused:8; // bits 24-31 + u32 timer_ini:24; // bits 0-23 +#else + u32 timer_ini:24; // bits 0-23 + u32 unused:8; // bits 24-31 +#endif + } bits; +} SLV_TIMER_t, *PSLV_TIMER_t; + +/* + * structure for MSI Configuration reg in global address map + * located at address 0x0030 + */ +typedef union _MSI_CONFIG_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused1:13; // bits 19-31 + u32 msi_tc:3; // bits 16-18 + u32 unused2:11; // bits 5-15 + u32 msi_vector:5; // bits 0-4 +#else + u32 msi_vector:5; // bits 0-4 + u32 unused2:11; // bits 5-15 + u32 msi_tc:3; // bits 16-18 + u32 unused1:13; // bits 19-31 +#endif + } bits; +} MSI_CONFIG_t, *PMSI_CONFIG_t; + +/* + * structure for Loopback reg in global address map + * located at address 0x0034 + */ +typedef union _LOOPBACK_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused:30; // bits 2-31 + u32 dma_loopback:1; // bit 1 + u32 mac_loopback:1; // bit 0 +#else + u32 mac_loopback:1; // bit 0 + u32 dma_loopback:1; // bit 1 + u32 unused:30; // bits 2-31 +#endif + } bits; +} LOOPBACK_t, *PLOOPBACK_t; + +/* + * GLOBAL Module of JAGCore Address Mapping + * Located at address 0x0000 + */ +typedef struct _GLOBAL_t { // Location: + Q_ADDR_t txq_start_addr; // 0x0000 + Q_ADDR_t txq_end_addr; // 0x0004 + Q_ADDR_t rxq_start_addr; // 0x0008 + Q_ADDR_t rxq_end_addr; // 0x000C + PM_CSR_t pm_csr; // 0x0010 + u32 unused; // 0x0014 + INTERRUPT_t int_status; // 0x0018 + INTERRUPT_t int_mask; // 0x001C + INTERRUPT_t int_alias_clr_en; // 0x0020 + INTERRUPT_t int_status_alias; // 0x0024 + SW_RESET_t sw_reset; // 0x0028 + SLV_TIMER_t slv_timer; // 0x002C + MSI_CONFIG_t msi_config; // 0x0030 + LOOPBACK_t loopback; // 0x0034 + u32 watchdog_timer; // 0x0038 +} GLOBAL_t, *PGLOBAL_t; + +/* END OF GLOBAL REGISTER ADDRESS MAP */ + + +/* START OF TXDMA REGISTER ADDRESS MAP */ + +/* + * structure for txdma control status reg in txdma address map + * located at address 0x1000 + */ +typedef union _TXDMA_CSR_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused2:19; // bits 13-31 + u32 traffic_class:4; // bits 9-12 + u32 sngl_epkt_mode:1; // bit 8 + u32 cache_thrshld:4; // bits 4-7 + u32 unused1:2; // bits 2-3 + u32 drop_TLP_disable:1; // bit 1 + u32 halt:1; // bit 0 +#else + u32 halt:1; // bit 0 + u32 drop_TLP_disable:1; // bit 1 + u32 unused1:2; // bits 2-3 + u32 cache_thrshld:4; // bits 4-7 + u32 sngl_epkt_mode:1; // bit 8 + u32 traffic_class:4; // bits 9-12 + u32 unused2:19; // bits 13-31 +#endif + } bits; +} TXDMA_CSR_t, *PTXDMA_CSR_t; + +/* + * structure for txdma packet ring base address hi reg in txdma address map + * located at address 0x1004 + * Defined earlier (u32) + */ + +/* + * structure for txdma packet ring base address low reg in txdma address map + * located at address 0x1008 + * Defined earlier (u32) + */ + +/* + * structure for txdma packet ring number of descriptor reg in txdma address + * map. Located at address 0x100C + */ +typedef union _TXDMA_PR_NUM_DES_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused:22; // bits 10-31 + u32 pr_ndes:10; // bits 0-9 +#else + u32 pr_ndes:10; // bits 0-9 + u32 unused:22; // bits 10-31 +#endif + } bits; +} TXDMA_PR_NUM_DES_t, *PTXDMA_PR_NUM_DES_t; + + +typedef union _DMA10W_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused:21; // bits 11-31 + u32 wrap:1; // bit 10 + u32 val:10; // bits 0-9 +#else + u32 val:10; // bits 0-9 + u32 wrap:1; // bit 10 + u32 unused:21; // bits 11-31 +#endif + } bits; +} DMA10W_t, *PDMA10W_t; + +/* + * structure for txdma tx queue write address reg in txdma address map + * located at address 0x1010 + * Defined earlier (DMA10W_t) + */ + +/* + * structure for txdma tx queue write address external reg in txdma address map + * located at address 0x1014 + * Defined earlier (DMA10W_t) + */ + +/* + * structure for txdma tx queue read address reg in txdma address map + * located at address 0x1018 + * Defined earlier (DMA10W_t) + */ + +/* + * structure for txdma status writeback address hi reg in txdma address map + * located at address 0x101C + * Defined earlier (u32) + */ + +/* + * structure for txdma status writeback address lo reg in txdma address map + * located at address 0x1020 + * Defined earlier (u32) + */ + +/* + * structure for txdma service request reg in txdma address map + * located at address 0x1024 + * Defined earlier (DMA10W_t) + */ + +/* + * structure for txdma service complete reg in txdma address map + * located at address 0x1028 + * Defined earlier (DMA10W_t) + */ + +typedef union _DMA4W_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused:27; // bits 5-31 + u32 wrap:1; // bit 4 + u32 val:4; // bit 0-3 +#else + u32 val:4; // bits 0-3 + u32 wrap:1; // bit 4 + u32 unused:27; // bits 5-31 +#endif + } bits; +} DMA4W_t, *PDMA4W_t; + +/* + * structure for txdma tx descriptor cache read index reg in txdma address map + * located at address 0x102C + * Defined earlier (DMA4W_t) + */ + +/* + * structure for txdma tx descriptor cache write index reg in txdma address map + * located at address 0x1030 + * Defined earlier (DMA4W_t) + */ + +/* + * structure for txdma error reg in txdma address map + * located at address 0x1034 + */ +typedef union _TXDMA_ERROR_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused3:22; // bits 10-31 + u32 WrbkRewind:1; // bit 9 + u32 WrbkResend:1; // bit 8 + u32 unused2:2; // bits 6-7 + u32 DescrRewind:1; // bit 5 + u32 DescrResend:1; // bit 4 + u32 unused1:2; // bits 2-3 + u32 PyldRewind:1; // bit 1 + u32 PyldResend:1; // bit 0 +#else + u32 PyldResend:1; // bit 0 + u32 PyldRewind:1; // bit 1 + u32 unused1:2; // bits 2-3 + u32 DescrResend:1; // bit 4 + u32 DescrRewind:1; // bit 5 + u32 unused2:2; // bits 6-7 + u32 WrbkResend:1; // bit 8 + u32 WrbkRewind:1; // bit 9 + u32 unused3:22; // bits 10-31 +#endif + } bits; +} TXDMA_ERROR_t, *PTXDMA_ERROR_t; + +/* + * Tx DMA Module of JAGCore Address Mapping + * Located at address 0x1000 + */ +typedef struct _TXDMA_t { // Location: + TXDMA_CSR_t csr; // 0x1000 + u32 pr_base_hi; // 0x1004 + u32 pr_base_lo; // 0x1008 + TXDMA_PR_NUM_DES_t pr_num_des; // 0x100C + DMA10W_t txq_wr_addr; // 0x1010 + DMA10W_t txq_wr_addr_ext; // 0x1014 + DMA10W_t txq_rd_addr; // 0x1018 + u32 dma_wb_base_hi; // 0x101C + u32 dma_wb_base_lo; // 0x1020 + DMA10W_t service_request; // 0x1024 + DMA10W_t service_complete; // 0x1028 + DMA4W_t cache_rd_index; // 0x102C + DMA4W_t cache_wr_index; // 0x1030 + TXDMA_ERROR_t TxDmaError; // 0x1034 + u32 DescAbortCount; // 0x1038 + u32 PayloadAbortCnt; // 0x103c + u32 WriteBackAbortCnt; // 0x1040 + u32 DescTimeoutCnt; // 0x1044 + u32 PayloadTimeoutCnt; // 0x1048 + u32 WriteBackTimeoutCnt; // 0x104c + u32 DescErrorCount; // 0x1050 + u32 PayloadErrorCnt; // 0x1054 + u32 WriteBackErrorCnt; // 0x1058 + u32 DroppedTLPCount; // 0x105c + DMA10W_t NewServiceComplete; // 0x1060 + u32 EthernetPacketCount; // 0x1064 +} TXDMA_t, *PTXDMA_t; + +/* END OF TXDMA REGISTER ADDRESS MAP */ + + +/* START OF RXDMA REGISTER ADDRESS MAP */ + +/* + * structure for control status reg in rxdma address map + * Located at address 0x2000 + */ +typedef union _RXDMA_CSR_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused2:14; // bits 18-31 + u32 halt_status:1; // bit 17 + u32 pkt_done_flush:1; // bit 16 + u32 pkt_drop_disable:1; // bit 15 + u32 unused1:1; // bit 14 + u32 fbr1_enable:1; // bit 13 + u32 fbr1_size:2; // bits 11-12 + u32 fbr0_enable:1; // bit 10 + u32 fbr0_size:2; // bits 8-9 + u32 dma_big_endian:1; // bit 7 + u32 pkt_big_endian:1; // bit 6 + u32 psr_big_endian:1; // bit 5 + u32 fbr_big_endian:1; // bit 4 + u32 tc:3; // bits 1-3 + u32 halt:1; // bit 0 +#else + u32 halt:1; // bit 0 + u32 tc:3; // bits 1-3 + u32 fbr_big_endian:1; // bit 4 + u32 psr_big_endian:1; // bit 5 + u32 pkt_big_endian:1; // bit 6 + u32 dma_big_endian:1; // bit 7 + u32 fbr0_size:2; // bits 8-9 + u32 fbr0_enable:1; // bit 10 + u32 fbr1_size:2; // bits 11-12 + u32 fbr1_enable:1; // bit 13 + u32 unused1:1; // bit 14 + u32 pkt_drop_disable:1; // bit 15 + u32 pkt_done_flush:1; // bit 16 + u32 halt_status:1; // bit 17 + u32 unused2:14; // bits 18-31 +#endif + } bits; +} RXDMA_CSR_t, *PRXDMA_CSR_t; + +/* + * structure for dma writeback lo reg in rxdma address map + * located at address 0x2004 + * Defined earlier (u32) + */ + +/* + * structure for dma writeback hi reg in rxdma address map + * located at address 0x2008 + * Defined earlier (u32) + */ + +/* + * structure for number of packets done reg in rxdma address map + * located at address 0x200C + */ +typedef union _RXDMA_NUM_PKT_DONE_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused:24; // bits 8-31 + u32 num_done:8; // bits 0-7 +#else + u32 num_done:8; // bits 0-7 + u32 unused:24; // bits 8-31 +#endif + } bits; +} RXDMA_NUM_PKT_DONE_t, *PRXDMA_NUM_PKT_DONE_t; + +/* + * structure for max packet time reg in rxdma address map + * located at address 0x2010 + */ +typedef union _RXDMA_MAX_PKT_TIME_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused:14; // bits 18-31 + u32 time_done:18; // bits 0-17 +#else + u32 time_done:18; // bits 0-17 + u32 unused:14; // bits 18-31 +#endif + } bits; +} RXDMA_MAX_PKT_TIME_t, *PRXDMA_MAX_PKT_TIME_t; + +/* + * structure for rx queue read address reg in rxdma address map + * located at address 0x2014 + * Defined earlier (DMA10W_t) + */ + +/* + * structure for rx queue read address external reg in rxdma address map + * located at address 0x2018 + * Defined earlier (DMA10W_t) + */ + +/* + * structure for rx queue write address reg in rxdma address map + * located at address 0x201C + * Defined earlier (DMA10W_t) + */ + +/* + * structure for packet status ring base address lo reg in rxdma address map + * located at address 0x2020 + * Defined earlier (u32) + */ + +/* + * structure for packet status ring base address hi reg in rxdma address map + * located at address 0x2024 + * Defined earlier (u32) + */ + +/* + * structure for packet status ring number of descriptors reg in rxdma address + * map. Located at address 0x2028 + */ +typedef union _RXDMA_PSR_NUM_DES_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused:20; // bits 12-31 + u32 psr_ndes:12; // bit 0-11 +#else + u32 psr_ndes:12; // bit 0-11 + u32 unused:20; // bits 12-31 +#endif + } bits; +} RXDMA_PSR_NUM_DES_t, *PRXDMA_PSR_NUM_DES_t; + +/* + * structure for packet status ring available offset reg in rxdma address map + * located at address 0x202C + */ +typedef union _RXDMA_PSR_AVAIL_OFFSET_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused:19; // bits 13-31 + u32 psr_avail_wrap:1; // bit 12 + u32 psr_avail:12; // bit 0-11 +#else + u32 psr_avail:12; // bit 0-11 + u32 psr_avail_wrap:1; // bit 12 + u32 unused:19; // bits 13-31 +#endif + } bits; +} RXDMA_PSR_AVAIL_OFFSET_t, *PRXDMA_PSR_AVAIL_OFFSET_t; + +/* + * structure for packet status ring full offset reg in rxdma address map + * located at address 0x2030 + */ +typedef union _RXDMA_PSR_FULL_OFFSET_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused:19; // bits 13-31 + u32 psr_full_wrap:1; // bit 12 + u32 psr_full:12; // bit 0-11 +#else + u32 psr_full:12; // bit 0-11 + u32 psr_full_wrap:1; // bit 12 + u32 unused:19; // bits 13-31 +#endif + } bits; +} RXDMA_PSR_FULL_OFFSET_t, *PRXDMA_PSR_FULL_OFFSET_t; + +/* + * structure for packet status ring access index reg in rxdma address map + * located at address 0x2034 + */ +typedef union _RXDMA_PSR_ACCESS_INDEX_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused:27; // bits 5-31 + u32 psr_ai:5; // bits 0-4 +#else + u32 psr_ai:5; // bits 0-4 + u32 unused:27; // bits 5-31 +#endif + } bits; +} RXDMA_PSR_ACCESS_INDEX_t, *PRXDMA_PSR_ACCESS_INDEX_t; + +/* + * structure for packet status ring minimum descriptors reg in rxdma address + * map. Located at address 0x2038 + */ +typedef union _RXDMA_PSR_MIN_DES_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused:20; // bits 12-31 + u32 psr_min:12; // bits 0-11 +#else + u32 psr_min:12; // bits 0-11 + u32 unused:20; // bits 12-31 +#endif + } bits; +} RXDMA_PSR_MIN_DES_t, *PRXDMA_PSR_MIN_DES_t; + +/* + * structure for free buffer ring base lo address reg in rxdma address map + * located at address 0x203C + * Defined earlier (u32) + */ + +/* + * structure for free buffer ring base hi address reg in rxdma address map + * located at address 0x2040 + * Defined earlier (u32) + */ + +/* + * structure for free buffer ring number of descriptors reg in rxdma address + * map. Located at address 0x2044 + */ +typedef union _RXDMA_FBR_NUM_DES_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused:22; // bits 10-31 + u32 fbr_ndesc:10; // bits 0-9 +#else + u32 fbr_ndesc:10; // bits 0-9 + u32 unused:22; // bits 10-31 +#endif + } bits; +} RXDMA_FBR_NUM_DES_t, *PRXDMA_FBR_NUM_DES_t; + +/* + * structure for free buffer ring 0 available offset reg in rxdma address map + * located at address 0x2048 + * Defined earlier (DMA10W_t) + */ + +/* + * structure for free buffer ring 0 full offset reg in rxdma address map + * located at address 0x204C + * Defined earlier (DMA10W_t) + */ + +/* + * structure for free buffer cache 0 full offset reg in rxdma address map + * located at address 0x2050 + */ +typedef union _RXDMA_FBC_RD_INDEX_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused:27; // bits 5-31 + u32 fbc_rdi:5; // bit 0-4 +#else + u32 fbc_rdi:5; // bit 0-4 + u32 unused:27; // bits 5-31 +#endif + } bits; +} RXDMA_FBC_RD_INDEX_t, *PRXDMA_FBC_RD_INDEX_t; + +/* + * structure for free buffer ring 0 minimum descriptor reg in rxdma address map + * located at address 0x2054 + */ +typedef union _RXDMA_FBR_MIN_DES_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused:22; // bits 10-31 + u32 fbr_min:10; // bits 0-9 +#else + u32 fbr_min:10; // bits 0-9 + u32 unused:22; // bits 10-31 +#endif + } bits; +} RXDMA_FBR_MIN_DES_t, *PRXDMA_FBR_MIN_DES_t; + +/* + * structure for free buffer ring 1 base address lo reg in rxdma address map + * located at address 0x2058 - 0x205C + * Defined earlier (RXDMA_FBR_BASE_LO_t and RXDMA_FBR_BASE_HI_t) + */ + +/* + * structure for free buffer ring 1 number of descriptors reg in rxdma address + * map. Located at address 0x2060 + * Defined earlier (RXDMA_FBR_NUM_DES_t) + */ + +/* + * structure for free buffer ring 1 available offset reg in rxdma address map + * located at address 0x2064 + * Defined Earlier (RXDMA_FBR_AVAIL_OFFSET_t) + */ + +/* + * structure for free buffer ring 1 full offset reg in rxdma address map + * located at address 0x2068 + * Defined Earlier (RXDMA_FBR_FULL_OFFSET_t) + */ + +/* + * structure for free buffer cache 1 read index reg in rxdma address map + * located at address 0x206C + * Defined Earlier (RXDMA_FBC_RD_INDEX_t) + */ + +/* + * structure for free buffer ring 1 minimum descriptor reg in rxdma address map + * located at address 0x2070 + * Defined Earlier (RXDMA_FBR_MIN_DES_t) + */ + +/* + * Rx DMA Module of JAGCore Address Mapping + * Located at address 0x2000 + */ +typedef struct _RXDMA_t { // Location: + RXDMA_CSR_t csr; // 0x2000 + u32 dma_wb_base_lo; // 0x2004 + u32 dma_wb_base_hi; // 0x2008 + RXDMA_NUM_PKT_DONE_t num_pkt_done; // 0x200C + RXDMA_MAX_PKT_TIME_t max_pkt_time; // 0x2010 + DMA10W_t rxq_rd_addr; // 0x2014 + DMA10W_t rxq_rd_addr_ext; // 0x2018 + DMA10W_t rxq_wr_addr; // 0x201C + u32 psr_base_lo; // 0x2020 + u32 psr_base_hi; // 0x2024 + RXDMA_PSR_NUM_DES_t psr_num_des; // 0x2028 + RXDMA_PSR_AVAIL_OFFSET_t psr_avail_offset; // 0x202C + RXDMA_PSR_FULL_OFFSET_t psr_full_offset; // 0x2030 + RXDMA_PSR_ACCESS_INDEX_t psr_access_index; // 0x2034 + RXDMA_PSR_MIN_DES_t psr_min_des; // 0x2038 + u32 fbr0_base_lo; // 0x203C + u32 fbr0_base_hi; // 0x2040 + RXDMA_FBR_NUM_DES_t fbr0_num_des; // 0x2044 + DMA10W_t fbr0_avail_offset; // 0x2048 + DMA10W_t fbr0_full_offset; // 0x204C + RXDMA_FBC_RD_INDEX_t fbr0_rd_index; // 0x2050 + RXDMA_FBR_MIN_DES_t fbr0_min_des; // 0x2054 + u32 fbr1_base_lo; // 0x2058 + u32 fbr1_base_hi; // 0x205C + RXDMA_FBR_NUM_DES_t fbr1_num_des; // 0x2060 + DMA10W_t fbr1_avail_offset; // 0x2064 + DMA10W_t fbr1_full_offset; // 0x2068 + RXDMA_FBC_RD_INDEX_t fbr1_rd_index; // 0x206C + RXDMA_FBR_MIN_DES_t fbr1_min_des; // 0x2070 +} RXDMA_t, *PRXDMA_t; + +/* END OF RXDMA REGISTER ADDRESS MAP */ + + +/* START OF TXMAC REGISTER ADDRESS MAP */ + +/* + * structure for control reg in txmac address map + * located at address 0x3000 + */ +typedef union _TXMAC_CTL_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused:24; // bits 8-31 + u32 cklseg_diable:1; // bit 7 + u32 ckbcnt_disable:1; // bit 6 + u32 cksegnum:1; // bit 5 + u32 async_disable:1; // bit 4 + u32 fc_disable:1; // bit 3 + u32 mcif_disable:1; // bit 2 + u32 mif_disable:1; // bit 1 + u32 txmac_en:1; // bit 0 +#else + u32 txmac_en:1; // bit 0 + u32 mif_disable:1; // bit 1 mac interface + u32 mcif_disable:1; // bit 2 mem. contr. interface + u32 fc_disable:1; // bit 3 + u32 async_disable:1; // bit 4 + u32 cksegnum:1; // bit 5 + u32 ckbcnt_disable:1; // bit 6 + u32 cklseg_diable:1; // bit 7 + u32 unused:24; // bits 8-31 +#endif + } bits; +} TXMAC_CTL_t, *PTXMAC_CTL_t; + +/* + * structure for shadow pointer reg in txmac address map + * located at address 0x3004 + */ +typedef union _TXMAC_SHADOW_PTR_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 reserved2:5; // bits 27-31 + u32 txq_rd_ptr:11; // bits 16-26 + u32 reserved:5; // bits 11-15 + u32 txq_wr_ptr:11; // bits 0-10 +#else + u32 txq_wr_ptr:11; // bits 0-10 + u32 reserved:5; // bits 11-15 + u32 txq_rd_ptr:11; // bits 16-26 + u32 reserved2:5; // bits 27-31 +#endif + } bits; +} TXMAC_SHADOW_PTR_t, *PTXMAC_SHADOW_PTR_t; + +/* + * structure for error count reg in txmac address map + * located at address 0x3008 + */ +typedef union _TXMAC_ERR_CNT_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused:20; // bits 12-31 + u32 reserved:4; // bits 8-11 + u32 txq_underrun:4; // bits 4-7 + u32 fifo_underrun:4; // bits 0-3 +#else + u32 fifo_underrun:4; // bits 0-3 + u32 txq_underrun:4; // bits 4-7 + u32 reserved:4; // bits 8-11 + u32 unused:20; // bits 12-31 +#endif + } bits; +} TXMAC_ERR_CNT_t, *PTXMAC_ERR_CNT_t; + +/* + * structure for max fill reg in txmac address map + * located at address 0x300C + */ +typedef union _TXMAC_MAX_FILL_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused:20; // bits 12-31 + u32 max_fill:12; // bits 0-11 +#else + u32 max_fill:12; // bits 0-11 + u32 unused:20; // bits 12-31 +#endif + } bits; +} TXMAC_MAX_FILL_t, *PTXMAC_MAX_FILL_t; + +/* + * structure for cf parameter reg in txmac address map + * located at address 0x3010 + */ +typedef union _TXMAC_CF_PARAM_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 cfep:16; // bits 16-31 + u32 cfpt:16; // bits 0-15 +#else + u32 cfpt:16; // bits 0-15 + u32 cfep:16; // bits 16-31 +#endif + } bits; +} TXMAC_CF_PARAM_t, *PTXMAC_CF_PARAM_t; + +/* + * structure for tx test reg in txmac address map + * located at address 0x3014 + */ +typedef union _TXMAC_TXTEST_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused2:15; // bits 17-31 + u32 reserved1:1; // bit 16 + u32 txtest_en:1; // bit 15 + u32 unused1:4; // bits 11-14 + u32 txqtest_ptr:11; // bits 0-11 +#else + u32 txqtest_ptr:11; // bits 0-10 + u32 unused1:4; // bits 11-14 + u32 txtest_en:1; // bit 15 + u32 reserved1:1; // bit 16 + u32 unused2:15; // bits 17-31 +#endif + } bits; +} TXMAC_TXTEST_t, *PTXMAC_TXTEST_t; + +/* + * structure for error reg in txmac address map + * located at address 0x3018 + */ +typedef union _TXMAC_ERR_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused2:23; // bits 9-31 + u32 fifo_underrun:1; // bit 8 + u32 unused1:2; // bits 6-7 + u32 ctrl2_err:1; // bit 5 + u32 txq_underrun:1; // bit 4 + u32 bcnt_err:1; // bit 3 + u32 lseg_err:1; // bit 2 + u32 segnum_err:1; // bit 1 + u32 seg0_err:1; // bit 0 +#else + u32 seg0_err:1; // bit 0 + u32 segnum_err:1; // bit 1 + u32 lseg_err:1; // bit 2 + u32 bcnt_err:1; // bit 3 + u32 txq_underrun:1; // bit 4 + u32 ctrl2_err:1; // bit 5 + u32 unused1:2; // bits 6-7 + u32 fifo_underrun:1; // bit 8 + u32 unused2:23; // bits 9-31 +#endif + } bits; +} TXMAC_ERR_t, *PTXMAC_ERR_t; + +/* + * structure for error interrupt reg in txmac address map + * located at address 0x301C + */ +typedef union _TXMAC_ERR_INT_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused2:23; // bits 9-31 + u32 fifo_underrun:1; // bit 8 + u32 unused1:2; // bits 6-7 + u32 ctrl2_err:1; // bit 5 + u32 txq_underrun:1; // bit 4 + u32 bcnt_err:1; // bit 3 + u32 lseg_err:1; // bit 2 + u32 segnum_err:1; // bit 1 + u32 seg0_err:1; // bit 0 +#else + u32 seg0_err:1; // bit 0 + u32 segnum_err:1; // bit 1 + u32 lseg_err:1; // bit 2 + u32 bcnt_err:1; // bit 3 + u32 txq_underrun:1; // bit 4 + u32 ctrl2_err:1; // bit 5 + u32 unused1:2; // bits 6-7 + u32 fifo_underrun:1; // bit 8 + u32 unused2:23; // bits 9-31 +#endif + } bits; +} TXMAC_ERR_INT_t, *PTXMAC_ERR_INT_t; + +/* + * structure for error interrupt reg in txmac address map + * located at address 0x3020 + */ +typedef union _TXMAC_CP_CTRL_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused:30; // bits 2-31 + u32 bp_req:1; // bit 1 + u32 bp_xonxoff:1; // bit 0 +#else + u32 bp_xonxoff:1; // bit 0 + u32 bp_req:1; // bit 1 + u32 unused:30; // bits 2-31 +#endif + } bits; +} TXMAC_BP_CTRL_t, *PTXMAC_BP_CTRL_t; + +/* + * Tx MAC Module of JAGCore Address Mapping + */ +typedef struct _TXMAC_t { // Location: + TXMAC_CTL_t ctl; // 0x3000 + TXMAC_SHADOW_PTR_t shadow_ptr; // 0x3004 + TXMAC_ERR_CNT_t err_cnt; // 0x3008 + TXMAC_MAX_FILL_t max_fill; // 0x300C + TXMAC_CF_PARAM_t cf_param; // 0x3010 + TXMAC_TXTEST_t tx_test; // 0x3014 + TXMAC_ERR_t err; // 0x3018 + TXMAC_ERR_INT_t err_int; // 0x301C + TXMAC_BP_CTRL_t bp_ctrl; // 0x3020 +} TXMAC_t, *PTXMAC_t; + +/* END OF TXMAC REGISTER ADDRESS MAP */ + +/* START OF RXMAC REGISTER ADDRESS MAP */ + +/* + * structure for rxmac control reg in rxmac address map + * located at address 0x4000 + */ +typedef union _RXMAC_CTRL_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 reserved:25; // bits 7-31 + u32 rxmac_int_disable:1; // bit 6 + u32 async_disable:1; // bit 5 + u32 mif_disable:1; // bit 4 + u32 wol_disable:1; // bit 3 + u32 pkt_filter_disable:1; // bit 2 + u32 mcif_disable:1; // bit 1 + u32 rxmac_en:1; // bit 0 +#else + u32 rxmac_en:1; // bit 0 + u32 mcif_disable:1; // bit 1 + u32 pkt_filter_disable:1; // bit 2 + u32 wol_disable:1; // bit 3 + u32 mif_disable:1; // bit 4 + u32 async_disable:1; // bit 5 + u32 rxmac_int_disable:1; // bit 6 + u32 reserved:25; // bits 7-31 +#endif + } bits; +} RXMAC_CTRL_t, *PRXMAC_CTRL_t; + +/* + * structure for Wake On Lan Control and CRC 0 reg in rxmac address map + * located at address 0x4004 + */ +typedef union _RXMAC_WOL_CTL_CRC0_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 crc0:16; // bits 16-31 + u32 reserve:4; // bits 12-15 + u32 ignore_pp:1; // bit 11 + u32 ignore_mp:1; // bit 10 + u32 clr_intr:1; // bit 9 + u32 ignore_link_chg:1; // bit 8 + u32 ignore_uni:1; // bit 7 + u32 ignore_multi:1; // bit 6 + u32 ignore_broad:1; // bit 5 + u32 valid_crc4:1; // bit 4 + u32 valid_crc3:1; // bit 3 + u32 valid_crc2:1; // bit 2 + u32 valid_crc1:1; // bit 1 + u32 valid_crc0:1; // bit 0 +#else + u32 valid_crc0:1; // bit 0 + u32 valid_crc1:1; // bit 1 + u32 valid_crc2:1; // bit 2 + u32 valid_crc3:1; // bit 3 + u32 valid_crc4:1; // bit 4 + u32 ignore_broad:1; // bit 5 + u32 ignore_multi:1; // bit 6 + u32 ignore_uni:1; // bit 7 + u32 ignore_link_chg:1; // bit 8 + u32 clr_intr:1; // bit 9 + u32 ignore_mp:1; // bit 10 + u32 ignore_pp:1; // bit 11 + u32 reserve:4; // bits 12-15 + u32 crc0:16; // bits 16-31 +#endif + } bits; +} RXMAC_WOL_CTL_CRC0_t, *PRXMAC_WOL_CTL_CRC0_t; + +/* + * structure for CRC 1 and CRC 2 reg in rxmac address map + * located at address 0x4008 + */ +typedef union _RXMAC_WOL_CRC12_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 crc2:16; // bits 16-31 + u32 crc1:16; // bits 0-15 +#else + u32 crc1:16; // bits 0-15 + u32 crc2:16; // bits 16-31 +#endif + } bits; +} RXMAC_WOL_CRC12_t, *PRXMAC_WOL_CRC12_t; + +/* + * structure for CRC 3 and CRC 4 reg in rxmac address map + * located at address 0x400C + */ +typedef union _RXMAC_WOL_CRC34_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 crc4:16; // bits 16-31 + u32 crc3:16; // bits 0-15 +#else + u32 crc3:16; // bits 0-15 + u32 crc4:16; // bits 16-31 +#endif + } bits; +} RXMAC_WOL_CRC34_t, *PRXMAC_WOL_CRC34_t; + +/* + * structure for Wake On Lan Source Address Lo reg in rxmac address map + * located at address 0x4010 + */ +typedef union _RXMAC_WOL_SA_LO_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 sa3:8; // bits 24-31 + u32 sa4:8; // bits 16-23 + u32 sa5:8; // bits 8-15 + u32 sa6:8; // bits 0-7 +#else + u32 sa6:8; // bits 0-7 + u32 sa5:8; // bits 8-15 + u32 sa4:8; // bits 16-23 + u32 sa3:8; // bits 24-31 +#endif + } bits; +} RXMAC_WOL_SA_LO_t, *PRXMAC_WOL_SA_LO_t; + +/* + * structure for Wake On Lan Source Address Hi reg in rxmac address map + * located at address 0x4014 + */ +typedef union _RXMAC_WOL_SA_HI_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 reserved:16; // bits 16-31 + u32 sa1:8; // bits 8-15 + u32 sa2:8; // bits 0-7 +#else + u32 sa2:8; // bits 0-7 + u32 sa1:8; // bits 8-15 + u32 reserved:16; // bits 16-31 +#endif + } bits; +} RXMAC_WOL_SA_HI_t, *PRXMAC_WOL_SA_HI_t; + +/* + * structure for Wake On Lan mask reg in rxmac address map + * located at address 0x4018 - 0x4064 + * Defined earlier (u32) + */ + +/* + * structure for Unicast Paket Filter Address 1 reg in rxmac address map + * located at address 0x4068 + */ +typedef union _RXMAC_UNI_PF_ADDR1_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 addr1_3:8; // bits 24-31 + u32 addr1_4:8; // bits 16-23 + u32 addr1_5:8; // bits 8-15 + u32 addr1_6:8; // bits 0-7 +#else + u32 addr1_6:8; // bits 0-7 + u32 addr1_5:8; // bits 8-15 + u32 addr1_4:8; // bits 16-23 + u32 addr1_3:8; // bits 24-31 +#endif + } bits; +} RXMAC_UNI_PF_ADDR1_t, *PRXMAC_UNI_PF_ADDR1_t; + +/* + * structure for Unicast Paket Filter Address 2 reg in rxmac address map + * located at address 0x406C + */ +typedef union _RXMAC_UNI_PF_ADDR2_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 addr2_3:8; // bits 24-31 + u32 addr2_4:8; // bits 16-23 + u32 addr2_5:8; // bits 8-15 + u32 addr2_6:8; // bits 0-7 +#else + u32 addr2_6:8; // bits 0-7 + u32 addr2_5:8; // bits 8-15 + u32 addr2_4:8; // bits 16-23 + u32 addr2_3:8; // bits 24-31 +#endif + } bits; +} RXMAC_UNI_PF_ADDR2_t, *PRXMAC_UNI_PF_ADDR2_t; + +/* + * structure for Unicast Paket Filter Address 1 & 2 reg in rxmac address map + * located at address 0x4070 + */ +typedef union _RXMAC_UNI_PF_ADDR3_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 addr2_1:8; // bits 24-31 + u32 addr2_2:8; // bits 16-23 + u32 addr1_1:8; // bits 8-15 + u32 addr1_2:8; // bits 0-7 +#else + u32 addr1_2:8; // bits 0-7 + u32 addr1_1:8; // bits 8-15 + u32 addr2_2:8; // bits 16-23 + u32 addr2_1:8; // bits 24-31 +#endif + } bits; +} RXMAC_UNI_PF_ADDR3_t, *PRXMAC_UNI_PF_ADDR3_t; + +/* + * structure for Multicast Hash reg in rxmac address map + * located at address 0x4074 - 0x4080 + * Defined earlier (u32) + */ + +/* + * structure for Packet Filter Control reg in rxmac address map + * located at address 0x4084 + */ +typedef union _RXMAC_PF_CTRL_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused2:9; // bits 23-31 + u32 min_pkt_size:7; // bits 16-22 + u32 unused1:12; // bits 4-15 + u32 filter_frag_en:1; // bit 3 + u32 filter_uni_en:1; // bit 2 + u32 filter_multi_en:1; // bit 1 + u32 filter_broad_en:1; // bit 0 +#else + u32 filter_broad_en:1; // bit 0 + u32 filter_multi_en:1; // bit 1 + u32 filter_uni_en:1; // bit 2 + u32 filter_frag_en:1; // bit 3 + u32 unused1:12; // bits 4-15 + u32 min_pkt_size:7; // bits 16-22 + u32 unused2:9; // bits 23-31 +#endif + } bits; +} RXMAC_PF_CTRL_t, *PRXMAC_PF_CTRL_t; + +/* + * structure for Memory Controller Interface Control Max Segment reg in rxmac + * address map. Located at address 0x4088 + */ +typedef union _RXMAC_MCIF_CTRL_MAX_SEG_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 reserved:22; // bits 10-31 + u32 max_size:8; // bits 2-9 + u32 fc_en:1; // bit 1 + u32 seg_en:1; // bit 0 +#else + u32 seg_en:1; // bit 0 + u32 fc_en:1; // bit 1 + u32 max_size:8; // bits 2-9 + u32 reserved:22; // bits 10-31 +#endif + } bits; +} RXMAC_MCIF_CTRL_MAX_SEG_t, *PRXMAC_MCIF_CTRL_MAX_SEG_t; + +/* + * structure for Memory Controller Interface Water Mark reg in rxmac address + * map. Located at address 0x408C + */ +typedef union _RXMAC_MCIF_WATER_MARK_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 reserved2:6; // bits 26-31 + u32 mark_hi:10; // bits 16-25 + u32 reserved1:6; // bits 10-15 + u32 mark_lo:10; // bits 0-9 +#else + u32 mark_lo:10; // bits 0-9 + u32 reserved1:6; // bits 10-15 + u32 mark_hi:10; // bits 16-25 + u32 reserved2:6; // bits 26-31 +#endif + } bits; +} RXMAC_MCIF_WATER_MARK_t, *PRXMAC_MCIF_WATER_MARK_t; + +/* + * structure for Rx Queue Dialog reg in rxmac address map. + * located at address 0x4090 + */ +typedef union _RXMAC_RXQ_DIAG_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 reserved2:6; // bits 26-31 + u32 rd_ptr:10; // bits 16-25 + u32 reserved1:6; // bits 10-15 + u32 wr_ptr:10; // bits 0-9 +#else + u32 wr_ptr:10; // bits 0-9 + u32 reserved1:6; // bits 10-15 + u32 rd_ptr:10; // bits 16-25 + u32 reserved2:6; // bits 26-31 +#endif + } bits; +} RXMAC_RXQ_DIAG_t, *PRXMAC_RXQ_DIAG_t; + +/* + * structure for space availiable reg in rxmac address map. + * located at address 0x4094 + */ +typedef union _RXMAC_SPACE_AVAIL_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 reserved2:15; // bits 17-31 + u32 space_avail_en:1; // bit 16 + u32 reserved1:6; // bits 10-15 + u32 space_avail:10; // bits 0-9 +#else + u32 space_avail:10; // bits 0-9 + u32 reserved1:6; // bits 10-15 + u32 space_avail_en:1; // bit 16 + u32 reserved2:15; // bits 17-31 +#endif + } bits; +} RXMAC_SPACE_AVAIL_t, *PRXMAC_SPACE_AVAIL_t; + +/* + * structure for management interface reg in rxmac address map. + * located at address 0x4098 + */ +typedef union _RXMAC_MIF_CTL_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 reserve:14; // bits 18-31 + u32 drop_pkt_en:1; // bit 17 + u32 drop_pkt_mask:17; // bits 0-16 +#else + u32 drop_pkt_mask:17; // bits 0-16 + u32 drop_pkt_en:1; // bit 17 + u32 reserve:14; // bits 18-31 +#endif + } bits; +} RXMAC_MIF_CTL_t, *PRXMAC_MIF_CTL_t; + +/* + * structure for Error reg in rxmac address map. + * located at address 0x409C + */ +typedef union _RXMAC_ERROR_REG_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 reserve:28; // bits 4-31 + u32 mif:1; // bit 3 + u32 async:1; // bit 2 + u32 pkt_filter:1; // bit 1 + u32 mcif:1; // bit 0 +#else + u32 mcif:1; // bit 0 + u32 pkt_filter:1; // bit 1 + u32 async:1; // bit 2 + u32 mif:1; // bit 3 + u32 reserve:28; // bits 4-31 +#endif + } bits; +} RXMAC_ERROR_REG_t, *PRXMAC_ERROR_REG_t; + +/* + * Rx MAC Module of JAGCore Address Mapping + */ +typedef struct _RXMAC_t { // Location: + RXMAC_CTRL_t ctrl; // 0x4000 + RXMAC_WOL_CTL_CRC0_t crc0; // 0x4004 + RXMAC_WOL_CRC12_t crc12; // 0x4008 + RXMAC_WOL_CRC34_t crc34; // 0x400C + RXMAC_WOL_SA_LO_t sa_lo; // 0x4010 + RXMAC_WOL_SA_HI_t sa_hi; // 0x4014 + u32 mask0_word0; // 0x4018 + u32 mask0_word1; // 0x401C + u32 mask0_word2; // 0x4020 + u32 mask0_word3; // 0x4024 + u32 mask1_word0; // 0x4028 + u32 mask1_word1; // 0x402C + u32 mask1_word2; // 0x4030 + u32 mask1_word3; // 0x4034 + u32 mask2_word0; // 0x4038 + u32 mask2_word1; // 0x403C + u32 mask2_word2; // 0x4040 + u32 mask2_word3; // 0x4044 + u32 mask3_word0; // 0x4048 + u32 mask3_word1; // 0x404C + u32 mask3_word2; // 0x4050 + u32 mask3_word3; // 0x4054 + u32 mask4_word0; // 0x4058 + u32 mask4_word1; // 0x405C + u32 mask4_word2; // 0x4060 + u32 mask4_word3; // 0x4064 + RXMAC_UNI_PF_ADDR1_t uni_pf_addr1; // 0x4068 + RXMAC_UNI_PF_ADDR2_t uni_pf_addr2; // 0x406C + RXMAC_UNI_PF_ADDR3_t uni_pf_addr3; // 0x4070 + u32 multi_hash1; // 0x4074 + u32 multi_hash2; // 0x4078 + u32 multi_hash3; // 0x407C + u32 multi_hash4; // 0x4080 + RXMAC_PF_CTRL_t pf_ctrl; // 0x4084 + RXMAC_MCIF_CTRL_MAX_SEG_t mcif_ctrl_max_seg; // 0x4088 + RXMAC_MCIF_WATER_MARK_t mcif_water_mark; // 0x408C + RXMAC_RXQ_DIAG_t rxq_diag; // 0x4090 + RXMAC_SPACE_AVAIL_t space_avail; // 0x4094 + + RXMAC_MIF_CTL_t mif_ctrl; // 0x4098 + RXMAC_ERROR_REG_t err_reg; // 0x409C +} RXMAC_t, *PRXMAC_t; + +/* END OF TXMAC REGISTER ADDRESS MAP */ + + +/* START OF MAC REGISTER ADDRESS MAP */ + +/* + * structure for configuration #1 reg in mac address map. + * located at address 0x5000 + */ +typedef union _MAC_CFG1_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 soft_reset:1; // bit 31 + u32 sim_reset:1; // bit 30 + u32 reserved3:10; // bits 20-29 + u32 reset_rx_mc:1; // bit 19 + u32 reset_tx_mc:1; // bit 18 + u32 reset_rx_fun:1; // bit 17 + u32 reset_tx_fun:1; // bit 16 + u32 reserved2:7; // bits 9-15 + u32 loop_back:1; // bit 8 + u32 reserved1:2; // bits 6-7 + u32 rx_flow:1; // bit 5 + u32 tx_flow:1; // bit 4 + u32 syncd_rx_en:1; // bit 3 + u32 rx_enable:1; // bit 2 + u32 syncd_tx_en:1; // bit 1 + u32 tx_enable:1; // bit 0 +#else + u32 tx_enable:1; // bit 0 + u32 syncd_tx_en:1; // bit 1 + u32 rx_enable:1; // bit 2 + u32 syncd_rx_en:1; // bit 3 + u32 tx_flow:1; // bit 4 + u32 rx_flow:1; // bit 5 + u32 reserved1:2; // bits 6-7 + u32 loop_back:1; // bit 8 + u32 reserved2:7; // bits 9-15 + u32 reset_tx_fun:1; // bit 16 + u32 reset_rx_fun:1; // bit 17 + u32 reset_tx_mc:1; // bit 18 + u32 reset_rx_mc:1; // bit 19 + u32 reserved3:10; // bits 20-29 + u32 sim_reset:1; // bit 30 + u32 soft_reset:1; // bit 31 +#endif + } bits; +} MAC_CFG1_t, *PMAC_CFG1_t; + +/* + * structure for configuration #2 reg in mac address map. + * located at address 0x5004 + */ +typedef union _MAC_CFG2_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 reserved3:16; // bits 16-31 + u32 preamble_len:4; // bits 12-15 + u32 reserved2:2; // bits 10-11 + u32 if_mode:2; // bits 8-9 + u32 reserved1:2; // bits 6-7 + u32 huge_frame:1; // bit 5 + u32 len_check:1; // bit 4 + u32 undefined:1; // bit 3 + u32 pad_crc:1; // bit 2 + u32 crc_enable:1; // bit 1 + u32 full_duplex:1; // bit 0 +#else + u32 full_duplex:1; // bit 0 + u32 crc_enable:1; // bit 1 + u32 pad_crc:1; // bit 2 + u32 undefined:1; // bit 3 + u32 len_check:1; // bit 4 + u32 huge_frame:1; // bit 5 + u32 reserved1:2; // bits 6-7 + u32 if_mode:2; // bits 8-9 + u32 reserved2:2; // bits 10-11 + u32 preamble_len:4; // bits 12-15 + u32 reserved3:16; // bits 16-31 +#endif + } bits; +} MAC_CFG2_t, *PMAC_CFG2_t; + +/* + * structure for Interpacket gap reg in mac address map. + * located at address 0x5008 + */ +typedef union _MAC_IPG_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 reserved:1; // bit 31 + u32 non_B2B_ipg_1:7; // bits 24-30 + u32 undefined2:1; // bit 23 + u32 non_B2B_ipg_2:7; // bits 16-22 + u32 min_ifg_enforce:8; // bits 8-15 + u32 undefined1:1; // bit 7 + u32 B2B_ipg:7; // bits 0-6 +#else + u32 B2B_ipg:7; // bits 0-6 + u32 undefined1:1; // bit 7 + u32 min_ifg_enforce:8; // bits 8-15 + u32 non_B2B_ipg_2:7; // bits 16-22 + u32 undefined2:1; // bit 23 + u32 non_B2B_ipg_1:7; // bits 24-30 + u32 reserved:1; // bit 31 +#endif + } bits; +} MAC_IPG_t, *PMAC_IPG_t; + +/* + * structure for half duplex reg in mac address map. + * located at address 0x500C + */ +typedef union _MAC_HFDP_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 reserved2:8; // bits 24-31 + u32 alt_beb_trunc:4; // bits 23-20 + u32 alt_beb_enable:1; // bit 19 + u32 bp_no_backoff:1; // bit 18 + u32 no_backoff:1; // bit 17 + u32 excess_defer:1; // bit 16 + u32 rexmit_max:4; // bits 12-15 + u32 reserved1:2; // bits 10-11 + u32 coll_window:10; // bits 0-9 +#else + u32 coll_window:10; // bits 0-9 + u32 reserved1:2; // bits 10-11 + u32 rexmit_max:4; // bits 12-15 + u32 excess_defer:1; // bit 16 + u32 no_backoff:1; // bit 17 + u32 bp_no_backoff:1; // bit 18 + u32 alt_beb_enable:1; // bit 19 + u32 alt_beb_trunc:4; // bits 23-20 + u32 reserved2:8; // bits 24-31 +#endif + } bits; +} MAC_HFDP_t, *PMAC_HFDP_t; + +/* + * structure for Maximum Frame Length reg in mac address map. + * located at address 0x5010 + */ +typedef union _MAC_MAX_FM_LEN_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 reserved:16; // bits 16-31 + u32 max_len:16; // bits 0-15 +#else + u32 max_len:16; // bits 0-15 + u32 reserved:16; // bits 16-31 +#endif + } bits; +} MAC_MAX_FM_LEN_t, *PMAC_MAX_FM_LEN_t; + +/* + * structure for Reserve 1 reg in mac address map. + * located at address 0x5014 - 0x5018 + * Defined earlier (u32) + */ + +/* + * structure for Test reg in mac address map. + * located at address 0x501C + */ +typedef union _MAC_TEST_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused:29; // bits 3-31 + u32 mac_test:3; // bits 0-2 +#else + u32 mac_test:3; // bits 0-2 + u32 unused:29; // bits 3-31 +#endif + } bits; +} MAC_TEST_t, *PMAC_TEST_t; + +/* + * structure for MII Management Configuration reg in mac address map. + * located at address 0x5020 + */ +typedef union _MII_MGMT_CFG_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 reset_mii_mgmt:1; // bit 31 + u32 reserved:25; // bits 6-30 + u32 scan_auto_incremt:1; // bit 5 + u32 preamble_suppress:1; // bit 4 + u32 undefined:1; // bit 3 + u32 mgmt_clk_reset:3; // bits 0-2 +#else + u32 mgmt_clk_reset:3; // bits 0-2 + u32 undefined:1; // bit 3 + u32 preamble_suppress:1; // bit 4 + u32 scan_auto_incremt:1; // bit 5 + u32 reserved:25; // bits 6-30 + u32 reset_mii_mgmt:1; // bit 31 +#endif + } bits; +} MII_MGMT_CFG_t, *PMII_MGMT_CFG_t; + +/* + * structure for MII Management Command reg in mac address map. + * located at address 0x5024 + */ +typedef union _MII_MGMT_CMD_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 reserved:30; // bits 2-31 + u32 scan_cycle:1; // bit 1 + u32 read_cycle:1; // bit 0 +#else + u32 read_cycle:1; // bit 0 + u32 scan_cycle:1; // bit 1 + u32 reserved:30; // bits 2-31 +#endif + } bits; +} MII_MGMT_CMD_t, *PMII_MGMT_CMD_t; + +/* + * structure for MII Management Address reg in mac address map. + * located at address 0x5028 + */ +typedef union _MII_MGMT_ADDR_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 reserved2:19; // bit 13-31 + u32 phy_addr:5; // bits 8-12 + u32 reserved1:3; // bits 5-7 + u32 reg_addr:5; // bits 0-4 +#else + u32 reg_addr:5; // bits 0-4 + u32 reserved1:3; // bits 5-7 + u32 phy_addr:5; // bits 8-12 + u32 reserved2:19; // bit 13-31 +#endif + } bits; +} MII_MGMT_ADDR_t, *PMII_MGMT_ADDR_t; + +/* + * structure for MII Management Control reg in mac address map. + * located at address 0x502C + */ +typedef union _MII_MGMT_CTRL_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 reserved:16; // bits 16-31 + u32 phy_ctrl:16; // bits 0-15 +#else + u32 phy_ctrl:16; // bits 0-15 + u32 reserved:16; // bits 16-31 +#endif + } bits; +} MII_MGMT_CTRL_t, *PMII_MGMT_CTRL_t; + +/* + * structure for MII Management Status reg in mac address map. + * located at address 0x5030 + */ +typedef union _MII_MGMT_STAT_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 reserved:16; // bits 16-31 + u32 phy_stat:16; // bits 0-15 +#else + u32 phy_stat:16; // bits 0-15 + u32 reserved:16; // bits 16-31 +#endif + } bits; +} MII_MGMT_STAT_t, *PMII_MGMT_STAT_t; + +/* + * structure for MII Management Indicators reg in mac address map. + * located at address 0x5034 + */ +typedef union _MII_MGMT_INDICATOR_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 reserved:29; // bits 3-31 + u32 not_valid:1; // bit 2 + u32 scanning:1; // bit 1 + u32 busy:1; // bit 0 +#else + u32 busy:1; // bit 0 + u32 scanning:1; // bit 1 + u32 not_valid:1; // bit 2 + u32 reserved:29; // bits 3-31 +#endif + } bits; +} MII_MGMT_INDICATOR_t, *PMII_MGMT_INDICATOR_t; + +/* + * structure for Interface Control reg in mac address map. + * located at address 0x5038 + */ +typedef union _MAC_IF_CTRL_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 reset_if_module:1; // bit 31 + u32 reserved4:3; // bit 28-30 + u32 tbi_mode:1; // bit 27 + u32 ghd_mode:1; // bit 26 + u32 lhd_mode:1; // bit 25 + u32 phy_mode:1; // bit 24 + u32 reset_per_mii:1; // bit 23 + u32 reserved3:6; // bits 17-22 + u32 speed:1; // bit 16 + u32 reset_pe100x:1; // bit 15 + u32 reserved2:4; // bits 11-14 + u32 force_quiet:1; // bit 10 + u32 no_cipher:1; // bit 9 + u32 disable_link_fail:1; // bit 8 + u32 reset_gpsi:1; // bit 7 + u32 reserved1:6; // bits 1-6 + u32 enab_jab_protect:1; // bit 0 +#else + u32 enab_jab_protect:1; // bit 0 + u32 reserved1:6; // bits 1-6 + u32 reset_gpsi:1; // bit 7 + u32 disable_link_fail:1; // bit 8 + u32 no_cipher:1; // bit 9 + u32 force_quiet:1; // bit 10 + u32 reserved2:4; // bits 11-14 + u32 reset_pe100x:1; // bit 15 + u32 speed:1; // bit 16 + u32 reserved3:6; // bits 17-22 + u32 reset_per_mii:1; // bit 23 + u32 phy_mode:1; // bit 24 + u32 lhd_mode:1; // bit 25 + u32 ghd_mode:1; // bit 26 + u32 tbi_mode:1; // bit 27 + u32 reserved4:3; // bit 28-30 + u32 reset_if_module:1; // bit 31 +#endif + } bits; +} MAC_IF_CTRL_t, *PMAC_IF_CTRL_t; + +/* + * structure for Interface Status reg in mac address map. + * located at address 0x503C + */ +typedef union _MAC_IF_STAT_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 reserved:22; // bits 10-31 + u32 excess_defer:1; // bit 9 + u32 clash:1; // bit 8 + u32 phy_jabber:1; // bit 7 + u32 phy_link_ok:1; // bit 6 + u32 phy_full_duplex:1; // bit 5 + u32 phy_speed:1; // bit 4 + u32 pe100x_link_fail:1; // bit 3 + u32 pe10t_loss_carrie:1; // bit 2 + u32 pe10t_sqe_error:1; // bit 1 + u32 pe10t_jabber:1; // bit 0 +#else + u32 pe10t_jabber:1; // bit 0 + u32 pe10t_sqe_error:1; // bit 1 + u32 pe10t_loss_carrie:1; // bit 2 + u32 pe100x_link_fail:1; // bit 3 + u32 phy_speed:1; // bit 4 + u32 phy_full_duplex:1; // bit 5 + u32 phy_link_ok:1; // bit 6 + u32 phy_jabber:1; // bit 7 + u32 clash:1; // bit 8 + u32 excess_defer:1; // bit 9 + u32 reserved:22; // bits 10-31 +#endif + } bits; +} MAC_IF_STAT_t, *PMAC_IF_STAT_t; + +/* + * structure for Mac Station Address, Part 1 reg in mac address map. + * located at address 0x5040 + */ +typedef union _MAC_STATION_ADDR1_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 Octet6:8; // bits 24-31 + u32 Octet5:8; // bits 16-23 + u32 Octet4:8; // bits 8-15 + u32 Octet3:8; // bits 0-7 +#else + u32 Octet3:8; // bits 0-7 + u32 Octet4:8; // bits 8-15 + u32 Octet5:8; // bits 16-23 + u32 Octet6:8; // bits 24-31 +#endif + } bits; +} MAC_STATION_ADDR1_t, *PMAC_STATION_ADDR1_t; + +/* + * structure for Mac Station Address, Part 2 reg in mac address map. + * located at address 0x5044 + */ +typedef union _MAC_STATION_ADDR2_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 Octet2:8; // bits 24-31 + u32 Octet1:8; // bits 16-23 + u32 reserved:16; // bits 0-15 +#else + u32 reserved:16; // bit 0-15 + u32 Octet1:8; // bits 16-23 + u32 Octet2:8; // bits 24-31 +#endif + } bits; +} MAC_STATION_ADDR2_t, *PMAC_STATION_ADDR2_t; + +/* + * MAC Module of JAGCore Address Mapping + */ +typedef struct _MAC_t { // Location: + MAC_CFG1_t cfg1; // 0x5000 + MAC_CFG2_t cfg2; // 0x5004 + MAC_IPG_t ipg; // 0x5008 + MAC_HFDP_t hfdp; // 0x500C + MAC_MAX_FM_LEN_t max_fm_len; // 0x5010 + u32 rsv1; // 0x5014 + u32 rsv2; // 0x5018 + MAC_TEST_t mac_test; // 0x501C + MII_MGMT_CFG_t mii_mgmt_cfg; // 0x5020 + MII_MGMT_CMD_t mii_mgmt_cmd; // 0x5024 + MII_MGMT_ADDR_t mii_mgmt_addr; // 0x5028 + MII_MGMT_CTRL_t mii_mgmt_ctrl; // 0x502C + MII_MGMT_STAT_t mii_mgmt_stat; // 0x5030 + MII_MGMT_INDICATOR_t mii_mgmt_indicator; // 0x5034 + MAC_IF_CTRL_t if_ctrl; // 0x5038 + MAC_IF_STAT_t if_stat; // 0x503C + MAC_STATION_ADDR1_t station_addr_1; // 0x5040 + MAC_STATION_ADDR2_t station_addr_2; // 0x5044 +} MAC_t, *PMAC_t; + +/* END OF MAC REGISTER ADDRESS MAP */ + +/* START OF MAC STAT REGISTER ADDRESS MAP */ + +/* + * structure for Carry Register One and it's Mask Register reg located in mac + * stat address map address 0x6130 and 0x6138. + */ +typedef union _MAC_STAT_REG_1_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 tr64:1; // bit 31 + u32 tr127:1; // bit 30 + u32 tr255:1; // bit 29 + u32 tr511:1; // bit 28 + u32 tr1k:1; // bit 27 + u32 trmax:1; // bit 26 + u32 trmgv:1; // bit 25 + u32 unused:8; // bits 17-24 + u32 rbyt:1; // bit 16 + u32 rpkt:1; // bit 15 + u32 rfcs:1; // bit 14 + u32 rmca:1; // bit 13 + u32 rbca:1; // bit 12 + u32 rxcf:1; // bit 11 + u32 rxpf:1; // bit 10 + u32 rxuo:1; // bit 9 + u32 raln:1; // bit 8 + u32 rflr:1; // bit 7 + u32 rcde:1; // bit 6 + u32 rcse:1; // bit 5 + u32 rund:1; // bit 4 + u32 rovr:1; // bit 3 + u32 rfrg:1; // bit 2 + u32 rjbr:1; // bit 1 + u32 rdrp:1; // bit 0 +#else + u32 rdrp:1; // bit 0 + u32 rjbr:1; // bit 1 + u32 rfrg:1; // bit 2 + u32 rovr:1; // bit 3 + u32 rund:1; // bit 4 + u32 rcse:1; // bit 5 + u32 rcde:1; // bit 6 + u32 rflr:1; // bit 7 + u32 raln:1; // bit 8 + u32 rxuo:1; // bit 9 + u32 rxpf:1; // bit 10 + u32 rxcf:1; // bit 11 + u32 rbca:1; // bit 12 + u32 rmca:1; // bit 13 + u32 rfcs:1; // bit 14 + u32 rpkt:1; // bit 15 + u32 rbyt:1; // bit 16 + u32 unused:8; // bits 17-24 + u32 trmgv:1; // bit 25 + u32 trmax:1; // bit 26 + u32 tr1k:1; // bit 27 + u32 tr511:1; // bit 28 + u32 tr255:1; // bit 29 + u32 tr127:1; // bit 30 + u32 tr64:1; // bit 31 +#endif + } bits; +} MAC_STAT_REG_1_t, *PMAC_STAT_REG_1_t; + +/* + * structure for Carry Register Two Mask Register reg in mac stat address map. + * located at address 0x613C + */ +typedef union _MAC_STAT_REG_2_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused:12; // bit 20-31 + u32 tjbr:1; // bit 19 + u32 tfcs:1; // bit 18 + u32 txcf:1; // bit 17 + u32 tovr:1; // bit 16 + u32 tund:1; // bit 15 + u32 tfrg:1; // bit 14 + u32 tbyt:1; // bit 13 + u32 tpkt:1; // bit 12 + u32 tmca:1; // bit 11 + u32 tbca:1; // bit 10 + u32 txpf:1; // bit 9 + u32 tdfr:1; // bit 8 + u32 tedf:1; // bit 7 + u32 tscl:1; // bit 6 + u32 tmcl:1; // bit 5 + u32 tlcl:1; // bit 4 + u32 txcl:1; // bit 3 + u32 tncl:1; // bit 2 + u32 tpfh:1; // bit 1 + u32 tdrp:1; // bit 0 +#else + u32 tdrp:1; // bit 0 + u32 tpfh:1; // bit 1 + u32 tncl:1; // bit 2 + u32 txcl:1; // bit 3 + u32 tlcl:1; // bit 4 + u32 tmcl:1; // bit 5 + u32 tscl:1; // bit 6 + u32 tedf:1; // bit 7 + u32 tdfr:1; // bit 8 + u32 txpf:1; // bit 9 + u32 tbca:1; // bit 10 + u32 tmca:1; // bit 11 + u32 tpkt:1; // bit 12 + u32 tbyt:1; // bit 13 + u32 tfrg:1; // bit 14 + u32 tund:1; // bit 15 + u32 tovr:1; // bit 16 + u32 txcf:1; // bit 17 + u32 tfcs:1; // bit 18 + u32 tjbr:1; // bit 19 + u32 unused:12; // bit 20-31 +#endif + } bits; +} MAC_STAT_REG_2_t, *PMAC_STAT_REG_2_t; + +/* + * MAC STATS Module of JAGCore Address Mapping + */ +typedef struct _MAC_STAT_t { // Location: + u32 pad[32]; // 0x6000 - 607C + + // Tx/Rx 0-64 Byte Frame Counter + u32 TR64; // 0x6080 + + // Tx/Rx 65-127 Byte Frame Counter + u32 TR127; // 0x6084 + + // Tx/Rx 128-255 Byte Frame Counter + u32 TR255; // 0x6088 + + // Tx/Rx 256-511 Byte Frame Counter + u32 TR511; // 0x608C + + // Tx/Rx 512-1023 Byte Frame Counter + u32 TR1K; // 0x6090 + + // Tx/Rx 1024-1518 Byte Frame Counter + u32 TRMax; // 0x6094 + + // Tx/Rx 1519-1522 Byte Good VLAN Frame Count + u32 TRMgv; // 0x6098 + + // Rx Byte Counter + u32 RByt; // 0x609C + + // Rx Packet Counter + u32 RPkt; // 0x60A0 + + // Rx FCS Error Counter + u32 RFcs; // 0x60A4 + + // Rx Multicast Packet Counter + u32 RMca; // 0x60A8 + + // Rx Broadcast Packet Counter + u32 RBca; // 0x60AC + + // Rx Control Frame Packet Counter + u32 RxCf; // 0x60B0 + + // Rx Pause Frame Packet Counter + u32 RxPf; // 0x60B4 + + // Rx Unknown OP Code Counter + u32 RxUo; // 0x60B8 + + // Rx Alignment Error Counter + u32 RAln; // 0x60BC + + // Rx Frame Length Error Counter + u32 RFlr; // 0x60C0 + + // Rx Code Error Counter + u32 RCde; // 0x60C4 + + // Rx Carrier Sense Error Counter + u32 RCse; // 0x60C8 + + // Rx Undersize Packet Counter + u32 RUnd; // 0x60CC + + // Rx Oversize Packet Counter + u32 ROvr; // 0x60D0 + + // Rx Fragment Counter + u32 RFrg; // 0x60D4 + + // Rx Jabber Counter + u32 RJbr; // 0x60D8 + + // Rx Drop + u32 RDrp; // 0x60DC + + // Tx Byte Counter + u32 TByt; // 0x60E0 + + // Tx Packet Counter + u32 TPkt; // 0x60E4 + + // Tx Multicast Packet Counter + u32 TMca; // 0x60E8 + + // Tx Broadcast Packet Counter + u32 TBca; // 0x60EC + + // Tx Pause Control Frame Counter + u32 TxPf; // 0x60F0 + + // Tx Deferral Packet Counter + u32 TDfr; // 0x60F4 + + // Tx Excessive Deferral Packet Counter + u32 TEdf; // 0x60F8 + + // Tx Single Collision Packet Counter + u32 TScl; // 0x60FC + + // Tx Multiple Collision Packet Counter + u32 TMcl; // 0x6100 + + // Tx Late Collision Packet Counter + u32 TLcl; // 0x6104 + + // Tx Excessive Collision Packet Counter + u32 TXcl; // 0x6108 + + // Tx Total Collision Packet Counter + u32 TNcl; // 0x610C + + // Tx Pause Frame Honored Counter + u32 TPfh; // 0x6110 + + // Tx Drop Frame Counter + u32 TDrp; // 0x6114 + + // Tx Jabber Frame Counter + u32 TJbr; // 0x6118 + + // Tx FCS Error Counter + u32 TFcs; // 0x611C + + // Tx Control Frame Counter + u32 TxCf; // 0x6120 + + // Tx Oversize Frame Counter + u32 TOvr; // 0x6124 + + // Tx Undersize Frame Counter + u32 TUnd; // 0x6128 + + // Tx Fragments Frame Counter + u32 TFrg; // 0x612C + + // Carry Register One Register + MAC_STAT_REG_1_t Carry1; // 0x6130 + + // Carry Register Two Register + MAC_STAT_REG_2_t Carry2; // 0x6134 + + // Carry Register One Mask Register + MAC_STAT_REG_1_t Carry1M; // 0x6138 + + // Carry Register Two Mask Register + MAC_STAT_REG_2_t Carry2M; // 0x613C +} MAC_STAT_t, *PMAC_STAT_t; + +/* END OF MAC STAT REGISTER ADDRESS MAP */ + + +/* START OF MMC REGISTER ADDRESS MAP */ + +/* + * structure for Main Memory Controller Control reg in mmc address map. + * located at address 0x7000 + */ +typedef union _MMC_CTRL_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 reserved:25; // bits 7-31 + u32 force_ce:1; // bit 6 + u32 rxdma_disable:1; // bit 5 + u32 txdma_disable:1; // bit 4 + u32 txmac_disable:1; // bit 3 + u32 rxmac_disable:1; // bit 2 + u32 arb_disable:1; // bit 1 + u32 mmc_enable:1; // bit 0 +#else + u32 mmc_enable:1; // bit 0 + u32 arb_disable:1; // bit 1 + u32 rxmac_disable:1; // bit 2 + u32 txmac_disable:1; // bit 3 + u32 txdma_disable:1; // bit 4 + u32 rxdma_disable:1; // bit 5 + u32 force_ce:1; // bit 6 + u32 reserved:25; // bits 7-31 +#endif + } bits; +} MMC_CTRL_t, *PMMC_CTRL_t; + +/* + * structure for Main Memory Controller Host Memory Access Address reg in mmc + * address map. Located at address 0x7004 + */ +typedef union _MMC_SRAM_ACCESS_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 byte_enable:16; // bits 16-31 + u32 reserved2:2; // bits 14-15 + u32 req_addr:10; // bits 4-13 + u32 reserved1:1; // bit 3 + u32 is_ctrl_word:1; // bit 2 + u32 wr_access:1; // bit 1 + u32 req_access:1; // bit 0 +#else + u32 req_access:1; // bit 0 + u32 wr_access:1; // bit 1 + u32 is_ctrl_word:1; // bit 2 + u32 reserved1:1; // bit 3 + u32 req_addr:10; // bits 4-13 + u32 reserved2:2; // bits 14-15 + u32 byte_enable:16; // bits 16-31 +#endif + } bits; +} MMC_SRAM_ACCESS_t, *PMMC_SRAM_ACCESS_t; + +/* + * structure for Main Memory Controller Host Memory Access Data reg in mmc + * address map. Located at address 0x7008 - 0x7014 + * Defined earlier (u32) + */ + +/* + * Memory Control Module of JAGCore Address Mapping + */ +typedef struct _MMC_t { // Location: + MMC_CTRL_t mmc_ctrl; // 0x7000 + MMC_SRAM_ACCESS_t sram_access; // 0x7004 + u32 sram_word1; // 0x7008 + u32 sram_word2; // 0x700C + u32 sram_word3; // 0x7010 + u32 sram_word4; // 0x7014 +} MMC_t, *PMMC_t; + +/* END OF MMC REGISTER ADDRESS MAP */ + + +/* START OF EXP ROM REGISTER ADDRESS MAP */ + +/* + * Expansion ROM Module of JAGCore Address Mapping + */ + +/* Take this out until it is not empty */ +#if 0 +typedef struct _EXP_ROM_t { + +} EXP_ROM_t, *PEXP_ROM_t; +#endif + +/* END OF EXP ROM REGISTER ADDRESS MAP */ + + +/* + * JAGCore Address Mapping + */ +typedef struct _ADDRESS_MAP_t { + GLOBAL_t global; + // unused section of global address map + u8 unused_global[4096 - sizeof(GLOBAL_t)]; + TXDMA_t txdma; + // unused section of txdma address map + u8 unused_txdma[4096 - sizeof(TXDMA_t)]; + RXDMA_t rxdma; + // unused section of rxdma address map + u8 unused_rxdma[4096 - sizeof(RXDMA_t)]; + TXMAC_t txmac; + // unused section of txmac address map + u8 unused_txmac[4096 - sizeof(TXMAC_t)]; + RXMAC_t rxmac; + // unused section of rxmac address map + u8 unused_rxmac[4096 - sizeof(RXMAC_t)]; + MAC_t mac; + // unused section of mac address map + u8 unused_mac[4096 - sizeof(MAC_t)]; + MAC_STAT_t macStat; + // unused section of mac stat address map + u8 unused_mac_stat[4096 - sizeof(MAC_STAT_t)]; + MMC_t mmc; + // unused section of mmc address map + u8 unused_mmc[4096 - sizeof(MMC_t)]; + // unused section of address map + u8 unused_[1015808]; + +/* Take this out until it is not empty */ +#if 0 + EXP_ROM_t exp_rom; +#endif + + u8 unused_exp_rom[4096]; // MGS-size TBD + u8 unused__[524288]; // unused section of address map +} ADDRESS_MAP_t, *PADDRESS_MAP_t; + +#endif /* _ET1310_ADDRESS_MAP_H_ */ diff --git a/src/et131x/et1310_eeprom.c b/src/et131x/et1310_eeprom.c new file mode 100644 index 0000000..c2b194e --- /dev/null +++ b/src/et131x/et1310_eeprom.c @@ -0,0 +1,480 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et1310_eeprom.c - Code used to access the device's EEPROM + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#include "et131x_version.h" +#include "et131x_debug.h" +#include "et131x_defs.h" + +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> + +#include <linux/sched.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/ctype.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/in.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/bitops.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/if_arp.h> +#include <linux/ioport.h> + +#include "et1310_phy.h" +#include "et1310_pm.h" +#include "et1310_jagcore.h" +#include "et1310_eeprom.h" + +#include "et131x_adapter.h" +#include "et131x_initpci.h" +#include "et131x_isr.h" + +#include "et1310_tx.h" + + +/* + * EEPROM Defines + */ + +/* LBCIF Register Groups (addressed via 32-bit offsets) */ +#define LBCIF_DWORD0_GROUP_OFFSET 0xAC +#define LBCIF_DWORD1_GROUP_OFFSET 0xB0 + +/* LBCIF Registers (addressed via 8-bit offsets) */ +#define LBCIF_ADDRESS_REGISTER_OFFSET 0xAC +#define LBCIF_DATA_REGISTER_OFFSET 0xB0 +#define LBCIF_CONTROL_REGISTER_OFFSET 0xB1 +#define LBCIF_STATUS_REGISTER_OFFSET 0xB2 + +/* LBCIF Control Register Bits */ +#define LBCIF_CONTROL_SEQUENTIAL_READ 0x01 +#define LBCIF_CONTROL_PAGE_WRITE 0x02 +#define LBCIF_CONTROL_UNUSED1 0x04 +#define LBCIF_CONTROL_EEPROM_RELOAD 0x08 +#define LBCIF_CONTROL_UNUSED2 0x10 +#define LBCIF_CONTROL_TWO_BYTE_ADDR 0x20 +#define LBCIF_CONTROL_I2C_WRITE 0x40 +#define LBCIF_CONTROL_LBCIF_ENABLE 0x80 + +/* LBCIF Status Register Bits */ +#define LBCIF_STATUS_PHY_QUEUE_AVAIL 0x01 +#define LBCIF_STATUS_I2C_IDLE 0x02 +#define LBCIF_STATUS_ACK_ERROR 0x04 +#define LBCIF_STATUS_GENERAL_ERROR 0x08 +#define LBCIF_STATUS_UNUSED 0x30 +#define LBCIF_STATUS_CHECKSUM_ERROR 0x40 +#define LBCIF_STATUS_EEPROM_PRESENT 0x80 + +/* Miscellaneous Constraints */ +#define MAX_NUM_REGISTER_POLLS 1000 +#define MAX_NUM_WRITE_RETRIES 2 + +/* + * Define macros that allow individual register values to be extracted from a + * DWORD1 register grouping + */ +#define EXTRACT_DATA_REGISTER(x) (uint8_t)(x & 0xFF) +#define EXTRACT_STATUS_REGISTER(x) (uint8_t)((x >> 16) & 0xFF) +#define EXTRACT_CONTROL_REG(x) (uint8_t)((x >> 8) & 0xFF) + +/** + * EepromWriteByte - Write a byte to the ET1310's EEPROM + * @pAdapter: pointer to our private adapter structure + * @unAddress: the address to write + * @bData: the value to write + * @unEepronId: the ID of the EEPROM + * @unAddressingMode: how the EEPROM is to be accessed + * + * Returns SUCCESS or FAILURE + */ +int32_t EepromWriteByte(struct et131x_adapter *pAdapter, uint32_t unAddress, + uint8_t bData, uint32_t unEepromId, + uint32_t unAddressingMode) +{ + struct pci_dev *pdev = pAdapter->pdev; + int32_t nIndex; + int32_t nRetries; + int32_t nError = false; + int32_t nI2CWriteActive = 0; + int32_t nWriteSuccessful = 0; + uint8_t bControl; + uint8_t bStatus = 0; + uint32_t unDword1 = 0; + uint32_t unData = 0; + + /* + * The following excerpt is from "Serial EEPROM HW Design + * Specification" Version 0.92 (9/20/2004): + * + * Single Byte Writes + * + * For an EEPROM, an I2C single byte write is defined as a START + * condition followed by the device address, EEPROM address, one byte + * of data and a STOP condition. The STOP condition will trigger the + * EEPROM's internally timed write cycle to the nonvolatile memory. + * All inputs are disabled during this write cycle and the EEPROM will + * not respond to any access until the internal write is complete. + * The steps to execute a single byte write are as follows: + * + * 1. Check LBCIF Status Register for bits 6 & 3:2 all equal to 0 and + * bits 7,1:0 both equal to 1, at least once after reset. + * Subsequent operations need only to check that bits 1:0 are + * equal to 1 prior to starting a single byte write. + * + * 2. Write to the LBCIF Control Register: bit 7=1, bit 6=1, bit 3=0, + * and bits 1:0 both =0. Bit 5 should be set according to the + * type of EEPROM being accessed (1=two byte addressing, 0=one + * byte addressing). + * + * 3. Write the address to the LBCIF Address Register. + * + * 4. Write the data to the LBCIF Data Register (the I2C write will + * begin). + * + * 5. Monitor bit 1:0 of the LBCIF Status Register. When bits 1:0 are + * both equal to 1, the I2C write has completed and the internal + * write cycle of the EEPROM is about to start. (bits 1:0 = 01 is + * a legal state while waiting from both equal to 1, but bits + * 1:0 = 10 is invalid and implies that something is broken). + * + * 6. Check bit 3 of the LBCIF Status Register. If equal to 1, an + * error has occurred. + * + * 7. Check bit 2 of the LBCIF Status Register. If equal to 1 an ACK + * error has occurred on the address phase of the write. This + * could be due to an actual hardware failure or the EEPROM may + * still be in its internal write cycle from a previous write. + * This write operation was ignored and must be repeated later. + * + * 8. Set bit 6 of the LBCIF Control Register = 0. If another write is + * required, go to step 1. + */ + + /* Step 1: */ + for (nIndex = 0; nIndex < MAX_NUM_REGISTER_POLLS; nIndex++) { + /* Read registers grouped in DWORD1 */ + if (pci_read_config_dword(pdev, LBCIF_DWORD1_GROUP_OFFSET, + &unDword1)) { + nError = 1; + break; + } + + bStatus = EXTRACT_STATUS_REGISTER(unDword1); + + if (bStatus & LBCIF_STATUS_PHY_QUEUE_AVAIL && + bStatus & LBCIF_STATUS_I2C_IDLE) { + /* bits 1:0 are equal to 1 */ + break; + } + } + + if (nError || (nIndex >= MAX_NUM_REGISTER_POLLS)) { + return FAILURE; + } + + /* Step 2: */ + bControl = 0; + bControl |= LBCIF_CONTROL_LBCIF_ENABLE | LBCIF_CONTROL_I2C_WRITE; + + if (unAddressingMode == DUAL_BYTE) { + bControl |= LBCIF_CONTROL_TWO_BYTE_ADDR; + } + + if (pci_write_config_byte(pdev, LBCIF_CONTROL_REGISTER_OFFSET, + bControl)) { + return FAILURE; + } + + nI2CWriteActive = 1; + + /* Prepare EEPROM address for Step 3 */ + unAddress |= (unAddressingMode == DUAL_BYTE) ? + (unEepromId << 16) : (unEepromId << 8); + + for (nRetries = 0; nRetries < MAX_NUM_WRITE_RETRIES; nRetries++) { + /* Step 3:*/ + if (pci_write_config_dword(pdev, LBCIF_ADDRESS_REGISTER_OFFSET, + unAddress)) { + break; + } + + /* Step 4: */ + if (pci_write_config_byte(pdev, LBCIF_DATA_REGISTER_OFFSET, + bData)) { + break; + } + + /* Step 5: */ + for (nIndex = 0; nIndex < MAX_NUM_REGISTER_POLLS; nIndex++) { + /* Read registers grouped in DWORD1 */ + if (pci_read_config_dword(pdev, + LBCIF_DWORD1_GROUP_OFFSET, + &unDword1)) { + nError = 1; + break; + } + + bStatus = EXTRACT_STATUS_REGISTER(unDword1); + + if (bStatus & LBCIF_STATUS_PHY_QUEUE_AVAIL && + bStatus & LBCIF_STATUS_I2C_IDLE) { + /* I2C write complete */ + break; + } + } + + if (nError || (nIndex >= MAX_NUM_REGISTER_POLLS)) { + break; + } + + /* + * Step 6: Don't break here if we are revision 1, this is + * so we do a blind write for load bug. + */ + if (bStatus & LBCIF_STATUS_GENERAL_ERROR + && pAdapter->RevisionID == 0) { + break; + } + + /* Step 7 */ + if (bStatus & LBCIF_STATUS_ACK_ERROR) { + /* + * This could be due to an actual hardware failure + * or the EEPROM may still be in its internal write + * cycle from a previous write. This write operation + * was ignored and must be repeated later. + */ + udelay(10); + continue; + } + + nWriteSuccessful = 1; + break; + } + + /* Step 8: */ + udelay(10); + nIndex = 0; + while (nI2CWriteActive) { + bControl &= ~LBCIF_CONTROL_I2C_WRITE; + + if (pci_write_config_byte(pdev, LBCIF_CONTROL_REGISTER_OFFSET, + bControl)) { + nWriteSuccessful = 0; + } + + /* Do read until internal ACK_ERROR goes away meaning write + * completed + */ + do { + pci_write_config_dword(pdev, + LBCIF_ADDRESS_REGISTER_OFFSET, + unAddress); + do { + pci_read_config_dword(pdev, + LBCIF_DATA_REGISTER_OFFSET, &unData); + } while ((unData & 0x00010000) == 0); + } while (unData & 0x00040000); + + bControl = EXTRACT_CONTROL_REG(unData); + + if (bControl != 0xC0 || nIndex == 10000) { + break; + } + + nIndex++; + } + + return nWriteSuccessful ? SUCCESS : FAILURE; +} + +/** + * EepromReadByte - Read a byte from the ET1310's EEPROM + * @pAdapter: pointer to our private adapter structure + * @unAddress: the address from which to read + * @pbData: a pointer to a byte in which to store the value of the read + * @unEepronId: the ID of the EEPROM + * @unAddressingMode: how the EEPROM is to be accessed + * + * Returns SUCCESS or FAILURE + */ +int32_t EepromReadByte(struct et131x_adapter *pAdapter, uint32_t unAddress, + uint8_t *pbData, uint32_t unEepromId, + uint32_t unAddressingMode) +{ + struct pci_dev *pdev = pAdapter->pdev; + int32_t nIndex; + int32_t nError = 0; + uint8_t bControl; + uint8_t bStatus = 0; + uint32_t unDword1 = 0; + + /* + * The following excerpt is from "Serial EEPROM HW Design + * Specification" Version 0.92 (9/20/2004): + * + * Single Byte Reads + * + * A single byte read is similar to the single byte write, with the + * exception of the data flow: + * + * 1. Check LBCIF Status Register for bits 6 & 3:2 all equal to 0 and + * bits 7,1:0 both equal to 1, at least once after reset. + * Subsequent operations need only to check that bits 1:0 are equal + * to 1 prior to starting a single byte read. + * + * 2. Write to the LBCIF Control Register: bit 7=1, bit 6=0, bit 3=0, + * and bits 1:0 both =0. Bit 5 should be set according to the type + * of EEPROM being accessed (1=two byte addressing, 0=one byte + * addressing). + * + * 3. Write the address to the LBCIF Address Register (I2C read will + * begin). + * + * 4. Monitor bit 0 of the LBCIF Status Register. When =1, I2C read + * is complete. (if bit 1 =1 and bit 0 stays =0, a hardware failure + * has occurred). + * + * 5. Check bit 2 of the LBCIF Status Register. If =1, then an error + * has occurred. The data that has been returned from the PHY may + * be invalid. + * + * 6. Regardless of error status, read data byte from LBCIF Data + * Register. If another byte is required, go to step 1. + */ + + /* Step 1: */ + for (nIndex = 0; nIndex < MAX_NUM_REGISTER_POLLS; nIndex++) { + /* Read registers grouped in DWORD1 */ + if (pci_read_config_dword(pdev, LBCIF_DWORD1_GROUP_OFFSET, + &unDword1)) { + nError = 1; + break; + } + + bStatus = EXTRACT_STATUS_REGISTER(unDword1); + + if (bStatus & LBCIF_STATUS_PHY_QUEUE_AVAIL && + bStatus & LBCIF_STATUS_I2C_IDLE) { + /* bits 1:0 are equal to 1 */ + break; + } + } + + if (nError || (nIndex >= MAX_NUM_REGISTER_POLLS)) { + return FAILURE; + } + + /* Step 2: */ + bControl = 0; + bControl |= LBCIF_CONTROL_LBCIF_ENABLE; + + if (unAddressingMode == DUAL_BYTE) { + bControl |= LBCIF_CONTROL_TWO_BYTE_ADDR; + } + + if (pci_write_config_byte(pdev, LBCIF_CONTROL_REGISTER_OFFSET, + bControl)) { + return FAILURE; + } + + /* Step 3: */ + unAddress |= (unAddressingMode == DUAL_BYTE) ? + (unEepromId << 16) : (unEepromId << 8); + + if (pci_write_config_dword(pdev, LBCIF_ADDRESS_REGISTER_OFFSET, + unAddress)) { + return FAILURE; + } + + /* Step 4: */ + for (nIndex = 0; nIndex < MAX_NUM_REGISTER_POLLS; nIndex++) { + /* Read registers grouped in DWORD1 */ + if (pci_read_config_dword(pdev, LBCIF_DWORD1_GROUP_OFFSET, + &unDword1)) { + nError = 1; + break; + } + + bStatus = EXTRACT_STATUS_REGISTER(unDword1); + + if (bStatus & LBCIF_STATUS_PHY_QUEUE_AVAIL + && bStatus & LBCIF_STATUS_I2C_IDLE) { + /* I2C read complete */ + break; + } + } + + if (nError || (nIndex >= MAX_NUM_REGISTER_POLLS)) { + return FAILURE; + } + + /* Step 6: */ + *pbData = EXTRACT_DATA_REGISTER(unDword1); + + return (bStatus & LBCIF_STATUS_ACK_ERROR) ? FAILURE : SUCCESS; +} diff --git a/src/et131x/et1310_eeprom.h b/src/et131x/et1310_eeprom.h new file mode 100644 index 0000000..9b6f8ad --- /dev/null +++ b/src/et131x/et1310_eeprom.h @@ -0,0 +1,89 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et1310_eeprom.h - Defines, structs, enums, prototypes, etc. used for EEPROM + * access routines + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#ifndef __ET1310_EEPROM_H__ +#define __ET1310_EEPROM_H__ + +#include "et1310_address_map.h" + +#ifndef SUCCESS +#define SUCCESS 0 +#define FAILURE 1 +#endif + +#ifndef READ +#define READ 0 +#define WRITE 1 +#endif + +#ifndef SINGLE_BYTE +#define SINGLE_BYTE 0 +#define DUAL_BYTE 1 +#endif + +/* Forward declaration of the private adapter structure */ +struct et131x_adapter; + +int32_t EepromWriteByte(struct et131x_adapter *adapter, u32 unAddress, + u8 bData, u32 unEepromId, + u32 unAddressingMode); +int32_t EepromReadByte(struct et131x_adapter *adapter, u32 unAddress, + u8 *pbData, u32 unEepromId, + u32 unAddressingMode); + +#endif /* _ET1310_EEPROM_H_ */ diff --git a/src/et131x/et1310_jagcore.c b/src/et131x/et1310_jagcore.c new file mode 100644 index 0000000..993b30e --- /dev/null +++ b/src/et131x/et1310_jagcore.c @@ -0,0 +1,220 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et1310_jagcore.c - All code pertaining to the ET1301/ET131x's JAGcore + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#include "et131x_version.h" +#include "et131x_debug.h" +#include "et131x_defs.h" + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> + +#include <linux/sched.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/ctype.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/in.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/bitops.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/if_arp.h> +#include <linux/ioport.h> + +#include "et1310_phy.h" +#include "et1310_pm.h" +#include "et1310_jagcore.h" + +#include "et131x_adapter.h" +#include "et131x_initpci.h" + +/* Data for debugging facilities */ +#ifdef CONFIG_ET131X_DEBUG +extern dbg_info_t *et131x_dbginfo; +#endif /* CONFIG_ET131X_DEBUG */ + +/** + * ConfigGlobalRegs - Used to configure the global registers on the JAGCore + * @pAdpater: pointer to our adapter structure + */ +void ConfigGlobalRegs(struct et131x_adapter *pAdapter) +{ + struct _GLOBAL_t __iomem *pGbl = &pAdapter->CSRAddress->global; + + DBG_ENTER(et131x_dbginfo); + + if (pAdapter->RegistryPhyLoopbk == false) { + if (pAdapter->RegistryJumboPacket < 2048) { + /* Tx / RxDMA and Tx/Rx MAC interfaces have a 1k word + * block of RAM that the driver can split between Tx + * and Rx as it desires. Our default is to split it + * 50/50: + */ + writel(0, &pGbl->rxq_start_addr.value); + writel(pAdapter->RegistryRxMemEnd, + &pGbl->rxq_end_addr.value); + writel(pAdapter->RegistryRxMemEnd + 1, + &pGbl->txq_start_addr.value); + writel(INTERNAL_MEM_SIZE - 1, + &pGbl->txq_end_addr.value); + } else if (pAdapter->RegistryJumboPacket < 8192) { + /* For jumbo packets > 2k but < 8k, split 50-50. */ + writel(0, &pGbl->rxq_start_addr.value); + writel(INTERNAL_MEM_RX_OFFSET, + &pGbl->rxq_end_addr.value); + writel(INTERNAL_MEM_RX_OFFSET + 1, + &pGbl->txq_start_addr.value); + writel(INTERNAL_MEM_SIZE - 1, + &pGbl->txq_end_addr.value); + } else { + /* 9216 is the only packet size greater than 8k that + * is available. The Tx buffer has to be big enough + * for one whole packet on the Tx side. We'll make + * the Tx 9408, and give the rest to Rx + */ + writel(0x0000, &pGbl->rxq_start_addr.value); + writel(0x01b3, &pGbl->rxq_end_addr.value); + writel(0x01b4, &pGbl->txq_start_addr.value); + writel(INTERNAL_MEM_SIZE - 1, + &pGbl->txq_end_addr.value); + } + + /* Initialize the loopback register. Disable all loopbacks. */ + writel(0, &pGbl->loopback.value); + } else { + /* For PHY Line loopback, the memory is configured as if Tx + * and Rx both have all the memory. This is because the + * RxMAC will write data into the space, and the TxMAC will + * read it out. + */ + writel(0, &pGbl->rxq_start_addr.value); + writel(INTERNAL_MEM_SIZE - 1, &pGbl->rxq_end_addr.value); + writel(0, &pGbl->txq_start_addr.value); + writel(INTERNAL_MEM_SIZE - 1, &pGbl->txq_end_addr.value); + + /* Initialize the loopback register (MAC loopback). */ + writel(1, &pGbl->loopback.value); + } + + /* MSI Register */ + writel(0, &pGbl->msi_config.value); + + /* By default, disable the watchdog timer. It will be enabled when + * a packet is queued. + */ + writel(0, &pGbl->watchdog_timer); + + DBG_LEAVE(et131x_dbginfo); +} + +/** + * ConfigMMCRegs - Used to configure the main memory registers in the JAGCore + * @pAdapter: pointer to our adapter structure + */ +void ConfigMMCRegs(struct et131x_adapter *pAdapter) +{ + MMC_CTRL_t mmc_ctrl = { 0 }; + + DBG_ENTER(et131x_dbginfo); + + /* All we need to do is initialize the Memory Control Register */ + mmc_ctrl.bits.force_ce = 0x0; + mmc_ctrl.bits.rxdma_disable = 0x0; + mmc_ctrl.bits.txdma_disable = 0x0; + mmc_ctrl.bits.txmac_disable = 0x0; + mmc_ctrl.bits.rxmac_disable = 0x0; + mmc_ctrl.bits.arb_disable = 0x0; + mmc_ctrl.bits.mmc_enable = 0x1; + + writel(mmc_ctrl.value, &pAdapter->CSRAddress->mmc.mmc_ctrl.value); + + DBG_LEAVE(et131x_dbginfo); +} + +void et131x_enable_interrupts(struct et131x_adapter *adapter) +{ + uint32_t MaskValue; + + /* Enable all global interrupts */ + if ((adapter->FlowControl == TxOnly) || (adapter->FlowControl == Both)) { + MaskValue = INT_MASK_ENABLE; + } else { + MaskValue = INT_MASK_ENABLE_NO_FLOW; + } + + if (adapter->DriverNoPhyAccess) { + MaskValue |= 0x10000; + } + + adapter->CachedMaskValue.value = MaskValue; + writel(MaskValue, &adapter->CSRAddress->global.int_mask.value); +} + +void et131x_disable_interrupts(struct et131x_adapter * adapter) +{ + /* Disable all global interrupts */ + adapter->CachedMaskValue.value = INT_MASK_DISABLE; + writel(INT_MASK_DISABLE, &adapter->CSRAddress->global.int_mask.value); +} diff --git a/src/et131x/et1310_jagcore.h b/src/et131x/et1310_jagcore.h new file mode 100644 index 0000000..9fc8293 --- /dev/null +++ b/src/et131x/et1310_jagcore.h @@ -0,0 +1,112 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et1310_jagcore.h - Defines, structs, enums, prototypes, etc. pertaining to + * the JAGCore + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#ifndef __ET1310_JAGCORE_H__ +#define __ET1310_JAGCORE_H__ + +#include "et1310_address_map.h" + + +#define INTERNAL_MEM_SIZE 0x400 //1024 of internal memory +#define INTERNAL_MEM_RX_OFFSET 0x1FF //50% Tx, 50% Rx + +#define REGS_MAX_ARRAY 4096 + +/* + * For interrupts, normal running is: + * rxdma_xfr_done, phy_interrupt, mac_stat_interrupt, + * watchdog_interrupt & txdma_xfer_done + * + * In both cases, when flow control is enabled for either Tx or bi-direction, + * we additional enable rx_fbr0_low and rx_fbr1_low, so we know when the + * buffer rings are running low. + */ +#define INT_MASK_DISABLE 0xffffffff + +// NOTE: Masking out MAC_STAT Interrupt for now... +//#define INT_MASK_ENABLE 0xfff6bf17 +//#define INT_MASK_ENABLE_NO_FLOW 0xfff6bfd7 +#define INT_MASK_ENABLE 0xfffebf17 +#define INT_MASK_ENABLE_NO_FLOW 0xfffebfd7 + +/* DATA STRUCTURES FOR DIRECT REGISTER ACCESS */ + +typedef struct { + u8 bReadWrite; + u32 nRegCount; + u32 nData[REGS_MAX_ARRAY]; + u32 nOffsets[REGS_MAX_ARRAY]; +} JAGCORE_ACCESS_REGS, *PJAGCORE_ACCESS_REGS; + +typedef struct { + u8 bReadWrite; + u32 nDataWidth; + u32 nRegCount; + u32 nOffsets[REGS_MAX_ARRAY]; + u32 nData[REGS_MAX_ARRAY]; +} PCI_CFG_SPACE_REGS, *PPCI_CFG_SPACE_REGS; + +/* Forward declaration of the private adapter structure */ +struct et131x_adapter; + +void ConfigGlobalRegs(struct et131x_adapter *pAdapter); +void ConfigMMCRegs(struct et131x_adapter *pAdapter); +void et131x_enable_interrupts(struct et131x_adapter *adapter); +void et131x_disable_interrupts(struct et131x_adapter *adapter); + +#endif /* __ET1310_JAGCORE_H__ */ diff --git a/src/et131x/et1310_mac.c b/src/et131x/et1310_mac.c new file mode 100644 index 0000000..1924968 --- /dev/null +++ b/src/et131x/et1310_mac.c @@ -0,0 +1,792 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et1310_mac.c - All code and routines pertaining to the MAC + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#include "et131x_version.h" +#include "et131x_debug.h" +#include "et131x_defs.h" + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> + +#include <linux/sched.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/ctype.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/in.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/bitops.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/if_arp.h> +#include <linux/ioport.h> +#include <linux/crc32.h> + +#include "et1310_phy.h" +#include "et1310_pm.h" +#include "et1310_jagcore.h" +#include "et1310_mac.h" + +#include "et131x_adapter.h" +#include "et131x_initpci.h" + +/* Data for debugging facilities */ +#ifdef CONFIG_ET131X_DEBUG +extern dbg_info_t *et131x_dbginfo; +#endif /* CONFIG_ET131X_DEBUG */ + +/** + * ConfigMacRegs1 - Initialize the first part of MAC regs + * @pAdpater: pointer to our adapter structure + */ +void ConfigMACRegs1(struct et131x_adapter *pAdapter) +{ + struct _MAC_t __iomem *pMac = &pAdapter->CSRAddress->mac; + MAC_STATION_ADDR1_t station1; + MAC_STATION_ADDR2_t station2; + MAC_IPG_t ipg; + MAC_HFDP_t hfdp; + MII_MGMT_CFG_t mii_mgmt_cfg; + + DBG_ENTER(et131x_dbginfo); + + /* First we need to reset everything. Write to MAC configuration + * register 1 to perform reset. + */ + writel(0xC00F0000, &pMac->cfg1.value); + + /* Next lets configure the MAC Inter-packet gap register */ + ipg.bits.non_B2B_ipg_1 = 0x38; // 58d + ipg.bits.non_B2B_ipg_2 = 0x58; // 88d + ipg.bits.min_ifg_enforce = 0x50; // 80d + ipg.bits.B2B_ipg = 0x60; // 96d + writel(ipg.value, &pMac->ipg.value); + + /* Next lets configure the MAC Half Duplex register */ + hfdp.bits.alt_beb_trunc = 0xA; + hfdp.bits.alt_beb_enable = 0x0; + hfdp.bits.bp_no_backoff = 0x0; + hfdp.bits.no_backoff = 0x0; + hfdp.bits.excess_defer = 0x1; + hfdp.bits.rexmit_max = 0xF; + hfdp.bits.coll_window = 0x37; // 55d + writel(hfdp.value, &pMac->hfdp.value); + + /* Next lets configure the MAC Interface Control register */ + writel(0, &pMac->if_ctrl.value); + + /* Let's move on to setting up the mii managment configuration */ + mii_mgmt_cfg.bits.reset_mii_mgmt = 0; + mii_mgmt_cfg.bits.scan_auto_incremt = 0; + mii_mgmt_cfg.bits.preamble_suppress = 0; + mii_mgmt_cfg.bits.mgmt_clk_reset = 0x7; + writel(mii_mgmt_cfg.value, &pMac->mii_mgmt_cfg.value); + + /* Next lets configure the MAC Station Address register. These + * values are read from the EEPROM during initialization and stored + * in the adapter structure. We write what is stored in the adapter + * structure to the MAC Station Address registers high and low. This + * station address is used for generating and checking pause control + * packets. + */ + station2.bits.Octet1 = pAdapter->CurrentAddress[0]; + station2.bits.Octet2 = pAdapter->CurrentAddress[1]; + station1.bits.Octet3 = pAdapter->CurrentAddress[2]; + station1.bits.Octet4 = pAdapter->CurrentAddress[3]; + station1.bits.Octet5 = pAdapter->CurrentAddress[4]; + station1.bits.Octet6 = pAdapter->CurrentAddress[5]; + writel(station1.value, &pMac->station_addr_1.value); + writel(station2.value, &pMac->station_addr_2.value); + + /* Max ethernet packet in bytes that will passed by the mac without + * being truncated. Allow the MAC to pass 4 more than our max packet + * size. This is 4 for the Ethernet CRC. + * + * Packets larger than (RegistryJumboPacket) that do not contain a + * VLAN ID will be dropped by the Rx function. + */ + writel(pAdapter->RegistryJumboPacket + 4, &pMac->max_fm_len.value); + + /* clear out MAC config reset */ + writel(0, &pMac->cfg1.value); + + DBG_LEAVE(et131x_dbginfo); +} + +/** + * ConfigMacRegs2 - Initialize the second part of MAC regs + * @pAdpater: pointer to our adapter structure + */ +void ConfigMACRegs2(struct et131x_adapter *pAdapter) +{ + int32_t delay = 0; + struct _MAC_t __iomem *pMac = &pAdapter->CSRAddress->mac; + MAC_CFG1_t cfg1; + MAC_CFG2_t cfg2; + MAC_IF_CTRL_t ifctrl; + TXMAC_CTL_t ctl; + + DBG_ENTER(et131x_dbginfo); + + ctl.value = readl(&pAdapter->CSRAddress->txmac.ctl.value); + cfg1.value = readl(&pMac->cfg1.value); + cfg2.value = readl(&pMac->cfg2.value); + ifctrl.value = readl(&pMac->if_ctrl.value); + + if (pAdapter->uiLinkSpeed == TRUEPHY_SPEED_1000MBPS) { + cfg2.bits.if_mode = 0x2; + ifctrl.bits.phy_mode = 0x0; + } else { + cfg2.bits.if_mode = 0x1; + ifctrl.bits.phy_mode = 0x1; + } + + /* We need to enable Rx/Tx */ + cfg1.bits.rx_enable = 0x1; + cfg1.bits.tx_enable = 0x1; + + /* Set up flow control */ + cfg1.bits.tx_flow = 0x1; + + if ((pAdapter->FlowControl == RxOnly) || + (pAdapter->FlowControl == Both)) { + cfg1.bits.rx_flow = 0x1; + } else { + cfg1.bits.rx_flow = 0x0; + } + + /* Initialize loop back to off */ + cfg1.bits.loop_back = 0; + + writel(cfg1.value, &pMac->cfg1.value); + + /* Now we need to initialize the MAC Configuration 2 register */ + cfg2.bits.preamble_len = 0x7; + cfg2.bits.huge_frame = 0x0; + /* LENGTH FIELD CHECKING bit4: Set this bit to cause the MAC to check + * the frame's length field to ensure it matches the actual data + * field length. Clear this bit if no length field checking is + * desired. Its default is 0. + */ + cfg2.bits.len_check = 0x1; + + if (pAdapter->RegistryPhyLoopbk == false) { + cfg2.bits.pad_crc = 0x1; + cfg2.bits.crc_enable = 0x1; + } else { + cfg2.bits.pad_crc = 0; + cfg2.bits.crc_enable = 0; + } + + /* 1 - full duplex, 0 - half-duplex */ + cfg2.bits.full_duplex = pAdapter->uiDuplexMode; + ifctrl.bits.ghd_mode = !pAdapter->uiDuplexMode; + + writel(ifctrl.value, &pMac->if_ctrl.value); + writel(cfg2.value, &pMac->cfg2.value); + + do { + udelay(10); + delay++; + cfg1.value = readl(&pMac->cfg1.value); + } while ((!cfg1.bits.syncd_rx_en || + !cfg1.bits.syncd_tx_en) && + delay < 100); + + if (delay == 100) { + DBG_ERROR(et131x_dbginfo, + "Syncd bits did not respond correctly cfg1 word 0x%08x\n", + cfg1.value); + } + + DBG_TRACE(et131x_dbginfo, + "Speed %d, Dup %d, CFG1 0x%08x, CFG2 0x%08x, if_ctrl 0x%08x\n", + pAdapter->uiLinkSpeed, pAdapter->uiDuplexMode, + readl(&pMac->cfg1.value), readl(&pMac->cfg2.value), + readl(&pMac->if_ctrl.value)); + + /* Enable TXMAC */ + ctl.bits.txmac_en = 0x1; + ctl.bits.fc_disable = 0x1; + writel(ctl.value, &pAdapter->CSRAddress->txmac.ctl.value); + + /* Ready to start the RXDMA/TXDMA engine */ + if (!MP_TEST_FLAG(pAdapter, fMP_ADAPTER_LOWER_POWER)) { + et131x_rx_dma_enable(pAdapter); + et131x_tx_dma_enable(pAdapter); + } else { + DBG_WARNING(et131x_dbginfo, + "Didn't enable Rx/Tx due to low-power mode\n"); + } + + DBG_LEAVE(et131x_dbginfo); +} + +void ConfigRxMacRegs(struct et131x_adapter *pAdapter) +{ + struct _RXMAC_t __iomem *pRxMac = &pAdapter->CSRAddress->rxmac; + RXMAC_WOL_SA_LO_t sa_lo; + RXMAC_WOL_SA_HI_t sa_hi; + RXMAC_PF_CTRL_t pf_ctrl = { 0 }; + + DBG_ENTER(et131x_dbginfo); + + /* Disable the MAC while it is being configured (also disable WOL) */ + writel(0x8, &pRxMac->ctrl.value); + + /* Initialize WOL to disabled. */ + writel(0, &pRxMac->crc0.value); + writel(0, &pRxMac->crc12.value); + writel(0, &pRxMac->crc34.value); + + /* We need to set the WOL mask0 - mask4 next. We initialize it to + * its default Values of 0x00000000 because there are not WOL masks + * as of this time. + */ + writel(0, &pRxMac->mask0_word0); + writel(0, &pRxMac->mask0_word1); + writel(0, &pRxMac->mask0_word2); + writel(0, &pRxMac->mask0_word3); + + writel(0, &pRxMac->mask1_word0); + writel(0, &pRxMac->mask1_word1); + writel(0, &pRxMac->mask1_word2); + writel(0, &pRxMac->mask1_word3); + + writel(0, &pRxMac->mask2_word0); + writel(0, &pRxMac->mask2_word1); + writel(0, &pRxMac->mask2_word2); + writel(0, &pRxMac->mask2_word3); + + writel(0, &pRxMac->mask3_word0); + writel(0, &pRxMac->mask3_word1); + writel(0, &pRxMac->mask3_word2); + writel(0, &pRxMac->mask3_word3); + + writel(0, &pRxMac->mask4_word0); + writel(0, &pRxMac->mask4_word1); + writel(0, &pRxMac->mask4_word2); + writel(0, &pRxMac->mask4_word3); + + /* Lets setup the WOL Source Address */ + sa_lo.bits.sa3 = pAdapter->CurrentAddress[2]; + sa_lo.bits.sa4 = pAdapter->CurrentAddress[3]; + sa_lo.bits.sa5 = pAdapter->CurrentAddress[4]; + sa_lo.bits.sa6 = pAdapter->CurrentAddress[5]; + writel(sa_lo.value, &pRxMac->sa_lo.value); + + sa_hi.bits.sa1 = pAdapter->CurrentAddress[0]; + sa_hi.bits.sa2 = pAdapter->CurrentAddress[1]; + writel(sa_hi.value, &pRxMac->sa_hi.value); + + /* Disable all Packet Filtering */ + writel(0, &pRxMac->pf_ctrl.value); + + /* Let's initialize the Unicast Packet filtering address */ + if (pAdapter->PacketFilter & ET131X_PACKET_TYPE_DIRECTED) { + SetupDeviceForUnicast(pAdapter); + pf_ctrl.bits.filter_uni_en = 1; + } else { + writel(0, &pRxMac->uni_pf_addr1.value); + writel(0, &pRxMac->uni_pf_addr2.value); + writel(0, &pRxMac->uni_pf_addr3.value); + } + + /* Let's initialize the Multicast hash */ + if (pAdapter->PacketFilter & ET131X_PACKET_TYPE_ALL_MULTICAST) { + pf_ctrl.bits.filter_multi_en = 0; + } else { + pf_ctrl.bits.filter_multi_en = 1; + SetupDeviceForMulticast(pAdapter); + } + + /* Runt packet filtering. Didn't work in version A silicon. */ + pf_ctrl.bits.min_pkt_size = NIC_MIN_PACKET_SIZE + 4; + pf_ctrl.bits.filter_frag_en = 1; + + if (pAdapter->RegistryJumboPacket > 8192) { + RXMAC_MCIF_CTRL_MAX_SEG_t mcif_ctrl_max_seg; + + /* In order to transmit jumbo packets greater than 8k, the + * FIFO between RxMAC and RxDMA needs to be reduced in size + * to (16k - Jumbo packet size). In order to implement this, + * we must use "cut through" mode in the RxMAC, which chops + * packets down into segments which are (max_size * 16). In + * this case we selected 256 bytes, since this is the size of + * the PCI-Express TLP's that the 1310 uses. + */ + mcif_ctrl_max_seg.bits.seg_en = 0x1; + mcif_ctrl_max_seg.bits.fc_en = 0x0; + mcif_ctrl_max_seg.bits.max_size = 0x10; + + writel(mcif_ctrl_max_seg.value, + &pRxMac->mcif_ctrl_max_seg.value); + } else { + writel(0, &pRxMac->mcif_ctrl_max_seg.value); + } + + /* Initialize the MCIF water marks */ + writel(0, &pRxMac->mcif_water_mark.value); + + /* Initialize the MIF control */ + writel(0, &pRxMac->mif_ctrl.value); + + /* Initialize the Space Available Register */ + writel(0, &pRxMac->space_avail.value); + + /* Initialize the the mif_ctrl register + * bit 3: Receive code error. One or more nibbles were signaled as + * errors during the reception of the packet. Clear this + * bit in Gigabit, set it in 100Mbit. This was derived + * experimentally at UNH. + * bit 4: Receive CRC error. The packet's CRC did not match the + * internally generated CRC. + * bit 5: Receive length check error. Indicates that frame length + * field value in the packet does not match the actual data + * byte length and is not a type field. + * bit 16: Receive frame truncated. + * bit 17: Drop packet enable + */ + if (pAdapter->uiLinkSpeed == TRUEPHY_SPEED_100MBPS) { + writel(0x30038, &pRxMac->mif_ctrl.value); + } else { + writel(0x30030, &pRxMac->mif_ctrl.value); + } + + /* Finally we initialize RxMac to be enabled & WOL disabled. Packet + * filter is always enabled since it is where the runt packets are + * supposed to be dropped. For version A silicon, runt packet + * dropping doesn't work, so it is disabled in the pf_ctrl register, + * but we still leave the packet filter on. + */ + writel(pf_ctrl.value, &pRxMac->pf_ctrl.value); + writel(0x9, &pRxMac->ctrl.value); + + DBG_LEAVE(et131x_dbginfo); +} + +void ConfigTxMacRegs(struct et131x_adapter *pAdapter) +{ + struct _TXMAC_t __iomem *pTxMac = &pAdapter->CSRAddress->txmac; + TXMAC_CF_PARAM_t Local; + + DBG_ENTER(et131x_dbginfo); + + /* We need to update the Control Frame Parameters + * cfpt - control frame pause timer set to 64 (0x40) + * cfep - control frame extended pause timer set to 0x0 + */ + if (pAdapter->FlowControl == None) { + writel(0, &pTxMac->cf_param.value); + } else { + Local.bits.cfpt = 0x40; + Local.bits.cfep = 0x0; + writel(Local.value, &pTxMac->cf_param.value); + } + + DBG_LEAVE(et131x_dbginfo); +} + +void ConfigMacStatRegs(struct et131x_adapter *pAdapter) +{ + struct _MAC_STAT_t __iomem *pDevMacStat = + &pAdapter->CSRAddress->macStat; + + DBG_ENTER(et131x_dbginfo); + + /* Next we need to initialize all the MAC_STAT registers to zero on + * the device. + */ + writel(0, &pDevMacStat->RFcs); + writel(0, &pDevMacStat->RAln); + writel(0, &pDevMacStat->RFlr); + writel(0, &pDevMacStat->RDrp); + writel(0, &pDevMacStat->RCde); + writel(0, &pDevMacStat->ROvr); + writel(0, &pDevMacStat->RFrg); + + writel(0, &pDevMacStat->TScl); + writel(0, &pDevMacStat->TDfr); + writel(0, &pDevMacStat->TMcl); + writel(0, &pDevMacStat->TLcl); + writel(0, &pDevMacStat->TNcl); + writel(0, &pDevMacStat->TOvr); + writel(0, &pDevMacStat->TUnd); + + /* Unmask any counters that we want to track the overflow of. + * Initially this will be all counters. It may become clear later + * that we do not need to track all counters. + */ + { + MAC_STAT_REG_1_t Carry1M = { 0xffffffff }; + + Carry1M.bits.rdrp = 0; + Carry1M.bits.rjbr = 1; + Carry1M.bits.rfrg = 0; + Carry1M.bits.rovr = 0; + Carry1M.bits.rund = 1; + Carry1M.bits.rcse = 1; + Carry1M.bits.rcde = 0; + Carry1M.bits.rflr = 0; + Carry1M.bits.raln = 0; + Carry1M.bits.rxuo = 1; + Carry1M.bits.rxpf = 1; + Carry1M.bits.rxcf = 1; + Carry1M.bits.rbca = 1; + Carry1M.bits.rmca = 1; + Carry1M.bits.rfcs = 0; + Carry1M.bits.rpkt = 1; + Carry1M.bits.rbyt = 1; + Carry1M.bits.trmgv = 1; + Carry1M.bits.trmax = 1; + Carry1M.bits.tr1k = 1; + Carry1M.bits.tr511 = 1; + Carry1M.bits.tr255 = 1; + Carry1M.bits.tr127 = 1; + Carry1M.bits.tr64 = 1; + + writel(Carry1M.value, &pDevMacStat->Carry1M.value); + } + + { + MAC_STAT_REG_2_t Carry2M = { 0xffffffff }; + + Carry2M.bits.tdrp = 1; + Carry2M.bits.tpfh = 1; + Carry2M.bits.tncl = 0; + Carry2M.bits.txcl = 1; + Carry2M.bits.tlcl = 0; + Carry2M.bits.tmcl = 0; + Carry2M.bits.tscl = 0; + Carry2M.bits.tedf = 1; + Carry2M.bits.tdfr = 0; + Carry2M.bits.txpf = 1; + Carry2M.bits.tbca = 1; + Carry2M.bits.tmca = 1; + Carry2M.bits.tpkt = 1; + Carry2M.bits.tbyt = 1; + Carry2M.bits.tfrg = 1; + Carry2M.bits.tund = 0; + Carry2M.bits.tovr = 0; + Carry2M.bits.txcf = 1; + Carry2M.bits.tfcs = 1; + Carry2M.bits.tjbr = 1; + + writel(Carry2M.value, &pDevMacStat->Carry2M.value); + } + + DBG_LEAVE(et131x_dbginfo); +} + +void ConfigFlowControl(struct et131x_adapter * pAdapter) +{ + if (pAdapter->uiDuplexMode == 0) { + pAdapter->FlowControl = None; + } else { + char RemotePause, RemoteAsyncPause; + + ET1310_PhyAccessMiBit(pAdapter, + TRUEPHY_BIT_READ, 5, 10, &RemotePause); + ET1310_PhyAccessMiBit(pAdapter, + TRUEPHY_BIT_READ, 5, 11, + &RemoteAsyncPause); + + if ((RemotePause == TRUEPHY_BIT_SET) && + (RemoteAsyncPause == TRUEPHY_BIT_SET)) { + pAdapter->FlowControl = pAdapter->RegistryFlowControl; + } else if ((RemotePause == TRUEPHY_BIT_SET) && + (RemoteAsyncPause == TRUEPHY_BIT_CLEAR)) { + if (pAdapter->RegistryFlowControl == Both) { + pAdapter->FlowControl = Both; + } else { + pAdapter->FlowControl = None; + } + } else if ((RemotePause == TRUEPHY_BIT_CLEAR) && + (RemoteAsyncPause == TRUEPHY_BIT_CLEAR)) { + pAdapter->FlowControl = None; + } else {/* if (RemotePause == TRUEPHY_CLEAR_BIT && + RemoteAsyncPause == TRUEPHY_SET_BIT) */ + if (pAdapter->RegistryFlowControl == Both) { + pAdapter->FlowControl = RxOnly; + } else { + pAdapter->FlowControl = None; + } + } + } +} + +/** + * UpdateMacStatHostCounters - Update the local copy of the statistics + * @pAdapter: pointer to the adapter structure + */ +void UpdateMacStatHostCounters(struct et131x_adapter *pAdapter) +{ + struct _ce_stats_t *stats = &pAdapter->Stats; + struct _MAC_STAT_t __iomem *pDevMacStat = + &pAdapter->CSRAddress->macStat; + + stats->collisions += readl(&pDevMacStat->TNcl); + stats->first_collision += readl(&pDevMacStat->TScl); + stats->tx_deferred += readl(&pDevMacStat->TDfr); + stats->excessive_collisions += readl(&pDevMacStat->TMcl); + stats->late_collisions += readl(&pDevMacStat->TLcl); + stats->tx_uflo += readl(&pDevMacStat->TUnd); + stats->max_pkt_error += readl(&pDevMacStat->TOvr); + + stats->alignment_err += readl(&pDevMacStat->RAln); + stats->crc_err += readl(&pDevMacStat->RCde); + stats->norcvbuf += readl(&pDevMacStat->RDrp); + stats->rx_ov_flow += readl(&pDevMacStat->ROvr); + stats->code_violations += readl(&pDevMacStat->RFcs); + stats->length_err += readl(&pDevMacStat->RFlr); + + stats->other_errors += readl(&pDevMacStat->RFrg); +} + +/** + * HandleMacStatInterrupt + * @pAdapter: pointer to the adapter structure + * + * One of the MACSTAT counters has wrapped. Update the local copy of + * the statistics held in the adapter structure, checking the "wrap" + * bit for each counter. + */ +void HandleMacStatInterrupt(struct et131x_adapter *pAdapter) +{ + MAC_STAT_REG_1_t Carry1; + MAC_STAT_REG_2_t Carry2; + + DBG_ENTER(et131x_dbginfo); + + /* Read the interrupt bits from the register(s). These are Clear On + * Write. + */ + Carry1.value = readl(&pAdapter->CSRAddress->macStat.Carry1.value); + Carry2.value = readl(&pAdapter->CSRAddress->macStat.Carry2.value); + + writel(Carry1.value, &pAdapter->CSRAddress->macStat.Carry1.value); + writel(Carry2.value, &pAdapter->CSRAddress->macStat.Carry2.value); + + /* We need to do update the host copy of all the MAC_STAT counters. + * For each counter, check it's overflow bit. If the overflow bit is + * set, then increment the host version of the count by one complete + * revolution of the counter. This routine is called when the counter + * block indicates that one of the counters has wrapped. + */ + if (Carry1.bits.rfcs) { + pAdapter->Stats.code_violations += COUNTER_WRAP_16_BIT; + } + if (Carry1.bits.raln) { + pAdapter->Stats.alignment_err += COUNTER_WRAP_12_BIT; + } + if (Carry1.bits.rflr) { + pAdapter->Stats.length_err += COUNTER_WRAP_16_BIT; + } + if (Carry1.bits.rfrg) { + pAdapter->Stats.other_errors += COUNTER_WRAP_16_BIT; + } + if (Carry1.bits.rcde) { + pAdapter->Stats.crc_err += COUNTER_WRAP_16_BIT; + } + if (Carry1.bits.rovr) { + pAdapter->Stats.rx_ov_flow += COUNTER_WRAP_16_BIT; + } + if (Carry1.bits.rdrp) { + pAdapter->Stats.norcvbuf += COUNTER_WRAP_16_BIT; + } + if (Carry2.bits.tovr) { + pAdapter->Stats.max_pkt_error += COUNTER_WRAP_12_BIT; + } + if (Carry2.bits.tund) { + pAdapter->Stats.tx_uflo += COUNTER_WRAP_12_BIT; + } + if (Carry2.bits.tscl) { + pAdapter->Stats.first_collision += COUNTER_WRAP_12_BIT; + } + if (Carry2.bits.tdfr) { + pAdapter->Stats.tx_deferred += COUNTER_WRAP_12_BIT; + } + if (Carry2.bits.tmcl) { + pAdapter->Stats.excessive_collisions += COUNTER_WRAP_12_BIT; + } + if (Carry2.bits.tlcl) { + pAdapter->Stats.late_collisions += COUNTER_WRAP_12_BIT; + } + if (Carry2.bits.tncl) { + pAdapter->Stats.collisions += COUNTER_WRAP_12_BIT; + } + + DBG_LEAVE(et131x_dbginfo); +} + +void SetupDeviceForMulticast(struct et131x_adapter *pAdapter) +{ + struct _RXMAC_t __iomem *rxmac = &pAdapter->CSRAddress->rxmac; + uint32_t nIndex; + uint32_t result; + uint32_t hash1 = 0; + uint32_t hash2 = 0; + uint32_t hash3 = 0; + uint32_t hash4 = 0; + PM_CSR_t pm_csr; + + DBG_ENTER(et131x_dbginfo); + + /* If ET131X_PACKET_TYPE_MULTICAST is specified, then we provision + * the multi-cast LIST. If it is NOT specified, (and "ALL" is not + * specified) then we should pass NO multi-cast addresses to the + * driver. + */ + if (pAdapter->PacketFilter & ET131X_PACKET_TYPE_MULTICAST) { + DBG_VERBOSE(et131x_dbginfo, + "MULTICAST flag is set, MCCount: %d\n", + pAdapter->MCAddressCount); + + /* Loop through our multicast array and set up the device */ + for (nIndex = 0; nIndex < pAdapter->MCAddressCount; nIndex++) { + DBG_VERBOSE(et131x_dbginfo, + "MCList[%d]: %02x:%02x:%02x:%02x:%02x:%02x\n", + nIndex, + pAdapter->MCList[nIndex][0], + pAdapter->MCList[nIndex][1], + pAdapter->MCList[nIndex][2], + pAdapter->MCList[nIndex][3], + pAdapter->MCList[nIndex][4], + pAdapter->MCList[nIndex][5]); + + result = ether_crc(6, pAdapter->MCList[nIndex]); + + result = (result & 0x3F800000) >> 23; + + if (result < 32) { + hash1 |= (1 << result); + } else if ((31 < result) && (result < 64)) { + result -= 32; + hash2 |= (1 << result); + } else if ((63 < result) && (result < 96)) { + result -= 64; + hash3 |= (1 << result); + } else { + result -= 96; + hash4 |= (1 << result); + } + } + } + + /* Write out the new hash to the device */ + pm_csr.value = readl(&pAdapter->CSRAddress->global.pm_csr.value); + if (pm_csr.bits.pm_phy_sw_coma == 0) { + writel(hash1, &rxmac->multi_hash1); + writel(hash2, &rxmac->multi_hash2); + writel(hash3, &rxmac->multi_hash3); + writel(hash4, &rxmac->multi_hash4); + } + + DBG_LEAVE(et131x_dbginfo); +} + +void SetupDeviceForUnicast(struct et131x_adapter *pAdapter) +{ + struct _RXMAC_t __iomem *rxmac = &pAdapter->CSRAddress->rxmac; + RXMAC_UNI_PF_ADDR1_t uni_pf1; + RXMAC_UNI_PF_ADDR2_t uni_pf2; + RXMAC_UNI_PF_ADDR3_t uni_pf3; + PM_CSR_t pm_csr; + + DBG_ENTER(et131x_dbginfo); + + /* Set up unicast packet filter reg 3 to be the first two octets of + * the MAC address for both address + * + * Set up unicast packet filter reg 2 to be the octets 2 - 5 of the + * MAC address for second address + * + * Set up unicast packet filter reg 3 to be the octets 2 - 5 of the + * MAC address for first address + */ + uni_pf3.bits.addr1_1 = pAdapter->CurrentAddress[0]; + uni_pf3.bits.addr1_2 = pAdapter->CurrentAddress[1]; + uni_pf3.bits.addr2_1 = pAdapter->CurrentAddress[0]; + uni_pf3.bits.addr2_2 = pAdapter->CurrentAddress[1]; + + uni_pf2.bits.addr2_3 = pAdapter->CurrentAddress[2]; + uni_pf2.bits.addr2_4 = pAdapter->CurrentAddress[3]; + uni_pf2.bits.addr2_5 = pAdapter->CurrentAddress[4]; + uni_pf2.bits.addr2_6 = pAdapter->CurrentAddress[5]; + + uni_pf1.bits.addr1_3 = pAdapter->CurrentAddress[2]; + uni_pf1.bits.addr1_4 = pAdapter->CurrentAddress[3]; + uni_pf1.bits.addr1_5 = pAdapter->CurrentAddress[4]; + uni_pf1.bits.addr1_6 = pAdapter->CurrentAddress[5]; + + pm_csr.value = readl(&pAdapter->CSRAddress->global.pm_csr.value); + if (pm_csr.bits.pm_phy_sw_coma == 0) { + writel(uni_pf1.value, &rxmac->uni_pf_addr1.value); + writel(uni_pf2.value, &rxmac->uni_pf_addr2.value); + writel(uni_pf3.value, &rxmac->uni_pf_addr3.value); + } + + DBG_LEAVE(et131x_dbginfo); +} diff --git a/src/et131x/et1310_mac.h b/src/et131x/et1310_mac.h new file mode 100644 index 0000000..bd26cd3 --- /dev/null +++ b/src/et131x/et1310_mac.h @@ -0,0 +1,93 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et1310_mac.h - Defines, structs, enums, prototypes, etc. pertaining to the + * MAC. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#ifndef _ET1310_MAC_H_ +#define _ET1310_MAC_H_ + + +#include "et1310_address_map.h" + + +#define COUNTER_WRAP_28_BIT 0x10000000 +#define COUNTER_WRAP_22_BIT 0x400000 +#define COUNTER_WRAP_16_BIT 0x10000 +#define COUNTER_WRAP_12_BIT 0x1000 + +#define COUNTER_MASK_28_BIT (COUNTER_WRAP_28_BIT - 1) +#define COUNTER_MASK_22_BIT (COUNTER_WRAP_22_BIT - 1) +#define COUNTER_MASK_16_BIT (COUNTER_WRAP_16_BIT - 1) +#define COUNTER_MASK_12_BIT (COUNTER_WRAP_12_BIT - 1) + +#define UPDATE_COUNTER(HostCnt,DevCnt) \ + HostCnt = HostCnt + DevCnt; + +/* Forward declaration of the private adapter structure */ +struct et131x_adapter; + +void ConfigMACRegs1(struct et131x_adapter *adapter); +void ConfigMACRegs2(struct et131x_adapter *adapter); +void ConfigRxMacRegs(struct et131x_adapter *adapter); +void ConfigTxMacRegs(struct et131x_adapter *adapter); +void ConfigMacStatRegs(struct et131x_adapter *adapter); +void ConfigFlowControl(struct et131x_adapter *adapter); +void UpdateMacStatHostCounters(struct et131x_adapter *adapter); +void HandleMacStatInterrupt(struct et131x_adapter *adapter); +void SetupDeviceForMulticast(struct et131x_adapter *adapter); +void SetupDeviceForUnicast(struct et131x_adapter *adapter); + +#endif /* _ET1310_MAC_H_ */ diff --git a/src/et131x/et1310_phy.c b/src/et131x/et1310_phy.c new file mode 100644 index 0000000..6c4fa54 --- /dev/null +++ b/src/et131x/et1310_phy.c @@ -0,0 +1,1281 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et1310_phy.c - Routines for configuring and accessing the PHY + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#include "et131x_version.h" +#include "et131x_debug.h" +#include "et131x_defs.h" + +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> + +#include <linux/sched.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/ctype.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/in.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/bitops.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/if_arp.h> +#include <linux/ioport.h> +#include <linux/random.h> +#include <linux/delay.h> + +#include "et1310_phy.h" +#include "et1310_pm.h" +#include "et1310_jagcore.h" + +#include "et131x_adapter.h" +#include "et131x_netdev.h" +#include "et131x_initpci.h" + +#include "et1310_address_map.h" +#include "et1310_jagcore.h" +#include "et1310_tx.h" +#include "et1310_rx.h" +#include "et1310_mac.h" + +/* Data for debugging facilities */ +#ifdef CONFIG_ET131X_DEBUG +extern dbg_info_t *et131x_dbginfo; +#endif /* CONFIG_ET131X_DEBUG */ + +/* Prototypes for functions with local scope */ +static int et131x_xcvr_init(struct et131x_adapter *adapter); + +/** + * PhyMiRead - Read from the PHY through the MII Interface on the MAC + * @adapter: pointer to our private adapter structure + * @xcvrAddr: the address of the transciever + * @xcvrReg: the register to read + * @value: pointer to a 16-bit value in which the value will be stored + * + * Returns 0 on success, errno on failure (as defined in errno.h) + */ +int PhyMiRead(struct et131x_adapter *adapter, uint8_t xcvrAddr, + uint8_t xcvrReg, uint16_t *value) +{ + struct _MAC_t __iomem *mac = &adapter->CSRAddress->mac; + int status = 0; + uint32_t delay; + MII_MGMT_ADDR_t miiAddr; + MII_MGMT_CMD_t miiCmd; + MII_MGMT_INDICATOR_t miiIndicator; + + /* Save a local copy of the registers we are dealing with so we can + * set them back + */ + miiAddr.value = readl(&mac->mii_mgmt_addr.value); + miiCmd.value = readl(&mac->mii_mgmt_cmd.value); + + /* Stop the current operation */ + writel(0, &mac->mii_mgmt_cmd.value); + + /* Set up the register we need to read from on the correct PHY */ + { + MII_MGMT_ADDR_t mii_mgmt_addr = { 0 }; + + mii_mgmt_addr.bits.phy_addr = xcvrAddr; + mii_mgmt_addr.bits.reg_addr = xcvrReg; + writel(mii_mgmt_addr.value, &mac->mii_mgmt_addr.value); + } + + /* Kick the read cycle off */ + delay = 0; + + writel(0x1, &mac->mii_mgmt_cmd.value); + + do { + udelay(50); + delay++; + miiIndicator.value = readl(&mac->mii_mgmt_indicator.value); + } while ((miiIndicator.bits.not_valid || miiIndicator.bits.busy) && + delay < 50); + + /* If we hit the max delay, we could not read the register */ + if (delay >= 50) { + DBG_WARNING(et131x_dbginfo, + "xcvrReg 0x%08x could not be read\n", xcvrReg); + DBG_WARNING(et131x_dbginfo, "status is 0x%08x\n", + miiIndicator.value); + + status = -EIO; + } + + /* If we hit here we were able to read the register and we need to + * return the value to the caller + */ + /* TODO: make this stuff a simple readw()?! */ + { + MII_MGMT_STAT_t mii_mgmt_stat; + + mii_mgmt_stat.value = readl(&mac->mii_mgmt_stat.value); + *value = (uint16_t) mii_mgmt_stat.bits.phy_stat; + } + + /* Stop the read operation */ + writel(0, &mac->mii_mgmt_cmd.value); + + DBG_VERBOSE(et131x_dbginfo, " xcvr_addr = 0x%02x, " + "xcvr_reg = 0x%02x, " + "value = 0x%04x.\n", xcvrAddr, xcvrReg, *value); + + /* set the registers we touched back to the state at which we entered + * this function + */ + writel(miiAddr.value, &mac->mii_mgmt_addr.value); + writel(miiCmd.value, &mac->mii_mgmt_cmd.value); + + return status; +} + +/** + * MiWrite - Write to a PHY register through the MII interface of the MAC + * @adapter: pointer to our private adapter structure + * @xcvrReg: the register to read + * @value: 16-bit value to write + * + * Return 0 on success, errno on failure (as defined in errno.h) + */ +int MiWrite(struct et131x_adapter *adapter, uint8_t xcvrReg, uint16_t value) +{ + struct _MAC_t __iomem *mac = &adapter->CSRAddress->mac; + int status = 0; + uint8_t xcvrAddr = adapter->Stats.xcvr_addr; + uint32_t delay; + MII_MGMT_ADDR_t miiAddr; + MII_MGMT_CMD_t miiCmd; + MII_MGMT_INDICATOR_t miiIndicator; + + /* Save a local copy of the registers we are dealing with so we can + * set them back + */ + miiAddr.value = readl(&mac->mii_mgmt_addr.value); + miiCmd.value = readl(&mac->mii_mgmt_cmd.value); + + /* Stop the current operation */ + writel(0, &mac->mii_mgmt_cmd.value); + + /* Set up the register we need to write to on the correct PHY */ + { + MII_MGMT_ADDR_t mii_mgmt_addr; + + mii_mgmt_addr.bits.phy_addr = xcvrAddr; + mii_mgmt_addr.bits.reg_addr = xcvrReg; + writel(mii_mgmt_addr.value, &mac->mii_mgmt_addr.value); + } + + /* Add the value to write to the registers to the mac */ + writel(value, &mac->mii_mgmt_ctrl.value); + delay = 0; + + do { + udelay(50); + delay++; + miiIndicator.value = readl(&mac->mii_mgmt_indicator.value); + } while (miiIndicator.bits.busy && delay < 100); + + /* If we hit the max delay, we could not write the register */ + if (delay == 100) { + uint16_t TempValue; + + DBG_WARNING(et131x_dbginfo, + "xcvrReg 0x%08x could not be written", xcvrReg); + DBG_WARNING(et131x_dbginfo, "status is 0x%08x\n", + miiIndicator.value); + DBG_WARNING(et131x_dbginfo, "command is 0x%08x\n", + readl(&mac->mii_mgmt_cmd.value)); + + MiRead(adapter, xcvrReg, &TempValue); + + status = -EIO; + } + + /* Stop the write operation */ + writel(0, &mac->mii_mgmt_cmd.value); + + /* set the registers we touched back to the state at which we entered + * this function + */ + writel(miiAddr.value, &mac->mii_mgmt_addr.value); + writel(miiCmd.value, &mac->mii_mgmt_cmd.value); + + DBG_VERBOSE(et131x_dbginfo, " xcvr_addr = 0x%02x, " + "xcvr_reg = 0x%02x, " + "value = 0x%04x.\n", xcvrAddr, xcvrReg, value); + + return status; +} + +/** + * et131x_xcvr_find - Find the PHY ID + * @adapter: pointer to our private adapter structure + * + * Returns 0 on success, errno on failure (as defined in errno.h) + */ +int et131x_xcvr_find(struct et131x_adapter *adapter) +{ + int status = -ENODEV; + uint8_t xcvr_addr; + MI_IDR1_t idr1; + MI_IDR2_t idr2; + uint32_t xcvr_id; + + DBG_ENTER(et131x_dbginfo); + + /* We need to get xcvr id and address we just get the first one */ + for (xcvr_addr = 0; xcvr_addr < 32; xcvr_addr++) { + /* Read the ID from the PHY */ + PhyMiRead(adapter, xcvr_addr, + (uint8_t) offsetof(MI_REGS_t, idr1), + &idr1.value); + PhyMiRead(adapter, xcvr_addr, + (uint8_t) offsetof(MI_REGS_t, idr2), + &idr2.value); + + xcvr_id = (uint32_t) ((idr1.value << 16) | idr2.value); + + if ((idr1.value != 0) && (idr1.value != 0xffff)) { + DBG_TRACE(et131x_dbginfo, + "Xcvr addr: 0x%02x\tXcvr_id: 0x%08x\n", + xcvr_addr, xcvr_id); + + adapter->Stats.xcvr_id = xcvr_id; + adapter->Stats.xcvr_addr = xcvr_addr; + + status = 0; + break; + } + } + + DBG_LEAVE(et131x_dbginfo); + return status; +} + +/** + * et131x_setphy_normal - Set PHY for normal operation. + * @adapter: pointer to our private adapter structure + * + * Used by Power Management to force the PHY into 10 Base T half-duplex mode, + * when going to D3 in WOL mode. Also used during initialization to set the + * PHY for normal operation. + */ +int et131x_setphy_normal(struct et131x_adapter *adapter) +{ + int status; + + DBG_ENTER(et131x_dbginfo); + + /* Make sure the PHY is powered up */ + ET1310_PhyPowerDown(adapter, 0); + status = et131x_xcvr_init(adapter); + + DBG_LEAVE(et131x_dbginfo); + return status; +} + +/** + * et131x_xcvr_init - Init the phy if we are setting it into force mode + * @adapter: pointer to our private adapter structure + * + * Returns 0 on success, errno on failure (as defined in errno.h) + */ +static int et131x_xcvr_init(struct et131x_adapter *adapter) +{ + int status = 0; + MI_IMR_t imr; + MI_ISR_t isr; + MI_LCR2_t lcr2; + + DBG_ENTER(et131x_dbginfo); + + /* Zero out the adapter structure variable representing BMSR */ + adapter->Bmsr.value = 0; + + MiRead(adapter, (uint8_t) offsetof(MI_REGS_t, isr), &isr.value); + + MiRead(adapter, (uint8_t) offsetof(MI_REGS_t, imr), &imr.value); + + /* Set the link status interrupt only. Bad behavior when link status + * and auto neg are set, we run into a nested interrupt problem + */ + imr.bits.int_en = 0x1; + imr.bits.link_status = 0x1; + imr.bits.autoneg_status = 0x1; + + MiWrite(adapter, (uint8_t) offsetof(MI_REGS_t, imr), imr.value); + + /* Set the LED behavior such that LED 1 indicates speed (off = + * 10Mbits, blink = 100Mbits, on = 1000Mbits) and LED 2 indicates + * link and activity (on for link, blink off for activity). + * + * NOTE: Some customizations have been added here for specific + * vendors; The LED behavior is now determined by vendor data in the + * EEPROM. However, the above description is the default. + */ + if ((adapter->eepromData[1] & 0x4) == 0) { + MiRead(adapter, (uint8_t) offsetof(MI_REGS_t, lcr2), + &lcr2.value); + if ((adapter->eepromData[1] & 0x8) == 0) + lcr2.bits.led_tx_rx = 0x3; + else + lcr2.bits.led_tx_rx = 0x4; + lcr2.bits.led_link = 0xa; + MiWrite(adapter, (uint8_t) offsetof(MI_REGS_t, lcr2), + lcr2.value); + } + + /* Determine if we need to go into a force mode and set it */ + if (adapter->AiForceSpeed == 0 && adapter->AiForceDpx == 0) { + if ((adapter->RegistryFlowControl == TxOnly) || + (adapter->RegistryFlowControl == Both)) { + ET1310_PhyAccessMiBit(adapter, + TRUEPHY_BIT_SET, 4, 11, NULL); + } else { + ET1310_PhyAccessMiBit(adapter, + TRUEPHY_BIT_CLEAR, 4, 11, NULL); + } + + if (adapter->RegistryFlowControl == Both) { + ET1310_PhyAccessMiBit(adapter, + TRUEPHY_BIT_SET, 4, 10, NULL); + } else { + ET1310_PhyAccessMiBit(adapter, + TRUEPHY_BIT_CLEAR, 4, 10, NULL); + } + + /* Set the phy to autonegotiation */ + ET1310_PhyAutoNeg(adapter, true); + + /* NOTE - Do we need this? */ + ET1310_PhyAccessMiBit(adapter, TRUEPHY_BIT_SET, 0, 9, NULL); + + DBG_LEAVE(et131x_dbginfo); + return status; + } else { + ET1310_PhyAutoNeg(adapter, false); + + /* Set to the correct force mode. */ + if (adapter->AiForceDpx != 1) { + if ((adapter->RegistryFlowControl == TxOnly) || + (adapter->RegistryFlowControl == Both)) { + ET1310_PhyAccessMiBit(adapter, + TRUEPHY_BIT_SET, 4, 11, + NULL); + } else { + ET1310_PhyAccessMiBit(adapter, + TRUEPHY_BIT_CLEAR, 4, 11, + NULL); + } + + if (adapter->RegistryFlowControl == Both) { + ET1310_PhyAccessMiBit(adapter, + TRUEPHY_BIT_SET, 4, 10, + NULL); + } else { + ET1310_PhyAccessMiBit(adapter, + TRUEPHY_BIT_CLEAR, 4, 10, + NULL); + } + } else { + ET1310_PhyAccessMiBit(adapter, + TRUEPHY_BIT_CLEAR, 4, 10, NULL); + ET1310_PhyAccessMiBit(adapter, + TRUEPHY_BIT_CLEAR, 4, 11, NULL); + } + + switch (adapter->AiForceSpeed) { + case 10: + if (adapter->AiForceDpx == 1) { + TPAL_SetPhy10HalfDuplex(adapter); + } else if (adapter->AiForceDpx == 2) { + TPAL_SetPhy10FullDuplex(adapter); + } else { + TPAL_SetPhy10Force(adapter); + } + break; + case 100: + if (adapter->AiForceDpx == 1) { + TPAL_SetPhy100HalfDuplex(adapter); + } else if (adapter->AiForceDpx == 2) { + TPAL_SetPhy100FullDuplex(adapter); + } else { + TPAL_SetPhy100Force(adapter); + } + break; + case 1000: + TPAL_SetPhy1000FullDuplex(adapter); + break; + } + + DBG_LEAVE(et131x_dbginfo); + return status; + } +} + +void et131x_Mii_check(struct et131x_adapter *pAdapter, + MI_BMSR_t bmsr, MI_BMSR_t bmsr_ints) +{ + uint8_t ucLinkStatus; + uint32_t uiAutoNegStatus; + uint32_t uiSpeed; + uint32_t uiDuplex; + uint32_t uiMdiMdix; + uint32_t uiMasterSlave; + uint32_t uiPolarity; + unsigned long lockflags; + + DBG_ENTER(et131x_dbginfo); + + if (bmsr_ints.bits.link_status) { + if (bmsr.bits.link_status) { + pAdapter->PoMgmt.TransPhyComaModeOnBoot = 20; + + /* Update our state variables and indicate the + * connected state + */ + spin_lock_irqsave(&pAdapter->Lock, lockflags); + + pAdapter->MediaState = NETIF_STATUS_MEDIA_CONNECT; + MP_CLEAR_FLAG(pAdapter, fMP_ADAPTER_LINK_DETECTION); + + spin_unlock_irqrestore(&pAdapter->Lock, lockflags); + + /* Don't indicate state if we're in loopback mode */ + if (pAdapter->RegistryPhyLoopbk == false) { + netif_carrier_on(pAdapter->netdev); + } + } else { + DBG_WARNING(et131x_dbginfo, + "Link down cable problem\n"); + + if (pAdapter->uiLinkSpeed == TRUEPHY_SPEED_10MBPS) { + // NOTE - Is there a way to query this without TruePHY? + // && TRU_QueryCoreType(pAdapter->hTruePhy, 0) == EMI_TRUEPHY_A13O) { + uint16_t Register18; + + MiRead(pAdapter, 0x12, &Register18); + MiWrite(pAdapter, 0x12, Register18 | 0x4); + MiWrite(pAdapter, 0x10, Register18 | 0x8402); + MiWrite(pAdapter, 0x11, Register18 | 511); + MiWrite(pAdapter, 0x12, Register18); + } + + /* For the first N seconds of life, we are in "link + * detection" When we are in this state, we should + * only report "connected". When the LinkDetection + * Timer expires, we can report disconnected (handled + * in the LinkDetectionDPC). + */ + if ((MP_IS_FLAG_CLEAR + (pAdapter, fMP_ADAPTER_LINK_DETECTION)) + || (pAdapter->MediaState == + NETIF_STATUS_MEDIA_DISCONNECT)) { + spin_lock_irqsave(&pAdapter->Lock, lockflags); + pAdapter->MediaState = + NETIF_STATUS_MEDIA_DISCONNECT; + spin_unlock_irqrestore(&pAdapter->Lock, + lockflags); + + /* Only indicate state if we're in loopback + * mode + */ + if (pAdapter->RegistryPhyLoopbk == false) { + netif_carrier_off(pAdapter->netdev); + } + } + + pAdapter->uiLinkSpeed = 0; + pAdapter->uiDuplexMode = 0; + + /* Free the packets being actively sent & stopped */ + et131x_free_busy_send_packets(pAdapter); + + /* Re-initialize the send structures */ + et131x_init_send(pAdapter); + + /* Reset the RFD list and re-start RU */ + et131x_reset_recv(pAdapter); + + /* + * Bring the device back to the state it was during + * init prior to autonegotiation being complete. This + * way, when we get the auto-neg complete interrupt, + * we can complete init by calling ConfigMacREGS2. + */ + et131x_soft_reset(pAdapter); + + /* Setup ET1310 as per the documentation */ + et131x_adapter_setup(pAdapter); + + /* Setup the PHY into coma mode until the cable is + * plugged back in + */ + if (pAdapter->RegistryPhyComa == 1) { + EnablePhyComa(pAdapter); + } + } + } + + if (bmsr_ints.bits.auto_neg_complete || + ((pAdapter->AiForceDpx == 3) && (bmsr_ints.bits.link_status))) { + if (bmsr.bits.auto_neg_complete || (pAdapter->AiForceDpx == 3)) { + ET1310_PhyLinkStatus(pAdapter, + &ucLinkStatus, &uiAutoNegStatus, + &uiSpeed, &uiDuplex, &uiMdiMdix, + &uiMasterSlave, &uiPolarity); + + pAdapter->uiLinkSpeed = uiSpeed; + pAdapter->uiDuplexMode = uiDuplex; + + DBG_TRACE(et131x_dbginfo, + "pAdapter->uiLinkSpeed 0x%04x, pAdapter->uiDuplex 0x%08x\n", + pAdapter->uiLinkSpeed, + pAdapter->uiDuplexMode); + + pAdapter->PoMgmt.TransPhyComaModeOnBoot = 20; + + if (pAdapter->uiLinkSpeed == TRUEPHY_SPEED_10MBPS) { + // NOTE - Is there a way to query this without TruePHY? + // && TRU_QueryCoreType(pAdapter->hTruePhy, 0) == EMI_TRUEPHY_A13O) { + uint16_t Register18; + + MiRead(pAdapter, 0x12, &Register18); + MiWrite(pAdapter, 0x12, Register18 | 0x4); + MiWrite(pAdapter, 0x10, Register18 | 0x8402); + MiWrite(pAdapter, 0x11, Register18 | 511); + MiWrite(pAdapter, 0x12, Register18); + } + + ConfigFlowControl(pAdapter); + + if ((pAdapter->uiLinkSpeed == TRUEPHY_SPEED_1000MBPS) && + (pAdapter->RegistryJumboPacket > 2048)) + { + ET1310_PhyAndOrReg(pAdapter, 0x16, 0xcfff, + 0x2000); + } + + SetRxDmaTimer(pAdapter); + ConfigMACRegs2(pAdapter); + } + } + + DBG_LEAVE(et131x_dbginfo); +} + +/** + * TPAL_SetPhy10HalfDuplex - Force the phy into 10 Base T Half Duplex mode. + * @pAdapter: pointer to the adapter structure + * + * Also sets the MAC so it is syncd up properly + */ +void TPAL_SetPhy10HalfDuplex(struct et131x_adapter *pAdapter) +{ + DBG_ENTER(et131x_dbginfo); + + /* Power down PHY */ + ET1310_PhyPowerDown(pAdapter, 1); + + /* First we need to turn off all other advertisement */ + ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); + + ET1310_PhyAdvertise100BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); + + /* Set our advertise values accordingly */ + ET1310_PhyAdvertise10BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_HALF); + + /* Power up PHY */ + ET1310_PhyPowerDown(pAdapter, 0); + + DBG_LEAVE(et131x_dbginfo); +} + +/** + * TPAL_SetPhy10FullDuplex - Force the phy into 10 Base T Full Duplex mode. + * @pAdapter: pointer to the adapter structure + * + * Also sets the MAC so it is syncd up properly + */ +void TPAL_SetPhy10FullDuplex(struct et131x_adapter *pAdapter) +{ + DBG_ENTER(et131x_dbginfo); + + /* Power down PHY */ + ET1310_PhyPowerDown(pAdapter, 1); + + /* First we need to turn off all other advertisement */ + ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); + + ET1310_PhyAdvertise100BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); + + /* Set our advertise values accordingly */ + ET1310_PhyAdvertise10BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_FULL); + + /* Power up PHY */ + ET1310_PhyPowerDown(pAdapter, 0); + + DBG_LEAVE(et131x_dbginfo); +} + +/** + * TPAL_SetPhy10Force - Force Base-T FD mode WITHOUT using autonegotiation + * @pAdapter: pointer to the adapter structure + */ +void TPAL_SetPhy10Force(struct et131x_adapter *pAdapter) +{ + DBG_ENTER(et131x_dbginfo); + + /* Power down PHY */ + ET1310_PhyPowerDown(pAdapter, 1); + + /* Disable autoneg */ + ET1310_PhyAutoNeg(pAdapter, false); + + /* Disable all advertisement */ + ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); + ET1310_PhyAdvertise10BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); + ET1310_PhyAdvertise100BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); + + /* Force 10 Mbps */ + ET1310_PhySpeedSelect(pAdapter, TRUEPHY_SPEED_10MBPS); + + /* Force Full duplex */ + ET1310_PhyDuplexMode(pAdapter, TRUEPHY_DUPLEX_FULL); + + /* Power up PHY */ + ET1310_PhyPowerDown(pAdapter, 0); + + DBG_LEAVE(et131x_dbginfo); +} + +/** + * TPAL_SetPhy100HalfDuplex - Force 100 Base T Half Duplex mode. + * @pAdapter: pointer to the adapter structure + * + * Also sets the MAC so it is syncd up properly. + */ +void TPAL_SetPhy100HalfDuplex(struct et131x_adapter *pAdapter) +{ + DBG_ENTER(et131x_dbginfo); + + /* Power down PHY */ + ET1310_PhyPowerDown(pAdapter, 1); + + /* first we need to turn off all other advertisement */ + ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); + + ET1310_PhyAdvertise10BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); + + /* Set our advertise values accordingly */ + ET1310_PhyAdvertise100BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_HALF); + + /* Set speed */ + ET1310_PhySpeedSelect(pAdapter, TRUEPHY_SPEED_100MBPS); + + /* Power up PHY */ + ET1310_PhyPowerDown(pAdapter, 0); + + DBG_LEAVE(et131x_dbginfo); +} + +/** + * TPAL_SetPhy100FullDuplex - Force 100 Base T Full Duplex mode. + * @pAdapter: pointer to the adapter structure + * + * Also sets the MAC so it is syncd up properly + */ +void TPAL_SetPhy100FullDuplex(struct et131x_adapter *pAdapter) +{ + DBG_ENTER(et131x_dbginfo); + + /* Power down PHY */ + ET1310_PhyPowerDown(pAdapter, 1); + + /* First we need to turn off all other advertisement */ + ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); + + ET1310_PhyAdvertise10BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); + + /* Set our advertise values accordingly */ + ET1310_PhyAdvertise100BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_FULL); + + /* Power up PHY */ + ET1310_PhyPowerDown(pAdapter, 0); + + DBG_LEAVE(et131x_dbginfo); +} + +/** + * TPAL_SetPhy100Force - Force 100 BaseT FD mode WITHOUT using autonegotiation + * @pAdapter: pointer to the adapter structure + */ +void TPAL_SetPhy100Force(struct et131x_adapter *pAdapter) +{ + DBG_ENTER(et131x_dbginfo); + + /* Power down PHY */ + ET1310_PhyPowerDown(pAdapter, 1); + + /* Disable autoneg */ + ET1310_PhyAutoNeg(pAdapter, false); + + /* Disable all advertisement */ + ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); + ET1310_PhyAdvertise10BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); + ET1310_PhyAdvertise100BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); + + /* Force 100 Mbps */ + ET1310_PhySpeedSelect(pAdapter, TRUEPHY_SPEED_100MBPS); + + /* Force Full duplex */ + ET1310_PhyDuplexMode(pAdapter, TRUEPHY_DUPLEX_FULL); + + /* Power up PHY */ + ET1310_PhyPowerDown(pAdapter, 0); + + DBG_LEAVE(et131x_dbginfo); +} + +/** + * TPAL_SetPhy1000FullDuplex - Force 1000 Base T Full Duplex mode + * @pAdapter: pointer to the adapter structure + * + * Also sets the MAC so it is syncd up properly. + */ +void TPAL_SetPhy1000FullDuplex(struct et131x_adapter *pAdapter) +{ + DBG_ENTER(et131x_dbginfo); + + /* Power down PHY */ + ET1310_PhyPowerDown(pAdapter, 1); + + /* first we need to turn off all other advertisement */ + ET1310_PhyAdvertise100BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); + + ET1310_PhyAdvertise10BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); + + /* set our advertise values accordingly */ + ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_FULL); + + /* power up PHY */ + ET1310_PhyPowerDown(pAdapter, 0); + + DBG_LEAVE(et131x_dbginfo); +} + +/** + * TPAL_SetPhyAutoNeg - Set phy to autonegotiation mode. + * @pAdapter: pointer to the adapter structure + */ +void TPAL_SetPhyAutoNeg(struct et131x_adapter *pAdapter) +{ + DBG_ENTER(et131x_dbginfo); + + /* Power down PHY */ + ET1310_PhyPowerDown(pAdapter, 1); + + /* Turn on advertisement of all capabilities */ + ET1310_PhyAdvertise10BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_BOTH); + + ET1310_PhyAdvertise100BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_BOTH); + + if (pAdapter->DeviceID != ET131X_PCI_DEVICE_ID_FAST) { + ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_FULL); + } else { + ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); + } + + /* Make sure auto-neg is ON (it is disabled in FORCE modes) */ + ET1310_PhyAutoNeg(pAdapter, true); + + /* Power up PHY */ + ET1310_PhyPowerDown(pAdapter, 0); + + DBG_LEAVE(et131x_dbginfo); +} + + +/* + * The routines which follow provide low-level access to the PHY, and are used + * primarily by the routines above (although there are a few places elsewhere + * in the driver where this level of access is required). + */ + +static const uint16_t ConfigPhy[25][2] = { + /* Reg Value Register */ + /* Addr */ + {0x880B, 0x0926}, /* AfeIfCreg4B1000Msbs */ + {0x880C, 0x0926}, /* AfeIfCreg4B100Msbs */ + {0x880D, 0x0926}, /* AfeIfCreg4B10Msbs */ + + {0x880E, 0xB4D3}, /* AfeIfCreg4B1000Lsbs */ + {0x880F, 0xB4D3}, /* AfeIfCreg4B100Lsbs */ + {0x8810, 0xB4D3}, /* AfeIfCreg4B10Lsbs */ + + {0x8805, 0xB03E}, /* AfeIfCreg3B1000Msbs */ + {0x8806, 0xB03E}, /* AfeIfCreg3B100Msbs */ + {0x8807, 0xFF00}, /* AfeIfCreg3B10Msbs */ + + {0x8808, 0xE090}, /* AfeIfCreg3B1000Lsbs */ + {0x8809, 0xE110}, /* AfeIfCreg3B100Lsbs */ + {0x880A, 0x0000}, /* AfeIfCreg3B10Lsbs */ + + {0x300D, 1}, /* DisableNorm */ + + {0x280C, 0x0180}, /* LinkHoldEnd */ + + {0x1C21, 0x0002}, /* AlphaM */ + + {0x3821, 6}, /* FfeLkgTx0 */ + {0x381D, 1}, /* FfeLkg1g4 */ + {0x381E, 1}, /* FfeLkg1g5 */ + {0x381F, 1}, /* FfeLkg1g6 */ + {0x3820, 1}, /* FfeLkg1g7 */ + + {0x8402, 0x01F0}, /* Btinact */ + {0x800E, 20}, /* LftrainTime */ + {0x800F, 24}, /* DvguardTime */ + {0x8010, 46}, /* IdlguardTime */ + + {0, 0} + +}; + +/* condensed version of the phy initialization routine */ +void ET1310_PhyInit(struct et131x_adapter *pAdapter) +{ + uint16_t usData, usIndex; + + if (pAdapter == NULL) { + return; + } + + // get the identity (again ?) + MiRead(pAdapter, PHY_ID_1, &usData); + MiRead(pAdapter, PHY_ID_2, &usData); + + // what does this do/achieve ? + MiRead(pAdapter, PHY_MPHY_CONTROL_REG, &usData); // should read 0002 + MiWrite(pAdapter, PHY_MPHY_CONTROL_REG, 0x0006); + + // read modem register 0402, should I do something with the return data ? + MiWrite(pAdapter, PHY_INDEX_REG, 0x0402); + MiRead(pAdapter, PHY_DATA_REG, &usData); + + // what does this do/achieve ? + MiWrite(pAdapter, PHY_MPHY_CONTROL_REG, 0x0002); + + // get the identity (again ?) + MiRead(pAdapter, PHY_ID_1, &usData); + MiRead(pAdapter, PHY_ID_2, &usData); + + // what does this achieve ? + MiRead(pAdapter, PHY_MPHY_CONTROL_REG, &usData); // should read 0002 + MiWrite(pAdapter, PHY_MPHY_CONTROL_REG, 0x0006); + + // read modem register 0402, should I do something with the return data? + MiWrite(pAdapter, PHY_INDEX_REG, 0x0402); + MiRead(pAdapter, PHY_DATA_REG, &usData); + + MiWrite(pAdapter, PHY_MPHY_CONTROL_REG, 0x0002); + + // what does this achieve (should return 0x1040) + MiRead(pAdapter, PHY_CONTROL, &usData); + MiRead(pAdapter, PHY_MPHY_CONTROL_REG, &usData); // should read 0002 + MiWrite(pAdapter, PHY_CONTROL, 0x1840); + + MiWrite(pAdapter, PHY_MPHY_CONTROL_REG, 0x0007); + + // here the writing of the array starts.... + usIndex = 0; + while (ConfigPhy[usIndex][0] != 0x0000) { + // write value + MiWrite(pAdapter, PHY_INDEX_REG, ConfigPhy[usIndex][0]); + MiWrite(pAdapter, PHY_DATA_REG, ConfigPhy[usIndex][1]); + + // read it back + MiWrite(pAdapter, PHY_INDEX_REG, ConfigPhy[usIndex][0]); + MiRead(pAdapter, PHY_DATA_REG, &usData); + + // do a check on the value read back ? + usIndex++; + } + // here the writing of the array ends... + + MiRead(pAdapter, PHY_CONTROL, &usData); // 0x1840 + MiRead(pAdapter, PHY_MPHY_CONTROL_REG, &usData); // should read 0007 + MiWrite(pAdapter, PHY_CONTROL, 0x1040); + MiWrite(pAdapter, PHY_MPHY_CONTROL_REG, 0x0002); +} + +void ET1310_PhyReset(struct et131x_adapter *pAdapter) +{ + MiWrite(pAdapter, PHY_CONTROL, 0x8000); +} + +void ET1310_PhyPowerDown(struct et131x_adapter *pAdapter, bool down) +{ + uint16_t usData; + + MiRead(pAdapter, PHY_CONTROL, &usData); + + if (down == false) { + // Power UP + usData &= ~0x0800; + MiWrite(pAdapter, PHY_CONTROL, usData); + } else { + // Power DOWN + usData |= 0x0800; + MiWrite(pAdapter, PHY_CONTROL, usData); + } +} + +void ET1310_PhyAutoNeg(struct et131x_adapter *pAdapter, bool enable) +{ + uint16_t usData; + + MiRead(pAdapter, PHY_CONTROL, &usData); + + if (enable == true) { + // Autonegotiation ON + usData |= 0x1000; + MiWrite(pAdapter, PHY_CONTROL, usData); + } else { + // Autonegotiation OFF + usData &= ~0x1000; + MiWrite(pAdapter, PHY_CONTROL, usData); + } +} + +void ET1310_PhyDuplexMode(struct et131x_adapter *pAdapter, uint16_t duplex) +{ + uint16_t usData; + + MiRead(pAdapter, PHY_CONTROL, &usData); + + if (duplex == TRUEPHY_DUPLEX_FULL) { + // Set Full Duplex + usData |= 0x100; + MiWrite(pAdapter, PHY_CONTROL, usData); + } else { + // Set Half Duplex + usData &= ~0x100; + MiWrite(pAdapter, PHY_CONTROL, usData); + } +} + +void ET1310_PhySpeedSelect(struct et131x_adapter *pAdapter, uint16_t speed) +{ + uint16_t usData; + + // Read the PHY control register + MiRead(pAdapter, PHY_CONTROL, &usData); + + // Clear all Speed settings (Bits 6, 13) + usData &= ~0x2040; + + // Reset the speed bits based on user selection + switch (speed) { + case TRUEPHY_SPEED_10MBPS: + // Bits already cleared above, do nothing + break; + + case TRUEPHY_SPEED_100MBPS: + // 100M == Set bit 13 + usData |= 0x2000; + break; + + case TRUEPHY_SPEED_1000MBPS: + default: + usData |= 0x0040; + break; + } + + // Write back the new speed + MiWrite(pAdapter, PHY_CONTROL, usData); +} + +void ET1310_PhyAdvertise1000BaseT(struct et131x_adapter *pAdapter, + uint16_t duplex) +{ + uint16_t usData; + + // Read the PHY 1000 Base-T Control Register + MiRead(pAdapter, PHY_1000_CONTROL, &usData); + + // Clear Bits 8,9 + usData &= ~0x0300; + + switch (duplex) { + case TRUEPHY_ADV_DUPLEX_NONE: + // Duplex already cleared, do nothing + break; + + case TRUEPHY_ADV_DUPLEX_FULL: + // Set Bit 9 + usData |= 0x0200; + break; + + case TRUEPHY_ADV_DUPLEX_HALF: + // Set Bit 8 + usData |= 0x0100; + break; + + case TRUEPHY_ADV_DUPLEX_BOTH: + default: + usData |= 0x0300; + break; + } + + // Write back advertisement + MiWrite(pAdapter, PHY_1000_CONTROL, usData); +} + +void ET1310_PhyAdvertise100BaseT(struct et131x_adapter *pAdapter, + uint16_t duplex) +{ + uint16_t usData; + + // Read the Autonegotiation Register (10/100) + MiRead(pAdapter, PHY_AUTO_ADVERTISEMENT, &usData); + + // Clear bits 7,8 + usData &= ~0x0180; + + switch (duplex) { + case TRUEPHY_ADV_DUPLEX_NONE: + // Duplex already cleared, do nothing + break; + + case TRUEPHY_ADV_DUPLEX_FULL: + // Set Bit 8 + usData |= 0x0100; + break; + + case TRUEPHY_ADV_DUPLEX_HALF: + // Set Bit 7 + usData |= 0x0080; + break; + + case TRUEPHY_ADV_DUPLEX_BOTH: + default: + // Set Bits 7,8 + usData |= 0x0180; + break; + } + + // Write back advertisement + MiWrite(pAdapter, PHY_AUTO_ADVERTISEMENT, usData); +} + +void ET1310_PhyAdvertise10BaseT(struct et131x_adapter *pAdapter, + uint16_t duplex) +{ + uint16_t usData; + + // Read the Autonegotiation Register (10/100) + MiRead(pAdapter, PHY_AUTO_ADVERTISEMENT, &usData); + + // Clear bits 5,6 + usData &= ~0x0060; + + switch (duplex) { + case TRUEPHY_ADV_DUPLEX_NONE: + // Duplex already cleared, do nothing + break; + + case TRUEPHY_ADV_DUPLEX_FULL: + // Set Bit 6 + usData |= 0x0040; + break; + + case TRUEPHY_ADV_DUPLEX_HALF: + // Set Bit 5 + usData |= 0x0020; + break; + + case TRUEPHY_ADV_DUPLEX_BOTH: + default: + // Set Bits 5,6 + usData |= 0x0060; + break; + } + + // Write back advertisement + MiWrite(pAdapter, PHY_AUTO_ADVERTISEMENT, usData); +} + +void ET1310_PhyLinkStatus(struct et131x_adapter *pAdapter, + uint8_t *ucLinkStatus, + uint32_t *uiAutoNeg, + uint32_t *uiLinkSpeed, + uint32_t *uiDuplexMode, + uint32_t *uiMdiMdix, + uint32_t *uiMasterSlave, uint32_t *uiPolarity) +{ + uint16_t usMiStatus = 0; + uint16_t us1000BaseT = 0; + uint16_t usVmiPhyStatus = 0; + uint16_t usControl = 0; + + MiRead(pAdapter, PHY_STATUS, &usMiStatus); + MiRead(pAdapter, PHY_1000_STATUS, &us1000BaseT); + MiRead(pAdapter, PHY_PHY_STATUS, &usVmiPhyStatus); + MiRead(pAdapter, PHY_CONTROL, &usControl); + + if (ucLinkStatus) { + *ucLinkStatus = + (unsigned char)((usVmiPhyStatus & 0x0040) ? 1 : 0); + } + + if (uiAutoNeg) { + *uiAutoNeg = + (usControl & 0x1000) ? ((usVmiPhyStatus & 0x0020) ? + TRUEPHY_ANEG_COMPLETE : + TRUEPHY_ANEG_NOT_COMPLETE) : + TRUEPHY_ANEG_DISABLED; + } + + if (uiLinkSpeed) { + *uiLinkSpeed = (usVmiPhyStatus & 0x0300) >> 8; + } + + if (uiDuplexMode) { + *uiDuplexMode = (usVmiPhyStatus & 0x0080) >> 7; + } + + if (uiMdiMdix) { + /* NOTE: Need to complete this */ + *uiMdiMdix = 0; + } + + if (uiMasterSlave) { + *uiMasterSlave = + (us1000BaseT & 0x4000) ? TRUEPHY_CFG_MASTER : + TRUEPHY_CFG_SLAVE; + } + + if (uiPolarity) { + *uiPolarity = + (usVmiPhyStatus & 0x0400) ? TRUEPHY_POLARITY_INVERTED : + TRUEPHY_POLARITY_NORMAL; + } +} + +void ET1310_PhyAndOrReg(struct et131x_adapter *pAdapter, + uint16_t regnum, uint16_t andMask, uint16_t orMask) +{ + uint16_t reg; + + // Read the requested register + MiRead(pAdapter, regnum, ®); + + // Apply the AND mask + reg &= andMask; + + // Apply the OR mask + reg |= orMask; + + // Write the value back to the register + MiWrite(pAdapter, regnum, reg); +} + +void ET1310_PhyAccessMiBit(struct et131x_adapter *pAdapter, uint16_t action, + uint16_t regnum, uint16_t bitnum, uint8_t *value) +{ + uint16_t reg; + uint16_t mask = 0; + + // Create a mask to isolate the requested bit + mask = 0x0001 << bitnum; + + // Read the requested register + MiRead(pAdapter, regnum, ®); + + switch (action) { + case TRUEPHY_BIT_READ: + if (value != NULL) { + *value = (reg & mask) >> bitnum; + } + break; + + case TRUEPHY_BIT_SET: + reg |= mask; + MiWrite(pAdapter, regnum, reg); + break; + + case TRUEPHY_BIT_CLEAR: + reg &= ~mask; + MiWrite(pAdapter, regnum, reg); + break; + + default: + break; + } +} diff --git a/src/et131x/et1310_phy.h b/src/et131x/et1310_phy.h new file mode 100644 index 0000000..d624cbb --- /dev/null +++ b/src/et131x/et1310_phy.h @@ -0,0 +1,910 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et1310_phy.h - Defines, structs, enums, prototypes, etc. pertaining to the + * PHY. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#ifndef _ET1310_PHY_H_ +#define _ET1310_PHY_H_ + +#include "et1310_address_map.h" + +#define TRUEPHY_SUCCESS 0 +#define TRUEPHY_FAILURE 1 +typedef void *TRUEPHY_HANDLE; +typedef void *TRUEPHY_PLATFORM_HANDLE; +typedef void *TRUEPHY_OSAL_HANDLE; + +/* MI Register Addresses */ +#define MI_CONTROL_REG 0 +#define MI_STATUS_REG 1 +#define MI_PHY_IDENTIFIER_1_REG 2 +#define MI_PHY_IDENTIFIER_2_REG 3 +#define MI_AUTONEG_ADVERTISEMENT_REG 4 +#define MI_AUTONEG_LINK_PARTNER_ABILITY_REG 5 +#define MI_AUTONEG_EXPANSION_REG 6 +#define MI_AUTONEG_NEXT_PAGE_TRANSMIT_REG 7 +#define MI_LINK_PARTNER_NEXT_PAGE_REG 8 +#define MI_1000BASET_CONTROL_REG 9 +#define MI_1000BASET_STATUS_REG 10 +#define MI_RESERVED11_REG 11 +#define MI_RESERVED12_REG 12 +#define MI_RESERVED13_REG 13 +#define MI_RESERVED14_REG 14 +#define MI_EXTENDED_STATUS_REG 15 + +/* VMI Register Addresses */ +#define VMI_RESERVED16_REG 16 +#define VMI_RESERVED17_REG 17 +#define VMI_RESERVED18_REG 18 +#define VMI_LOOPBACK_CONTROL_REG 19 +#define VMI_RESERVED20_REG 20 +#define VMI_MI_CONTROL_REG 21 +#define VMI_PHY_CONFIGURATION_REG 22 +#define VMI_PHY_CONTROL_REG 23 +#define VMI_INTERRUPT_MASK_REG 24 +#define VMI_INTERRUPT_STATUS_REG 25 +#define VMI_PHY_STATUS_REG 26 +#define VMI_LED_CONTROL_1_REG 27 +#define VMI_LED_CONTROL_2_REG 28 +#define VMI_RESERVED29_REG 29 +#define VMI_RESERVED30_REG 30 +#define VMI_RESERVED31_REG 31 + +/* PHY Register Mapping(MI) Management Interface Regs */ +typedef struct _MI_REGS_t { + u8 bmcr; // Basic mode control reg(Reg 0x00) + u8 bmsr; // Basic mode status reg(Reg 0x01) + u8 idr1; // Phy identifier reg 1(Reg 0x02) + u8 idr2; // Phy identifier reg 2(Reg 0x03) + u8 anar; // Auto-Negotiation advertisement(Reg 0x04) + u8 anlpar; // Auto-Negotiation link Partner Ability(Reg 0x05) + u8 aner; // Auto-Negotiation expansion reg(Reg 0x06) + u8 annptr; // Auto-Negotiation next page transmit reg(Reg 0x07) + u8 lpnpr; // link partner next page reg(Reg 0x08) + u8 gcr; // Gigabit basic mode control reg(Reg 0x09) + u8 gsr; // Gigabit basic mode status reg(Reg 0x0A) + u8 mi_res1[4]; // Future use by MI working group(Reg 0x0B - 0x0E) + u8 esr; // Extended status reg(Reg 0x0F) + u8 mi_res2[3]; // Future use by MI working group(Reg 0x10 - 0x12) + u8 loop_ctl; // Loopback Control Reg(Reg 0x13) + u8 mi_res3; // Future use by MI working group(Reg 0x14) + u8 mcr; // MI Control Reg(Reg 0x15) + u8 pcr; // Configuration Reg(Reg 0x16) + u8 phy_ctl; // PHY Control Reg(Reg 0x17) + u8 imr; // Interrupt Mask Reg(Reg 0x18) + u8 isr; // Interrupt Status Reg(Reg 0x19) + u8 psr; // PHY Status Reg(Reg 0x1A) + u8 lcr1; // LED Control 1 Reg(Reg 0x1B) + u8 lcr2; // LED Control 2 Reg(Reg 0x1C) + u8 mi_res4[3]; // Future use by MI working group(Reg 0x1D - 0x1F) +} MI_REGS_t, *PMI_REGS_t; + +/* MI Register 0: Basic mode control register */ +typedef union _MI_BMCR_t { + u16 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u16 reset:1; // bit 15 + u16 loopback:1; // bit 14 + u16 speed_sel:1; // bit 13 + u16 enable_autoneg:1; // bit 12 + u16 power_down:1; // bit 11 + u16 isolate:1; // bit 10 + u16 restart_autoneg:1; // bit 9 + u16 duplex_mode:1; // bit 8 + u16 col_test:1; // bit 7 + u16 speed_1000_sel:1; // bit 6 + u16 res1:6; // bits 0-5 +#else + u16 res1:6; // bits 0-5 + u16 speed_1000_sel:1; // bit 6 + u16 col_test:1; // bit 7 + u16 duplex_mode:1; // bit 8 + u16 restart_autoneg:1; // bit 9 + u16 isolate:1; // bit 10 + u16 power_down:1; // bit 11 + u16 enable_autoneg:1; // bit 12 + u16 speed_sel:1; // bit 13 + u16 loopback:1; // bit 14 + u16 reset:1; // bit 15 +#endif + } bits; +} MI_BMCR_t, *PMI_BMCR_t; + +/* MI Register 1: Basic mode status register */ +typedef union _MI_BMSR_t { + u16 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u16 link_100T4:1; // bit 15 + u16 link_100fdx:1; // bit 14 + u16 link_100hdx:1; // bit 13 + u16 link_10fdx:1; // bit 12 + u16 link_10hdx:1; // bit 11 + u16 link_100T2fdx:1; // bit 10 + u16 link_100T2hdx:1; // bit 9 + u16 extend_status:1; // bit 8 + u16 res1:1; // bit 7 + u16 preamble_supress:1; // bit 6 + u16 auto_neg_complete:1; // bit 5 + u16 remote_fault:1; // bit 4 + u16 auto_neg_able:1; // bit 3 + u16 link_status:1; // bit 2 + u16 jabber_detect:1; // bit 1 + u16 ext_cap:1; // bit 0 +#else + u16 ext_cap:1; // bit 0 + u16 jabber_detect:1; // bit 1 + u16 link_status:1; // bit 2 + u16 auto_neg_able:1; // bit 3 + u16 remote_fault:1; // bit 4 + u16 auto_neg_complete:1; // bit 5 + u16 preamble_supress:1; // bit 6 + u16 res1:1; // bit 7 + u16 extend_status:1; // bit 8 + u16 link_100T2hdx:1; // bit 9 + u16 link_100T2fdx:1; // bit 10 + u16 link_10hdx:1; // bit 11 + u16 link_10fdx:1; // bit 12 + u16 link_100hdx:1; // bit 13 + u16 link_100fdx:1; // bit 14 + u16 link_100T4:1; // bit 15 +#endif + } bits; +} MI_BMSR_t, *PMI_BMSR_t; + +/* MI Register 2: Physical Identifier 1 */ +typedef union _MI_IDR1_t { + u16 value; + struct { + u16 ieee_address:16; // 0x0282 default(bits 0-15) + } bits; +} MI_IDR1_t, *PMI_IDR1_t; + +/* MI Register 3: Physical Identifier 2 */ +typedef union _MI_IDR2_t { + u16 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u16 ieee_address:6; // 111100 default(bits 10-15) + u16 model_no:6; // 000001 default(bits 4-9) + u16 rev_no:4; // 0010 default(bits 0-3) +#else + u16 rev_no:4; // 0010 default(bits 0-3) + u16 model_no:6; // 000001 default(bits 4-9) + u16 ieee_address:6; // 111100 default(bits 10-15) +#endif + } bits; +} MI_IDR2_t, *PMI_IDR2_t; + +/* MI Register 4: Auto-negotiation advertisement register */ +typedef union _MI_ANAR_t { + u16 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u16 np_indication:1; // bit 15 + u16 res2:1; // bit 14 + u16 remote_fault:1; // bit 13 + u16 res1:1; // bit 12 + u16 cap_asmpause:1; // bit 11 + u16 cap_pause:1; // bit 10 + u16 cap_100T4:1; // bit 9 + u16 cap_100fdx:1; // bit 8 + u16 cap_100hdx:1; // bit 7 + u16 cap_10fdx:1; // bit 6 + u16 cap_10hdx:1; // bit 5 + u16 selector:5; // bits 0-4 +#else + u16 selector:5; // bits 0-4 + u16 cap_10hdx:1; // bit 5 + u16 cap_10fdx:1; // bit 6 + u16 cap_100hdx:1; // bit 7 + u16 cap_100fdx:1; // bit 8 + u16 cap_100T4:1; // bit 9 + u16 cap_pause:1; // bit 10 + u16 cap_asmpause:1; // bit 11 + u16 res1:1; // bit 12 + u16 remote_fault:1; // bit 13 + u16 res2:1; // bit 14 + u16 np_indication:1; // bit 15 +#endif + } bits; +} MI_ANAR_t, *PMI_ANAR_t; + +/* MI Register 5: Auto-negotiation link partner advertisement register */ +typedef struct _MI_ANLPAR_t { + u16 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u16 np_indication:1; // bit 15 + u16 acknowledge:1; // bit 14 + u16 remote_fault:1; // bit 13 + u16 res1:1; // bit 12 + u16 cap_asmpause:1; // bit 11 + u16 cap_pause:1; // bit 10 + u16 cap_100T4:1; // bit 9 + u16 cap_100fdx:1; // bit 8 + u16 cap_100hdx:1; // bit 7 + u16 cap_10fdx:1; // bit 6 + u16 cap_10hdx:1; // bit 5 + u16 selector:5; // bits 0-4 +#else + u16 selector:5; // bits 0-4 + u16 cap_10hdx:1; // bit 5 + u16 cap_10fdx:1; // bit 6 + u16 cap_100hdx:1; // bit 7 + u16 cap_100fdx:1; // bit 8 + u16 cap_100T4:1; // bit 9 + u16 cap_pause:1; // bit 10 + u16 cap_asmpause:1; // bit 11 + u16 res1:1; // bit 12 + u16 remote_fault:1; // bit 13 + u16 acknowledge:1; // bit 14 + u16 np_indication:1; // bit 15 +#endif + } bits; +} MI_ANLPAR_t, *PMI_ANLPAR_t; + +/* MI Register 6: Auto-negotiation expansion register */ +typedef union _MI_ANER_t { + u16 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u16 res:11; // bits 5-15 + u16 pdf:1; // bit 4 + u16 lp_np_able:1; // bit 3 + u16 np_able:1; // bit 2 + u16 page_rx:1; // bit 1 + u16 lp_an_able:1; // bit 0 +#else + u16 lp_an_able:1; // bit 0 + u16 page_rx:1; // bit 1 + u16 np_able:1; // bit 2 + u16 lp_np_able:1; // bit 3 + u16 pdf:1; // bit 4 + u16 res:11; // bits 5-15 +#endif + } bits; +} MI_ANER_t, *PMI_ANER_t; + +/* MI Register 7: Auto-negotiation next page transmit reg(0x07) */ +typedef union _MI_ANNPTR_t { + u16 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u16 np:1; // bit 15 + u16 res1:1; // bit 14 + u16 msg_page:1; // bit 13 + u16 ack2:1; // bit 12 + u16 toggle:1; // bit 11 + u16 msg:11; // bits 0-10 +#else + u16 msg:11; // bits 0-10 + u16 toggle:1; // bit 11 + u16 ack2:1; // bit 12 + u16 msg_page:1; // bit 13 + u16 res1:1; // bit 14 + u16 np:1; // bit 15 +#endif + } bits; +} MI_ANNPTR_t, *PMI_ANNPTR_t; + +/* MI Register 8: Link Partner Next Page Reg(0x08) */ +typedef union _MI_LPNPR_t { + u16 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u16 np:1; // bit 15 + u16 ack:1; // bit 14 + u16 msg_page:1; // bit 13 + u16 ack2:1; // bit 12 + u16 toggle:1; // bit 11 + u16 msg:11; // bits 0-10 +#else + u16 msg:11; // bits 0-10 + u16 toggle:1; // bit 11 + u16 ack2:1; // bit 12 + u16 msg_page:1; // bit 13 + u16 ack:1; // bit 14 + u16 np:1; // bit 15 +#endif + } bits; +} MI_LPNPR_t, *PMI_LPNPR_t; + +/* MI Register 9: 1000BaseT Control Reg(0x09) */ +typedef union _MI_GCR_t { + u16 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u16 test_mode:3; // bits 13-15 + u16 ms_config_en:1; // bit 12 + u16 ms_value:1; // bit 11 + u16 port_type:1; // bit 10 + u16 link_1000fdx:1; // bit 9 + u16 link_1000hdx:1; // bit 8 + u16 res:8; // bit 0-7 +#else + u16 res:8; // bit 0-7 + u16 link_1000hdx:1; // bit 8 + u16 link_1000fdx:1; // bit 9 + u16 port_type:1; // bit 10 + u16 ms_value:1; // bit 11 + u16 ms_config_en:1; // bit 12 + u16 test_mode:3; // bits 13-15 +#endif + } bits; +} MI_GCR_t, *PMI_GCR_t; + +/* MI Register 10: 1000BaseT Status Reg(0x0A) */ +typedef union _MI_GSR_t { + u16 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u16 ms_config_fault:1; // bit 15 + u16 ms_resolve:1; // bit 14 + u16 local_rx_status:1; // bit 13 + u16 remote_rx_status:1; // bit 12 + u16 link_1000fdx:1; // bit 11 + u16 link_1000hdx:1; // bit 10 + u16 res:2; // bits 8-9 + u16 idle_err_cnt:8; // bits 0-7 +#else + u16 idle_err_cnt:8; // bits 0-7 + u16 res:2; // bits 8-9 + u16 link_1000hdx:1; // bit 10 + u16 link_1000fdx:1; // bit 11 + u16 remote_rx_status:1; // bit 12 + u16 local_rx_status:1; // bit 13 + u16 ms_resolve:1; // bit 14 + u16 ms_config_fault:1; // bit 15 +#endif + } bits; +} MI_GSR_t, *PMI_GSR_t; + +/* MI Register 11 - 14: Reserved Regs(0x0B - 0x0E) */ +typedef union _MI_RES_t { + u16 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u16 res15:1; // bit 15 + u16 res14:1; // bit 14 + u16 res13:1; // bit 13 + u16 res12:1; // bit 12 + u16 res11:1; // bit 11 + u16 res10:1; // bit 10 + u16 res9:1; // bit 9 + u16 res8:1; // bit 8 + u16 res7:1; // bit 7 + u16 res6:1; // bit 6 + u16 res5:1; // bit 5 + u16 res4:1; // bit 4 + u16 res3:1; // bit 3 + u16 res2:1; // bit 2 + u16 res1:1; // bit 1 + u16 res0:1; // bit 0 +#else + u16 res0:1; // bit 0 + u16 res1:1; // bit 1 + u16 res2:1; // bit 2 + u16 res3:1; // bit 3 + u16 res4:1; // bit 4 + u16 res5:1; // bit 5 + u16 res6:1; // bit 6 + u16 res7:1; // bit 7 + u16 res8:1; // bit 8 + u16 res9:1; // bit 9 + u16 res10:1; // bit 10 + u16 res11:1; // bit 11 + u16 res12:1; // bit 12 + u16 res13:1; // bit 13 + u16 res14:1; // bit 14 + u16 res15:1; // bit 15 +#endif + } bits; +} MI_RES_t, *PMI_RES_t; + +/* MI Register 15: Extended status Reg(0x0F) */ +typedef union _MI_ESR_t { + u16 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u16 link_1000Xfdx:1; // bit 15 + u16 link_1000Xhdx:1; // bit 14 + u16 link_1000fdx:1; // bit 13 + u16 link_1000hdx:1; // bit 12 + u16 res:12; // bit 0-11 +#else + u16 res:12; // bit 0-11 + u16 link_1000hdx:1; // bit 12 + u16 link_1000fdx:1; // bit 13 + u16 link_1000Xhdx:1; // bit 14 + u16 link_1000Xfdx:1; // bit 15 +#endif + } bits; +} MI_ESR_t, *PMI_ESR_t; + +/* MI Register 16 - 18: Reserved Reg(0x10-0x12) */ + +/* MI Register 19: Loopback Control Reg(0x13) */ +typedef union _MI_LCR_t { + u16 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u16 mii_en:1; // bit 15 + u16 pcs_en:1; // bit 14 + u16 pmd_en:1; // bit 13 + u16 all_digital_en:1; // bit 12 + u16 replica_en:1; // bit 11 + u16 line_driver_en:1; // bit 10 + u16 res:10; // bit 0-9 +#else + u16 res:10; // bit 0-9 + u16 line_driver_en:1; // bit 10 + u16 replica_en:1; // bit 11 + u16 all_digital_en:1; // bit 12 + u16 pmd_en:1; // bit 13 + u16 pcs_en:1; // bit 14 + u16 mii_en:1; // bit 15 +#endif + } bits; +} MI_LCR_t, *PMI_LCR_t; + +/* MI Register 20: Reserved Reg(0x14) */ + +/* MI Register 21: Management Interface Control Reg(0x15) */ +typedef union _MI_MICR_t { + u16 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u16 res1:5; // bits 11-15 + u16 mi_error_count:7; // bits 4-10 + u16 res2:1; // bit 3 + u16 ignore_10g_fr:1; // bit 2 + u16 res3:1; // bit 1 + u16 preamble_supress_en:1; // bit 0 +#else + u16 preamble_supress_en:1; // bit 0 + u16 res3:1; // bit 1 + u16 ignore_10g_fr:1; // bit 2 + u16 res2:1; // bit 3 + u16 mi_error_count:7; // bits 4-10 + u16 res1:5; // bits 11-15 +#endif + } bits; +} MI_MICR_t, *PMI_MICR_t; + +/* MI Register 22: PHY Configuration Reg(0x16) */ +typedef union _MI_PHY_CONFIG_t { + u16 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u16 crs_tx_en:1; // bit 15 + u16 res1:1; // bit 14 + u16 tx_fifo_depth:2; // bits 12-13 + u16 speed_downshift:2; // bits 10-11 + u16 pbi_detect:1; // bit 9 + u16 tbi_rate:1; // bit 8 + u16 alternate_np:1; // bit 7 + u16 group_mdio_en:1; // bit 6 + u16 tx_clock_en:1; // bit 5 + u16 sys_clock_en:1; // bit 4 + u16 res2:1; // bit 3 + u16 mac_if_mode:3; // bits 0-2 +#else + u16 mac_if_mode:3; // bits 0-2 + u16 res2:1; // bit 3 + u16 sys_clock_en:1; // bit 4 + u16 tx_clock_en:1; // bit 5 + u16 group_mdio_en:1; // bit 6 + u16 alternate_np:1; // bit 7 + u16 tbi_rate:1; // bit 8 + u16 pbi_detect:1; // bit 9 + u16 speed_downshift:2; // bits 10-11 + u16 tx_fifo_depth:2; // bits 12-13 + u16 res1:1; // bit 14 + u16 crs_tx_en:1; // bit 15 +#endif + } bits; +} MI_PHY_CONFIG_t, *PMI_PHY_CONFIG_t; + +/* MI Register 23: PHY CONTROL Reg(0x17) */ +typedef union _MI_PHY_CONTROL_t { + u16 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u16 res1:1; // bit 15 + u16 tdr_en:1; // bit 14 + u16 res2:1; // bit 13 + u16 downshift_attempts:2; // bits 11-12 + u16 res3:5; // bit 6-10 + u16 jabber_10baseT:1; // bit 5 + u16 sqe_10baseT:1; // bit 4 + u16 tp_loopback_10baseT:1; // bit 3 + u16 preamble_gen_en:1; // bit 2 + u16 res4:1; // bit 1 + u16 force_int:1; // bit 0 +#else + u16 force_int:1; // bit 0 + u16 res4:1; // bit 1 + u16 preamble_gen_en:1; // bit 2 + u16 tp_loopback_10baseT:1; // bit 3 + u16 sqe_10baseT:1; // bit 4 + u16 jabber_10baseT:1; // bit 5 + u16 res3:5; // bit 6-10 + u16 downshift_attempts:2; // bits 11-12 + u16 res2:1; // bit 13 + u16 tdr_en:1; // bit 14 + u16 res1:1; // bit 15 +#endif + } bits; +} MI_PHY_CONTROL_t, *PMI_PHY_CONTROL_t; + +/* MI Register 24: Interrupt Mask Reg(0x18) */ +typedef union _MI_IMR_t { + u16 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u16 res1:6; // bits 10-15 + u16 mdio_sync_lost:1; // bit 9 + u16 autoneg_status:1; // bit 8 + u16 hi_bit_err:1; // bit 7 + u16 np_rx:1; // bit 6 + u16 err_counter_full:1; // bit 5 + u16 fifo_over_underflow:1; // bit 4 + u16 rx_status:1; // bit 3 + u16 link_status:1; // bit 2 + u16 automatic_speed:1; // bit 1 + u16 int_en:1; // bit 0 +#else + u16 int_en:1; // bit 0 + u16 automatic_speed:1; // bit 1 + u16 link_status:1; // bit 2 + u16 rx_status:1; // bit 3 + u16 fifo_over_underflow:1; // bit 4 + u16 err_counter_full:1; // bit 5 + u16 np_rx:1; // bit 6 + u16 hi_bit_err:1; // bit 7 + u16 autoneg_status:1; // bit 8 + u16 mdio_sync_lost:1; // bit 9 + u16 res1:6; // bits 10-15 +#endif + } bits; +} MI_IMR_t, *PMI_IMR_t; + +/* MI Register 25: Interrupt Status Reg(0x19) */ +typedef union _MI_ISR_t { + u16 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u16 res1:6; // bits 10-15 + u16 mdio_sync_lost:1; // bit 9 + u16 autoneg_status:1; // bit 8 + u16 hi_bit_err:1; // bit 7 + u16 np_rx:1; // bit 6 + u16 err_counter_full:1; // bit 5 + u16 fifo_over_underflow:1; // bit 4 + u16 rx_status:1; // bit 3 + u16 link_status:1; // bit 2 + u16 automatic_speed:1; // bit 1 + u16 int_en:1; // bit 0 +#else + u16 int_en:1; // bit 0 + u16 automatic_speed:1; // bit 1 + u16 link_status:1; // bit 2 + u16 rx_status:1; // bit 3 + u16 fifo_over_underflow:1; // bit 4 + u16 err_counter_full:1; // bit 5 + u16 np_rx:1; // bit 6 + u16 hi_bit_err:1; // bit 7 + u16 autoneg_status:1; // bit 8 + u16 mdio_sync_lost:1; // bit 9 + u16 res1:6; // bits 10-15 +#endif + } bits; +} MI_ISR_t, *PMI_ISR_t; + +/* MI Register 26: PHY Status Reg(0x1A) */ +typedef union _MI_PSR_t { + u16 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u16 res1:1; // bit 15 + u16 autoneg_fault:2; // bit 13-14 + u16 autoneg_status:1; // bit 12 + u16 mdi_x_status:1; // bit 11 + u16 polarity_status:1; // bit 10 + u16 speed_status:2; // bits 8-9 + u16 duplex_status:1; // bit 7 + u16 link_status:1; // bit 6 + u16 tx_status:1; // bit 5 + u16 rx_status:1; // bit 4 + u16 collision_status:1; // bit 3 + u16 autoneg_en:1; // bit 2 + u16 pause_en:1; // bit 1 + u16 asymmetric_dir:1; // bit 0 +#else + u16 asymmetric_dir:1; // bit 0 + u16 pause_en:1; // bit 1 + u16 autoneg_en:1; // bit 2 + u16 collision_status:1; // bit 3 + u16 rx_status:1; // bit 4 + u16 tx_status:1; // bit 5 + u16 link_status:1; // bit 6 + u16 duplex_status:1; // bit 7 + u16 speed_status:2; // bits 8-9 + u16 polarity_status:1; // bit 10 + u16 mdi_x_status:1; // bit 11 + u16 autoneg_status:1; // bit 12 + u16 autoneg_fault:2; // bit 13-14 + u16 res1:1; // bit 15 +#endif + } bits; +} MI_PSR_t, *PMI_PSR_t; + +/* MI Register 27: LED Control Reg 1(0x1B) */ +typedef union _MI_LCR1_t { + u16 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u16 res1:2; // bits 14-15 + u16 led_dup_indicate:2; // bits 12-13 + u16 led_10baseT:2; // bits 10-11 + u16 led_collision:2; // bits 8-9 + u16 res2:2; // bits 6-7 + u16 res3:2; // bits 4-5 + u16 pulse_dur:2; // bits 2-3 + u16 pulse_stretch1:1; // bit 1 + u16 pulse_stretch0:1; // bit 0 +#else + u16 pulse_stretch0:1; // bit 0 + u16 pulse_stretch1:1; // bit 1 + u16 pulse_dur:2; // bits 2-3 + u16 res3:2; // bits 4-5 + u16 res2:2; // bits 6-7 + u16 led_collision:2; // bits 8-9 + u16 led_10baseT:2; // bits 10-11 + u16 led_dup_indicate:2; // bits 12-13 + u16 res1:2; // bits 14-15 +#endif + } bits; +} MI_LCR1_t, *PMI_LCR1_t; + +/* MI Register 28: LED Control Reg 2(0x1C) */ +typedef union _MI_LCR2_t { + u16 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u16 led_link:4; // bits 12-15 + u16 led_tx_rx:4; // bits 8-11 + u16 led_100BaseTX:4; // bits 4-7 + u16 led_1000BaseT:4; // bits 0-3 +#else + u16 led_1000BaseT:4; // bits 0-3 + u16 led_100BaseTX:4; // bits 4-7 + u16 led_tx_rx:4; // bits 8-11 + u16 led_link:4; // bits 12-15 +#endif + } bits; +} MI_LCR2_t, *PMI_LCR2_t; + +/* MI Register 29 - 31: Reserved Reg(0x1D - 0x1E) */ + +/* TruePHY headers */ +typedef struct _TRUEPHY_ACCESS_MI_REGS_ { + TRUEPHY_HANDLE hTruePhy; + int32_t nPhyId; + u8 bReadWrite; + u8 *pbyRegs; + u8 *pwData; + int32_t nRegCount; +} TRUEPHY_ACCESS_MI_REGS, *PTRUEPHY_ACCESS_MI_REGS; + +/* TruePHY headers */ +typedef struct _TAG_TPAL_ACCESS_MI_REGS_ { + u32 nPhyId; + u8 bReadWrite; + u32 nRegCount; + u16 Data[4096]; + u8 Regs[4096]; +} TPAL_ACCESS_MI_REGS, *PTPAL_ACCESS_MI_REGS; + + +typedef TRUEPHY_HANDLE TPAL_HANDLE; + +/* Forward declaration of the private adapter structure */ +struct et131x_adapter; + +/* OS Specific Functions*/ +void TPAL_SetPhy10HalfDuplex(struct et131x_adapter *adapter); +void TPAL_SetPhy10FullDuplex(struct et131x_adapter *adapter); +void TPAL_SetPhy10Force(struct et131x_adapter *pAdapter); +void TPAL_SetPhy100HalfDuplex(struct et131x_adapter *adapter); +void TPAL_SetPhy100FullDuplex(struct et131x_adapter *adapter); +void TPAL_SetPhy100Force(struct et131x_adapter *pAdapter); +void TPAL_SetPhy1000FullDuplex(struct et131x_adapter *adapter); +void TPAL_SetPhyAutoNeg(struct et131x_adapter *adapter); + +/* Prototypes for ET1310_phy.c */ +int et131x_xcvr_find(struct et131x_adapter *adapter); +int et131x_setphy_normal(struct et131x_adapter *adapter); +int32_t PhyMiRead(struct et131x_adapter *adapter, + u8 xcvrAddr, u8 xcvrReg, u16 *value); + +/* static inline function does not work because et131x_adapter is not always + * defined + */ +#define MiRead(adapter, xcvrReg, value) \ + PhyMiRead((adapter), (adapter)->Stats.xcvr_addr, (xcvrReg), (value)) + +int32_t MiWrite(struct et131x_adapter *adapter, + u8 xcvReg, u16 value); +void et131x_Mii_check(struct et131x_adapter *pAdapter, + MI_BMSR_t bmsr, MI_BMSR_t bmsr_ints); + +/* This last is not strictly required (the driver could call the TPAL + * version instead), but this sets the adapter up correctly, and calls the + * access routine indirectly. This protects the driver from changes in TPAL. + */ +void SetPhy_10BaseTHalfDuplex(struct et131x_adapter *adapter); + +/* Defines for PHY access routines */ + +// Define bit operation flags +#define TRUEPHY_BIT_CLEAR 0 +#define TRUEPHY_BIT_SET 1 +#define TRUEPHY_BIT_READ 2 + +// Define read/write operation flags +#ifndef TRUEPHY_READ +#define TRUEPHY_READ 0 +#define TRUEPHY_WRITE 1 +#define TRUEPHY_MASK 2 +#endif + +// Define speeds +#define TRUEPHY_SPEED_10MBPS 0 +#define TRUEPHY_SPEED_100MBPS 1 +#define TRUEPHY_SPEED_1000MBPS 2 + +// Define duplex modes +#define TRUEPHY_DUPLEX_HALF 0 +#define TRUEPHY_DUPLEX_FULL 1 + +// Define master/slave configuration values +#define TRUEPHY_CFG_SLAVE 0 +#define TRUEPHY_CFG_MASTER 1 + +// Define MDI/MDI-X settings +#define TRUEPHY_MDI 0 +#define TRUEPHY_MDIX 1 +#define TRUEPHY_AUTO_MDI_MDIX 2 + +// Define 10Base-T link polarities +#define TRUEPHY_POLARITY_NORMAL 0 +#define TRUEPHY_POLARITY_INVERTED 1 + +// Define auto-negotiation results +#define TRUEPHY_ANEG_NOT_COMPLETE 0 +#define TRUEPHY_ANEG_COMPLETE 1 +#define TRUEPHY_ANEG_DISABLED 2 + +/* Define duplex advertisment flags */ +#define TRUEPHY_ADV_DUPLEX_NONE 0x00 +#define TRUEPHY_ADV_DUPLEX_FULL 0x01 +#define TRUEPHY_ADV_DUPLEX_HALF 0x02 +#define TRUEPHY_ADV_DUPLEX_BOTH \ + (TRUEPHY_ADV_DUPLEX_FULL | TRUEPHY_ADV_DUPLEX_HALF) + +#define PHY_CONTROL 0x00 //#define TRU_MI_CONTROL_REGISTER 0 +#define PHY_STATUS 0x01 //#define TRU_MI_STATUS_REGISTER 1 +#define PHY_ID_1 0x02 //#define TRU_MI_PHY_IDENTIFIER_1_REGISTER 2 +#define PHY_ID_2 0x03 //#define TRU_MI_PHY_IDENTIFIER_2_REGISTER 3 +#define PHY_AUTO_ADVERTISEMENT 0x04 //#define TRU_MI_ADVERTISEMENT_REGISTER 4 +#define PHY_AUTO_LINK_PARTNER 0x05 //#define TRU_MI_LINK_PARTNER_ABILITY_REGISTER 5 +#define PHY_AUTO_EXPANSION 0x06 //#define TRU_MI_EXPANSION_REGISTER 6 +#define PHY_AUTO_NEXT_PAGE_TX 0x07 //#define TRU_MI_NEXT_PAGE_TRANSMIT_REGISTER 7 +#define PHY_LINK_PARTNER_NEXT_PAGE 0x08 //#define TRU_MI_LINK_PARTNER_NEXT_PAGE_REGISTER 8 +#define PHY_1000_CONTROL 0x09 //#define TRU_MI_1000BASET_CONTROL_REGISTER 9 +#define PHY_1000_STATUS 0x0A //#define TRU_MI_1000BASET_STATUS_REGISTER 10 + +#define PHY_EXTENDED_STATUS 0x0F //#define TRU_MI_EXTENDED_STATUS_REGISTER 15 + +// some defines for modem registers that seem to be 'reserved' +#define PHY_INDEX_REG 0x10 +#define PHY_DATA_REG 0x11 + +#define PHY_MPHY_CONTROL_REG 0x12 //#define TRU_VMI_MPHY_CONTROL_REGISTER 18 + +#define PHY_LOOPBACK_CONTROL 0x13 //#define TRU_VMI_LOOPBACK_CONTROL_1_REGISTER 19 + //#define TRU_VMI_LOOPBACK_CONTROL_2_REGISTER 20 +#define PHY_REGISTER_MGMT_CONTROL 0x15 //#define TRU_VMI_MI_SEQ_CONTROL_REGISTER 21 +#define PHY_CONFIG 0x16 //#define TRU_VMI_CONFIGURATION_REGISTER 22 +#define PHY_PHY_CONTROL 0x17 //#define TRU_VMI_PHY_CONTROL_REGISTER 23 +#define PHY_INTERRUPT_MASK 0x18 //#define TRU_VMI_INTERRUPT_MASK_REGISTER 24 +#define PHY_INTERRUPT_STATUS 0x19 //#define TRU_VMI_INTERRUPT_STATUS_REGISTER 25 +#define PHY_PHY_STATUS 0x1A //#define TRU_VMI_PHY_STATUS_REGISTER 26 +#define PHY_LED_1 0x1B //#define TRU_VMI_LED_CONTROL_1_REGISTER 27 +#define PHY_LED_2 0x1C //#define TRU_VMI_LED_CONTROL_2_REGISTER 28 + //#define TRU_VMI_LINK_CONTROL_REGISTER 29 + //#define TRU_VMI_TIMING_CONTROL_REGISTER + +/* Prototypes for PHY access routines */ +void ET1310_PhyInit(struct et131x_adapter *adapter); +void ET1310_PhyReset(struct et131x_adapter *adapter); +void ET1310_PhyPowerDown(struct et131x_adapter *adapter, bool down); +void ET1310_PhyAutoNeg(struct et131x_adapter *adapter, bool enable); +void ET1310_PhyDuplexMode(struct et131x_adapter *adapter, u16 duplex); +void ET1310_PhySpeedSelect(struct et131x_adapter *adapter, u16 speed); +void ET1310_PhyAdvertise1000BaseT(struct et131x_adapter *adapter, + u16 duplex); +void ET1310_PhyAdvertise100BaseT(struct et131x_adapter *adapter, + u16 duplex); +void ET1310_PhyAdvertise10BaseT(struct et131x_adapter *adapter, + u16 duplex); +void ET1310_PhyLinkStatus(struct et131x_adapter *adapter, + u8 *ucLinkStatus, + u32 *uiAutoNeg, + u32 *uiLinkSpeed, + u32 *uiDuplexMode, + u32 *uiMdiMdix, + u32 *uiMasterSlave, u32 *uiPolarity); +void ET1310_PhyAndOrReg(struct et131x_adapter *adapter, + u16 regnum, u16 andMask, u16 orMask); +void ET1310_PhyAccessMiBit(struct et131x_adapter *adapter, + u16 action, + u16 regnum, u16 bitnum, u8 *value); + +#endif /* _ET1310_PHY_H_ */ diff --git a/src/et131x/et1310_pm.c b/src/et131x/et1310_pm.c new file mode 100644 index 0000000..9539bc6 --- /dev/null +++ b/src/et131x/et1310_pm.c @@ -0,0 +1,207 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et1310_pm.c - All power management related code (not completely implemented) + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#include "et131x_version.h" +#include "et131x_debug.h" +#include "et131x_defs.h" + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> + +#include <linux/sched.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/ctype.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/in.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/bitops.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/if_arp.h> +#include <linux/ioport.h> + +#include "et1310_phy.h" +#include "et1310_pm.h" +#include "et1310_jagcore.h" +#include "et1310_mac.h" +#include "et1310_rx.h" + +#include "et131x_adapter.h" +#include "et131x_initpci.h" + +/* Data for debugging facilities */ +#ifdef CONFIG_ET131X_DEBUG +extern dbg_info_t *et131x_dbginfo; +#endif /* CONFIG_ET131X_DEBUG */ + +/** + * EnablePhyComa - called when network cable is unplugged + * @pAdapter: pointer to our adapter structure + * + * driver receive an phy status change interrupt while in D0 and check that + * phy_status is down. + * + * -- gate off JAGCore; + * -- set gigE PHY in Coma mode + * -- wake on phy_interrupt; Perform software reset JAGCore, + * re-initialize jagcore and gigE PHY + * + * Add D0-ASPM-PhyLinkDown Support: + * -- while in D0, when there is a phy_interrupt indicating phy link + * down status, call the MPSetPhyComa routine to enter this active + * state power saving mode + * -- while in D0-ASPM-PhyLinkDown mode, when there is a phy_interrupt + * indicating linkup status, call the MPDisablePhyComa routine to + * restore JAGCore and gigE PHY + */ +void EnablePhyComa(struct et131x_adapter *pAdapter) +{ + unsigned long lockflags; + PM_CSR_t GlobalPmCSR; + int32_t LoopCounter = 10; + + DBG_ENTER(et131x_dbginfo); + + GlobalPmCSR.value = readl(&pAdapter->CSRAddress->global.pm_csr.value); + + /* Save the GbE PHY speed and duplex modes. Need to restore this + * when cable is plugged back in + */ + pAdapter->PoMgmt.PowerDownSpeed = pAdapter->AiForceSpeed; + pAdapter->PoMgmt.PowerDownDuplex = pAdapter->AiForceDpx; + + /* Stop sending packets. */ + spin_lock_irqsave(&pAdapter->SendHWLock, lockflags); + MP_SET_FLAG(pAdapter, fMP_ADAPTER_LOWER_POWER); + spin_unlock_irqrestore(&pAdapter->SendHWLock, lockflags); + + /* Wait for outstanding Receive packets */ + while ((MP_GET_RCV_REF(pAdapter) != 0) && (LoopCounter-- > 0)) { + mdelay(2); + } + + /* Gate off JAGCore 3 clock domains */ + GlobalPmCSR.bits.pm_sysclk_gate = 0; + GlobalPmCSR.bits.pm_txclk_gate = 0; + GlobalPmCSR.bits.pm_rxclk_gate = 0; + writel(GlobalPmCSR.value, &pAdapter->CSRAddress->global.pm_csr.value); + + /* Program gigE PHY in to Coma mode */ + GlobalPmCSR.bits.pm_phy_sw_coma = 1; + writel(GlobalPmCSR.value, &pAdapter->CSRAddress->global.pm_csr.value); + + DBG_LEAVE(et131x_dbginfo); +} + +/** + * DisablePhyComa - Disable the Phy Coma Mode + * @pAdapter: pointer to our adapter structure + */ +void DisablePhyComa(struct et131x_adapter *pAdapter) +{ + PM_CSR_t GlobalPmCSR; + + DBG_ENTER(et131x_dbginfo); + + GlobalPmCSR.value = readl(&pAdapter->CSRAddress->global.pm_csr.value); + + /* Disable phy_sw_coma register and re-enable JAGCore clocks */ + GlobalPmCSR.bits.pm_sysclk_gate = 1; + GlobalPmCSR.bits.pm_txclk_gate = 1; + GlobalPmCSR.bits.pm_rxclk_gate = 1; + GlobalPmCSR.bits.pm_phy_sw_coma = 0; + writel(GlobalPmCSR.value, &pAdapter->CSRAddress->global.pm_csr.value); + + /* Restore the GbE PHY speed and duplex modes; + * Reset JAGCore; re-configure and initialize JAGCore and gigE PHY + */ + pAdapter->AiForceSpeed = pAdapter->PoMgmt.PowerDownSpeed; + pAdapter->AiForceDpx = pAdapter->PoMgmt.PowerDownDuplex; + + /* Re-initialize the send structures */ + et131x_init_send(pAdapter); + + /* Reset the RFD list and re-start RU */ + et131x_reset_recv(pAdapter); + + /* Bring the device back to the state it was during init prior to + * autonegotiation being complete. This way, when we get the auto-neg + * complete interrupt, we can complete init by calling ConfigMacREGS2. + */ + et131x_soft_reset(pAdapter); + + /* setup et1310 as per the documentation ?? */ + et131x_adapter_setup(pAdapter); + + /* Allow Tx to restart */ + MP_CLEAR_FLAG(pAdapter, fMP_ADAPTER_LOWER_POWER); + + /* Need to re-enable Rx. */ + et131x_rx_dma_enable(pAdapter); + + DBG_LEAVE(et131x_dbginfo); +} + diff --git a/src/et131x/et1310_pm.h b/src/et131x/et1310_pm.h new file mode 100644 index 0000000..6802338 --- /dev/null +++ b/src/et131x/et1310_pm.h @@ -0,0 +1,125 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et1310_pm.h - Defines, structs, enums, prototypes, etc. pertaining to power + * management. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#ifndef _ET1310_PM_H_ +#define _ET1310_PM_H_ + +#include "et1310_address_map.h" + +#define MAX_WOL_PACKET_SIZE 0x80 +#define MAX_WOL_MASK_SIZE ( MAX_WOL_PACKET_SIZE / 8 ) +#define NUM_WOL_PATTERNS 0x5 +#define CRC16_POLY 0x1021 + +/* Definition of NDIS_DEVICE_POWER_STATE */ +typedef enum { + NdisDeviceStateUnspecified = 0, + NdisDeviceStateD0, + NdisDeviceStateD1, + NdisDeviceStateD2, + NdisDeviceStateD3 +} NDIS_DEVICE_POWER_STATE; + +typedef struct _MP_POWER_MGMT { + /* variable putting the phy into coma mode when boot up with no cable + * plugged in after 5 seconds + */ + u8 TransPhyComaModeOnBoot; + + /* Array holding the five CRC values that the device is currently + * using for WOL. This will be queried when a pattern is to be + * removed. + */ + u32 localWolAndCrc0; + u16 WOLPatternList[NUM_WOL_PATTERNS]; + u8 WOLMaskList[NUM_WOL_PATTERNS][MAX_WOL_MASK_SIZE]; + u32 WOLMaskSize[NUM_WOL_PATTERNS]; + + /* IP address */ + union { + u32 u32; + u8 u8[4]; + } IPAddress; + + /* Current Power state of the adapter. */ + NDIS_DEVICE_POWER_STATE PowerState; + bool WOLState; + bool WOLEnabled; + bool Failed10Half; + bool bFailedStateTransition; + + /* Next two used to save power information at power down. This + * information will be used during power up to set up parts of Power + * Management in JAGCore + */ + u32 tx_en; + u32 rx_en; + u16 PowerDownSpeed; + u8 PowerDownDuplex; +} MP_POWER_MGMT, *PMP_POWER_MGMT; + +/* Forward declaration of the private adapter structure + * ( IS THERE A WAY TO DO THIS WITH A TYPEDEF??? ) + */ +struct et131x_adapter; + +u16 CalculateCCITCRC16(u8 *Pattern, u8 *Mask, u32 MaskSize); +void EnablePhyComa(struct et131x_adapter *adapter); +void DisablePhyComa(struct et131x_adapter *adapter); + +#endif /* _ET1310_PM_H_ */ diff --git a/src/et131x/et1310_rx.c b/src/et131x/et1310_rx.c new file mode 100644 index 0000000..ec98da5 --- /dev/null +++ b/src/et131x/et1310_rx.c @@ -0,0 +1,1391 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et1310_rx.c - Routines used to perform data reception + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#include "et131x_version.h" +#include "et131x_debug.h" +#include "et131x_defs.h" + +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> + +#include <linux/sched.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/ctype.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/in.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/bitops.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/if_arp.h> +#include <linux/ioport.h> + +#include "et1310_phy.h" +#include "et1310_pm.h" +#include "et1310_jagcore.h" + +#include "et131x_adapter.h" +#include "et131x_initpci.h" + +#include "et1310_rx.h" + +/* Data for debugging facilities */ +#ifdef CONFIG_ET131X_DEBUG +extern dbg_info_t *et131x_dbginfo; +#endif /* CONFIG_ET131X_DEBUG */ + + +void nic_return_rfd(struct et131x_adapter *pAdapter, PMP_RFD pMpRfd); + +/** + * et131x_rx_dma_memory_alloc + * @adapter: pointer to our private adapter structure + * + * Returns 0 on success and errno on failure (as defined in errno.h) + * + * Allocates Free buffer ring 1 for sure, free buffer ring 0 if required, + * and the Packet Status Ring. + */ +int et131x_rx_dma_memory_alloc(struct et131x_adapter *adapter) +{ + uint32_t OuterLoop, InnerLoop; + uint32_t bufsize; + uint32_t pktStatRingSize, FBRChunkSize; + RX_RING_t *rx_ring; + + DBG_ENTER(et131x_dbginfo); + + /* Setup some convenience pointers */ + rx_ring = (RX_RING_t *) & adapter->RxRing; + + /* Alloc memory for the lookup table */ +#ifdef USE_FBR0 + rx_ring->Fbr[0] = kmalloc(sizeof(FBRLOOKUPTABLE), GFP_KERNEL); +#endif + + rx_ring->Fbr[1] = kmalloc(sizeof(FBRLOOKUPTABLE), GFP_KERNEL); + + /* The first thing we will do is configure the sizes of the buffer + * rings. These will change based on jumbo packet support. Larger + * jumbo packets increases the size of each entry in FBR0, and the + * number of entries in FBR0, while at the same time decreasing the + * number of entries in FBR1. + * + * FBR1 holds "large" frames, FBR0 holds "small" frames. If FBR1 + * entries are huge in order to accomodate a "jumbo" frame, then it + * will have less entries. Conversely, FBR1 will now be relied upon + * to carry more "normal" frames, thus it's entry size also increases + * and the number of entries goes up too (since it now carries + * "small" + "regular" packets. + * + * In this scheme, we try to maintain 512 entries between the two + * rings. Also, FBR1 remains a constant size - when it's size doubles + * the number of entries halves. FBR0 increases in size, however. + */ + + if (adapter->RegistryJumboPacket < 2048) { +#ifdef USE_FBR0 + rx_ring->Fbr0BufferSize = 256; + rx_ring->Fbr0NumEntries = 512; +#endif + rx_ring->Fbr1BufferSize = 2048; + rx_ring->Fbr1NumEntries = 512; + } else if (adapter->RegistryJumboPacket < 4096) { +#ifdef USE_FBR0 + rx_ring->Fbr0BufferSize = 512; + rx_ring->Fbr0NumEntries = 1024; +#endif + rx_ring->Fbr1BufferSize = 4096; + rx_ring->Fbr1NumEntries = 512; + } else { +#ifdef USE_FBR0 + rx_ring->Fbr0BufferSize = 1024; + rx_ring->Fbr0NumEntries = 768; +#endif + rx_ring->Fbr1BufferSize = 16384; + rx_ring->Fbr1NumEntries = 128; + } + +#ifdef USE_FBR0 + adapter->RxRing.PsrNumEntries = adapter->RxRing.Fbr0NumEntries + + adapter->RxRing.Fbr1NumEntries; +#else + adapter->RxRing.PsrNumEntries = adapter->RxRing.Fbr1NumEntries; +#endif + + /* Allocate an area of memory for Free Buffer Ring 1 */ + bufsize = (sizeof(FBR_DESC_t) * rx_ring->Fbr1NumEntries) + 0xfff; + rx_ring->pFbr1RingVa = pci_alloc_consistent(adapter->pdev, + bufsize, + &rx_ring->pFbr1RingPa); + if (!rx_ring->pFbr1RingVa) { + DBG_ERROR(et131x_dbginfo, + "Cannot alloc memory for Free Buffer Ring 1\n"); + DBG_LEAVE(et131x_dbginfo); + return -ENOMEM; + } + + /* Save physical address + * + * NOTE: pci_alloc_consistent(), used above to alloc DMA regions, + * ALWAYS returns SAC (32-bit) addresses. If DAC (64-bit) addresses + * are ever returned, make sure the high part is retrieved here + * before storing the adjusted address. + */ + rx_ring->Fbr1Realpa = rx_ring->pFbr1RingPa; + + /* Align Free Buffer Ring 1 on a 4K boundary */ + et131x_align_allocated_memory(adapter, + &rx_ring->Fbr1Realpa, + &rx_ring->Fbr1offset, 0x0FFF); + + rx_ring->pFbr1RingVa = (void *)((uint8_t *) rx_ring->pFbr1RingVa + + rx_ring->Fbr1offset); + +#ifdef USE_FBR0 + /* Allocate an area of memory for Free Buffer Ring 0 */ + bufsize = (sizeof(FBR_DESC_t) * rx_ring->Fbr0NumEntries) + 0xfff; + rx_ring->pFbr0RingVa = pci_alloc_consistent(adapter->pdev, + bufsize, + &rx_ring->pFbr0RingPa); + if (!rx_ring->pFbr0RingVa) { + DBG_ERROR(et131x_dbginfo, + "Cannot alloc memory for Free Buffer Ring 0\n"); + DBG_LEAVE(et131x_dbginfo); + return -ENOMEM; + } + + /* Save physical address + * + * NOTE: pci_alloc_consistent(), used above to alloc DMA regions, + * ALWAYS returns SAC (32-bit) addresses. If DAC (64-bit) addresses + * are ever returned, make sure the high part is retrieved here before + * storing the adjusted address. + */ + rx_ring->Fbr0Realpa = rx_ring->pFbr0RingPa; + + /* Align Free Buffer Ring 0 on a 4K boundary */ + et131x_align_allocated_memory(adapter, + &rx_ring->Fbr0Realpa, + &rx_ring->Fbr0offset, 0x0FFF); + + rx_ring->pFbr0RingVa = (void *)((uint8_t *) rx_ring->pFbr0RingVa + + rx_ring->Fbr0offset); +#endif + + for (OuterLoop = 0; OuterLoop < (rx_ring->Fbr1NumEntries / FBR_CHUNKS); + OuterLoop++) { + uint64_t Fbr1Offset; + uint64_t Fbr1TempPa; + uint32_t Fbr1Align; + + /* This code allocates an area of memory big enough for N + * free buffers + (buffer_size - 1) so that the buffers can + * be aligned on 4k boundaries. If each buffer were aligned + * to a buffer_size boundary, the effect would be to double + * the size of FBR0. By allocating N buffers at once, we + * reduce this overhead. + */ + if (rx_ring->Fbr1BufferSize > 4096) { + Fbr1Align = 4096; + } else { + Fbr1Align = rx_ring->Fbr1BufferSize; + } + + FBRChunkSize = + (FBR_CHUNKS * rx_ring->Fbr1BufferSize) + Fbr1Align - 1; + rx_ring->Fbr1MemVa[OuterLoop] = + pci_alloc_consistent(adapter->pdev, FBRChunkSize, + &rx_ring->Fbr1MemPa[OuterLoop]); + + if (!rx_ring->Fbr1MemVa[OuterLoop]) { + DBG_ERROR(et131x_dbginfo, "Could not alloc memory\n"); + DBG_LEAVE(et131x_dbginfo); + return -ENOMEM; + } + + /* See NOTE in "Save Physical Address" comment above */ + Fbr1TempPa = rx_ring->Fbr1MemPa[OuterLoop]; + + et131x_align_allocated_memory(adapter, + &Fbr1TempPa, + &Fbr1Offset, (Fbr1Align - 1)); + + for (InnerLoop = 0; InnerLoop < FBR_CHUNKS; InnerLoop++) { + uint32_t index = (OuterLoop * FBR_CHUNKS) + InnerLoop; + + /* Save the Virtual address of this index for quick + * access later + */ + rx_ring->Fbr[1]->Va[index] = + (uint8_t *) rx_ring->Fbr1MemVa[OuterLoop] + + (InnerLoop * rx_ring->Fbr1BufferSize) + Fbr1Offset; + + /* now store the physical address in the descriptor + * so the device can access it + */ + rx_ring->Fbr[1]->PAHigh[index] = + (uint32_t) (Fbr1TempPa >> 32); + rx_ring->Fbr[1]->PALow[index] = (uint32_t) Fbr1TempPa; + + Fbr1TempPa += rx_ring->Fbr1BufferSize; + + rx_ring->Fbr[1]->Buffer1[index] = + rx_ring->Fbr[1]->Va[index]; + rx_ring->Fbr[1]->Buffer2[index] = + rx_ring->Fbr[1]->Va[index] - 4; + } + } + +#ifdef USE_FBR0 + /* Same for FBR0 (if in use) */ + for (OuterLoop = 0; OuterLoop < (rx_ring->Fbr0NumEntries / FBR_CHUNKS); + OuterLoop++) { + uint64_t Fbr0Offset; + uint64_t Fbr0TempPa; + + FBRChunkSize = ((FBR_CHUNKS + 1) * rx_ring->Fbr0BufferSize) - 1; + rx_ring->Fbr0MemVa[OuterLoop] = + pci_alloc_consistent(adapter->pdev, FBRChunkSize, + &rx_ring->Fbr0MemPa[OuterLoop]); + + if (!rx_ring->Fbr0MemVa[OuterLoop]) { + DBG_ERROR(et131x_dbginfo, "Could not alloc memory\n"); + DBG_LEAVE(et131x_dbginfo); + return -ENOMEM; + } + + /* See NOTE in "Save Physical Address" comment above */ + Fbr0TempPa = rx_ring->Fbr0MemPa[OuterLoop]; + + et131x_align_allocated_memory(adapter, + &Fbr0TempPa, + &Fbr0Offset, + rx_ring->Fbr0BufferSize - 1); + + for (InnerLoop = 0; InnerLoop < FBR_CHUNKS; InnerLoop++) { + uint32_t index = (OuterLoop * FBR_CHUNKS) + InnerLoop; + + rx_ring->Fbr[0]->Va[index] = + (uint8_t *) rx_ring->Fbr0MemVa[OuterLoop] + + (InnerLoop * rx_ring->Fbr0BufferSize) + Fbr0Offset; + + rx_ring->Fbr[0]->PAHigh[index] = + (uint32_t) (Fbr0TempPa >> 32); + rx_ring->Fbr[0]->PALow[index] = (uint32_t) Fbr0TempPa; + + Fbr0TempPa += rx_ring->Fbr0BufferSize; + + rx_ring->Fbr[0]->Buffer1[index] = + rx_ring->Fbr[0]->Va[index]; + rx_ring->Fbr[0]->Buffer2[index] = + rx_ring->Fbr[0]->Va[index] - 4; + } + } +#endif + + /* Allocate an area of memory for FIFO of Packet Status ring entries */ + pktStatRingSize = + sizeof(PKT_STAT_DESC_t) * adapter->RxRing.PsrNumEntries; + + rx_ring->pPSRingVa = pci_alloc_consistent(adapter->pdev, + pktStatRingSize + 0x0fff, + &rx_ring->pPSRingPa); + + if (!rx_ring->pPSRingVa) { + DBG_ERROR(et131x_dbginfo, + "Cannot alloc memory for Packet Status Ring\n"); + DBG_LEAVE(et131x_dbginfo); + return -ENOMEM; + } + + /* Save physical address + * + * NOTE : pci_alloc_consistent(), used above to alloc DMA regions, + * ALWAYS returns SAC (32-bit) addresses. If DAC (64-bit) addresses + * are ever returned, make sure the high part is retrieved here before + * storing the adjusted address. + */ + rx_ring->pPSRingRealPa = rx_ring->pPSRingPa; + + /* Align Packet Status Ring on a 4K boundary */ + et131x_align_allocated_memory(adapter, + &rx_ring->pPSRingRealPa, + &rx_ring->pPSRingOffset, 0x0FFF); + + rx_ring->pPSRingVa = (void *)((uint8_t *) rx_ring->pPSRingVa + + rx_ring->pPSRingOffset); + + /* Allocate an area of memory for writeback of status information */ + rx_ring->pRxStatusVa = pci_alloc_consistent(adapter->pdev, + sizeof(RX_STATUS_BLOCK_t) + + 0x7, &rx_ring->pRxStatusPa); + if (!rx_ring->pRxStatusVa) { + DBG_ERROR(et131x_dbginfo, + "Cannot alloc memory for Status Block\n"); + DBG_LEAVE(et131x_dbginfo); + return -ENOMEM; + } + + /* Save physical address */ + rx_ring->RxStatusRealPA = rx_ring->pRxStatusPa; + + /* Align write back on an 8 byte boundary */ + et131x_align_allocated_memory(adapter, + &rx_ring->RxStatusRealPA, + &rx_ring->RxStatusOffset, 0x07); + + rx_ring->pRxStatusVa = (void *)((uint8_t *) rx_ring->pRxStatusVa + + rx_ring->RxStatusOffset); + rx_ring->NumRfd = NIC_DEFAULT_NUM_RFD; + + /* Recv + * pci_pool_create initializes a lookaside list. After successful + * creation, nonpaged fixed-size blocks can be allocated from and + * freed to the lookaside list. + * RFDs will be allocated from this pool. + */ + rx_ring->RecvLookaside = kmem_cache_create(adapter->netdev->name, + sizeof(MP_RFD), + 0, + SLAB_CACHE_DMA | + SLAB_HWCACHE_ALIGN, + NULL); + + MP_SET_FLAG(adapter, fMP_ADAPTER_RECV_LOOKASIDE); + + /* The RFDs are going to be put on lists later on, so initialize the + * lists now. + */ + INIT_LIST_HEAD(&rx_ring->RecvList); + INIT_LIST_HEAD(&rx_ring->RecvPendingList); + + DBG_LEAVE(et131x_dbginfo); + return 0; +} + +/** + * et131x_rx_dma_memory_free - Free all memory allocated within this module. + * @adapter: pointer to our private adapter structure + */ +void et131x_rx_dma_memory_free(struct et131x_adapter *adapter) +{ + uint32_t index; + uint32_t bufsize; + uint32_t pktStatRingSize; + PMP_RFD pMpRfd; + RX_RING_t *rx_ring; + + DBG_ENTER(et131x_dbginfo); + + /* Setup some convenience pointers */ + rx_ring = (RX_RING_t *) & adapter->RxRing; + + /* Free RFDs and associated packet descriptors */ + DBG_ASSERT(rx_ring->nReadyRecv == rx_ring->NumRfd); + + while (!list_empty(&rx_ring->RecvList)) { + pMpRfd = (MP_RFD *) list_entry(rx_ring->RecvList.next, + MP_RFD, list_node); + + list_del(&pMpRfd->list_node); + et131x_rfd_resources_free(adapter, pMpRfd); + } + + while (!list_empty(&rx_ring->RecvPendingList)) { + pMpRfd = (MP_RFD *) list_entry(rx_ring->RecvPendingList.next, + MP_RFD, list_node); + list_del(&pMpRfd->list_node); + et131x_rfd_resources_free(adapter, pMpRfd); + } + + /* Free Free Buffer Ring 1 */ + if (rx_ring->pFbr1RingVa) { + /* First the packet memory */ + for (index = 0; index < + (rx_ring->Fbr1NumEntries / FBR_CHUNKS); index++) { + if (rx_ring->Fbr1MemVa[index]) { + uint32_t Fbr1Align; + + if (rx_ring->Fbr1BufferSize > 4096) { + Fbr1Align = 4096; + } else { + Fbr1Align = rx_ring->Fbr1BufferSize; + } + + bufsize = + (rx_ring->Fbr1BufferSize * FBR_CHUNKS) + + Fbr1Align - 1; + + pci_free_consistent(adapter->pdev, + bufsize, + rx_ring->Fbr1MemVa[index], + rx_ring->Fbr1MemPa[index]); + + rx_ring->Fbr1MemVa[index] = NULL; + } + } + + /* Now the FIFO itself */ + rx_ring->pFbr1RingVa = (void *)((uint8_t *) rx_ring->pFbr1RingVa - + rx_ring->Fbr1offset); + + bufsize = + (sizeof(FBR_DESC_t) * rx_ring->Fbr1NumEntries) + 0xfff; + + pci_free_consistent(adapter->pdev, + bufsize, + rx_ring->pFbr1RingVa, rx_ring->pFbr1RingPa); + + rx_ring->pFbr1RingVa = NULL; + } + +#ifdef USE_FBR0 + /* Now the same for Free Buffer Ring 0 */ + if (rx_ring->pFbr0RingVa) { + /* First the packet memory */ + for (index = 0; index < + (rx_ring->Fbr0NumEntries / FBR_CHUNKS); index++) { + if (rx_ring->Fbr0MemVa[index]) { + bufsize = + (rx_ring->Fbr0BufferSize * + (FBR_CHUNKS + 1)) - 1; + + pci_free_consistent(adapter->pdev, + bufsize, + rx_ring->Fbr0MemVa[index], + rx_ring->Fbr0MemPa[index]); + + rx_ring->Fbr0MemVa[index] = NULL; + } + } + + /* Now the FIFO itself */ + rx_ring->pFbr0RingVa = (void *)((uint8_t *) rx_ring->pFbr0RingVa - + rx_ring->Fbr0offset); + + bufsize = + (sizeof(FBR_DESC_t) * rx_ring->Fbr0NumEntries) + 0xfff; + + pci_free_consistent(adapter->pdev, + bufsize, + rx_ring->pFbr0RingVa, rx_ring->pFbr0RingPa); + + rx_ring->pFbr0RingVa = NULL; + } +#endif + + /* Free Packet Status Ring */ + if (rx_ring->pPSRingVa) { + rx_ring->pPSRingVa = (void *)((uint8_t *) rx_ring->pPSRingVa - + rx_ring->pPSRingOffset); + + pktStatRingSize = + sizeof(PKT_STAT_DESC_t) * adapter->RxRing.PsrNumEntries; + + pci_free_consistent(adapter->pdev, + pktStatRingSize + 0x0fff, + rx_ring->pPSRingVa, rx_ring->pPSRingPa); + + rx_ring->pPSRingVa = NULL; + } + + /* Free area of memory for the writeback of status information */ + if (rx_ring->pRxStatusVa) { + rx_ring->pRxStatusVa = (void *)((uint8_t *) rx_ring->pRxStatusVa - + rx_ring->RxStatusOffset); + + pci_free_consistent(adapter->pdev, + sizeof(RX_STATUS_BLOCK_t) + 0x7, + rx_ring->pRxStatusVa, rx_ring->pRxStatusPa); + + rx_ring->pRxStatusVa = NULL; + } + + /* Free receive buffer pool */ + + /* Free receive packet pool */ + + /* Destroy the lookaside (RFD) pool */ + if (MP_TEST_FLAG(adapter, fMP_ADAPTER_RECV_LOOKASIDE)) { + kmem_cache_destroy(rx_ring->RecvLookaside); + MP_CLEAR_FLAG(adapter, fMP_ADAPTER_RECV_LOOKASIDE); + } + + /* Free the FBR Lookup Table */ +#ifdef USE_FBR0 + kfree(rx_ring->Fbr[0]); +#endif + + kfree(rx_ring->Fbr[1]); + + /* Reset Counters */ + rx_ring->nReadyRecv = 0; + + DBG_LEAVE(et131x_dbginfo); +} + +/** + * et131x_init_recv - Initialize receive data structures. + * @adapter: pointer to our private adapter structure + * + * Returns 0 on success and errno on failure (as defined in errno.h) + */ +int et131x_init_recv(struct et131x_adapter *adapter) +{ + int status = -ENOMEM; + PMP_RFD pMpRfd = NULL; + uint32_t RfdCount; + uint32_t TotalNumRfd = 0; + RX_RING_t *rx_ring = NULL; + + DBG_ENTER(et131x_dbginfo); + + /* Setup some convenience pointers */ + rx_ring = (RX_RING_t *) & adapter->RxRing; + + /* Setup each RFD */ + for (RfdCount = 0; RfdCount < rx_ring->NumRfd; RfdCount++) { + pMpRfd = (MP_RFD *) kmem_cache_alloc(rx_ring->RecvLookaside, + GFP_ATOMIC | GFP_DMA); + + if (!pMpRfd) { + DBG_ERROR(et131x_dbginfo, + "Couldn't alloc RFD out of kmem_cache\n"); + status = -ENOMEM; + continue; + } + + status = et131x_rfd_resources_alloc(adapter, pMpRfd); + if (status != 0) { + DBG_ERROR(et131x_dbginfo, + "Couldn't alloc packet for RFD\n"); + kmem_cache_free(rx_ring->RecvLookaside, pMpRfd); + continue; + } + + /* Add this RFD to the RecvList */ + list_add_tail(&pMpRfd->list_node, &rx_ring->RecvList); + + /* Increment both the available RFD's, and the total RFD's. */ + rx_ring->nReadyRecv++; + TotalNumRfd++; + } + + if (TotalNumRfd > NIC_MIN_NUM_RFD) { + status = 0; + } + + rx_ring->NumRfd = TotalNumRfd; + + if (status != 0) { + kmem_cache_free(rx_ring->RecvLookaside, pMpRfd); + DBG_ERROR(et131x_dbginfo, + "Allocation problems in et131x_init_recv\n"); + } + + DBG_LEAVE(et131x_dbginfo); + return status; +} + +/** + * et131x_rfd_resources_alloc + * @adapter: pointer to our private adapter structure + * @pMpRfd: pointer to a RFD + * + * Returns 0 on success and errno on failure (as defined in errno.h) + */ +int et131x_rfd_resources_alloc(struct et131x_adapter *adapter, MP_RFD *pMpRfd) +{ + pMpRfd->Packet = NULL; + + return 0; +} + +/** + * et131x_rfd_resources_free - Free the packet allocated for the given RFD + * @adapter: pointer to our private adapter structure + * @pMpRfd: pointer to a RFD + */ +void et131x_rfd_resources_free(struct et131x_adapter *adapter, MP_RFD *pMpRfd) +{ + pMpRfd->Packet = NULL; + kmem_cache_free(adapter->RxRing.RecvLookaside, pMpRfd); +} + +/** + * ConfigRxDmaRegs - Start of Rx_DMA init sequence + * @pAdapter: pointer to our adapter structure + */ +void ConfigRxDmaRegs(struct et131x_adapter *pAdapter) +{ + struct _RXDMA_t __iomem *pRxDma = &pAdapter->CSRAddress->rxdma; + struct _rx_ring_t *pRxLocal = &pAdapter->RxRing; + PFBR_DESC_t pFbrEntry; + uint32_t iEntry; + RXDMA_PSR_NUM_DES_t psr_num_des; + unsigned long lockflags; + + DBG_ENTER(et131x_dbginfo); + + /* Halt RXDMA to perform the reconfigure. */ + et131x_rx_dma_disable(pAdapter); + + /* Load the completion writeback physical address + * + * NOTE : pci_alloc_consistent(), used above to alloc DMA regions, + * ALWAYS returns SAC (32-bit) addresses. If DAC (64-bit) addresses + * are ever returned, make sure the high part is retrieved here + * before storing the adjusted address. + */ + writel((uint32_t) (pRxLocal->RxStatusRealPA >> 32), + &pRxDma->dma_wb_base_hi); + writel((uint32_t) pRxLocal->RxStatusRealPA, &pRxDma->dma_wb_base_lo); + + memset(pRxLocal->pRxStatusVa, 0, sizeof(RX_STATUS_BLOCK_t)); + + /* Set the address and parameters of the packet status ring into the + * 1310's registers + */ + writel((uint32_t) (pRxLocal->pPSRingRealPa >> 32), + &pRxDma->psr_base_hi); + writel((uint32_t) pRxLocal->pPSRingRealPa, &pRxDma->psr_base_lo); + writel(pRxLocal->PsrNumEntries - 1, &pRxDma->psr_num_des.value); + writel(0, &pRxDma->psr_full_offset.value); + + psr_num_des.value = readl(&pRxDma->psr_num_des.value); + writel((psr_num_des.bits.psr_ndes * LO_MARK_PERCENT_FOR_PSR) / 100, + &pRxDma->psr_min_des.value); + + spin_lock_irqsave(&pAdapter->RcvLock, lockflags); + + /* These local variables track the PSR in the adapter structure */ + pRxLocal->local_psr_full.bits.psr_full = 0; + pRxLocal->local_psr_full.bits.psr_full_wrap = 0; + + /* Now's the best time to initialize FBR1 contents */ + pFbrEntry = (PFBR_DESC_t) pRxLocal->pFbr1RingVa; + for (iEntry = 0; iEntry < pRxLocal->Fbr1NumEntries; iEntry++) { + pFbrEntry->addr_hi = pRxLocal->Fbr[1]->PAHigh[iEntry]; + pFbrEntry->addr_lo = pRxLocal->Fbr[1]->PALow[iEntry]; + pFbrEntry->word2.bits.bi = iEntry; + pFbrEntry++; + } + + /* Set the address and parameters of Free buffer ring 1 (and 0 if + * required) into the 1310's registers + */ + writel((uint32_t) (pRxLocal->Fbr1Realpa >> 32), &pRxDma->fbr1_base_hi); + writel((uint32_t) pRxLocal->Fbr1Realpa, &pRxDma->fbr1_base_lo); + writel(pRxLocal->Fbr1NumEntries - 1, &pRxDma->fbr1_num_des.value); + + { + DMA10W_t fbr1_full = { 0 }; + + fbr1_full.bits.val = 0; + fbr1_full.bits.wrap = 1; + writel(fbr1_full.value, &pRxDma->fbr1_full_offset.value); + } + + /* This variable tracks the free buffer ring 1 full position, so it + * has to match the above. + */ + pRxLocal->local_Fbr1_full.bits.val = 0; + pRxLocal->local_Fbr1_full.bits.wrap = 1; + writel(((pRxLocal->Fbr1NumEntries * LO_MARK_PERCENT_FOR_RX) / 100) - 1, + &pRxDma->fbr1_min_des.value); + +#ifdef USE_FBR0 + /* Now's the best time to initialize FBR0 contents */ + pFbrEntry = (PFBR_DESC_t) pRxLocal->pFbr0RingVa; + for (iEntry = 0; iEntry < pRxLocal->Fbr0NumEntries; iEntry++) { + pFbrEntry->addr_hi = pRxLocal->Fbr[0]->PAHigh[iEntry]; + pFbrEntry->addr_lo = pRxLocal->Fbr[0]->PALow[iEntry]; + pFbrEntry->word2.bits.bi = iEntry; + pFbrEntry++; + } + + writel((uint32_t) (pRxLocal->Fbr0Realpa >> 32), &pRxDma->fbr0_base_hi); + writel((uint32_t) pRxLocal->Fbr0Realpa, &pRxDma->fbr0_base_lo); + writel(pRxLocal->Fbr0NumEntries - 1, &pRxDma->fbr0_num_des.value); + + { + DMA10W_t fbr0_full = { 0 }; + + fbr0_full.bits.val = 0; + fbr0_full.bits.wrap = 1; + writel(fbr0_full.value, &pRxDma->fbr0_full_offset.value); + } + + /* This variable tracks the free buffer ring 0 full position, so it + * has to match the above. + */ + pRxLocal->local_Fbr0_full.bits.val = 0; + pRxLocal->local_Fbr0_full.bits.wrap = 1; + writel(((pRxLocal->Fbr0NumEntries * LO_MARK_PERCENT_FOR_RX) / 100) - 1, + &pRxDma->fbr0_min_des.value); +#endif + + /* Program the number of packets we will receive before generating an + * interrupt. + * For version B silicon, this value gets updated once autoneg is + *complete. + */ + writel(pAdapter->RegistryRxNumBuffers, &pRxDma->num_pkt_done.value); + + /* The "time_done" is not working correctly to coalesce interrupts + * after a given time period, but rather is giving us an interrupt + * regardless of whether we have received packets. + * This value gets updated once autoneg is complete. + */ + writel(pAdapter->RegistryRxTimeInterval, &pRxDma->max_pkt_time.value); + + spin_unlock_irqrestore(&pAdapter->RcvLock, lockflags); + + DBG_LEAVE(et131x_dbginfo); +} + +/** + * SetRxDmaTimer - Set the heartbeat timer according to line rate. + * @pAdapter: pointer to our adapter structure + */ +void SetRxDmaTimer(struct et131x_adapter *pAdapter) +{ + /* For version B silicon, we do not use the RxDMA timer for 10 and 100 + * Mbits/s line rates. We do not enable and RxDMA interrupt coalescing. + */ + if ((pAdapter->uiLinkSpeed == TRUEPHY_SPEED_100MBPS) || + (pAdapter->uiLinkSpeed == TRUEPHY_SPEED_10MBPS)) { + writel(0, &pAdapter->CSRAddress->rxdma.max_pkt_time.value); + writel(1, &pAdapter->CSRAddress->rxdma.num_pkt_done.value); + } +} + +/** + * et131x_rx_dma_disable - Stop of Rx_DMA on the ET1310 + * @pAdapter: pointer to our adapter structure + */ +void et131x_rx_dma_disable(struct et131x_adapter *pAdapter) +{ + RXDMA_CSR_t csr; + + DBG_ENTER(et131x_dbginfo); + + /* Setup the receive dma configuration register */ + writel(0x00002001, &pAdapter->CSRAddress->rxdma.csr.value); + csr.value = readl(&pAdapter->CSRAddress->rxdma.csr.value); + if (csr.bits.halt_status != 1) { + udelay(5); + csr.value = readl(&pAdapter->CSRAddress->rxdma.csr.value); + if (csr.bits.halt_status != 1) { + DBG_ERROR(et131x_dbginfo, + "RX Dma failed to enter halt state. CSR 0x%08x\n", + csr.value); + } + } + + DBG_LEAVE(et131x_dbginfo); +} + +/** + * et131x_rx_dma_enable - re-start of Rx_DMA on the ET1310. + * @pAdapter: pointer to our adapter structure + */ +void et131x_rx_dma_enable(struct et131x_adapter *pAdapter) +{ + DBG_RX_ENTER(et131x_dbginfo); + + if (pAdapter->RegistryPhyLoopbk) { + /* RxDMA is disabled for loopback operation. */ + writel(0x1, &pAdapter->CSRAddress->rxdma.csr.value); + } else { + /* Setup the receive dma configuration register for normal operation */ + RXDMA_CSR_t csr = { 0 }; + + csr.bits.fbr1_enable = 1; + if (pAdapter->RxRing.Fbr1BufferSize == 4096) { + csr.bits.fbr1_size = 1; + } else if (pAdapter->RxRing.Fbr1BufferSize == 8192) { + csr.bits.fbr1_size = 2; + } else if (pAdapter->RxRing.Fbr1BufferSize == 16384) { + csr.bits.fbr1_size = 3; + } +#ifdef USE_FBR0 + csr.bits.fbr0_enable = 1; + if (pAdapter->RxRing.Fbr0BufferSize == 256) { + csr.bits.fbr0_size = 1; + } else if (pAdapter->RxRing.Fbr0BufferSize == 512) { + csr.bits.fbr0_size = 2; + } else if (pAdapter->RxRing.Fbr0BufferSize == 1024) { + csr.bits.fbr0_size = 3; + } +#endif + writel(csr.value, &pAdapter->CSRAddress->rxdma.csr.value); + + csr.value = readl(&pAdapter->CSRAddress->rxdma.csr.value); + if (csr.bits.halt_status != 0) { + udelay(5); + csr.value = readl(&pAdapter->CSRAddress->rxdma.csr.value); + if (csr.bits.halt_status != 0) { + DBG_ERROR(et131x_dbginfo, + "RX Dma failed to exit halt state. CSR 0x%08x\n", + csr.value); + } + } + } + + DBG_RX_LEAVE(et131x_dbginfo); +} + +/** + * nic_rx_pkts - Checks the hardware for available packets + * @pAdapter: pointer to our adapter + * + * Returns pMpRfd, a pointer to our MPRFD. + * + * Checks the hardware for available packets, using completion ring + * If packets are available, it gets an RFD from the RecvList, attaches + * the packet to it, puts the RFD in the RecvPendList, and also returns + * the pointer to the RFD. + */ +PMP_RFD nic_rx_pkts(struct et131x_adapter *pAdapter) +{ + struct _rx_ring_t *pRxLocal = &pAdapter->RxRing; + PRX_STATUS_BLOCK_t pRxStatusBlock; + PPKT_STAT_DESC_t pPSREntry; + PMP_RFD pMpRfd; + uint32_t nIndex; + uint8_t *pBufVa; + unsigned long lockflags; + struct list_head *element; + uint8_t ringIndex; + uint16_t bufferIndex; + uint32_t localLen; + PKT_STAT_DESC_WORD0_t Word0; + + + DBG_RX_ENTER(et131x_dbginfo); + + /* RX Status block is written by the DMA engine prior to every + * interrupt. It contains the next to be used entry in the Packet + * Status Ring, and also the two Free Buffer rings. + */ + pRxStatusBlock = (PRX_STATUS_BLOCK_t) pRxLocal->pRxStatusVa; + + if (pRxStatusBlock->Word1.bits.PSRoffset == + pRxLocal->local_psr_full.bits.psr_full && + pRxStatusBlock->Word1.bits.PSRwrap == + pRxLocal->local_psr_full.bits.psr_full_wrap) { + /* Looks like this ring is not updated yet */ + DBG_RX(et131x_dbginfo, "(0)\n"); + DBG_RX_LEAVE(et131x_dbginfo); + return NULL; + } + + /* The packet status ring indicates that data is available. */ + pPSREntry = (PPKT_STAT_DESC_t) (pRxLocal->pPSRingVa) + + pRxLocal->local_psr_full.bits.psr_full; + + /* Grab any information that is required once the PSR is + * advanced, since we can no longer rely on the memory being + * accurate + */ + localLen = pPSREntry->word1.bits.length; + ringIndex = (uint8_t) pPSREntry->word1.bits.ri; + bufferIndex = (uint16_t) pPSREntry->word1.bits.bi; + Word0 = pPSREntry->word0; + + DBG_RX(et131x_dbginfo, "RX PACKET STATUS\n"); + DBG_RX(et131x_dbginfo, "\tlength : %d\n", localLen); + DBG_RX(et131x_dbginfo, "\tringIndex : %d\n", ringIndex); + DBG_RX(et131x_dbginfo, "\tbufferIndex : %d\n", bufferIndex); + DBG_RX(et131x_dbginfo, "\tword0 : 0x%08x\n", Word0.value); + +#if 0 + /* Check the Status Word that the MAC has appended to the PSR + * entry in case the MAC has detected errors. + */ + if (Word0.value & ALCATEL_BAD_STATUS) { + DBG_ERROR(et131x_dbginfo, + "NICRxPkts >> Alcatel Status Word error." + "Value 0x%08x\n", pPSREntry->word0.value); + } +#endif + + /* Indicate that we have used this PSR entry. */ + if (++pRxLocal->local_psr_full.bits.psr_full > + pRxLocal->PsrNumEntries - 1) { + pRxLocal->local_psr_full.bits.psr_full = 0; + pRxLocal->local_psr_full.bits.psr_full_wrap ^= 1; + } + + writel(pRxLocal->local_psr_full.value, + &pAdapter->CSRAddress->rxdma.psr_full_offset.value); + +#ifndef USE_FBR0 + if (ringIndex != 1) { + DBG_ERROR(et131x_dbginfo, + "NICRxPkts PSR Entry %d indicates " + "Buffer Ring 0 in use\n", + pRxLocal->local_psr_full.bits.psr_full); + DBG_RX_LEAVE(et131x_dbginfo); + return NULL; + } +#endif + +#ifdef USE_FBR0 + if (ringIndex > 1 || + (ringIndex == 0 && + bufferIndex > pRxLocal->Fbr0NumEntries - 1) || + (ringIndex == 1 && + bufferIndex > pRxLocal->Fbr1NumEntries - 1)) +#else + if (ringIndex != 1 || + bufferIndex > pRxLocal->Fbr1NumEntries - 1) +#endif + { + /* Illegal buffer or ring index cannot be used by S/W*/ + DBG_ERROR(et131x_dbginfo, + "NICRxPkts PSR Entry %d indicates " + "length of %d and/or bad bi(%d)\n", + pRxLocal->local_psr_full.bits.psr_full, + localLen, bufferIndex); + DBG_RX_LEAVE(et131x_dbginfo); + return NULL; + } + + /* Get and fill the RFD. */ + spin_lock_irqsave(&pAdapter->RcvLock, lockflags); + + pMpRfd = NULL; + element = pRxLocal->RecvList.next; + pMpRfd = (PMP_RFD) list_entry(element, MP_RFD, list_node); + + if (pMpRfd == NULL) { + DBG_RX(et131x_dbginfo, + "NULL RFD returned from RecvList via list_entry()\n"); + DBG_RX_LEAVE(et131x_dbginfo); + spin_unlock_irqrestore(&pAdapter->RcvLock, lockflags); + return NULL; + } + + list_del(&pMpRfd->list_node); + pRxLocal->nReadyRecv--; + + spin_unlock_irqrestore(&pAdapter->RcvLock, lockflags); + + pMpRfd->iBufferIndex = bufferIndex; + pMpRfd->iRingIndex = ringIndex; + + /* In V1 silicon, there is a bug which screws up filtering of + * runt packets. Therefore runt packet filtering is disabled + * in the MAC and the packets are dropped here. They are + * also counted here. + */ + if (localLen < (NIC_MIN_PACKET_SIZE + 4)) { + pAdapter->Stats.other_errors++; + localLen = 0; + } + + if (localLen) { + if (pAdapter->ReplicaPhyLoopbk == 1) { + pBufVa = pRxLocal->Fbr[ringIndex]->Va[bufferIndex]; + + if (memcmp(&pBufVa[6], &pAdapter->CurrentAddress[0], + ETH_ALEN) == 0) { + if (memcmp(&pBufVa[42], "Replica packet", + ETH_HLEN)) { + pAdapter->ReplicaPhyLoopbkPF = 1; + } + } + DBG_WARNING(et131x_dbginfo, + "pBufVa:\t%02x:%02x:%02x:%02x:%02x:%02x\n", + pBufVa[6], pBufVa[7], pBufVa[8], + pBufVa[9], pBufVa[10], pBufVa[11]); + + DBG_WARNING(et131x_dbginfo, + "CurrentAddr:\t%02x:%02x:%02x:%02x:%02x:%02x\n", + pAdapter->CurrentAddress[0], + pAdapter->CurrentAddress[1], + pAdapter->CurrentAddress[2], + pAdapter->CurrentAddress[3], + pAdapter->CurrentAddress[4], + pAdapter->CurrentAddress[5]); + } + + /* Determine if this is a multicast packet coming in */ + if ((Word0.value & ALCATEL_MULTICAST_PKT) && + !(Word0.value & ALCATEL_BROADCAST_PKT)) { + /* Promiscuous mode and Multicast mode are + * not mutually exclusive as was first + * thought. I guess Promiscuous is just + * considered a super-set of the other + * filters. Generally filter is 0x2b when in + * promiscuous mode. + */ + if ((pAdapter->PacketFilter & ET131X_PACKET_TYPE_MULTICAST) + && !(pAdapter->PacketFilter & ET131X_PACKET_TYPE_PROMISCUOUS) + && !(pAdapter->PacketFilter & ET131X_PACKET_TYPE_ALL_MULTICAST)) { + pBufVa = pRxLocal->Fbr[ringIndex]-> + Va[bufferIndex]; + + /* Loop through our list to see if the + * destination address of this packet + * matches one in our list. + */ + for (nIndex = 0; + nIndex < pAdapter->MCAddressCount; + nIndex++) { + if (pBufVa[0] == + pAdapter->MCList[nIndex][0] + && pBufVa[1] == + pAdapter->MCList[nIndex][1] + && pBufVa[2] == + pAdapter->MCList[nIndex][2] + && pBufVa[3] == + pAdapter->MCList[nIndex][3] + && pBufVa[4] == + pAdapter->MCList[nIndex][4] + && pBufVa[5] == + pAdapter->MCList[nIndex][5]) { + break; + } + } + + /* If our index is equal to the number + * of Multicast address we have, then + * this means we did not find this + * packet's matching address in our + * list. Set the PacketSize to zero, + * so we free our RFD when we return + * from this function. + */ + if (nIndex == pAdapter->MCAddressCount) { + localLen = 0; + } + } + + if (localLen > 0) { + pAdapter->Stats.multircv++; + } + } else if (Word0.value & ALCATEL_BROADCAST_PKT) { + pAdapter->Stats.brdcstrcv++; + } else { + /* Not sure what this counter measures in + * promiscuous mode. Perhaps we should check + * the MAC address to see if it is directed + * to us in promiscuous mode. + */ + pAdapter->Stats.unircv++; + } + } + + if (localLen > 0) { + struct sk_buff *skb = NULL; + + //pMpRfd->PacketSize = localLen - 4; + pMpRfd->PacketSize = localLen; + + skb = dev_alloc_skb(pMpRfd->PacketSize + 2); + if (!skb) { + DBG_ERROR(et131x_dbginfo, + "Couldn't alloc an SKB for Rx\n"); + DBG_RX_LEAVE(et131x_dbginfo); + return NULL; + } + + pAdapter->net_stats.rx_bytes += pMpRfd->PacketSize; + + memcpy(skb_put(skb, pMpRfd->PacketSize), + pRxLocal->Fbr[ringIndex]->Va[bufferIndex], + pMpRfd->PacketSize); + + skb->dev = pAdapter->netdev; + skb->protocol = eth_type_trans(skb, pAdapter->netdev); + skb->ip_summed = CHECKSUM_NONE; + + netif_rx(skb); + } else { + pMpRfd->PacketSize = 0; + } + + nic_return_rfd(pAdapter, pMpRfd); + + DBG_RX(et131x_dbginfo, "(1)\n"); + DBG_RX_LEAVE(et131x_dbginfo); + return pMpRfd; +} + +/** + * et131x_reset_recv - Reset the receive list + * @pAdapter: pointer to our adapter + * + * Assumption, Rcv spinlock has been acquired. + */ +void et131x_reset_recv(struct et131x_adapter *pAdapter) +{ + PMP_RFD pMpRfd; + struct list_head *element; + + DBG_ENTER(et131x_dbginfo); + + DBG_ASSERT(!list_empty(&pAdapter->RxRing.RecvList)); + + /* Take all the RFD's from the pending list, and stick them on the + * RecvList. + */ + while (!list_empty(&pAdapter->RxRing.RecvPendingList)) { + element = pAdapter->RxRing.RecvPendingList.next; + + pMpRfd = (PMP_RFD) list_entry(element, MP_RFD, list_node); + + list_del(&pMpRfd->list_node); + list_add_tail(&pMpRfd->list_node, &pAdapter->RxRing.RecvList); + } + + DBG_LEAVE(et131x_dbginfo); +} + +/** + * et131x_handle_recv_interrupt - Interrupt handler for receive processing + * @pAdapter: pointer to our adapter + * + * Assumption, Rcv spinlock has been acquired. + */ +void et131x_handle_recv_interrupt(struct et131x_adapter *pAdapter) +{ + PMP_RFD pMpRfd = NULL; + struct sk_buff *PacketArray[NUM_PACKETS_HANDLED]; + PMP_RFD RFDFreeArray[NUM_PACKETS_HANDLED]; + uint32_t PacketArrayCount = 0; + uint32_t PacketsToHandle; + uint32_t PacketFreeCount = 0; + bool TempUnfinishedRec = false; + + DBG_RX_ENTER(et131x_dbginfo); + + PacketsToHandle = NUM_PACKETS_HANDLED; + + /* Process up to available RFD's */ + while (PacketArrayCount < PacketsToHandle) { + if (list_empty(&pAdapter->RxRing.RecvList)) { + DBG_ASSERT(pAdapter->RxRing.nReadyRecv == 0); + DBG_ERROR(et131x_dbginfo, "NO RFD's !!!!!!!!!!!!!\n"); + TempUnfinishedRec = true; + break; + } + + pMpRfd = nic_rx_pkts(pAdapter); + + if (pMpRfd == NULL) { + break; + } + + /* Do not receive any packets until a filter has been set. + * Do not receive any packets until we are at D0. + * Do not receive any packets until we have link. + * If length is zero, return the RFD in order to advance the + * Free buffer ring. + */ + if ((!pAdapter->PacketFilter) || + (pAdapter->PoMgmt.PowerState != NdisDeviceStateD0) || + (!MP_LINK_DETECTED(pAdapter)) || + (pMpRfd->PacketSize == 0)) { + continue; + } + + /* Increment the number of packets we received */ + pAdapter->Stats.ipackets++; + + /* Set the status on the packet, either resources or success */ + if (pAdapter->RxRing.nReadyRecv >= RFD_LOW_WATER_MARK) { + /* Put this RFD on the pending list + * + * NOTE: nic_rx_pkts() above is already returning the + * RFD to the RecvList, so don't additionally do that + * here. + * Besides, we don't really need (at this point) the + * pending list anyway. + */ + //spin_lock_irqsave( &pAdapter->RcvPendLock, lockflags ); + //list_add_tail( &pMpRfd->list_node, &pAdapter->RxRing.RecvPendingList ); + //spin_unlock_irqrestore( &pAdapter->RcvPendLock, lockflags ); + + /* Update the number of outstanding Recvs */ + //MP_INC_RCV_REF( pAdapter ); + } else { + RFDFreeArray[PacketFreeCount] = pMpRfd; + PacketFreeCount++; + + DBG_WARNING(et131x_dbginfo, + "RFD's are running out !!!!!!!!!!!!!\n"); + } + + PacketArray[PacketArrayCount] = pMpRfd->Packet; + PacketArrayCount++; + } + + if ((PacketArrayCount == NUM_PACKETS_HANDLED) || TempUnfinishedRec) { + pAdapter->RxRing.UnfinishedReceives = true; + writel(pAdapter->RegistryTxTimeInterval * NANO_IN_A_MICRO, + &pAdapter->CSRAddress->global.watchdog_timer); + } else { + /* Watchdog timer will disable itself if appropriate. */ + pAdapter->RxRing.UnfinishedReceives = false; + } + + DBG_RX_LEAVE(et131x_dbginfo); +} + +/** + * NICReturnRFD - Recycle a RFD and put it back onto the receive list + * @pAdapter: pointer to our adapter + * @pMpRfd: pointer to the RFD + */ +void nic_return_rfd(struct et131x_adapter *pAdapter, PMP_RFD pMpRfd) +{ + struct _rx_ring_t *pRxLocal = &pAdapter->RxRing; + struct _RXDMA_t __iomem *pRxDma = &pAdapter->CSRAddress->rxdma; + uint16_t bi = pMpRfd->iBufferIndex; + uint8_t ri = pMpRfd->iRingIndex; + unsigned long lockflags; + + DBG_RX_ENTER(et131x_dbginfo); + + /* We don't use any of the OOB data besides status. Otherwise, we + * need to clean up OOB data + */ + if ( +#ifdef USE_FBR0 + (ri == 0 && bi < pRxLocal->Fbr0NumEntries) || +#endif + (ri == 1 && bi < pRxLocal->Fbr1NumEntries)) { + spin_lock_irqsave(&pAdapter->FbrLock, lockflags); + + if (ri == 1) { + PFBR_DESC_t pNextDesc = + (PFBR_DESC_t) (pRxLocal->pFbr1RingVa) + + pRxLocal->local_Fbr1_full.bits.val; + + /* Handle the Free Buffer Ring advancement here. Write + * the PA / Buffer Index for the returned buffer into + * the oldest (next to be freed)FBR entry + */ + pNextDesc->addr_hi = pRxLocal->Fbr[1]->PAHigh[bi]; + pNextDesc->addr_lo = pRxLocal->Fbr[1]->PALow[bi]; + pNextDesc->word2.value = bi; + + if (++pRxLocal->local_Fbr1_full.bits.val > + (pRxLocal->Fbr1NumEntries - 1)) { + pRxLocal->local_Fbr1_full.bits.val = 0; + pRxLocal->local_Fbr1_full.bits.wrap ^= 1; + } + + writel(pRxLocal->local_Fbr1_full.value, + &pRxDma->fbr1_full_offset.value); + } +#ifdef USE_FBR0 + else { + PFBR_DESC_t pNextDesc = + (PFBR_DESC_t) pRxLocal->pFbr0RingVa + + pRxLocal->local_Fbr0_full.bits.val; + + /* Handle the Free Buffer Ring advancement here. Write + * the PA / Buffer Index for the returned buffer into + * the oldest (next to be freed) FBR entry + */ + pNextDesc->addr_hi = pRxLocal->Fbr[0]->PAHigh[bi]; + pNextDesc->addr_lo = pRxLocal->Fbr[0]->PALow[bi]; + pNextDesc->word2.value = bi; + + if (++pRxLocal->local_Fbr0_full.bits.val > + (pRxLocal->Fbr0NumEntries - 1)) { + pRxLocal->local_Fbr0_full.bits.val = 0; + pRxLocal->local_Fbr0_full.bits.wrap ^= 1; + } + + writel(pRxLocal->local_Fbr0_full.value, + &pRxDma->fbr0_full_offset.value); + } +#endif + spin_unlock_irqrestore(&pAdapter->FbrLock, lockflags); + } else { + DBG_ERROR(et131x_dbginfo, + "NICReturnRFD illegal Buffer Index returned\n"); + } + + /* The processing on this RFD is done, so put it back on the tail of + * our list + */ + spin_lock_irqsave(&pAdapter->RcvLock, lockflags); + list_add_tail(&pMpRfd->list_node, &pRxLocal->RecvList); + pRxLocal->nReadyRecv++; + spin_unlock_irqrestore(&pAdapter->RcvLock, lockflags); + + DBG_ASSERT(pRxLocal->nReadyRecv <= pRxLocal->NumRfd); + DBG_RX_LEAVE(et131x_dbginfo); +} diff --git a/src/et131x/et1310_rx.h b/src/et131x/et1310_rx.h new file mode 100644 index 0000000..ea66dbc --- /dev/null +++ b/src/et131x/et1310_rx.h @@ -0,0 +1,373 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et1310_rx.h - Defines, structs, enums, prototypes, etc. pertaining to data + * reception. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#ifndef __ET1310_RX_H__ +#define __ET1310_RX_H__ + +#include "et1310_address_map.h" + +#define USE_FBR0 true + +#ifdef USE_FBR0 +//#define FBR0_BUFFER_SIZE 256 +#endif + +//#define FBR1_BUFFER_SIZE 2048 + +#define FBR_CHUNKS 32 + +#define MAX_DESC_PER_RING_RX 1024 + +/* number of RFDs - default and min */ +#ifdef USE_FBR0 +#define RFD_LOW_WATER_MARK 40 +#define NIC_MIN_NUM_RFD 64 +#define NIC_DEFAULT_NUM_RFD 1024 +#else +#define RFD_LOW_WATER_MARK 20 +#define NIC_MIN_NUM_RFD 64 +#define NIC_DEFAULT_NUM_RFD 256 +#endif + +#define NUM_PACKETS_HANDLED 256 + +#define ALCATEL_BAD_STATUS 0xe47f0000 +#define ALCATEL_MULTICAST_PKT 0x01000000 +#define ALCATEL_BROADCAST_PKT 0x02000000 + +/* typedefs for Free Buffer Descriptors */ +typedef union _FBR_WORD2_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 reserved:22; // bits 10-31 + u32 bi:10; // bits 0-9(Buffer Index) +#else + u32 bi:10; // bits 0-9(Buffer Index) + u32 reserved:22; // bit 10-31 +#endif + } bits; +} FBR_WORD2_t, *PFBR_WORD2_t; + +typedef struct _FBR_DESC_t { + u32 addr_lo; + u32 addr_hi; + FBR_WORD2_t word2; +} FBR_DESC_t, *PFBR_DESC_t; + +/* Typedefs for Packet Status Ring Descriptors */ +typedef union _PKT_STAT_DESC_WORD0_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + // top 16 bits are from the Alcatel Status Word as enumerated in + // PE-MCXMAC Data Sheet IPD DS54 0210-1 (also IPD-DS80 0205-2) +#if 0 + u32 asw_trunc:1; // bit 31(Rx frame truncated) +#endif + u32 asw_long_evt:1; // bit 31(Rx long event) + u32 asw_VLAN_tag:1; // bit 30(VLAN tag detected) + u32 asw_unsupported_op:1; // bit 29(unsupported OP code) + u32 asw_pause_frame:1; // bit 28(is a pause frame) + u32 asw_control_frame:1; // bit 27(is a control frame) + u32 asw_dribble_nibble:1; // bit 26(spurious bits after EOP) + u32 asw_broadcast:1; // bit 25(has a broadcast address) + u32 asw_multicast:1; // bit 24(has a multicast address) + u32 asw_OK:1; // bit 23(valid CRC + no code error) + u32 asw_too_long:1; // bit 22(frame length > 1518 bytes) + u32 asw_len_chk_err:1; // bit 21(frame length field incorrect) + u32 asw_CRC_err:1; // bit 20(CRC error) + u32 asw_code_err:1; // bit 19(one or more nibbles signalled as errors) + u32 asw_false_carrier_event:1; // bit 18(bad carrier since last good packet) + u32 asw_RX_DV_event:1; // bit 17(short receive event detected) + u32 asw_prev_pkt_dropped:1;// bit 16(e.g. IFG too small on previous) + u32 unused:5; // bits 11-15 + u32 vp:1; // bit 10(VLAN Packet) + u32 jp:1; // bit 9(Jumbo Packet) + u32 ft:1; // bit 8(Frame Truncated) + u32 drop:1; // bit 7(Drop packet) + u32 rxmac_error:1; // bit 6(RXMAC Error Indicator) + u32 wol:1; // bit 5(WOL Event) + u32 tcpp:1; // bit 4(TCP checksum pass) + u32 tcpa:1; // bit 3(TCP checksum assist) + u32 ipp:1; // bit 2(IP checksum pass) + u32 ipa:1; // bit 1(IP checksum assist) + u32 hp:1; // bit 0(hash pass) +#else + u32 hp:1; // bit 0(hash pass) + u32 ipa:1; // bit 1(IP checksum assist) + u32 ipp:1; // bit 2(IP checksum pass) + u32 tcpa:1; // bit 3(TCP checksum assist) + u32 tcpp:1; // bit 4(TCP checksum pass) + u32 wol:1; // bit 5(WOL Event) + u32 rxmac_error:1; // bit 6(RXMAC Error Indicator) + u32 drop:1; // bit 7(Drop packet) + u32 ft:1; // bit 8(Frame Truncated) + u32 jp:1; // bit 9(Jumbo Packet) + u32 vp:1; // bit 10(VLAN Packet) + u32 unused:5; // bits 11-15 + u32 asw_prev_pkt_dropped:1;// bit 16(e.g. IFG too small on previous) + u32 asw_RX_DV_event:1; // bit 17(short receive event detected) + u32 asw_false_carrier_event:1; // bit 18(bad carrier since last good packet) + u32 asw_code_err:1; // bit 19(one or more nibbles signalled as errors) + u32 asw_CRC_err:1; // bit 20(CRC error) + u32 asw_len_chk_err:1; // bit 21(frame length field incorrect) + u32 asw_too_long:1; // bit 22(frame length > 1518 bytes) + u32 asw_OK:1; // bit 23(valid CRC + no code error) + u32 asw_multicast:1; // bit 24(has a multicast address) + u32 asw_broadcast:1; // bit 25(has a broadcast address) + u32 asw_dribble_nibble:1; // bit 26(spurious bits after EOP) + u32 asw_control_frame:1; // bit 27(is a control frame) + u32 asw_pause_frame:1; // bit 28(is a pause frame) + u32 asw_unsupported_op:1; // bit 29(unsupported OP code) + u32 asw_VLAN_tag:1; // bit 30(VLAN tag detected) + u32 asw_long_evt:1; // bit 31(Rx long event) +#if 0 + u32 asw_trunc:1; // bit 31(Rx frame truncated) +#endif +#endif + } bits; +} PKT_STAT_DESC_WORD0_t, *PPKT_STAT_WORD0_t; + +typedef union _PKT_STAT_DESC_WORD1_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused:4; // bits 28-31 + u32 ri:2; // bits 26-27(Ring Index) + u32 bi:10; // bits 16-25(Buffer Index) + u32 length:16; // bit 0-15(length in bytes) +#else + u32 length:16; // bit 0-15(length in bytes) + u32 bi:10; // bits 16-25(Buffer Index) + u32 ri:2; // bits 26-27(Ring Index) + u32 unused:4; // bits 28-31 +#endif + } bits; +} PKT_STAT_DESC_WORD1_t, *PPKT_STAT_WORD1_t; + +typedef struct _PKT_STAT_DESC_t { + PKT_STAT_DESC_WORD0_t word0; + PKT_STAT_DESC_WORD1_t word1; +} PKT_STAT_DESC_t, *PPKT_STAT_DESC_t; + +/* Typedefs for the RX DMA status word */ + +/* + * RXSTAT_WORD0_t structure holds part of the status bits of the Rx DMA engine + * that get copied out to memory by the ET-1310. Word 0 is a 32 bit word + * whichcontains Free Buffer ring 0 and 1 available offset. + */ +typedef union _rxstat_word0_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 FBR1unused:5; // bits 27-31 + u32 FBR1wrap:1; // bit 26 + u32 FBR1offset:10; // bits 16-25 + u32 FBR0unused:5; // bits 11-15 + u32 FBR0wrap:1; // bit 10 + u32 FBR0offset:10; // bits 0-9 +#else + u32 FBR0offset:10; // bits 0-9 + u32 FBR0wrap:1; // bit 10 + u32 FBR0unused:5; // bits 11-15 + u32 FBR1offset:10; // bits 16-25 + u32 FBR1wrap:1; // bit 26 + u32 FBR1unused:5; // bits 27-31 +#endif + } bits; +} RXSTAT_WORD0_t, *PRXSTAT_WORD0_t; + +/* + * RXSTAT_WORD1_t structure holds part of the status bits of the Rx DMA engine + * that get copied out to memory by the ET-1310. Word 3 is a 32 bit word + * which contains the Packet Status Ring available offset. + */ +typedef union _rxstat_word1_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 PSRunused:3; // bits 29-31 + u32 PSRwrap:1; // bit 28 + u32 PSRoffset:12; // bits 16-27 + u32 reserved:16; // bits 0-15 +#else + u32 reserved:16; // bits 0-15 + u32 PSRoffset:12; // bits 16-27 + u32 PSRwrap:1; // bit 28 + u32 PSRunused:3; // bits 29-31 +#endif + } bits; +} RXSTAT_WORD1_t, *PRXSTAT_WORD1_t; + +/* + * RX_STATUS_BLOCK_t is sructure representing the status of the Rx DMA engine + * it sits in free memory, and is pointed to by 0x101c / 0x1020 + */ +typedef struct _rx_status_block_t { + RXSTAT_WORD0_t Word0; + RXSTAT_WORD1_t Word1; +} RX_STATUS_BLOCK_t, *PRX_STATUS_BLOCK_t; + +/* + * Structure for look-up table holding free buffer ring pointers + */ +typedef struct _FbrLookupTable { + void *Va[MAX_DESC_PER_RING_RX]; + void *Buffer1[MAX_DESC_PER_RING_RX]; + void *Buffer2[MAX_DESC_PER_RING_RX]; + u32 PAHigh[MAX_DESC_PER_RING_RX]; + u32 PALow[MAX_DESC_PER_RING_RX]; +} FBRLOOKUPTABLE, *PFBRLOOKUPTABLE; + +typedef enum { + ONE_PACKET_INTERRUPT, + FOUR_PACKET_INTERRUPT +} eRX_INTERRUPT_STATE_t, *PeRX_INTERRUPT_STATE_t; + +/* + * Structure to hold the skb's in a list + */ +typedef struct rx_skb_list_elem { + struct list_head skb_list_elem; + dma_addr_t dma_addr; + struct sk_buff *skb; +} RX_SKB_LIST_ELEM, *PRX_SKB_LIST_ELEM; + +/* + * RX_RING_t is sructure representing the adaptor's local reference(s) to the + * rings + */ +typedef struct _rx_ring_t { +#ifdef USE_FBR0 + void *pFbr0RingVa; + dma_addr_t pFbr0RingPa; + void *Fbr0MemVa[MAX_DESC_PER_RING_RX / FBR_CHUNKS]; + dma_addr_t Fbr0MemPa[MAX_DESC_PER_RING_RX / FBR_CHUNKS]; + uint64_t Fbr0Realpa; + uint64_t Fbr0offset; + DMA10W_t local_Fbr0_full; + u32 Fbr0NumEntries; + u32 Fbr0BufferSize; +#endif + void *pFbr1RingVa; + dma_addr_t pFbr1RingPa; + void *Fbr1MemVa[MAX_DESC_PER_RING_RX / FBR_CHUNKS]; + dma_addr_t Fbr1MemPa[MAX_DESC_PER_RING_RX / FBR_CHUNKS]; + uint64_t Fbr1Realpa; + uint64_t Fbr1offset; + FBRLOOKUPTABLE *Fbr[2]; + DMA10W_t local_Fbr1_full; + u32 Fbr1NumEntries; + u32 Fbr1BufferSize; + + void *pPSRingVa; + dma_addr_t pPSRingPa; + uint64_t pPSRingRealPa; + uint64_t pPSRingOffset; + RXDMA_PSR_FULL_OFFSET_t local_psr_full; + u32 PsrNumEntries; + + void *pRxStatusVa; + dma_addr_t pRxStatusPa; + uint64_t RxStatusRealPA; + uint64_t RxStatusOffset; + + struct list_head RecvBufferPool; + + /* RECV */ + struct list_head RecvList; + struct list_head RecvPendingList; + u32 nReadyRecv; + + u32 NumRfd; + + bool UnfinishedReceives; + + struct list_head RecvPacketPool; + + /* lookaside lists */ + struct kmem_cache *RecvLookaside; +} RX_RING_t, *PRX_RING_t; + +/* Forward reference of RFD */ +struct _MP_RFD; + +/* Forward declaration of the private adapter structure */ +struct et131x_adapter; + +/* PROTOTYPES for Initialization */ +int et131x_rx_dma_memory_alloc(struct et131x_adapter *adapter); +void et131x_rx_dma_memory_free(struct et131x_adapter *adapter); +int et131x_rfd_resources_alloc(struct et131x_adapter *adapter, + struct _MP_RFD *pMpRfd); +void et131x_rfd_resources_free(struct et131x_adapter *adapter, + struct _MP_RFD *pMpRfd); +int et131x_init_recv(struct et131x_adapter *adapter); + +void ConfigRxDmaRegs(struct et131x_adapter *adapter); +void SetRxDmaTimer(struct et131x_adapter *adapter); +void et131x_rx_dma_disable(struct et131x_adapter *adapter); +void et131x_rx_dma_enable(struct et131x_adapter *adapter); + +void et131x_reset_recv(struct et131x_adapter *adapter); + +void et131x_handle_recv_interrupt(struct et131x_adapter *adapter); + +#endif /* __ET1310_RX_H__ */ diff --git a/src/et131x/et1310_tx.c b/src/et131x/et1310_tx.c new file mode 100644 index 0000000..a95c260 --- /dev/null +++ b/src/et131x/et1310_tx.c @@ -0,0 +1,1525 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et1310_tx.c - Routines used to perform data transmission. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#include "et131x_version.h" +#include "et131x_debug.h" +#include "et131x_defs.h" + +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> + +#include <linux/sched.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/ctype.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/in.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/bitops.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/if_arp.h> +#include <linux/ioport.h> + +#include "et1310_phy.h" +#include "et1310_pm.h" +#include "et1310_jagcore.h" + +#include "et131x_adapter.h" +#include "et131x_initpci.h" +#include "et131x_isr.h" + +#include "et1310_tx.h" + +/* Data for debugging facilities */ +#ifdef CONFIG_ET131X_DEBUG +extern dbg_info_t *et131x_dbginfo; +#endif /* CONFIG_ET131X_DEBUG */ + +static void et131x_update_tcb_list(struct et131x_adapter *pAdapter); +static void et131x_check_send_wait_list(struct et131x_adapter *pAdapter); +static inline void et131x_free_send_packet(struct et131x_adapter *pAdapter, + PMP_TCB pMpTcb); +static int et131x_send_packet(struct sk_buff *skb, + struct et131x_adapter *pAdapter); +static int nic_send_packet(struct et131x_adapter *pAdapter, PMP_TCB pMpTcb); + +/** + * et131x_tx_dma_memory_alloc + * @adapter: pointer to our private adapter structure + * + * Returns 0 on success and errno on failure (as defined in errno.h). + * + * Allocates memory that will be visible both to the device and to the CPU. + * The OS will pass us packets, pointers to which we will insert in the Tx + * Descriptor queue. The device will read this queue to find the packets in + * memory. The device will update the "status" in memory each time it xmits a + * packet. + */ +int et131x_tx_dma_memory_alloc(struct et131x_adapter *adapter) +{ + int desc_size = 0; + TX_RING_t *tx_ring = &adapter->TxRing; + + DBG_ENTER(et131x_dbginfo); + + /* Allocate memory for the TCB's (Transmit Control Block) */ + adapter->TxRing.MpTcbMem = (MP_TCB *) kcalloc(NUM_TCB, sizeof(MP_TCB), + GFP_ATOMIC | GFP_DMA); + if (!adapter->TxRing.MpTcbMem) { + DBG_ERROR(et131x_dbginfo, "Cannot alloc memory for TCBs\n"); + DBG_LEAVE(et131x_dbginfo); + return -ENOMEM; + } + + /* Allocate enough memory for the Tx descriptor ring, and allocate + * some extra so that the ring can be aligned on a 4k boundary. + */ + desc_size = (sizeof(TX_DESC_ENTRY_t) * NUM_DESC_PER_RING_TX) + 4096 - 1; + tx_ring->pTxDescRingVa = + (PTX_DESC_ENTRY_t) pci_alloc_consistent(adapter->pdev, desc_size, + &tx_ring->pTxDescRingPa); + if (!adapter->TxRing.pTxDescRingVa) { + DBG_ERROR(et131x_dbginfo, "Cannot alloc memory for Tx Ring\n"); + DBG_LEAVE(et131x_dbginfo); + return -ENOMEM; + } + + /* Save physical address + * + * NOTE: pci_alloc_consistent(), used above to alloc DMA regions, + * ALWAYS returns SAC (32-bit) addresses. If DAC (64-bit) addresses + * are ever returned, make sure the high part is retrieved here before + * storing the adjusted address. + */ + tx_ring->pTxDescRingAdjustedPa = tx_ring->pTxDescRingPa; + + /* Align Tx Descriptor Ring on a 4k (0x1000) byte boundary */ + et131x_align_allocated_memory(adapter, + &tx_ring->pTxDescRingAdjustedPa, + &tx_ring->TxDescOffset, 0x0FFF); + + tx_ring->pTxDescRingVa += tx_ring->TxDescOffset; + + /* Allocate memory for the Tx status block */ + tx_ring->pTxStatusVa = pci_alloc_consistent(adapter->pdev, + sizeof(TX_STATUS_BLOCK_t), + &tx_ring->pTxStatusPa); + if (!adapter->TxRing.pTxStatusPa) { + DBG_ERROR(et131x_dbginfo, + "Cannot alloc memory for Tx status block\n"); + DBG_LEAVE(et131x_dbginfo); + return -ENOMEM; + } + + /* Allocate memory for a dummy buffer */ + tx_ring->pTxDummyBlkVa = pci_alloc_consistent(adapter->pdev, + NIC_MIN_PACKET_SIZE, + &tx_ring->pTxDummyBlkPa); + if (!adapter->TxRing.pTxDummyBlkPa) { + DBG_ERROR(et131x_dbginfo, + "Cannot alloc memory for Tx dummy buffer\n"); + DBG_LEAVE(et131x_dbginfo); + return -ENOMEM; + } + + DBG_LEAVE(et131x_dbginfo); + return 0; +} + +/** + * et131x_tx_dma_memory_free - Free all memory allocated within this module + * @adapter: pointer to our private adapter structure + * + * Returns 0 on success and errno on failure (as defined in errno.h). + */ +void et131x_tx_dma_memory_free(struct et131x_adapter *adapter) +{ + int desc_size = 0; + + DBG_ENTER(et131x_dbginfo); + + if (adapter->TxRing.pTxDescRingVa) { + /* Free memory relating to Tx rings here */ + adapter->TxRing.pTxDescRingVa -= adapter->TxRing.TxDescOffset; + + desc_size = + (sizeof(TX_DESC_ENTRY_t) * NUM_DESC_PER_RING_TX) + 4096 - 1; + + pci_free_consistent(adapter->pdev, + desc_size, + adapter->TxRing.pTxDescRingVa, + adapter->TxRing.pTxDescRingPa); + + adapter->TxRing.pTxDescRingVa = NULL; + } + + /* Free memory for the Tx status block */ + if (adapter->TxRing.pTxStatusVa) { + pci_free_consistent(adapter->pdev, + sizeof(TX_STATUS_BLOCK_t), + adapter->TxRing.pTxStatusVa, + adapter->TxRing.pTxStatusPa); + + adapter->TxRing.pTxStatusVa = NULL; + } + + /* Free memory for the dummy buffer */ + if (adapter->TxRing.pTxDummyBlkVa) { + pci_free_consistent(adapter->pdev, + NIC_MIN_PACKET_SIZE, + adapter->TxRing.pTxDummyBlkVa, + adapter->TxRing.pTxDummyBlkPa); + + adapter->TxRing.pTxDummyBlkVa = NULL; + } + + /* Free the memory for MP_TCB structures */ + if (adapter->TxRing.MpTcbMem) { + kfree(adapter->TxRing.MpTcbMem); + adapter->TxRing.MpTcbMem = NULL; + } + + DBG_LEAVE(et131x_dbginfo); +} + +/** + * ConfigTxDmaRegs - Set up the tx dma section of the JAGCore. + * @adapter: pointer to our private adapter structure + */ +void ConfigTxDmaRegs(struct et131x_adapter *pAdapter) +{ + struct _TXDMA_t __iomem *pTxDma = &pAdapter->CSRAddress->txdma; + + DBG_ENTER(et131x_dbginfo); + + /* Load the hardware with the start of the transmit descriptor ring. */ + writel((uint32_t) (pAdapter->TxRing.pTxDescRingAdjustedPa >> 32), + &pTxDma->pr_base_hi); + writel((uint32_t) pAdapter->TxRing.pTxDescRingAdjustedPa, + &pTxDma->pr_base_lo); + + /* Initialise the transmit DMA engine */ + writel(NUM_DESC_PER_RING_TX - 1, &pTxDma->pr_num_des.value); + + /* Load the completion writeback physical address + * + * NOTE: pci_alloc_consistent(), used above to alloc DMA regions, + * ALWAYS returns SAC (32-bit) addresses. If DAC (64-bit) addresses + * are ever returned, make sure the high part is retrieved here before + * storing the adjusted address. + */ + writel(0, &pTxDma->dma_wb_base_hi); + writel(pAdapter->TxRing.pTxStatusPa, &pTxDma->dma_wb_base_lo); + + memset(pAdapter->TxRing.pTxStatusVa, 0, sizeof(TX_STATUS_BLOCK_t)); + + writel(0, &pTxDma->service_request.value); + pAdapter->TxRing.txDmaReadyToSend.value = 0; + + DBG_LEAVE(et131x_dbginfo); +} + +/** + * et131x_tx_dma_disable - Stop of Tx_DMA on the ET1310 + * @pAdapter: pointer to our adapter structure + */ +void et131x_tx_dma_disable(struct et131x_adapter *pAdapter) +{ + DBG_ENTER(et131x_dbginfo); + + /* Setup the tramsmit dma configuration register */ + writel(0x101, &pAdapter->CSRAddress->txdma.csr.value); + + DBG_LEAVE(et131x_dbginfo); +} + +/** + * et131x_tx_dma_enable - re-start of Tx_DMA on the ET1310. + * @pAdapter: pointer to our adapter structure + * + * Mainly used after a return to the D0 (full-power) state from a lower state. + */ +void et131x_tx_dma_enable(struct et131x_adapter *pAdapter) +{ + DBG_ENTER(et131x_dbginfo); + + if (pAdapter->RegistryPhyLoopbk) { + /* TxDMA is disabled for loopback operation. */ + writel(0x101, &pAdapter->CSRAddress->txdma.csr.value); + } else { + TXDMA_CSR_t csr = { 0 }; + + /* Setup the transmit dma configuration register for normal + * operation + */ + csr.bits.sngl_epkt_mode = 1; + csr.bits.halt = 0; + csr.bits.cache_thrshld = pAdapter->RegistryDMACache; + writel(csr.value, &pAdapter->CSRAddress->txdma.csr.value); + } + + DBG_LEAVE(et131x_dbginfo); +} + +/** + * et131x_init_send - Initialize send data structures + * @adapter: pointer to our private adapter structure + */ +void et131x_init_send(struct et131x_adapter *adapter) +{ + PMP_TCB pMpTcb; + uint32_t TcbCount; + TX_RING_t *tx_ring; + + DBG_ENTER(et131x_dbginfo); + + /* Setup some convenience pointers */ + tx_ring = &adapter->TxRing; + pMpTcb = adapter->TxRing.MpTcbMem; + + tx_ring->TCBReadyQueueHead = pMpTcb; + + /* Go through and set up each TCB */ + for (TcbCount = 0; TcbCount < NUM_TCB; TcbCount++) { + memset(pMpTcb, 0, sizeof(MP_TCB)); + + /* Set the link pointer in HW TCB to the next TCB in the + * chain. If this is the last TCB in the chain, also set the + * tail pointer. + */ + if (TcbCount < NUM_TCB - 1) { + pMpTcb->Next = pMpTcb + 1; + } else { + tx_ring->TCBReadyQueueTail = pMpTcb; + pMpTcb->Next = (PMP_TCB) NULL; + } + + pMpTcb++; + } + + /* Curr send queue should now be empty */ + tx_ring->CurrSendHead = (PMP_TCB) NULL; + tx_ring->CurrSendTail = (PMP_TCB) NULL; + + INIT_LIST_HEAD(&adapter->TxRing.SendWaitQueue); + + DBG_LEAVE(et131x_dbginfo); +} + +/** + * et131x_send_packets - This function is called by the OS to send packets + * @skb: the packet(s) to send + * @netdev:device on which to TX the above packet(s) + * + * Return 0 in almost all cases; non-zero value in extreme hard failure only + */ +int et131x_send_packets(struct sk_buff *skb, struct net_device *netdev) +{ + int status = 0; + struct et131x_adapter *pAdapter = NULL; + + DBG_TX_ENTER(et131x_dbginfo); + + pAdapter = netdev_priv(netdev); + + /* Send these packets + * + * NOTE: The Linux Tx entry point is only given one packet at a time + * to Tx, so the PacketCount and it's array used makes no sense here + */ + + /* Queue is not empty or TCB is not available */ + if (!list_empty(&pAdapter->TxRing.SendWaitQueue) || + MP_TCB_RESOURCES_NOT_AVAILABLE(pAdapter)) { + /* NOTE: If there's an error on send, no need to queue the + * packet under Linux; if we just send an error up to the + * netif layer, it will resend the skb to us. + */ + DBG_VERBOSE(et131x_dbginfo, "TCB Resources Not Available\n"); + status = -ENOMEM; + } else { + /* We need to see if the link is up; if it's not, make the + * netif layer think we're good and drop the packet + */ + //if( MP_SHOULD_FAIL_SEND( pAdapter ) || pAdapter->DriverNoPhyAccess ) + if (MP_SHOULD_FAIL_SEND(pAdapter) || pAdapter->DriverNoPhyAccess + || !netif_carrier_ok(netdev)) { + DBG_VERBOSE(et131x_dbginfo, + "Can't Tx, Link is DOWN; drop the packet\n"); + + dev_kfree_skb_any(skb); + skb = NULL; + + pAdapter->net_stats.tx_dropped++; + } else { + status = et131x_send_packet(skb, pAdapter); + + if (status == -ENOMEM) { + + /* NOTE: If there's an error on send, no need + * to queue the packet under Linux; if we just + * send an error up to the netif layer, it + * will resend the skb to us. + */ + DBG_WARNING(et131x_dbginfo, + "Resources problem, Queue tx packet\n"); + } else if (status != 0) { + /* On any other error, make netif think we're + * OK and drop the packet + */ + DBG_WARNING(et131x_dbginfo, + "General error, drop packet\n"); + + dev_kfree_skb_any(skb); + skb = NULL; + + pAdapter->net_stats.tx_dropped++; + } + } + } + + DBG_TX_LEAVE(et131x_dbginfo); + return status; +} + +/** + * et131x_send_packet - Do the work to send a packet + * @skb: the packet(s) to send + * @pAdapter: a pointer to the device's private adapter structure + * + * Return 0 in almost all cases; non-zero value in extreme hard failure only. + * + * Assumption: Send spinlock has been acquired + */ +static int et131x_send_packet(struct sk_buff *skb, + struct et131x_adapter *pAdapter) +{ + int status = 0; + PMP_TCB pMpTcb = NULL; + uint16_t *pShBufVa; + unsigned long lockflags; + + DBG_TX_ENTER(et131x_dbginfo); + + /* Is our buffer scattered, or continuous? */ + if (skb_shinfo(skb)->nr_frags == 0) { + DBG_TX(et131x_dbginfo, "Scattered buffer: NO\n"); + } else { + DBG_TX(et131x_dbginfo, "Scattered buffer: YES, Num Frags: %d\n", + skb_shinfo(skb)->nr_frags); + } + + /* All packets must have at least a MAC address and a protocol type */ + if (skb->len < ETH_HLEN) { + DBG_ERROR(et131x_dbginfo, + "Packet size < ETH_HLEN (14 bytes)\n"); + DBG_LEAVE(et131x_dbginfo); + return -EIO; + } + + /* Get a TCB for this packet */ + spin_lock_irqsave(&pAdapter->TCBReadyQLock, lockflags); + + pMpTcb = pAdapter->TxRing.TCBReadyQueueHead; + + if (pMpTcb == NULL) { + spin_unlock_irqrestore(&pAdapter->TCBReadyQLock, lockflags); + + DBG_WARNING(et131x_dbginfo, "Can't obtain a TCB\n"); + DBG_TX_LEAVE(et131x_dbginfo); + return -ENOMEM; + } + + pAdapter->TxRing.TCBReadyQueueHead = pMpTcb->Next; + + if (pAdapter->TxRing.TCBReadyQueueHead == NULL) { + pAdapter->TxRing.TCBReadyQueueTail = NULL; + } + + spin_unlock_irqrestore(&pAdapter->TCBReadyQLock, lockflags); + + pMpTcb->PacketLength = skb->len; + pMpTcb->Packet = skb; + + if ((skb->data != NULL) && ((skb->len - skb->data_len) >= 6)) { + pShBufVa = (uint16_t *) skb->data; + + if ((pShBufVa[0] == 0xffff) && + (pShBufVa[1] == 0xffff) && (pShBufVa[2] == 0xffff)) { + MP_SET_FLAG(pMpTcb, fMP_DEST_BROAD); + } else if ((pShBufVa[0] & 0x3) == 0x0001) { + MP_SET_FLAG(pMpTcb, fMP_DEST_MULTI); + } + } + + pMpTcb->Next = NULL; + + /* Call the NIC specific send handler. */ + if (status == 0) { + status = nic_send_packet(pAdapter, pMpTcb); + } + + if (status != 0) { + spin_lock_irqsave(&pAdapter->TCBReadyQLock, lockflags); + + if (pAdapter->TxRing.TCBReadyQueueTail) { + pAdapter->TxRing.TCBReadyQueueTail->Next = pMpTcb; + } else { + /* Apparently ready Q is empty. */ + pAdapter->TxRing.TCBReadyQueueHead = pMpTcb; + } + + pAdapter->TxRing.TCBReadyQueueTail = pMpTcb; + + spin_unlock_irqrestore(&pAdapter->TCBReadyQLock, lockflags); + + DBG_TX_LEAVE(et131x_dbginfo); + return status; + } + + DBG_ASSERT(pAdapter->TxRing.nBusySend <= NUM_TCB); + + DBG_TX_LEAVE(et131x_dbginfo); + return 0; +} + +/** + * nic_send_packet - NIC specific send handler for version B silicon. + * @pAdapter: pointer to our adapter + * @pMpTcb: pointer to MP_TCB + * + * Returns 0 or errno. + */ +static int nic_send_packet(struct et131x_adapter *pAdapter, PMP_TCB pMpTcb) +{ + uint32_t loopIndex; + TX_DESC_ENTRY_t CurDesc[24]; + uint32_t FragmentNumber = 0; + uint32_t iThisCopy, iRemainder; + struct sk_buff *pPacket = pMpTcb->Packet; + uint32_t FragListCount = skb_shinfo(pPacket)->nr_frags + 1; + struct skb_frag_struct *pFragList = &skb_shinfo(pPacket)->frags[0]; + unsigned long lockflags1, lockflags2; + + DBG_TX_ENTER(et131x_dbginfo); + + /* Part of the optimizations of this send routine restrict us to + * sending 24 fragments at a pass. In practice we should never see + * more than 5 fragments. + * + * NOTE: The older version of this function (below) can handle any + * number of fragments. If needed, we can call this function, + * although it is less efficient. + */ + if (FragListCount > 23) { + DBG_TX_LEAVE(et131x_dbginfo); + return -EIO; + } + + memset(CurDesc, 0, sizeof(TX_DESC_ENTRY_t) * (FragListCount + 1)); + + for (loopIndex = 0; loopIndex < FragListCount; loopIndex++) { + /* If there is something in this element, lets get a + * descriptor from the ring and get the necessary data + */ + if (loopIndex == 0) { + /* If the fragments are smaller than a standard MTU, + * then map them to a single descriptor in the Tx + * Desc ring. However, if they're larger, as is + * possible with support for jumbo packets, then + * split them each across 2 descriptors. + * + * This will work until we determine why the hardware + * doesn't seem to like large fragments. + */ + if ((pPacket->len - pPacket->data_len) <= 1514) { + DBG_TX(et131x_dbginfo, + "Got packet of length %d, " + "filling desc entry %d, " + "TCB: 0x%p\n", + (pPacket->len - pPacket->data_len), + pAdapter->TxRing.txDmaReadyToSend.bits. + val, pMpTcb); + + CurDesc[FragmentNumber].DataBufferPtrHigh = 0; + + CurDesc[FragmentNumber].word2.bits. + length_in_bytes = + pPacket->len - pPacket->data_len; + + /* NOTE: Here, the dma_addr_t returned from + * pci_map_single() is implicitly cast as a + * uint32_t. Although dma_addr_t can be + * 64-bit, the address returned by + * pci_map_single() is always 32-bit + * addressable (as defined by the pci/dma + * subsystem) + */ + CurDesc[FragmentNumber++].DataBufferPtrLow = + pci_map_single(pAdapter->pdev, + pPacket->data, + pPacket->len - + pPacket->data_len, + PCI_DMA_TODEVICE); + } else { + DBG_TX(et131x_dbginfo, + "Got packet of length %d, " + "filling desc entry %d, " + "TCB: 0x%p\n", + (pPacket->len - pPacket->data_len), + pAdapter->TxRing.txDmaReadyToSend.bits. + val, pMpTcb); + + CurDesc[FragmentNumber].DataBufferPtrHigh = 0; + + CurDesc[FragmentNumber].word2.bits. + length_in_bytes = + ((pPacket->len - pPacket->data_len) / 2); + + /* NOTE: Here, the dma_addr_t returned from + * pci_map_single() is implicitly cast as a + * uint32_t. Although dma_addr_t can be + * 64-bit, the address returned by + * pci_map_single() is always 32-bit + * addressable (as defined by the pci/dma + * subsystem) + */ + CurDesc[FragmentNumber++].DataBufferPtrLow = + pci_map_single(pAdapter->pdev, + pPacket->data, + ((pPacket->len - + pPacket->data_len) / 2), + PCI_DMA_TODEVICE); + CurDesc[FragmentNumber].DataBufferPtrHigh = 0; + + CurDesc[FragmentNumber].word2.bits. + length_in_bytes = + ((pPacket->len - pPacket->data_len) / 2); + + /* NOTE: Here, the dma_addr_t returned from + * pci_map_single() is implicitly cast as a + * uint32_t. Although dma_addr_t can be + * 64-bit, the address returned by + * pci_map_single() is always 32-bit + * addressable (as defined by the pci/dma + * subsystem) + */ + CurDesc[FragmentNumber++].DataBufferPtrLow = + pci_map_single(pAdapter->pdev, + pPacket->data + + ((pPacket->len - + pPacket->data_len) / 2), + ((pPacket->len - + pPacket->data_len) / 2), + PCI_DMA_TODEVICE); + } + } else { + DBG_TX(et131x_dbginfo, + "Got packet of length %d," + "filling desc entry %d\n" + "TCB: 0x%p\n", + pFragList[loopIndex].size, + pAdapter->TxRing.txDmaReadyToSend.bits.val, + pMpTcb); + + CurDesc[FragmentNumber].DataBufferPtrHigh = 0; + + CurDesc[FragmentNumber].word2.bits.length_in_bytes = + pFragList[loopIndex - 1].size; + + /* NOTE: Here, the dma_addr_t returned from + * pci_map_page() is implicitly cast as a uint32_t. + * Although dma_addr_t can be 64-bit, the address + * returned by pci_map_page() is always 32-bit + * addressable (as defined by the pci/dma subsystem) + */ + CurDesc[FragmentNumber++].DataBufferPtrLow = + pci_map_page(pAdapter->pdev, + pFragList[loopIndex - 1].page, + pFragList[loopIndex - 1].page_offset, + pFragList[loopIndex - 1].size, + PCI_DMA_TODEVICE); + } + } + + if (FragmentNumber == 0) { + DBG_WARNING(et131x_dbginfo, "No. frags is 0\n"); + return -EIO; + } + + if (pAdapter->uiLinkSpeed == TRUEPHY_SPEED_1000MBPS) { + if (++pAdapter->TxRing.TxPacketsSinceLastinterrupt == + pAdapter->RegistryTxNumBuffers) { + CurDesc[FragmentNumber - 1].word3.value = 0x5; + pAdapter->TxRing.TxPacketsSinceLastinterrupt = 0; + } else { + CurDesc[FragmentNumber - 1].word3.value = 0x1; + } + } else { + CurDesc[FragmentNumber - 1].word3.value = 0x5; + } + + CurDesc[0].word3.bits.f = 1; + + pMpTcb->WrIndexStart = pAdapter->TxRing.txDmaReadyToSend; + pMpTcb->PacketStaleCount = 0; + + spin_lock_irqsave(&pAdapter->SendHWLock, lockflags1); + + iThisCopy = + NUM_DESC_PER_RING_TX - pAdapter->TxRing.txDmaReadyToSend.bits.val; + + if (iThisCopy >= FragmentNumber) { + iRemainder = 0; + iThisCopy = FragmentNumber; + } else { + iRemainder = FragmentNumber - iThisCopy; + } + + memcpy(pAdapter->TxRing.pTxDescRingVa + + pAdapter->TxRing.txDmaReadyToSend.bits.val, CurDesc, + sizeof(TX_DESC_ENTRY_t) * iThisCopy); + + pAdapter->TxRing.txDmaReadyToSend.bits.val += iThisCopy; + + if ((pAdapter->TxRing.txDmaReadyToSend.bits.val == 0) || + (pAdapter->TxRing.txDmaReadyToSend.bits.val == + NUM_DESC_PER_RING_TX)) { + if (pAdapter->TxRing.txDmaReadyToSend.bits.wrap) { + pAdapter->TxRing.txDmaReadyToSend.value = 0; + } else { + pAdapter->TxRing.txDmaReadyToSend.value = 0x400; + } + } + + if (iRemainder) { + memcpy(pAdapter->TxRing.pTxDescRingVa, + CurDesc + iThisCopy, + sizeof(TX_DESC_ENTRY_t) * iRemainder); + + pAdapter->TxRing.txDmaReadyToSend.bits.val += iRemainder; + } + + if (pAdapter->TxRing.txDmaReadyToSend.bits.val == 0) { + if (pAdapter->TxRing.txDmaReadyToSend.value) { + pMpTcb->WrIndex.value = NUM_DESC_PER_RING_TX - 1; + } else { + pMpTcb->WrIndex.value = + 0x400 | (NUM_DESC_PER_RING_TX - 1); + } + } else { + pMpTcb->WrIndex.value = + pAdapter->TxRing.txDmaReadyToSend.value - 1; + } + + spin_lock_irqsave(&pAdapter->TCBSendQLock, lockflags2); + + if (pAdapter->TxRing.CurrSendTail) { + pAdapter->TxRing.CurrSendTail->Next = pMpTcb; + } else { + pAdapter->TxRing.CurrSendHead = pMpTcb; + } + + pAdapter->TxRing.CurrSendTail = pMpTcb; + + DBG_ASSERT(pMpTcb->Next == NULL); + + pAdapter->TxRing.nBusySend++; + + spin_unlock_irqrestore(&pAdapter->TCBSendQLock, lockflags2); + + /* Write the new write pointer back to the device. */ + writel(pAdapter->TxRing.txDmaReadyToSend.value, + &pAdapter->CSRAddress->txdma.service_request.value); + + /* For Gig only, we use Tx Interrupt coalescing. Enable the software + * timer to wake us up if this packet isn't followed by N more. + */ + if (pAdapter->uiLinkSpeed == TRUEPHY_SPEED_1000MBPS) { + writel(pAdapter->RegistryTxTimeInterval * NANO_IN_A_MICRO, + &pAdapter->CSRAddress->global.watchdog_timer); + } + + spin_unlock_irqrestore(&pAdapter->SendHWLock, lockflags1); + + DBG_TX_LEAVE(et131x_dbginfo); + return 0; +} + +/* + * NOTE: For now, keep this older version of NICSendPacket around for + * reference, even though it's not used + */ +#if 0 + +/** + * NICSendPacket - NIC specific send handler. + * @pAdapter: pointer to our adapter + * @pMpTcb: pointer to MP_TCB + * + * Returns 0 on succes, errno on failure. + * + * This version of the send routine is designed for version A silicon. + * Assumption - Send spinlock has been acquired. + */ +static int nic_send_packet(struct et131x_adapter *pAdapter, PMP_TCB pMpTcb) +{ + uint32_t loopIndex, fragIndex, loopEnd; + uint32_t iSplitFirstElement = 0; + uint32_t SegmentSize = 0; + TX_DESC_ENTRY_t CurDesc; + TX_DESC_ENTRY_t *CurDescPostCopy = NULL; + uint32_t SlotsAvailable; + DMA10W_t ServiceComplete; + unsigned int lockflags1, lockflags2; + struct sk_buff *pPacket = pMpTcb->Packet; + uint32_t FragListCount = skb_shinfo(pPacket)->nr_frags + 1; + struct skb_frag_struct *pFragList = &skb_shinfo(pPacket)->frags[0]; + + DBG_TX_ENTER(et131x_dbginfo); + + ServiceComplete.value = + readl(&pAdapter->CSRAddress->txdma.NewServiceComplete.value); + + /* + * Attempt to fix TWO hardware bugs: + * 1) NEVER write an odd number of descriptors. + * 2) If packet length is less than NIC_MIN_PACKET_SIZE, then pad the + * packet to NIC_MIN_PACKET_SIZE bytes by adding a new last + * descriptor IN HALF DUPLEX MODE ONLY + * NOTE that (2) interacts with (1). If the packet is less than + * NIC_MIN_PACKET_SIZE bytes then we will append a descriptor. + * Therefore if it is even now, it will eventually end up odd, and + * so will need adjusting. + * + * VLAN tags get involved since VLAN tags add another one or two + * segments. + */ + DBG_TX(et131x_dbginfo, + "pMpTcb->PacketLength: %d\n", pMpTcb->PacketLength); + + if ((pAdapter->uiDuplexMode == 0) + && (pMpTcb->PacketLength < NIC_MIN_PACKET_SIZE)) { + DBG_TX(et131x_dbginfo, + "HALF DUPLEX mode AND len < MIN_PKT_SIZE\n"); + if ((FragListCount & 0x1) == 0) { + DBG_TX(et131x_dbginfo, + "Even number of descs, split 1st elem\n"); + iSplitFirstElement = 1; + //SegmentSize = pFragList[0].size / 2; + SegmentSize = (pPacket->len - pPacket->data_len) / 2; + } + } else if (FragListCount & 0x1) { + DBG_TX(et131x_dbginfo, "Odd number of descs, split 1st elem\n"); + + iSplitFirstElement = 1; + //SegmentSize = pFragList[0].size / 2; + SegmentSize = (pPacket->len - pPacket->data_len) / 2; + } + + spin_lock_irqsave(&pAdapter->SendHWLock, lockflags1); + + if (pAdapter->TxRing.txDmaReadyToSend.bits.serv_req_wrap == + ServiceComplete.bits.serv_cpl_wrap) { + /* The ring hasn't wrapped. Slots available should be + * (RING_SIZE) - the difference between the two pointers. + */ + SlotsAvailable = NUM_DESC_PER_RING_TX - + (pAdapter->TxRing.txDmaReadyToSend.bits.serv_req - + ServiceComplete.bits.serv_cpl); + } else { + /* The ring has wrapped. Slots available should be the + * difference between the two pointers. + */ + SlotsAvailable = ServiceComplete.bits.serv_cpl - + pAdapter->TxRing.txDmaReadyToSend.bits.serv_req; + } + + if ((FragListCount + iSplitFirstElement) > SlotsAvailable) { + DBG_WARNING(et131x_dbginfo, + "Not Enough Space in Tx Desc Ring\n"); + spin_unlock_irqrestore(&pAdapter->SendHWLock, lockflags1); + return -ENOMEM; + } + + loopEnd = (FragListCount) + iSplitFirstElement; + fragIndex = 0; + + DBG_TX(et131x_dbginfo, + "TCB : 0x%p\n" + "Packet (SKB) : 0x%p\t Packet->len: %d\t Packet->data_len: %d\n" + "FragListCount : %d\t iSplitFirstElement: %d\t loopEnd:%d\n", + pMpTcb, + pPacket, pPacket->len, pPacket->data_len, + FragListCount, iSplitFirstElement, loopEnd); + + for (loopIndex = 0; loopIndex < loopEnd; loopIndex++) { + if (loopIndex > iSplitFirstElement) { + fragIndex++; + } + + DBG_TX(et131x_dbginfo, + "In loop, loopIndex: %d\t fragIndex: %d\n", loopIndex, + fragIndex); + + /* If there is something in this element, let's get a + * descriptor from the ring and get the necessary data + */ + DBG_TX(et131x_dbginfo, + "Packet Length %d," + "filling desc entry %d\n", + pPacket->len, + pAdapter->TxRing.txDmaReadyToSend.bits.serv_req); + + // NOTE - Should we do a paranoia check here to make sure the fragment + // actually has a length? It's HIGHLY unlikely the fragment would + // contain no data... + if (1) { + // NOTE - Currently always getting 32-bit addrs, and dma_addr_t is + // only 32-bit, so leave "high" ptr value out for now + CurDesc.DataBufferPtrHigh = 0; + + CurDesc.word2.value = 0; + CurDesc.word3.value = 0; + + if (fragIndex == 0) { + if (iSplitFirstElement) { + DBG_TX(et131x_dbginfo, + "Split first element: YES\n"); + + if (loopIndex == 0) { + DBG_TX(et131x_dbginfo, + "Got fragment of length %d, fragIndex: %d\n", + pPacket->len - + pPacket->data_len, + fragIndex); + DBG_TX(et131x_dbginfo, + "SegmentSize: %d\n", + SegmentSize); + + CurDesc.word2.bits. + length_in_bytes = + SegmentSize; + CurDesc.DataBufferPtrLow = + pci_map_single(pAdapter-> + pdev, + pPacket-> + data, + SegmentSize, + PCI_DMA_TODEVICE); + DBG_TX(et131x_dbginfo, + "pci_map_single() returns: 0x%08x\n", + CurDesc. + DataBufferPtrLow); + } else { + DBG_TX(et131x_dbginfo, + "Got fragment of length %d, fragIndex: %d\n", + pPacket->len - + pPacket->data_len, + fragIndex); + DBG_TX(et131x_dbginfo, + "Leftover Size: %d\n", + (pPacket->len - + pPacket->data_len - + SegmentSize)); + + CurDesc.word2.bits. + length_in_bytes = + ((pPacket->len - + pPacket->data_len) - + SegmentSize); + CurDesc.DataBufferPtrLow = + pci_map_single(pAdapter-> + pdev, + (pPacket-> + data + + SegmentSize), + (pPacket-> + len - + pPacket-> + data_len - + SegmentSize), + PCI_DMA_TODEVICE); + DBG_TX(et131x_dbginfo, + "pci_map_single() returns: 0x%08x\n", + CurDesc. + DataBufferPtrLow); + } + } else { + DBG_TX(et131x_dbginfo, + "Split first element: NO\n"); + + CurDesc.word2.bits.length_in_bytes = + pPacket->len - pPacket->data_len; + + CurDesc.DataBufferPtrLow = + pci_map_single(pAdapter->pdev, + pPacket->data, + (pPacket->len - + pPacket->data_len), + PCI_DMA_TODEVICE); + DBG_TX(et131x_dbginfo, + "pci_map_single() returns: 0x%08x\n", + CurDesc.DataBufferPtrLow); + } + } else { + + CurDesc.word2.bits.length_in_bytes = + pFragList[fragIndex - 1].size; + CurDesc.DataBufferPtrLow = + pci_map_page(pAdapter->pdev, + pFragList[fragIndex - 1].page, + pFragList[fragIndex - + 1].page_offset, + pFragList[fragIndex - 1].size, + PCI_DMA_TODEVICE); + DBG_TX(et131x_dbginfo, + "pci_map_page() returns: 0x%08x\n", + CurDesc.DataBufferPtrLow); + } + + if (loopIndex == 0) { + /* This is the first descriptor of the packet + * + * Set the "f" bit to indicate this is the + * first descriptor in the packet. + */ + DBG_TX(et131x_dbginfo, + "This is our FIRST descriptor\n"); + CurDesc.word3.bits.f = 1; + + pMpTcb->WrIndexStart = + pAdapter->TxRing.txDmaReadyToSend; + } + + if ((loopIndex == (loopEnd - 1)) && + (pAdapter->uiDuplexMode || + (pMpTcb->PacketLength >= NIC_MIN_PACKET_SIZE))) { + /* This is the Last descriptor of the packet */ + DBG_TX(et131x_dbginfo, + "THIS is our LAST descriptor\n"); + + if (pAdapter->uiLinkSpeed == + TRUEPHY_SPEED_1000MBPS) { + if (++pAdapter->TxRing. + TxPacketsSinceLastinterrupt >= + pAdapter->RegistryTxNumBuffers) { + CurDesc.word3.value = 0x5; + pAdapter->TxRing. + TxPacketsSinceLastinterrupt + = 0; + } else { + CurDesc.word3.value = 0x1; + } + } else { + CurDesc.word3.value = 0x5; + } + + /* Following index will be used during freeing + * of packet + */ + pMpTcb->WrIndex = + pAdapter->TxRing.txDmaReadyToSend; + pMpTcb->PacketStaleCount = 0; + } + + /* Copy the descriptor (filled above) into the + * descriptor ring at the next free entry. Advance + * the "next free entry" variable + */ + memcpy(pAdapter->TxRing.pTxDescRingVa + + pAdapter->TxRing.txDmaReadyToSend.bits.serv_req, + &CurDesc, sizeof(TX_DESC_ENTRY_t)); + + CurDescPostCopy = + pAdapter->TxRing.pTxDescRingVa + + pAdapter->TxRing.txDmaReadyToSend.bits.serv_req; + + DBG_TX(et131x_dbginfo, + "CURRENT DESCRIPTOR\n" + "\tAddress : 0x%p\n" + "\tDataBufferPtrHigh : 0x%08x\n" + "\tDataBufferPtrLow : 0x%08x\n" + "\tword2 : 0x%08x\n" + "\tword3 : 0x%08x\n", + CurDescPostCopy, + CurDescPostCopy->DataBufferPtrHigh, + CurDescPostCopy->DataBufferPtrLow, + CurDescPostCopy->word2.value, + CurDescPostCopy->word3.value); + + if (++pAdapter->TxRing.txDmaReadyToSend.bits.serv_req >= + NUM_DESC_PER_RING_TX) { + if (pAdapter->TxRing.txDmaReadyToSend.bits. + serv_req_wrap) { + pAdapter->TxRing.txDmaReadyToSend. + value = 0; + } else { + pAdapter->TxRing.txDmaReadyToSend. + value = 0x400; + } + } + } + } + + if (pAdapter->uiDuplexMode == 0 && + pMpTcb->PacketLength < NIC_MIN_PACKET_SIZE) { + // NOTE - Same 32/64-bit issue as above... + CurDesc.DataBufferPtrHigh = 0x0; + CurDesc.DataBufferPtrLow = pAdapter->TxRing.pTxDummyBlkPa; + CurDesc.word2.value = 0; + + if (pAdapter->uiLinkSpeed == TRUEPHY_SPEED_1000MBPS) { + if (++pAdapter->TxRing.TxPacketsSinceLastinterrupt >= + pAdapter->RegistryTxNumBuffers) { + CurDesc.word3.value = 0x5; + pAdapter->TxRing.TxPacketsSinceLastinterrupt = + 0; + } else { + CurDesc.word3.value = 0x1; + } + } else { + CurDesc.word3.value = 0x5; + } + + CurDesc.word2.bits.length_in_bytes = + NIC_MIN_PACKET_SIZE - pMpTcb->PacketLength; + + pMpTcb->WrIndex = pAdapter->TxRing.txDmaReadyToSend; + + memcpy(pAdapter->TxRing.pTxDescRingVa + + pAdapter->TxRing.txDmaReadyToSend.bits.serv_req, + &CurDesc, sizeof(TX_DESC_ENTRY_t)); + + CurDescPostCopy = + pAdapter->TxRing.pTxDescRingVa + + pAdapter->TxRing.txDmaReadyToSend.bits.serv_req; + + DBG_TX(et131x_dbginfo, + "CURRENT DESCRIPTOR\n" + "\tAddress : 0x%p\n" + "\tDataBufferPtrHigh : 0x%08x\n" + "\tDataBufferPtrLow : 0x%08x\n" + "\tword2 : 0x%08x\n" + "\tword3 : 0x%08x\n", + CurDescPostCopy, + CurDescPostCopy->DataBufferPtrHigh, + CurDescPostCopy->DataBufferPtrLow, + CurDescPostCopy->word2.value, + CurDescPostCopy->word3.value); + + if (++pAdapter->TxRing.txDmaReadyToSend.bits.serv_req >= + NUM_DESC_PER_RING_TX) { + if (pAdapter->TxRing.txDmaReadyToSend.bits. + serv_req_wrap) { + pAdapter->TxRing.txDmaReadyToSend.value = 0; + } else { + pAdapter->TxRing.txDmaReadyToSend.value = 0x400; + } + } + + DBG_TX(et131x_dbginfo, "Padding descriptor %d by %d bytes\n", + //pAdapter->TxRing.txDmaReadyToSend.value, + pAdapter->TxRing.txDmaReadyToSend.bits.serv_req, + NIC_MIN_PACKET_SIZE - pMpTcb->PacketLength); + } + + spin_lock_irqsave(&pAdapter->TCBSendQLock, lockflags2); + + if (pAdapter->TxRing.CurrSendTail) { + pAdapter->TxRing.CurrSendTail->Next = pMpTcb; + } else { + pAdapter->TxRing.CurrSendHead = pMpTcb; + } + + pAdapter->TxRing.CurrSendTail = pMpTcb; + + DBG_ASSERT(pMpTcb->Next == NULL); + + pAdapter->TxRing.nBusySend++; + + spin_unlock_irqrestore(&pAdapter->TCBSendQLock, lockflags2); + + /* Write the new write pointer back to the device. */ + writel(pAdapter->TxRing.txDmaReadyToSend.value, + &pAdapter->CSRAddress->txdma.service_request.value); + +#ifdef CONFIG_ET131X_DEBUG + DumpDeviceBlock(DBG_TX_ON, pAdapter, 1); +#endif + + /* For Gig only, we use Tx Interrupt coalescing. Enable the software + * timer to wake us up if this packet isn't followed by N more. + */ + if (pAdapter->uiLinkSpeed == TRUEPHY_SPEED_1000MBPS) { + writel(pAdapter->RegistryTxTimeInterval * NANO_IN_A_MICRO, + &pAdapter->CSRAddress->global.watchdog_timer); + } + + spin_unlock_irqrestore(&pAdapter->SendHWLock, lockflags1); + + DBG_TX_LEAVE(et131x_dbginfo); + return 0; +} + +#endif + +/** + * et131x_free_send_packet - Recycle a MP_TCB, complete the packet if necessary + * @pAdapter: pointer to our adapter + * @pMpTcb: pointer to MP_TCB + * + * Assumption - Send spinlock has been acquired + */ +__inline void et131x_free_send_packet(struct et131x_adapter *pAdapter, PMP_TCB pMpTcb) +{ + unsigned long lockflags; + TX_DESC_ENTRY_t *desc = NULL; + struct net_device_stats *stats = &pAdapter->net_stats; + + if (MP_TEST_FLAG(pMpTcb, fMP_DEST_BROAD)) { + atomic_inc(&pAdapter->Stats.brdcstxmt); + } else if (MP_TEST_FLAG(pMpTcb, fMP_DEST_MULTI)) { + atomic_inc(&pAdapter->Stats.multixmt); + } else { + atomic_inc(&pAdapter->Stats.unixmt); + } + + if (pMpTcb->Packet) { + stats->tx_bytes += pMpTcb->Packet->len; + + /* Iterate through the TX descriptors on the ring + * corresponding to this packet and umap the fragments + * they point to + */ + DBG_TX(et131x_dbginfo, + "Unmap descriptors Here\n" + "TCB : 0x%p\n" + "TCB Next : 0x%p\n" + "TCB PacketLength : %d\n" + "TCB WrIndex.value : 0x%08x\n" + "TCB WrIndex.bits.val : %d\n" + "TCB WrIndex.value : 0x%08x\n" + "TCB WrIndex.bits.val : %d\n", + pMpTcb, + pMpTcb->Next, + pMpTcb->PacketLength, + pMpTcb->WrIndexStart.value, + pMpTcb->WrIndexStart.bits.val, + pMpTcb->WrIndex.value, + pMpTcb->WrIndex.bits.val); + + do { + desc = + (TX_DESC_ENTRY_t *) (pAdapter->TxRing. + pTxDescRingVa + + pMpTcb->WrIndexStart.bits.val); + + DBG_TX(et131x_dbginfo, + "CURRENT DESCRIPTOR\n" + "\tAddress : 0x%p\n" + "\tDataBufferPtrHigh : 0x%08x\n" + "\tDataBufferPtrLow : 0x%08x\n" + "\tword2 : 0x%08x\n" + "\tword3 : 0x%08x\n", + desc, + desc->DataBufferPtrHigh, + desc->DataBufferPtrLow, + desc->word2.value, + desc->word3.value); + + pci_unmap_single(pAdapter->pdev, + desc->DataBufferPtrLow, + desc->word2.value, PCI_DMA_TODEVICE); + + if (++pMpTcb->WrIndexStart.bits.val >= + NUM_DESC_PER_RING_TX) { + if (pMpTcb->WrIndexStart.bits.wrap) { + pMpTcb->WrIndexStart.value = 0; + } else { + pMpTcb->WrIndexStart.value = 0x400; + } + } + } + while (desc != (pAdapter->TxRing.pTxDescRingVa + + pMpTcb->WrIndex.bits.val)); + + DBG_TX(et131x_dbginfo, + "Free Packet (SKB) : 0x%p\n", pMpTcb->Packet); + + dev_kfree_skb_any(pMpTcb->Packet); + } + + memset(pMpTcb, 0, sizeof(MP_TCB)); + + /* Add the TCB to the Ready Q */ + spin_lock_irqsave(&pAdapter->TCBReadyQLock, lockflags); + + pAdapter->Stats.opackets++; + + if (pAdapter->TxRing.TCBReadyQueueTail) { + pAdapter->TxRing.TCBReadyQueueTail->Next = pMpTcb; + } else { + /* Apparently ready Q is empty. */ + pAdapter->TxRing.TCBReadyQueueHead = pMpTcb; + } + + pAdapter->TxRing.TCBReadyQueueTail = pMpTcb; + + spin_unlock_irqrestore(&pAdapter->TCBReadyQLock, lockflags); + + DBG_ASSERT(pAdapter->TxRing.nBusySend >= 0); +} + +/** + * et131x_free_busy_send_packets - Free and complete the stopped active sends + * @pAdapter: pointer to our adapter + * + * Assumption - Send spinlock has been acquired + */ +void et131x_free_busy_send_packets(struct et131x_adapter *pAdapter) +{ + PMP_TCB pMpTcb; + struct list_head *pEntry; + struct sk_buff *pPacket = NULL; + unsigned long lockflags; + uint32_t FreeCounter = 0; + + DBG_ENTER(et131x_dbginfo); + + while (!list_empty(&pAdapter->TxRing.SendWaitQueue)) { + spin_lock_irqsave(&pAdapter->SendWaitLock, lockflags); + + pAdapter->TxRing.nWaitSend--; + spin_unlock_irqrestore(&pAdapter->SendWaitLock, lockflags); + + pEntry = pAdapter->TxRing.SendWaitQueue.next; + + pPacket = NULL; + } + + pAdapter->TxRing.nWaitSend = 0; + + /* Any packets being sent? Check the first TCB on the send list */ + spin_lock_irqsave(&pAdapter->TCBSendQLock, lockflags); + + pMpTcb = pAdapter->TxRing.CurrSendHead; + + while ((pMpTcb != NULL) && (FreeCounter < NUM_TCB)) { + PMP_TCB pNext = pMpTcb->Next; + + pAdapter->TxRing.CurrSendHead = pNext; + + if (pNext == NULL) { + pAdapter->TxRing.CurrSendTail = NULL; + } + + pAdapter->TxRing.nBusySend--; + + spin_unlock_irqrestore(&pAdapter->TCBSendQLock, lockflags); + + DBG_VERBOSE(et131x_dbginfo, "pMpTcb = 0x%p\n", pMpTcb); + + FreeCounter++; + MP_FREE_SEND_PACKET_FUN(pAdapter, pMpTcb); + + spin_lock_irqsave(&pAdapter->TCBSendQLock, lockflags); + + pMpTcb = pAdapter->TxRing.CurrSendHead; + } + + if (FreeCounter == NUM_TCB) { + DBG_ERROR(et131x_dbginfo, + "MpFreeBusySendPackets exitted loop for a bad reason\n"); + BUG(); + } + + spin_unlock_irqrestore(&pAdapter->TCBSendQLock, lockflags); + + pAdapter->TxRing.nBusySend = 0; + + DBG_LEAVE(et131x_dbginfo); +} + +/** + * et131x_handle_send_interrupt - Interrupt handler for sending processing + * @pAdapter: pointer to our adapter + * + * Re-claim the send resources, complete sends and get more to send from + * the send wait queue. + * + * Assumption - Send spinlock has been acquired + */ +void et131x_handle_send_interrupt(struct et131x_adapter *pAdapter) +{ + DBG_TX_ENTER(et131x_dbginfo); + + /* Mark as completed any packets which have been sent by the device. */ + et131x_update_tcb_list(pAdapter); + + /* If we queued any transmits because we didn't have any TCBs earlier, + * dequeue and send those packets now, as long as we have free TCBs. + */ + et131x_check_send_wait_list(pAdapter); + + DBG_TX_LEAVE(et131x_dbginfo); +} + +/** + * et131x_update_tcb_list - Helper routine for Send Interrupt handler + * @pAdapter: pointer to our adapter + * + * Re-claims the send resources and completes sends. Can also be called as + * part of the NIC send routine when the "ServiceComplete" indication has + * wrapped. + */ +static void et131x_update_tcb_list(struct et131x_adapter *pAdapter) +{ + unsigned long lockflags; + DMA10W_t ServiceComplete; + PMP_TCB pMpTcb; + + ServiceComplete.value = + readl(&pAdapter->CSRAddress->txdma.NewServiceComplete.value); + + /* Has the ring wrapped? Process any descriptors that do not have + * the same "wrap" indicator as the current completion indicator + */ + spin_lock_irqsave(&pAdapter->TCBSendQLock, lockflags); + + pMpTcb = pAdapter->TxRing.CurrSendHead; + while (pMpTcb && + ServiceComplete.bits.wrap != pMpTcb->WrIndex.bits.wrap && + ServiceComplete.bits.val < pMpTcb->WrIndex.bits.val) { + pAdapter->TxRing.nBusySend--; + pAdapter->TxRing.CurrSendHead = pMpTcb->Next; + if (pMpTcb->Next == NULL) { + pAdapter->TxRing.CurrSendTail = NULL; + } + + spin_unlock_irqrestore(&pAdapter->TCBSendQLock, lockflags); + MP_FREE_SEND_PACKET_FUN(pAdapter, pMpTcb); + spin_lock_irqsave(&pAdapter->TCBSendQLock, lockflags); + + /* Goto the next packet */ + pMpTcb = pAdapter->TxRing.CurrSendHead; + } + while (pMpTcb && + ServiceComplete.bits.wrap == pMpTcb->WrIndex.bits.wrap && + ServiceComplete.bits.val > pMpTcb->WrIndex.bits.val) { + pAdapter->TxRing.nBusySend--; + pAdapter->TxRing.CurrSendHead = pMpTcb->Next; + if (pMpTcb->Next == NULL) { + pAdapter->TxRing.CurrSendTail = NULL; + } + + spin_unlock_irqrestore(&pAdapter->TCBSendQLock, lockflags); + MP_FREE_SEND_PACKET_FUN(pAdapter, pMpTcb); + spin_lock_irqsave(&pAdapter->TCBSendQLock, lockflags); + + /* Goto the next packet */ + pMpTcb = pAdapter->TxRing.CurrSendHead; + } + + /* Wake up the queue when we hit a low-water mark */ + if (pAdapter->TxRing.nBusySend <= (NUM_TCB / 3)) { + netif_wake_queue(pAdapter->netdev); + } + + spin_unlock_irqrestore(&pAdapter->TCBSendQLock, lockflags); +} + +/** + * et131x_check_send_wait_list - Helper routine for the interrupt handler + * @pAdapter: pointer to our adapter + * + * Takes packets from the send wait queue and posts them to the device (if + * room available). + */ +static void et131x_check_send_wait_list(struct et131x_adapter *pAdapter) +{ + unsigned long lockflags; + + spin_lock_irqsave(&pAdapter->SendWaitLock, lockflags); + + while (!list_empty(&pAdapter->TxRing.SendWaitQueue) && + MP_TCB_RESOURCES_AVAILABLE(pAdapter)) { + struct list_head *pEntry; + + DBG_VERBOSE(et131x_dbginfo, "Tx packets on the wait queue\n"); + + pEntry = pAdapter->TxRing.SendWaitQueue.next; + + pAdapter->TxRing.nWaitSend--; + + DBG_WARNING(et131x_dbginfo, + "MpHandleSendInterrupt - sent a queued pkt. Waiting %d\n", + pAdapter->TxRing.nWaitSend); + } + + spin_unlock_irqrestore(&pAdapter->SendWaitLock, lockflags); +} diff --git a/src/et131x/et1310_tx.h b/src/et131x/et1310_tx.h new file mode 100644 index 0000000..2819c78 --- /dev/null +++ b/src/et131x/et1310_tx.h @@ -0,0 +1,242 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et1310_tx.h - Defines, structs, enums, prototypes, etc. pertaining to data + * transmission. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#ifndef __ET1310_TX_H__ +#define __ET1310_TX_H__ + + +/* Typedefs for Tx Descriptor Ring */ + +/* + * TXDESC_WORD2_t structure holds part of the control bits in the Tx Descriptor + * ring for the ET-1310 + */ +typedef union _txdesc_word2_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 vlan_prio:3; // bits 29-31(VLAN priority) + u32 vlan_cfi:1; // bit 28(cfi) + u32 vlan_tag:12; // bits 16-27(VLAN tag) + u32 length_in_bytes:16; // bits 0-15(packet length) +#else + u32 length_in_bytes:16; // bits 0-15(packet length) + u32 vlan_tag:12; // bits 16-27(VLAN tag) + u32 vlan_cfi:1; // bit 28(cfi) + u32 vlan_prio:3; // bits 29-31(VLAN priority) +#endif /* _BIT_FIELDS_HTOL */ + } bits; +} TXDESC_WORD2_t, *PTXDESC_WORD2_t; + +/* + * TXDESC_WORD3_t structure holds part of the control bits in the Tx Descriptor + * ring for the ET-1310 + */ +typedef union _txdesc_word3_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused:17; // bits 15-31 + u32 udpa:1; // bit 14(UDP checksum assist) + u32 tcpa:1; // bit 13(TCP checksum assist) + u32 ipa:1; // bit 12(IP checksum assist) + u32 vlan:1; // bit 11(append VLAN tag) + u32 hp:1; // bit 10(Packet is a Huge packet) + u32 pp:1; // bit 9(pad packet) + u32 mac:1; // bit 8(MAC override) + u32 crc:1; // bit 7(append CRC) + u32 e:1; // bit 6(Tx frame has error) + u32 pf:1; // bit 5(send pause frame) + u32 bp:1; // bit 4(Issue half-duplex backpressure (XON/XOFF) + u32 cw:1; // bit 3(Control word - no packet data) + u32 ir:1; // bit 2(interrupt the processor when this pkt sent) + u32 f:1; // bit 1(first packet in the sequence) + u32 l:1; // bit 0(last packet in the sequence) +#else + u32 l:1; // bit 0(last packet in the sequence) + u32 f:1; // bit 1(first packet in the sequence) + u32 ir:1; // bit 2(interrupt the processor when this pkt sent) + u32 cw:1; // bit 3(Control word - no packet data) + u32 bp:1; // bit 4(Issue half-duplex backpressure (XON/XOFF) + u32 pf:1; // bit 5(send pause frame) + u32 e:1; // bit 6(Tx frame has error) + u32 crc:1; // bit 7(append CRC) + u32 mac:1; // bit 8(MAC override) + u32 pp:1; // bit 9(pad packet) + u32 hp:1; // bit 10(Packet is a Huge packet) + u32 vlan:1; // bit 11(append VLAN tag) + u32 ipa:1; // bit 12(IP checksum assist) + u32 tcpa:1; // bit 13(TCP checksum assist) + u32 udpa:1; // bit 14(UDP checksum assist) + u32 unused:17; // bits 15-31 +#endif /* _BIT_FIELDS_HTOL */ + } bits; +} TXDESC_WORD3_t, *PTXDESC_WORD3_t; + +/* TX_DESC_ENTRY_t is sructure representing each descriptor on the ring */ +typedef struct _tx_desc_entry_t { + u32 DataBufferPtrHigh; + u32 DataBufferPtrLow; + TXDESC_WORD2_t word2; // control words how to xmit the + TXDESC_WORD3_t word3; // data (detailed above) +} TX_DESC_ENTRY_t, *PTX_DESC_ENTRY_t; + + +/* Typedefs for Tx DMA engine status writeback */ + +/* + * TX_STATUS_BLOCK_t is sructure representing the status of the Tx DMA engine + * it sits in free memory, and is pointed to by 0x101c / 0x1020 + */ +typedef union _tx_status_block_t { + u32 value; + struct { +#ifdef _BIT_FIELDS_HTOL + u32 unused:21; // bits 11-31 + u32 serv_cpl_wrap:1; // bit 10 + u32 serv_cpl:10; // bits 0-9 +#else + u32 serv_cpl:10; // bits 0-9 + u32 serv_cpl_wrap:1; // bit 10 + u32 unused:21; // bits 11-31 +#endif + } bits; +} TX_STATUS_BLOCK_t, *PTX_STATUS_BLOCK_t; + +/* TCB (Transmit Control Block) */ +typedef struct _MP_TCB { + struct _MP_TCB *Next; + u32 Flags; + u32 Count; + u32 PacketStaleCount; + struct sk_buff *Packet; + u32 PacketLength; + DMA10W_t WrIndex; + DMA10W_t WrIndexStart; +} MP_TCB, *PMP_TCB; + +/* Structure to hold the skb's in a list */ +typedef struct tx_skb_list_elem { + struct list_head skb_list_elem; + struct sk_buff *skb; +} TX_SKB_LIST_ELEM, *PTX_SKB_LIST_ELEM; + +/* TX_RING_t is sructure representing our local reference(s) to the ring */ +typedef struct _tx_ring_t { + /* TCB (Transmit Control Block) memory and lists */ + PMP_TCB MpTcbMem; + + /* List of TCBs that are ready to be used */ + PMP_TCB TCBReadyQueueHead; + PMP_TCB TCBReadyQueueTail; + + /* list of TCBs that are currently being sent. NOTE that access to all + * three of these (including nBusySend) are controlled via the + * TCBSendQLock. This lock should be secured prior to incementing / + * decrementing nBusySend, or any queue manipulation on CurrSendHead / + * Tail + */ + PMP_TCB CurrSendHead; + PMP_TCB CurrSendTail; + int32_t nBusySend; + + /* List of packets (not TCBs) that were queued for lack of resources */ + struct list_head SendWaitQueue; + int32_t nWaitSend; + + /* The actual descriptor ring */ + PTX_DESC_ENTRY_t pTxDescRingVa; + dma_addr_t pTxDescRingPa; + uint64_t pTxDescRingAdjustedPa; + uint64_t TxDescOffset; + + /* ReadyToSend indicates where we last wrote to in the descriptor ring. */ + DMA10W_t txDmaReadyToSend; + + /* The location of the write-back status block */ + PTX_STATUS_BLOCK_t pTxStatusVa; + dma_addr_t pTxStatusPa; + + /* A Block of zeroes used to pad packets that are less than 60 bytes */ + void *pTxDummyBlkVa; + dma_addr_t pTxDummyBlkPa; + + TXMAC_ERR_t TxMacErr; + + /* Variables to track the Tx interrupt coalescing features */ + int32_t TxPacketsSinceLastinterrupt; +} TX_RING_t, *PTX_RING_t; + +/* Forward declaration of the frag-list for the following prototypes */ +typedef struct _MP_FRAG_LIST MP_FRAG_LIST, *PMP_FRAG_LIST; + +/* Forward declaration of the private adapter structure */ +struct et131x_adapter; + +/* PROTOTYPES for et1310_tx.c */ +int et131x_tx_dma_memory_alloc(struct et131x_adapter *adapter); +void et131x_tx_dma_memory_free(struct et131x_adapter *adapter); +void ConfigTxDmaRegs(struct et131x_adapter *pAdapter); +void et131x_init_send(struct et131x_adapter *adapter); +void et131x_tx_dma_disable(struct et131x_adapter *pAdapter); +void et131x_tx_dma_enable(struct et131x_adapter *pAdapter); +void et131x_handle_send_interrupt(struct et131x_adapter *pAdapter); +void et131x_free_busy_send_packets(struct et131x_adapter *pAdapter); +int et131x_send_packets(struct sk_buff *skb, struct net_device *netdev); + +#endif /* __ET1310_TX_H__ */ diff --git a/src/et131x/et131x_adapter.h b/src/et131x/et131x_adapter.h new file mode 100644 index 0000000..36e61a4 --- /dev/null +++ b/src/et131x/et131x_adapter.h @@ -0,0 +1,347 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_adapter.h - Header which includes the private adapter structure, along + * with related support structures, macros, definitions, etc. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#ifndef __ET131X_ADAPTER_H__ +#define __ET131X_ADAPTER_H__ + +#include "et1310_address_map.h" +#include "et1310_tx.h" +#include "et1310_rx.h" + +/* + * Do not change these values: if changed, then change also in respective + * TXdma and Rxdma engines + */ +#define NUM_DESC_PER_RING_TX 512 // TX Do not change these values +#define NUM_TCB 64 + +/* + * These values are all superseded by registry entries to facilitate tuning. + * Once the desired performance has been achieved, the optimal registry values + * should be re-populated to these #defines: + */ +#define NUM_TRAFFIC_CLASSES 1 + +/* + * There are three ways of counting errors - if there are more than X errors + * in Y packets (represented by the "SAMPLE" macros), if there are more than + * N errors in a S mSec time period (the "PERIOD" macros), or if there are + * consecutive packets with errors (CONSEC_ERRORED_THRESH). This last covers + * for "Bursty" errors, and the errored packets may well not be contiguous, + * but several errors where the packet counter has changed by less than a + * small amount will cause this count to increment. + */ +#define TX_PACKETS_IN_SAMPLE 10000 +#define TX_MAX_ERRORS_IN_SAMPLE 50 + +#define TX_ERROR_PERIOD 1000 +#define TX_MAX_ERRORS_IN_PERIOD 10 + +#define LINK_DETECTION_TIMER 5000 + +#define TX_CONSEC_RANGE 5 +#define TX_CONSEC_ERRORED_THRESH 10 + +#define LO_MARK_PERCENT_FOR_PSR 15 +#define LO_MARK_PERCENT_FOR_RX 15 + +/* Macros for flag and ref count operations */ +#define MP_SET_FLAG(_M, _F) ((_M)->Flags |= (_F)) +#define MP_CLEAR_FLAG(_M, _F) ((_M)->Flags &= ~(_F)) +#define MP_CLEAR_FLAGS(_M) ((_M)->Flags = 0) +#define MP_TEST_FLAG(_M, _F) (((_M)->Flags & (_F)) != 0) +#define MP_TEST_FLAGS(_M, _F) (((_M)->Flags & (_F)) == (_F)) +#define MP_IS_FLAG_CLEAR(_M, _F) (((_M)->Flags & (_F)) == 0) + +#define MP_INC_RCV_REF(_A) atomic_inc(&(_A)->RcvRefCount) +#define MP_DEC_RCV_REF(_A) atomic_dec(&(_A)->RcvRefCount) +#define MP_GET_RCV_REF(_A) atomic_read(&(_A)->RcvRefCount) + +/* Macros specific to the private adapter structure */ +#define MP_TCB_RESOURCES_AVAILABLE(_M) ((_M)->TxRing.nBusySend < NUM_TCB) +#define MP_TCB_RESOURCES_NOT_AVAILABLE(_M) ((_M)->TxRing.nBusySend >= NUM_TCB) + +#define MP_SHOULD_FAIL_SEND(_M) ((_M)->Flags & fMP_ADAPTER_FAIL_SEND_MASK) +#define MP_IS_NOT_READY(_M) ((_M)->Flags & fMP_ADAPTER_NOT_READY_MASK) +#define MP_IS_READY(_M) !((_M)->Flags & fMP_ADAPTER_NOT_READY_MASK) + +#define MP_HAS_CABLE(_M) !((_M)->Flags & fMP_ADAPTER_NO_CABLE) +#define MP_LINK_DETECTED(_M) !((_M)->Flags & fMP_ADAPTER_LINK_DETECTION) + +/* Counters for error rate monitoring */ +typedef struct _MP_ERR_COUNTERS { + u32 PktCountTxPackets; + u32 PktCountTxErrors; + u32 TimerBasedTxErrors; + u32 PktCountLastError; + u32 ErredConsecPackets; +} MP_ERR_COUNTERS, *PMP_ERR_COUNTERS; + +/* RFD (Receive Frame Descriptor) */ +typedef struct _MP_RFD { + struct list_head list_node; + struct sk_buff *Packet; + u32 PacketSize; // total size of receive frame + u16 iBufferIndex; + u8 iRingIndex; +} MP_RFD, *PMP_RFD; + +/* Enum for Flow Control */ +typedef enum _eflow_control_t { + Both = 0, + TxOnly = 1, + RxOnly = 2, + None = 3 +} eFLOW_CONTROL_t, *PeFLOW_CONTROL_t; + +/* Struct to define some device statistics */ +typedef struct _ce_stats_t { + /* Link Input/Output stats */ + uint64_t ipackets; // # of in packets + uint64_t opackets; // # of out packets + + /* MIB II variables + * + * NOTE: atomic_t types are only guaranteed to store 24-bits; if we + * MUST have 32, then we'll need another way to perform atomic + * operations + */ + u32 unircv; // # multicast packets received + atomic_t unixmt; // # multicast packets for Tx + u32 multircv; // # multicast packets received + atomic_t multixmt; // # multicast packets for Tx + u32 brdcstrcv; // # broadcast packets received + atomic_t brdcstxmt; // # broadcast packets for Tx + u32 norcvbuf; // # Rx packets discarded + u32 noxmtbuf; // # Tx packets discarded + + /* Transciever state informations. */ + u8 xcvr_addr; + u32 xcvr_id; + + /* Tx Statistics. */ + u32 tx_uflo; // Tx Underruns + + u32 collisions; + u32 excessive_collisions; + u32 first_collision; + u32 late_collisions; + u32 max_pkt_error; + u32 tx_deferred; + + /* Rx Statistics. */ + u32 rx_ov_flow; // Rx Over Flow + + u32 length_err; + u32 alignment_err; + u32 crc_err; + u32 code_violations; + u32 other_errors; + +#ifdef CONFIG_ET131X_DEBUG + u32 UnhandledInterruptsPerSec; + u32 RxDmaInterruptsPerSec; + u32 TxDmaInterruptsPerSec; + u32 WatchDogInterruptsPerSec; +#endif /* CONFIG_ET131X_DEBUG */ + + u32 SynchrounousIterations; + INTERRUPT_t InterruptStatus; +} CE_STATS_t, *PCE_STATS_t; + +/* The private adapter structure */ +struct et131x_adapter { + struct net_device *netdev; + struct pci_dev *pdev; + + struct work_struct task; + + /* Flags that indicate current state of the adapter */ + u32 Flags; + u32 HwErrCount; + + /* Configuration */ + u8 PermanentAddress[ETH_ALEN]; + u8 CurrentAddress[ETH_ALEN]; + bool bOverrideAddress; + bool bEepromPresent; + u8 eepromData[2]; + + /* Spinlocks */ + spinlock_t Lock; + + spinlock_t TCBSendQLock; + spinlock_t TCBReadyQLock; + spinlock_t SendHWLock; + spinlock_t SendWaitLock; + + spinlock_t RcvLock; + spinlock_t RcvPendLock; + spinlock_t FbrLock; + + spinlock_t PHYLock; + + /* Packet Filter and look ahead size */ + u32 PacketFilter; + u32 ulLookAhead; + u32 uiLinkSpeed; + u32 uiDuplexMode; + u32 uiAutoNegStatus; + u8 ucLinkStatus; + + /* multicast list */ + u32 MCAddressCount; + u8 MCList[NIC_MAX_MCAST_LIST][ETH_ALEN]; + + /* MAC test */ + TXMAC_TXTEST_t TxMacTest; + + /* Pointer to the device's PCI register space */ + ADDRESS_MAP_t __iomem *CSRAddress; + + /* PCI config space info, for debug purposes only. */ + u8 RevisionID; + u16 VendorID; + u16 DeviceID; + u16 SubVendorID; + u16 SubSystemID; + u32 CacheFillSize; + u16 PciXDevCtl; + u8 pci_lat_timer; + u8 pci_hdr_type; + u8 pci_bist; + u32 pci_cfg_state[64 / sizeof(u32)]; + + /* Registry parameters */ + u8 SpeedDuplex; // speed/duplex + eFLOW_CONTROL_t RegistryFlowControl; // for 802.3x flow control + u8 RegistryWOLMatch; // Enable WOL pattern-matching + u8 RegistryWOLLink; // Link state change is independant + u8 RegistryPhyComa; // Phy Coma mode enable/disable + + u32 RegistryRxMemEnd; // Size of internal rx memory + u8 RegistryMACStat; // If set, read MACSTAT, else don't + u32 RegistryVlanTag; // 802.1q Vlan TAG + u32 RegistryJumboPacket; // Max supported ethernet packet size + + u32 RegistryTxNumBuffers; + u32 RegistryTxTimeInterval; + + u32 RegistryRxNumBuffers; + u32 RegistryRxTimeInterval; + + /* Validation helpers */ + u8 RegistryPMWOL; + u8 RegistryNMIDisable; + u32 RegistryDMACache; + u32 RegistrySCGain; + u8 RegistryPhyLoopbk; // Enable Phy loopback + + /* Derived from the registry: */ + u8 AiForceDpx; // duplex setting + u16 AiForceSpeed; // 'Speed', user over-ride of line speed + eFLOW_CONTROL_t FlowControl; // flow control validated by the far-end + enum { + NETIF_STATUS_INVALID = 0, + NETIF_STATUS_MEDIA_CONNECT, + NETIF_STATUS_MEDIA_DISCONNECT, + NETIF_STATUS_MAX + } MediaState; + u8 DriverNoPhyAccess; + + /* Minimize init-time */ + bool bQueryPending; + bool bSetPending; + bool bResetPending; + struct timer_list ErrorTimer; + bool bLinkTimerActive; + MP_POWER_MGMT PoMgmt; + INTERRUPT_t CachedMaskValue; + + atomic_t RcvRefCount; // Num packets not yet returned + + /* Xcvr status at last poll */ + MI_BMSR_t Bmsr; + + /* Tx Memory Variables */ + TX_RING_t TxRing; + + /* Rx Memory Variables */ + RX_RING_t RxRing; + + /* ET1310 register Access */ + JAGCORE_ACCESS_REGS JagCoreRegs; + PCI_CFG_SPACE_REGS PciCfgRegs; + + /* Loopback specifics */ + u8 ReplicaPhyLoopbk; // Replica Enable + u8 ReplicaPhyLoopbkPF; // Replica Enable Pass/Fail + + /* Stats */ + CE_STATS_t Stats; + + struct net_device_stats net_stats; + struct net_device_stats net_stats_prev; +}; + +#define MPSendPacketsHandler MPSendPackets +#define MP_FREE_SEND_PACKET_FUN(Adapter, pMpTcb) \ + et131x_free_send_packet(Adapter, pMpTcb) +#define MpSendPacketFun(Adapter, Packet) MpSendPacket(Adapter, Packet) + +#endif /* __ET131X_ADAPTER_H__ */ diff --git a/src/et131x/et131x_config.c b/src/et131x/et131x_config.c new file mode 100644 index 0000000..0adbaa6 --- /dev/null +++ b/src/et131x/et131x_config.c @@ -0,0 +1,325 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_config.c - Handles parsing of configuration data during + * initialization. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#include "et131x_version.h" +#include "et131x_debug.h" +#include "et131x_defs.h" + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> + +#include <linux/sched.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/ctype.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/in.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/bitops.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/if_arp.h> +#include <linux/ioport.h> + +#include "et1310_phy.h" +#include "et1310_pm.h" +#include "et1310_jagcore.h" + +#include "et131x_adapter.h" +#include "et131x_initpci.h" +#include "et131x_config.h" + +#include "et1310_tx.h" + +/* Data for debugging facilities */ +#ifdef CONFIG_ET131X_DEBUG +extern dbg_info_t *et131x_dbginfo; +#endif /* CONFIG_ET131X_DEBUG */ + +/* Defines for Parameter Default/Min/Max vaules */ +#define PARM_SPEED_DUPLEX_DEF 0 +#define PARM_SPEED_DUPLEX_MIN 0 +#define PARM_SPEED_DUPLEX_MAX 5 + +#define PARM_VLAN_TAG_DEF 0 +#define PARM_VLAN_TAG_MIN 0 +#define PARM_VLAN_TAG_MAX 4095 + +#define PARM_FLOW_CTL_DEF 0 +#define PARM_FLOW_CTL_MIN 0 +#define PARM_FLOW_CTL_MAX 3 + +#define PARM_WOL_LINK_DEF 3 +#define PARM_WOL_LINK_MIN 0 +#define PARM_WOL_LINK_MAX 3 + +#define PARM_WOL_MATCH_DEF 7 +#define PARM_WOL_MATCH_MIN 0 +#define PARM_WOL_MATCH_MAX 7 + +#define PARM_JUMBO_PKT_DEF 1514 +#define PARM_JUMBO_PKT_MIN 1514 +#define PARM_JUMBO_PKT_MAX 9216 + +#define PARM_PHY_COMA_DEF 0 +#define PARM_PHY_COMA_MIN 0 +#define PARM_PHY_COMA_MAX 1 + +#define PARM_RX_NUM_BUFS_DEF 4 +#define PARM_RX_NUM_BUFS_MIN 1 +#define PARM_RX_NUM_BUFS_MAX 64 + +#define PARM_RX_TIME_INT_DEF 10 +#define PARM_RX_TIME_INT_MIN 2 +#define PARM_RX_TIME_INT_MAX 320 + +#define PARM_TX_NUM_BUFS_DEF 4 +#define PARM_TX_NUM_BUFS_MIN 1 +#define PARM_TX_NUM_BUFS_MAX 40 + +#define PARM_TX_TIME_INT_DEF 40 +#define PARM_TX_TIME_INT_MIN 1 +#define PARM_TX_TIME_INT_MAX 140 + +#define PARM_RX_MEM_END_DEF 0x2bc +#define PARM_RX_MEM_END_MIN 0 +#define PARM_RX_MEM_END_MAX 0x3ff + +#define PARM_MAC_STAT_DEF 1 +#define PARM_MAC_STAT_MIN 0 +#define PARM_MAC_STAT_MAX 1 + +#define PARM_SC_GAIN_DEF 7 +#define PARM_SC_GAIN_MIN 0 +#define PARM_SC_GAIN_MAX 7 + +#define PARM_PM_WOL_DEF 0 +#define PARM_PM_WOL_MIN 0 +#define PARM_PM_WOL_MAX 1 + +#define PARM_NMI_DISABLE_DEF 0 +#define PARM_NMI_DISABLE_MIN 0 +#define PARM_NMI_DISABLE_MAX 2 + +#define PARM_DMA_CACHE_DEF 0 +#define PARM_DMA_CACHE_MIN 0 +#define PARM_DMA_CACHE_MAX 15 + +#define PARM_PHY_LOOPBK_DEF 0 +#define PARM_PHY_LOOPBK_MIN 0 +#define PARM_PHY_LOOPBK_MAX 1 + +#define PARM_MAC_ADDRESS_DEF { 0x00, 0x05, 0x3d, 0x00, 0x02, 0x00 } + +/* Module parameter for disabling NMI + * et131x_speed_set : + * Set Link speed and dublex manually (0-5) [0] + * 1 : 10Mb Half-Duplex + * 2 : 10Mb Full-Duplex + * 3 : 100Mb Half-Duplex + * 4 : 100Mb Full-Duplex + * 5 : 1000Mb Full-Duplex + * 0 : Auto Speed Auto Dublex // default + */ +static u32 et131x_nmi_disable = PARM_NMI_DISABLE_DEF; +module_param(et131x_nmi_disable, uint, 0); +MODULE_PARM_DESC(et131x_nmi_disable, "Disable NMI (0-2) [0]"); + +/* Module parameter for manual speed setting + * et131x_nmi_disable : + * Disable NMI (0-2) [0] + * 0 : + * 1 : + * 2 : + */ +static u32 et131x_speed_set = PARM_SPEED_DUPLEX_DEF; +module_param(et131x_speed_set, uint, 0); +MODULE_PARM_DESC(et131x_speed_set, + "Set Link speed and dublex manually (0-5) [0] \n 1 : 10Mb Half-Duplex \n 2 : 10Mb Full-Duplex \n 3 : 100Mb Half-Duplex \n 4 : 100Mb Full-Duplex \n 5 : 1000Mb Full-Duplex \n 0 : Auto Speed Auto Dublex"); + +/** + * et131x_config_parse + * @pAdapter: pointer to the private adapter struct + * + * Parses a configuration from some location (module parameters, for example) + * into the private adapter struct + */ +void et131x_config_parse(struct et131x_adapter *pAdapter) +{ + uint8_t macAddrDef[] = PARM_MAC_ADDRESS_DEF; + + DBG_ENTER(et131x_dbginfo); + + /* + * The NDIS driver uses the registry to store persistent per-device + * configuration, and reads this configuration into the appropriate + * elements of the private adapter structure on initialization. + * Because Linux has no analog to the registry, use this function to + * initialize the private adapter structure with a default + * configuration. + * + * One other possibility is to use a series of module parameters which + * can be passed in by the caller when the module is initialized. + * However, this implementation does not allow for seperate + * configurations in the event multiple devices are present, and hence + * will not suffice. + * + * If another method is derived which addresses this problem, this is + * where it should be implemented. + */ + + /* Set the private adapter struct with default values for the + * corresponding parameters + */ + if (et131x_speed_set != PARM_SPEED_DUPLEX_DEF) { + DBG_VERBOSE(et131x_dbginfo, "Speed set manually to : %d \n", + et131x_speed_set); + pAdapter->SpeedDuplex = et131x_speed_set; + } else { + pAdapter->SpeedDuplex = PARM_SPEED_DUPLEX_DEF; + } + + // pAdapter->SpeedDuplex = PARM_SPEED_DUPLEX_DEF; + + pAdapter->RegistryVlanTag = PARM_VLAN_TAG_DEF; + pAdapter->RegistryFlowControl = PARM_FLOW_CTL_DEF; + pAdapter->RegistryWOLLink = PARM_WOL_LINK_DEF; + pAdapter->RegistryWOLMatch = PARM_WOL_MATCH_DEF; + pAdapter->RegistryJumboPacket = PARM_JUMBO_PKT_DEF; + pAdapter->RegistryPhyComa = PARM_PHY_COMA_DEF; + pAdapter->RegistryRxNumBuffers = PARM_RX_NUM_BUFS_DEF; + pAdapter->RegistryRxTimeInterval = PARM_RX_TIME_INT_DEF; + pAdapter->RegistryTxNumBuffers = PARM_TX_NUM_BUFS_DEF; + pAdapter->RegistryTxTimeInterval = PARM_TX_TIME_INT_DEF; + pAdapter->RegistryRxMemEnd = PARM_RX_MEM_END_DEF; + pAdapter->RegistryMACStat = PARM_MAC_STAT_DEF; + pAdapter->RegistrySCGain = PARM_SC_GAIN_DEF; + pAdapter->RegistryPMWOL = PARM_PM_WOL_DEF; + + if (et131x_nmi_disable != PARM_NMI_DISABLE_DEF) { + pAdapter->RegistryNMIDisable = et131x_nmi_disable; + } else { + pAdapter->RegistryNMIDisable = PARM_NMI_DISABLE_DEF; + } + + pAdapter->RegistryDMACache = PARM_DMA_CACHE_DEF; + pAdapter->RegistryPhyLoopbk = PARM_PHY_LOOPBK_DEF; + + /* Set the MAC address to a default */ + memcpy(pAdapter->CurrentAddress, macAddrDef, ETH_ALEN); + pAdapter->bOverrideAddress = false; + + DBG_TRACE(et131x_dbginfo, + "Default MAC Address : %02x:%02x:%02x:%02x:%02x:%02x\n", + pAdapter->CurrentAddress[0], pAdapter->CurrentAddress[1], + pAdapter->CurrentAddress[2], pAdapter->CurrentAddress[3], + pAdapter->CurrentAddress[4], pAdapter->CurrentAddress[5]); + + /* Decode SpeedDuplex + * + * Set up as if we are auto negotiating always and then change if we + * go into force mode + */ + pAdapter->AiForceSpeed = 0; // Auto speed + pAdapter->AiForceDpx = 0; // Auto FDX + + /* If we are the 10/100 device, and gigabit is somehow requested then + * knock it down to 100 full. + */ + if ((pAdapter->DeviceID == ET131X_PCI_DEVICE_ID_FAST) && + (pAdapter->SpeedDuplex == 5)) { + pAdapter->SpeedDuplex = 4; + } + + switch (pAdapter->SpeedDuplex) { + case 1: // 10Mb Half-Duplex + pAdapter->AiForceSpeed = 10; + pAdapter->AiForceDpx = 1; + break; + + case 2: // 10Mb Full-Duplex + pAdapter->AiForceSpeed = 10; + pAdapter->AiForceDpx = 2; + break; + + case 3: // 100Mb Half-Duplex + pAdapter->AiForceSpeed = 100; + pAdapter->AiForceDpx = 1; + break; + + case 4: // 100Mb Full-Duplex + pAdapter->AiForceSpeed = 100; + pAdapter->AiForceDpx = 2; + break; + + case 5: // 1000Mb Full-Duplex + pAdapter->AiForceSpeed = 1000; + pAdapter->AiForceDpx = 2; + break; + } + + DBG_LEAVE(et131x_dbginfo); +} diff --git a/src/et131x/et131x_config.h b/src/et131x/et131x_config.h new file mode 100644 index 0000000..642c0f6 --- /dev/null +++ b/src/et131x/et131x_config.h @@ -0,0 +1,67 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_config.h - Defines, structs, enums, prototypes, etc. to support + * et131x_config.c + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#ifndef __ET131X_CONFIG_H__ +#define __ET131X_CONFIG_H__ + +/* Forward declaration of the private adapter structure */ +struct et131x_adapter; + +void et131x_config_parse(struct et131x_adapter *adapter); + +#endif /* __ET131X_CONFIG_H__ */ diff --git a/src/et131x/et131x_debug.c b/src/et131x/et131x_debug.c new file mode 100644 index 0000000..9ee5bce --- /dev/null +++ b/src/et131x/et131x_debug.c @@ -0,0 +1,218 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_debug.c - Routines used for debugging. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#ifdef CONFIG_ET131X_DEBUG + +#include "et131x_version.h" +#include "et131x_debug.h" +#include "et131x_defs.h" + +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> + +#include <linux/sched.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/ctype.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/in.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/bitops.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/if_arp.h> +#include <linux/ioport.h> +#include <linux/random.h> + +#include "et1310_phy.h" +#include "et1310_pm.h" +#include "et1310_jagcore.h" + +#include "et131x_adapter.h" +#include "et131x_netdev.h" +#include "et131x_config.h" +#include "et131x_isr.h" + +#include "et1310_address_map.h" +#include "et1310_jagcore.h" +#include "et1310_tx.h" +#include "et1310_rx.h" +#include "et1310_mac.h" + +/* Data for debugging facilities */ +extern dbg_info_t *et131x_dbginfo; + +/** + * DumpTxQueueContents - Dump out the tx queue and the shadow pointers + * @pAdapter: pointer to our adapter structure + */ +void DumpTxQueueContents(int dbgLvl, struct et131x_adapter *pAdapter) +{ + MMC_t __iomem *mmc = &pAdapter->CSRAddress->mmc; + uint32_t TxQueueAddr; + + if (DBG_FLAGS(et131x_dbginfo) & dbgLvl) { + for (TxQueueAddr = 0x200; TxQueueAddr < 0x3ff; TxQueueAddr++) { + MMC_SRAM_ACCESS_t sram_access; + + sram_access.value = readl(&mmc->sram_access.value); + sram_access.bits.req_addr = TxQueueAddr; + sram_access.bits.req_access = 1; + writel(sram_access.value, &mmc->sram_access.value); + + DBG_PRINT("Addr 0x%x, Access 0x%08x\t" + "Value 1 0x%08x, Value 2 0x%08x, " + "Value 3 0x%08x, Value 4 0x%08x, \n", + TxQueueAddr, + readl(&mmc->sram_access.value), + readl(&mmc->sram_word1), + readl(&mmc->sram_word2), + readl(&mmc->sram_word3), + readl(&mmc->sram_word4)); + } + + DBG_PRINT("Shadow Pointers 0x%08x\n", + readl(&pAdapter->CSRAddress->txmac.shadow_ptr.value)); + } +} + +/** + * DumpDeviceBlock + * @pAdapter: pointer to our adapter + * + * Dumps the first 64 regs of each block of the et-1310 (each block is + * mapped to a new page, each page is 4096 bytes). + */ +#define NUM_BLOCKS 8 +void DumpDeviceBlock(int dbgLvl, struct et131x_adapter *pAdapter, + uint32_t Block) +{ + uint32_t Address1, Address2; + uint32_t __iomem *BigDevicePointer = + (uint32_t __iomem *) pAdapter->CSRAddress; + const char *BlockNames[NUM_BLOCKS] = { + "Global", "Tx DMA", "Rx DMA", "Tx MAC", + "Rx MAC", "MAC", "MAC Stat", "MMC" + }; + + /* Output the debug counters to the debug terminal */ + if (DBG_FLAGS(et131x_dbginfo) & dbgLvl) { + DBG_PRINT("%s block\n", BlockNames[Block]); + BigDevicePointer += Block * 1024; + for (Address1 = 0; Address1 < 8; Address1++) { + for (Address2 = 0; Address2 < 8; Address2++) { + if (Block == 0 && + (Address1 * 8 + Address2) == 6) { + DBG_PRINT(" ISR , "); + } else { + DBG_PRINT("0x%08x, ", + readl(BigDevicePointer++)); + } + } + DBG_PRINT("\n"); + } + DBG_PRINT("\n"); + } +} + +/** + * DumpDeviceReg + * @pAdapter: pointer to our adapter + * + * Dumps the first 64 regs of each block of the et-1310 (each block is + * mapped to a new page, each page is 4096 bytes). + */ +void DumpDeviceReg(int dbgLvl, struct et131x_adapter *pAdapter) +{ + uint32_t Address1, Address2; + uint32_t Block; + uint32_t __iomem *BigDevicePointer = + (uint32_t __iomem *) pAdapter->CSRAddress; + uint32_t __iomem *Pointer; + const char *BlockNames[NUM_BLOCKS] = { + "Global", "Tx DMA", "Rx DMA", "Tx MAC", + "Rx MAC", "MAC", "MAC Stat", "MMC" + }; + + /* Output the debug counters to the debug terminal */ + if (DBG_FLAGS(et131x_dbginfo) & dbgLvl) { + for (Block = 0; Block < NUM_BLOCKS; Block++) { + DBG_PRINT("%s block\n", BlockNames[Block]); + Pointer = BigDevicePointer + (Block * 1024); + + for (Address1 = 0; Address1 < 8; Address1++) { + for (Address2 = 0; Address2 < 8; Address2++) { + DBG_PRINT("0x%08x, ", + readl(Pointer++)); + } + DBG_PRINT("\n"); + } + DBG_PRINT("\n"); + } + } +} + +#endif // CONFIG_ET131X_DEBUG diff --git a/src/et131x/et131x_debug.h b/src/et131x/et131x_debug.h new file mode 100644 index 0000000..dab6080 --- /dev/null +++ b/src/et131x/et131x_debug.h @@ -0,0 +1,201 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_debug.h - Defines, structs, enums, prototypes, etc. used for + * outputting debug messages to the system logging facility + * (ksyslogd) + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#ifndef __ET131X_DBG_H__ +#define __ET131X_DBG_H__ + +/* Define Masks for debugging types/levels */ +#define DBG_ERROR_ON 0x00000001L +#define DBG_WARNING_ON 0x00000002L +#define DBG_NOTICE_ON 0x00000004L +#define DBG_TRACE_ON 0x00000008L +#define DBG_VERBOSE_ON 0x00000010L +#define DBG_PARAM_ON 0x00000020L +#define DBG_BREAK_ON 0x00000040L +#define DBG_RX_ON 0x00000100L +#define DBG_TX_ON 0x00000200L + +#ifdef CONFIG_ET131X_DEBUG + +/* + * Set the level of debugging if not done with a preprocessor define. See + * et131x_main.c, function et131x_init_module() for how the debug level + * translates into the types of messages displayed. + */ +#ifndef DBG_LVL +#define DBG_LVL 3 +#endif /* DBG_LVL */ + +#define DBG_DEFAULTS (DBG_ERROR_ON | DBG_WARNING_ON | DBG_BREAK_ON ) + +#define DBG_FLAGS(A) (A)->dbgFlags +#define DBG_NAME(A) (A)->dbgName +#define DBG_LEVEL(A) (A)->dbgLevel + +#ifndef DBG_PRINT +#define DBG_PRINT(S...) printk(KERN_DEBUG S) +#endif /* DBG_PRINT */ + +#ifndef DBG_PRINTC +#define DBG_PRINTC(S...) printk(S) +#endif /* DBG_PRINTC */ + +#ifndef DBG_TRAP +#define DBG_TRAP {} /* BUG() */ +#endif /* DBG_TRAP */ + +#define _ENTER_STR ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" +#define _LEAVE_STR "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" + +#define _DBG_ENTER(A) printk(KERN_DEBUG "%s:%.*s:%s\n", DBG_NAME(A), \ + ++DBG_LEVEL(A), _ENTER_STR, __func__) +#define _DBG_LEAVE(A) printk(KERN_DEBUG "%s:%.*s:%s\n", DBG_NAME(A), \ + DBG_LEVEL(A)--, _LEAVE_STR, __func__) + +#define DBG_ENTER(A) {if (DBG_FLAGS(A) & DBG_TRACE_ON) \ + _DBG_ENTER(A);} + +#define DBG_LEAVE(A) {if (DBG_FLAGS(A) & DBG_TRACE_ON) \ + _DBG_LEAVE(A);} + +#define DBG_PARAM(A,N,F,S...) {if (DBG_FLAGS(A) & DBG_PARAM_ON) \ + DBG_PRINT(" %s -- "F"\n",N,S);} + +#define DBG_ERROR(A,S...) \ + if (DBG_FLAGS(A) & DBG_ERROR_ON) { \ + DBG_PRINT("%s:ERROR:%s ",DBG_NAME(A), __func__); \ + DBG_PRINTC(S); \ + DBG_TRAP; \ + } + +#define DBG_WARNING(A,S...) {if (DBG_FLAGS(A) & DBG_WARNING_ON) \ + {DBG_PRINT("%s:WARNING:%s ",DBG_NAME(A),__func__);DBG_PRINTC(S);}} + +#define DBG_NOTICE(A,S...) {if (DBG_FLAGS(A) & DBG_NOTICE_ON) \ + {DBG_PRINT("%s:NOTICE:%s ",DBG_NAME(A),__func__);DBG_PRINTC(S);}} + +#define DBG_TRACE(A,S...) {if (DBG_FLAGS(A) & DBG_TRACE_ON) \ + {DBG_PRINT("%s:TRACE:%s ",DBG_NAME(A), __func__);DBG_PRINTC(S);}} + +#define DBG_VERBOSE(A,S...) {if (DBG_FLAGS(A) & DBG_VERBOSE_ON) \ + {DBG_PRINT("%s:VERBOSE:%s ",DBG_NAME(A), __func__);DBG_PRINTC(S);}} + +#define DBG_RX(A,S...) {if (DBG_FLAGS(A) & DBG_RX_ON) \ + {DBG_PRINT(S);}} + +#define DBG_RX_ENTER(A) {if (DBG_FLAGS(A) & DBG_RX_ON) \ + _DBG_ENTER(A);} + +#define DBG_RX_LEAVE(A) {if (DBG_FLAGS(A) & DBG_RX_ON) \ + _DBG_LEAVE(A);} + +#define DBG_TX(A,S...) {if (DBG_FLAGS(A) & DBG_TX_ON) \ + {DBG_PRINT(S);}} + +#define DBG_TX_ENTER(A) {if (DBG_FLAGS(A) & DBG_TX_ON) \ + _DBG_ENTER(A);} + +#define DBG_TX_LEAVE(A) {if (DBG_FLAGS(A) & DBG_TX_ON) \ + _DBG_LEAVE(A);} + +#define DBG_ASSERT(C) {if (!(C)) \ + {DBG_PRINT("ASSERT(%s) -- %s#%d (%s)\n", \ + #C,__FILE__,__LINE__,__func__); \ + DBG_TRAP;}} +#define STATIC + +typedef struct { + char *dbgName; + int dbgLevel; + unsigned long dbgFlags; +} dbg_info_t; + +#else /* CONFIG_ET131X_DEBUG */ + +#define DBG_DEFN +#define DBG_TRAP +#define DBG_PRINT(S...) +#define DBG_ENTER(A) +#define DBG_LEAVE(A) +#define DBG_PARAM(A,N,F,S...) +#define DBG_ERROR(A,S...) +#define DBG_WARNING(A,S...) +#define DBG_NOTICE(A,S...) +#define DBG_TRACE(A,S...) +#define DBG_VERBOSE(A,S...) +#define DBG_RX(A,S...) +#define DBG_RX_ENTER(A) +#define DBG_RX_LEAVE(A) +#define DBG_TX(A,S...) +#define DBG_TX_ENTER(A) +#define DBG_TX_LEAVE(A) +#define DBG_ASSERT(C) +#define STATIC static + +#endif /* CONFIG_ET131X_DEBUG */ + +/* Forward declaration of the private adapter structure */ +struct et131x_adapter; + +void DumpTxQueueContents(int dbgLvl, struct et131x_adapter *adapter); +void DumpDeviceBlock(int dbgLvl, struct et131x_adapter *adapter, + unsigned int Block); +void DumpDeviceReg(int dbgLvl, struct et131x_adapter *adapter); + +#endif /* __ET131X_DBG_H__ */ diff --git a/src/et131x/et131x_defs.h b/src/et131x/et131x_defs.h new file mode 100644 index 0000000..886cb78 --- /dev/null +++ b/src/et131x/et131x_defs.h @@ -0,0 +1,128 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_defs.h - Defines, structs, enums, prototypes, etc. to assist with OS + * compatibility + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#ifndef __ET131X_DEFS_H__ +#define __ET131X_DEFS_H__ + +/* Packet and header sizes */ +#define NIC_MIN_PACKET_SIZE 60 +#define NIC_HEADER_SIZE ETH_HLEN /* 14 */ + +/* Multicast list size */ +#define NIC_MAX_MCAST_LIST 128 + +/* Supported Filters */ +#define ET131X_PACKET_TYPE_DIRECTED 0x0001 +#define ET131X_PACKET_TYPE_MULTICAST 0x0002 +#define ET131X_PACKET_TYPE_BROADCAST 0x0004 +#define ET131X_PACKET_TYPE_PROMISCUOUS 0x0008 +#define ET131X_PACKET_TYPE_ALL_MULTICAST 0x0010 + +/* Tx Timeout */ +#define ET131X_TX_TIMEOUT (1 * HZ) +#define NIC_SEND_HANG_THRESHOLD 0 + +/* MP_TCB flags */ +#define fMP_DEST_MULTI 0x00000001 +#define fMP_DEST_BROAD 0x00000002 + +/* MP_ADAPTER flags */ +#define fMP_ADAPTER_RECV_LOOKASIDE 0x00000004 +#define fMP_ADAPTER_INTERRUPT_IN_USE 0x00000008 +#define fMP_ADAPTER_SECONDARY 0x00000010 + +/* MP_SHARED flags */ +#define fMP_ADAPTER_SHUTDOWN 0x00100000 +#define fMP_ADAPTER_LOWER_POWER 0x00200000 + +#define fMP_ADAPTER_NON_RECOVER_ERROR 0x00800000 +#define fMP_ADAPTER_RESET_IN_PROGRESS 0x01000000 +#define fMP_ADAPTER_NO_CABLE 0x02000000 +#define fMP_ADAPTER_HARDWARE_ERROR 0x04000000 +#define fMP_ADAPTER_REMOVE_IN_PROGRESS 0x08000000 +#define fMP_ADAPTER_HALT_IN_PROGRESS 0x10000000 +#define fMP_ADAPTER_LINK_DETECTION 0x20000000 + +#define fMP_ADAPTER_FAIL_SEND_MASK 0x3ff00000 +#define fMP_ADAPTER_NOT_READY_MASK 0x3ff00000 + +/* Some offsets in PCI config space that are actually used. */ +#define ET1310_PCI_PM_CAPABILITY 0x40 +#define ET1310_PCI_PM_CSR 0x44 +#define ET1310_PCI_MAX_PYLD 0x4C +#define ET1310_PCI_DEV_CTRL 0x50 +#define ET1310_PCI_DEV_STAT 0x52 +#define ET1310_NMI_DISABLE 0x61 +#define ET1310_PCI_MAC_ADDRESS 0xA4 +#define ET1310_PCI_EEPROM_STATUS 0xB2 +#define ET1310_PCI_PHY_INDEX_REG 0xB4 +#define ET1310_PCI_ACK_NACK 0xC0 +#define ET1310_PCI_REPLAY 0xC2 +#define ET1310_PCI_L0L1LATENCY 0xCF +#define ET1310_PCI_SEL_PHY_CTRL 0xE4 +#define ET1310_PCI_ADVANCED_ERR 0x100 + +/* PCI Vendor/Product IDs */ +#define ET131X_PCI_VENDOR_ID 0x11C1 // Agere Systems +#define ET131X_PCI_DEVICE_ID_GIG 0xED00 // ET1310 1000 Base-T +#define ET131X_PCI_DEVICE_ID_FAST 0xED01 // ET1310 100 Base-T + +/* Define order of magnitude converter */ +#define NANO_IN_A_MICRO 1000 + +#endif /* __ET131X_DEFS_H__ */ diff --git a/src/et131x/et131x_initpci.c b/src/et131x/et131x_initpci.c new file mode 100644 index 0000000..4c6f171 --- /dev/null +++ b/src/et131x/et131x_initpci.c @@ -0,0 +1,1046 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_initpci.c - Routines and data used to register the driver with the + * PCI (and PCI Express) subsystem, as well as basic driver + * init and startup. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#include "et131x_version.h" +#include "et131x_debug.h" +#include "et131x_defs.h" + +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> + +#include <linux/sched.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/ctype.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/in.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/bitops.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/if_arp.h> +#include <linux/ioport.h> +#include <linux/random.h> + +#include "et1310_phy.h" +#include "et1310_pm.h" +#include "et1310_jagcore.h" + +#include "et131x_adapter.h" +#include "et131x_netdev.h" +#include "et131x_config.h" +#include "et131x_isr.h" + +#include "et1310_address_map.h" +#include "et1310_jagcore.h" +#include "et1310_tx.h" +#include "et1310_rx.h" +#include "et1310_mac.h" +#include "et1310_eeprom.h" + + +int __devinit et131x_pci_setup(struct pci_dev *pdev, + const struct pci_device_id *ent); +void __devexit et131x_pci_remove(struct pci_dev *pdev); + + +/* Modinfo parameters (filled out using defines from et131x_version.h) */ +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_INFO); +MODULE_LICENSE(DRIVER_LICENSE); + +/* Module Parameters and related data for debugging facilities */ +#ifdef CONFIG_ET131X_DEBUG +static u32 et131x_debug_level = DBG_LVL; +static u32 et131x_debug_flags = DBG_DEFAULTS; + +/* +et131x_debug_level : + Level of debugging desired (0-7) + 7 : DBG_RX_ON | DBG_TX_ON + 6 : DBG_PARAM_ON + 5 : DBG_VERBOSE_ON + 4 : DBG_TRACE_ON + 3 : DBG_NOTICE_ON + 2 : no debug info + 1 : no debug info + 0 : no debug info +*/ + +module_param(et131x_debug_level, uint, 0); +module_param(et131x_debug_flags, uint, 0); + +MODULE_PARM_DESC(et131x_debug_level, "Level of debugging desired (0-7)"); + +static dbg_info_t et131x_info = { DRIVER_NAME_EXT, 0, 0 }; +dbg_info_t *et131x_dbginfo = &et131x_info; +#endif /* CONFIG_ET131X_DEBUG */ + +static struct pci_device_id et131x_pci_table[] __devinitdata = { + {ET131X_PCI_VENDOR_ID, ET131X_PCI_DEVICE_ID_GIG, PCI_ANY_ID, + PCI_ANY_ID, 0, 0, 0UL}, + {ET131X_PCI_VENDOR_ID, ET131X_PCI_DEVICE_ID_FAST, PCI_ANY_ID, + PCI_ANY_ID, 0, 0, 0UL}, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, et131x_pci_table); + +static struct pci_driver et131x_driver = { + .name = DRIVER_NAME, + .id_table = et131x_pci_table, + .probe = et131x_pci_setup, + .remove = __devexit_p(et131x_pci_remove), + .suspend = NULL, //et131x_pci_suspend, + .resume = NULL, //et131x_pci_resume, +}; + + +/** + * et131x_init_module - The "main" entry point called on driver initialization + * + * Returns 0 on success, errno on failure (as defined in errno.h) + */ +int et131x_init_module(void) +{ + int result; + +#ifdef CONFIG_ET131X_DEBUG + /* Set the level of debug messages displayed using the module + * parameter + */ + et131x_dbginfo->dbgFlags = et131x_debug_flags; + + switch (et131x_debug_level) { + case 7: + et131x_dbginfo->dbgFlags |= (DBG_RX_ON | DBG_TX_ON); + + case 6: + et131x_dbginfo->dbgFlags |= DBG_PARAM_ON; + + case 5: + et131x_dbginfo->dbgFlags |= DBG_VERBOSE_ON; + + case 4: + et131x_dbginfo->dbgFlags |= DBG_TRACE_ON; + + case 3: + et131x_dbginfo->dbgFlags |= DBG_NOTICE_ON; + + case 2: + case 1: + case 0: + default: + break; + } +#endif /* CONFIG_ET131X_DEBUG */ + + DBG_ENTER(et131x_dbginfo); + DBG_PRINT("%s\n", DRIVER_INFO); + + result = pci_register_driver(&et131x_driver); + + DBG_LEAVE(et131x_dbginfo); + return result; +} + +/** + * et131x_cleanup_module - The entry point called on driver cleanup + */ +void et131x_cleanup_module(void) +{ + DBG_ENTER(et131x_dbginfo); + + pci_unregister_driver(&et131x_driver); + + DBG_LEAVE(et131x_dbginfo); +} + +/* + * These macros map the driver-specific init_module() and cleanup_module() + * routines so they can be called by the kernel. + */ +module_init(et131x_init_module); +module_exit(et131x_cleanup_module); + + +/** + * et131x_find_adapter - Find the adapter and get all the assigned resources + * @adapter: pointer to our private adapter structure + * + * Returns 0 on success, errno on failure (as defined in errno.h) + */ +int et131x_find_adapter(struct et131x_adapter *adapter, struct pci_dev *pdev) +{ + int result; + uint8_t eepromStat; + uint8_t maxPayload = 0; + uint8_t read_size_reg; + + DBG_ENTER(et131x_dbginfo); + + /* Allow disabling of Non-Maskable Interrupts in I/O space, to + * support validation. + */ + if (adapter->RegistryNMIDisable) { + uint8_t RegisterVal; + + RegisterVal = inb(ET1310_NMI_DISABLE); + RegisterVal &= 0xf3; + + if (adapter->RegistryNMIDisable == 2) { + RegisterVal |= 0xc; + } + + outb(ET1310_NMI_DISABLE, RegisterVal); + } + + /* We first need to check the EEPROM Status code located at offset + * 0xB2 of config space + */ + result = pci_read_config_byte(pdev, ET1310_PCI_EEPROM_STATUS, + &eepromStat); + + /* THIS IS A WORKAROUND: + * I need to call this function twice to get my card in a + * LG M1 Express Dual running. I tried also a msleep before this + * function, because I thougth there could be some time condidions + * but it didn't work. Call the whole function twice also work. + */ + result = pci_read_config_byte(pdev, ET1310_PCI_EEPROM_STATUS, + &eepromStat); + if (result != PCIBIOS_SUCCESSFUL) { + DBG_ERROR(et131x_dbginfo, "Could not read PCI config space for " + "EEPROM Status\n"); + DBG_LEAVE(et131x_dbginfo); + return -EIO; + } + + /* Determine if the error(s) we care about are present. If they are + * present, we need to fail. + */ + if (eepromStat & 0x4C) { + result = pci_read_config_byte(pdev, PCI_REVISION_ID, + &adapter->RevisionID); + if (result != PCIBIOS_SUCCESSFUL) { + DBG_ERROR(et131x_dbginfo, + "Could not read PCI config space for " + "Revision ID\n"); + DBG_LEAVE(et131x_dbginfo); + return -EIO; + } else if (adapter->RevisionID == 0x01) { + int32_t nLoop; + uint8_t ucTemp[4] = { 0xFE, 0x13, 0x10, 0xFF }; + + /* Re-write the first 4 bytes if we have an eeprom + * present and the revision id is 1, this fixes the + * corruption seen with 1310 B Silicon + */ + for (nLoop = 0; nLoop < 3; nLoop++) { + EepromWriteByte(adapter, nLoop, ucTemp[nLoop], + 0, SINGLE_BYTE); + } + } + + DBG_ERROR(et131x_dbginfo, + "Fatal EEPROM Status Error - 0x%04x\n", eepromStat); + + /* This error could mean that there was an error reading the + * eeprom or that the eeprom doesn't exist. We will treat + * each case the same and not try to gather additional + * information that normally would come from the eeprom, like + * MAC Address + */ + adapter->bEepromPresent = false; + + DBG_LEAVE(et131x_dbginfo); + return -EIO; + } else { + DBG_TRACE(et131x_dbginfo, "EEPROM Status Code - 0x%04x\n", + eepromStat); + adapter->bEepromPresent = true; + } + + /* Read the EEPROM for information regarding LED behavior. Refer to + * ET1310_phy.c, et131x_xcvr_init(), for its use. + */ + EepromReadByte(adapter, 0x70, &adapter->eepromData[0], 0, SINGLE_BYTE); + EepromReadByte(adapter, 0x71, &adapter->eepromData[1], 0, SINGLE_BYTE); + + if (adapter->eepromData[0] != 0xcd) { + adapter->eepromData[1] = 0x00; // Disable all optional features + } + + /* Let's set up the PORT LOGIC Register. First we need to know what + * the max_payload_size is + */ + result = pci_read_config_byte(pdev, ET1310_PCI_MAX_PYLD, &maxPayload); + if (result != PCIBIOS_SUCCESSFUL) { + DBG_ERROR(et131x_dbginfo, "Could not read PCI config space for " + "Max Payload Size\n"); + DBG_LEAVE(et131x_dbginfo); + return -EIO; + } + + /* Program the Ack/Nak latency and replay timers */ + maxPayload &= 0x07; // Only the lower 3 bits are valid + + if (maxPayload < 2) { + const uint16_t AckNak[2] = { 0x76, 0xD0 }; + const uint16_t Replay[2] = { 0x1E0, 0x2ED }; + + result = pci_write_config_word(pdev, ET1310_PCI_ACK_NACK, + AckNak[maxPayload]); + if (result != PCIBIOS_SUCCESSFUL) { + DBG_ERROR(et131x_dbginfo, + "Could not write PCI config space " + "for ACK/NAK\n"); + DBG_LEAVE(et131x_dbginfo); + return -EIO; + } + + result = pci_write_config_word(pdev, ET1310_PCI_REPLAY, + Replay[maxPayload]); + if (result != PCIBIOS_SUCCESSFUL) { + DBG_ERROR(et131x_dbginfo, + "Could not write PCI config space " + "for Replay Timer\n"); + DBG_LEAVE(et131x_dbginfo); + return -EIO; + } + } + + /* l0s and l1 latency timers. We are using default values. + * Representing 001 for L0s and 010 for L1 + */ + result = pci_write_config_byte(pdev, ET1310_PCI_L0L1LATENCY, 0x11); + if (result != PCIBIOS_SUCCESSFUL) { + DBG_ERROR(et131x_dbginfo, + "Could not write PCI config space for " + "Latency Timers\n"); + DBG_LEAVE(et131x_dbginfo); + return -EIO; + } + + /* Change the max read size to 2k */ + result = pci_read_config_byte(pdev, 0x51, &read_size_reg); + if (result != PCIBIOS_SUCCESSFUL) { + DBG_ERROR(et131x_dbginfo, + "Could not read PCI config space for Max read size\n"); + DBG_LEAVE(et131x_dbginfo); + return -EIO; + } + + read_size_reg &= 0x8f; + read_size_reg |= 0x40; + + result = pci_write_config_byte(pdev, 0x51, read_size_reg); + if (result != PCIBIOS_SUCCESSFUL) { + DBG_ERROR(et131x_dbginfo, + "Could not write PCI config space for Max read size\n"); + DBG_LEAVE(et131x_dbginfo); + return -EIO; + } + + /* PCI Express Configuration registers 0x48-0x5B (Device Control) */ + result = pci_read_config_word(pdev, ET1310_PCI_DEV_CTRL, + &adapter->PciXDevCtl); + if (result != PCIBIOS_SUCCESSFUL) { + DBG_ERROR(et131x_dbginfo, + "Could not read PCI config space for PCI Express Dev Ctl\n"); + DBG_LEAVE(et131x_dbginfo); + return -EIO; + } + + /* Get MAC address from config space if an eeprom exists, otherwise + * the MAC address there will not be valid + */ + if (adapter->bEepromPresent) { + int i; + + for (i = 0; i < ETH_ALEN; i++) { + result = pci_read_config_byte( + pdev, ET1310_PCI_MAC_ADDRESS + i, + adapter->PermanentAddress + i); + if (result != PCIBIOS_SUCCESSFUL) { + DBG_ERROR(et131x_dbginfo, + "Could not read PCI config space for MAC address\n"); + DBG_LEAVE(et131x_dbginfo); + return -EIO; + } + } + } + + DBG_LEAVE(et131x_dbginfo); + return 0; +} + +/** + * et131x_error_timer_handler + * @data: timer-specific variable; here a pointer to our adapter structure + * + * The routine called when the error timer expires, to track the number of + * recurring errors. + */ +void et131x_error_timer_handler(unsigned long data) +{ + struct et131x_adapter *pAdapter = (struct et131x_adapter *) data; + PM_CSR_t pm_csr; + + pm_csr.value = readl(&pAdapter->CSRAddress->global.pm_csr.value); + + if (pm_csr.bits.pm_phy_sw_coma == 0) { + if (pAdapter->RegistryMACStat) { + UpdateMacStatHostCounters(pAdapter); + } + } else { + DBG_VERBOSE(et131x_dbginfo, + "No interrupts, in PHY coma, pm_csr = 0x%x\n", + pm_csr.value); + } + + if (!pAdapter->Bmsr.bits.link_status && + pAdapter->RegistryPhyComa && + pAdapter->PoMgmt.TransPhyComaModeOnBoot < 11) { + pAdapter->PoMgmt.TransPhyComaModeOnBoot++; + } + + if (pAdapter->PoMgmt.TransPhyComaModeOnBoot == 10) { + if (!pAdapter->Bmsr.bits.link_status + && pAdapter->RegistryPhyComa) { + if (pm_csr.bits.pm_phy_sw_coma == 0) { + // NOTE - This was originally a 'sync with interrupt'. How + // to do that under Linux? + et131x_enable_interrupts(pAdapter); + EnablePhyComa(pAdapter); + } + } + } + + /* This is a periodic timer, so reschedule */ + mod_timer(&pAdapter->ErrorTimer, jiffies + + TX_ERROR_PERIOD * HZ / 1000); +} + +/** + * et131x_link_detection_handler + * + * Timer function for link up at driver load time + */ +void et131x_link_detection_handler(unsigned long data) +{ + struct et131x_adapter *pAdapter = (struct et131x_adapter *) data; + unsigned long lockflags; + + /* Let everyone know that we have run */ + pAdapter->bLinkTimerActive = false; + + if (pAdapter->MediaState == 0) { + spin_lock_irqsave(&pAdapter->Lock, lockflags); + + pAdapter->MediaState = NETIF_STATUS_MEDIA_DISCONNECT; + MP_CLEAR_FLAG(pAdapter, fMP_ADAPTER_LINK_DETECTION); + + spin_unlock_irqrestore(&pAdapter->Lock, lockflags); + + netif_carrier_off(pAdapter->netdev); + + pAdapter->bSetPending = false; + } +} + +/** + * et131x_adapter_setup - Set the adapter up as per cassini+ documentation + * @adapter: pointer to our private adapter structure + * + * Returns 0 on success, errno on failure (as defined in errno.h) + */ +int et131x_adapter_setup(struct et131x_adapter *pAdapter) +{ + int status = 0; + + DBG_ENTER(et131x_dbginfo); + + /* Configure the JAGCore */ + ConfigGlobalRegs(pAdapter); + + ConfigMACRegs1(pAdapter); + ConfigMMCRegs(pAdapter); + + ConfigRxMacRegs(pAdapter); + ConfigTxMacRegs(pAdapter); + + ConfigRxDmaRegs(pAdapter); + ConfigTxDmaRegs(pAdapter); + + ConfigMacStatRegs(pAdapter); + + /* Move the following code to Timer function?? */ + status = et131x_xcvr_find(pAdapter); + + if (status != 0) { + DBG_WARNING(et131x_dbginfo, "Could not find the xcvr\n"); + } + + /* Prepare the TRUEPHY library. */ + ET1310_PhyInit(pAdapter); + + /* Reset the phy now so changes take place */ + ET1310_PhyReset(pAdapter); + + /* Power down PHY */ + ET1310_PhyPowerDown(pAdapter, 1); + + /* + * We need to turn off 1000 base half dulplex, the mac does not + * support it. For the 10/100 part, turn off all gig advertisement + */ + if (pAdapter->DeviceID != ET131X_PCI_DEVICE_ID_FAST) { + ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_FULL); + } else { + ET1310_PhyAdvertise1000BaseT(pAdapter, TRUEPHY_ADV_DUPLEX_NONE); + } + + /* Power up PHY */ + ET1310_PhyPowerDown(pAdapter, 0); + + et131x_setphy_normal(pAdapter); + + DBG_LEAVE(et131x_dbginfo); + return status; +} + +/** + * et131x_setup_hardware_properties - set up the MAC Address on the ET1310 + * @adapter: pointer to our private adapter structure + */ +void et131x_setup_hardware_properties(struct et131x_adapter *adapter) +{ + DBG_ENTER(et131x_dbginfo); + + /* If have our default mac from registry and no mac address from + * EEPROM then we need to generate the last octet and set it on the + * device + */ + if (!adapter->bOverrideAddress) { + if (adapter->PermanentAddress[0] == 0x00 && + adapter->PermanentAddress[1] == 0x00 && + adapter->PermanentAddress[2] == 0x00 && + adapter->PermanentAddress[3] == 0x00 && + adapter->PermanentAddress[4] == 0x00 && + adapter->PermanentAddress[5] == 0x00) { + /* + * We need to randomly generate the last octet so we + * decrease our chances of setting the mac address to + * same as another one of our cards in the system + */ + get_random_bytes(&adapter->CurrentAddress[5], 1); + + /* + * We have the default value in the register we are + * working with so we need to copy the current + * address into the permanent address + */ + memcpy(adapter->PermanentAddress, + adapter->CurrentAddress, ETH_ALEN); + } else { + /* We do not have an override address, so set the + * current address to the permanent address and add + * it to the device + */ + memcpy(adapter->CurrentAddress, + adapter->PermanentAddress, ETH_ALEN); + } + } + + DBG_LEAVE(et131x_dbginfo); +} + +/** + * et131x_soft_reset - Issue a soft reset to the hardware, complete for ET1310 + * @adapter: pointer to our private adapter structure + */ +void et131x_soft_reset(struct et131x_adapter *adapter) +{ + DBG_ENTER(et131x_dbginfo); + + /* Disable MAC Core */ + writel(0xc00f0000, &adapter->CSRAddress->mac.cfg1.value); + + /* Set everything to a reset value */ + writel(0x7F, &adapter->CSRAddress->global.sw_reset.value); + writel(0x000f0000, &adapter->CSRAddress->mac.cfg1.value); + writel(0x00000000, &adapter->CSRAddress->mac.cfg1.value); + + DBG_LEAVE(et131x_dbginfo); +} + +/** + * et131x_align_allocated_memory - Align allocated memory on a given boundary + * @adapter: pointer to our adapter structure + * @phys_addr: pointer to Physical address + * @offset: pointer to the offset variable + * @mask: correct mask + */ +void et131x_align_allocated_memory(struct et131x_adapter *adapter, + uint64_t *phys_addr, + uint64_t *offset, uint64_t mask) +{ + uint64_t new_addr; + + DBG_ENTER(et131x_dbginfo); + + *offset = 0; + + new_addr = *phys_addr & ~mask; + + if (new_addr != *phys_addr) { + /* Move to next aligned block */ + new_addr += mask + 1; + /* Return offset for adjusting virt addr */ + *offset = new_addr - *phys_addr; + /* Return new physical address */ + *phys_addr = new_addr; + } + + DBG_LEAVE(et131x_dbginfo); +} + +/** + * et131x_adapter_memory_alloc + * @adapter: pointer to our private adapter structure + * + * Returns 0 on success, errno on failure (as defined in errno.h). + * + * Allocate all the memory blocks for send, receive and others. + */ +int et131x_adapter_memory_alloc(struct et131x_adapter *adapter) +{ + int status = 0; + + DBG_ENTER(et131x_dbginfo); + + do { + /* Allocate memory for the Tx Ring */ + status = et131x_tx_dma_memory_alloc(adapter); + if (status != 0) { + DBG_ERROR(et131x_dbginfo, + "et131x_tx_dma_memory_alloc FAILED\n"); + break; + } + + /* Receive buffer memory allocation */ + status = et131x_rx_dma_memory_alloc(adapter); + if (status != 0) { + DBG_ERROR(et131x_dbginfo, + "et131x_rx_dma_memory_alloc FAILED\n"); + et131x_tx_dma_memory_free(adapter); + break; + } + + /* Init receive data structures */ + status = et131x_init_recv(adapter); + if (status != 0) { + DBG_ERROR(et131x_dbginfo, "et131x_init_recv FAILED\n"); + et131x_tx_dma_memory_free(adapter); + et131x_rx_dma_memory_free(adapter); + break; + } + } while (0); + + DBG_LEAVE(et131x_dbginfo); + return status; +} + +/** + * et131x_adapter_memory_free - Free all memory allocated for use by Tx & Rx + * @adapter: pointer to our private adapter structure + */ +void et131x_adapter_memory_free(struct et131x_adapter *adapter) +{ + DBG_ENTER(et131x_dbginfo); + + /* Free DMA memory */ + et131x_tx_dma_memory_free(adapter); + et131x_rx_dma_memory_free(adapter); + + DBG_LEAVE(et131x_dbginfo); +} + +/** + * et131x_pci_remove + * @pdev: a pointer to the device's pci_dev structure + * + * Registered in the pci_driver structure, this function is called when the + * PCI subsystem detects that a PCI device which matches the information + * contained in the pci_device_id table has been removed. + */ +void __devexit et131x_pci_remove(struct pci_dev *pdev) +{ + struct net_device *netdev; + struct et131x_adapter *adapter; + + DBG_ENTER(et131x_dbginfo); + + /* Retrieve the net_device pointer from the pci_dev struct, as well + * as the private adapter struct + */ + netdev = (struct net_device *) pci_get_drvdata(pdev); + adapter = netdev_priv(netdev); + + /* Perform device cleanup */ + unregister_netdev(netdev); + et131x_adapter_memory_free(adapter); + iounmap(adapter->CSRAddress); + free_netdev(netdev); + pci_release_regions(pdev); + pci_disable_device(pdev); + + DBG_LEAVE(et131x_dbginfo); +} + +/** + * et131x_pci_setup - Perform device initialization + * @pdev: a pointer to the device's pci_dev structure + * @ent: this device's entry in the pci_device_id table + * + * Returns 0 on success, errno on failure (as defined in errno.h) + * + * Registered in the pci_driver structure, this function is called when the + * PCI subsystem finds a new PCI device which matches the information + * contained in the pci_device_id table. This routine is the equivalent to + * a device insertion routine. + */ +int __devinit et131x_pci_setup(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int result = 0; + int pm_cap; + bool pci_using_dac; + struct net_device *netdev = NULL; + struct et131x_adapter *adapter = NULL; + + DBG_ENTER(et131x_dbginfo); + + /* Enable the device via the PCI subsystem */ + result = pci_enable_device(pdev); + if (result != 0) { + DBG_ERROR(et131x_dbginfo, "pci_enable_device() failed\n"); + goto out; + } + + /* Perform some basic PCI checks */ + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { + DBG_ERROR(et131x_dbginfo, + "Can't find PCI device's base address\n"); + result = -ENODEV; + goto out; + } + + result = pci_request_regions(pdev, DRIVER_NAME); + if (result != 0) { + DBG_ERROR(et131x_dbginfo, "Can't get PCI resources\n"); + goto err_disable; + } + + /* Enable PCI bus mastering */ + DBG_TRACE(et131x_dbginfo, "Setting PCI Bus Mastering...\n"); + pci_set_master(pdev); + + /* Query PCI for Power Mgmt Capabilities + * + * NOTE: Now reading PowerMgmt in another location; is this still + * needed? + */ + pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); + if (pm_cap == 0) { + DBG_ERROR(et131x_dbginfo, + "Cannot find Power Management capabilities\n"); + result = -EIO; + goto err_release_res; + } + + /* Check the DMA addressing support of this device */ + if (!pci_set_dma_mask(pdev, 0xffffffffffffffffULL)) { + DBG_TRACE(et131x_dbginfo, "64-bit DMA addressing supported\n"); + pci_using_dac = true; + + result = + pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL); + if (result != 0) { + DBG_ERROR(et131x_dbginfo, + "Unable to obtain 64 bit DMA for consistent allocations\n"); + goto err_release_res; + } + } else if (!pci_set_dma_mask(pdev, 0xffffffffULL)) { + DBG_TRACE(et131x_dbginfo, + "64-bit DMA addressing NOT supported\n"); + DBG_TRACE(et131x_dbginfo, + "32-bit DMA addressing will be used\n"); + pci_using_dac = false; + } else { + DBG_ERROR(et131x_dbginfo, "No usable DMA addressing method\n"); + result = -EIO; + goto err_release_res; + } + + /* Allocate netdev and private adapter structs */ + DBG_TRACE(et131x_dbginfo, + "Allocate netdev and private adapter structs...\n"); + netdev = et131x_device_alloc(); + if (netdev == NULL) { + DBG_ERROR(et131x_dbginfo, "Couldn't alloc netdev struct\n"); + result = -ENOMEM; + goto err_release_res; + } + + /* Setup the fundamental net_device and private adapter structure elements */ + DBG_TRACE(et131x_dbginfo, "Setting fundamental net_device info...\n"); + SET_NETDEV_DEV(netdev, &pdev->dev); + if (pci_using_dac) { + //netdev->features |= NETIF_F_HIGHDMA; + } + + /* + * NOTE - Turn this on when we're ready to deal with SG-DMA + * + * NOTE: According to "Linux Device Drivers", 3rd ed, Rubini et al, + * if checksumming is not performed in HW, then the kernel will not + * use SG. + * From pp 510-511: + * + * "Note that the kernel does not perform scatter/gather I/O to your + * device if it does not also provide some form of checksumming as + * well. The reason is that, if the kernel has to make a pass over a + * fragmented ("nonlinear") packet to calculate the checksum, it + * might as well copy the data and coalesce the packet at the same + * time." + * + * This has been verified by setting the flags below and still not + * receiving a scattered buffer from the network stack, so leave it + * off until checksums are calculated in HW. + */ + //netdev->features |= NETIF_F_SG; + //netdev->features |= NETIF_F_NO_CSUM; + //netdev->features |= NETIF_F_LLTX; + + /* Allocate private adapter struct and copy in relevant information */ + adapter = netdev_priv(netdev); + adapter->pdev = pdev; + adapter->netdev = netdev; + adapter->VendorID = pdev->vendor; + adapter->DeviceID = pdev->device; + + /* Do the same for the netdev struct */ + netdev->irq = pdev->irq; + netdev->base_addr = pdev->resource[0].start; + + /* Initialize spinlocks here */ + DBG_TRACE(et131x_dbginfo, "Initialize spinlocks...\n"); + + spin_lock_init(&adapter->Lock); + spin_lock_init(&adapter->TCBSendQLock); + spin_lock_init(&adapter->TCBReadyQLock); + spin_lock_init(&adapter->SendHWLock); + spin_lock_init(&adapter->SendWaitLock); + spin_lock_init(&adapter->RcvLock); + spin_lock_init(&adapter->RcvPendLock); + spin_lock_init(&adapter->FbrLock); + spin_lock_init(&adapter->PHYLock); + + /* Parse configuration parameters into the private adapter struct */ + et131x_config_parse(adapter); + + /* Find the physical adapter + * + * NOTE: This is the equivalent of the MpFindAdapter() routine; can we + * lump it's init with the device specific init below into a + * single init function? + */ + //while (et131x_find_adapter(adapter, pdev) != 0); + et131x_find_adapter(adapter, pdev); + + /* Map the bus-relative registers to system virtual memory */ + DBG_TRACE(et131x_dbginfo, + "Mapping bus-relative registers to virtual memory...\n"); + + adapter->CSRAddress = ioremap_nocache(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (adapter->CSRAddress == NULL) { + DBG_ERROR(et131x_dbginfo, "Cannot map device registers\n"); + result = -ENOMEM; + goto err_free_dev; + } + + /* Perform device-specific initialization here (See code below) */ + + /* If Phy COMA mode was enabled when we went down, disable it here. */ + { + PM_CSR_t GlobalPmCSR = { 0 }; + + GlobalPmCSR.bits.pm_sysclk_gate = 1; + GlobalPmCSR.bits.pm_txclk_gate = 1; + GlobalPmCSR.bits.pm_rxclk_gate = 1; + writel(GlobalPmCSR.value, + &adapter->CSRAddress->global.pm_csr.value); + } + + /* Issue a global reset to the et1310 */ + DBG_TRACE(et131x_dbginfo, "Issuing soft reset...\n"); + et131x_soft_reset(adapter); + + /* Disable all interrupts (paranoid) */ + DBG_TRACE(et131x_dbginfo, "Disable device interrupts...\n"); + et131x_disable_interrupts(adapter); + + /* Allocate DMA memory */ + result = et131x_adapter_memory_alloc(adapter); + if (result != 0) { + DBG_ERROR(et131x_dbginfo, + "Could not alloc adapater memory (DMA)\n"); + goto err_iounmap; + } + + /* Init send data structures */ + DBG_TRACE(et131x_dbginfo, "Init send data structures...\n"); + et131x_init_send(adapter); + + adapter->PoMgmt.PowerState = NdisDeviceStateD0; + + /* Register the interrupt + * + * NOTE - This is being done in the open routine, where most other + * Linux drivers setup IRQ handlers. Make sure device + * interrupts are not turned on before the IRQ is registered!! + * + * What we will do here is setup the task structure for the + * ISR's deferred handler + */ + INIT_WORK(&adapter->task, et131x_isr_handler); + + /* Determine MAC Address, and copy into the net_device struct */ + DBG_TRACE(et131x_dbginfo, "Retrieve MAC address...\n"); + et131x_setup_hardware_properties(adapter); + + memcpy(netdev->dev_addr, adapter->CurrentAddress, ETH_ALEN); + + /* Setup et1310 as per the documentation */ + DBG_TRACE(et131x_dbginfo, "Setup the adapter...\n"); + et131x_adapter_setup(adapter); + + /* Create a timer to count errors received by the NIC */ + init_timer(&adapter->ErrorTimer); + + adapter->ErrorTimer.expires = jiffies + TX_ERROR_PERIOD * HZ / 1000; + adapter->ErrorTimer.function = et131x_error_timer_handler; + adapter->ErrorTimer.data = (unsigned long)adapter; + + /* Initialize link state */ + et131x_link_detection_handler((unsigned long)adapter); + + /* Intialize variable for counting how long we do not have link status */ + adapter->PoMgmt.TransPhyComaModeOnBoot = 0; + + /* We can enable interrupts now + * + * NOTE - Because registration of interrupt handler is done in the + * device's open(), defer enabling device interrupts to that + * point + */ + + /* Register the net_device struct with the Linux network layer */ + DBG_TRACE(et131x_dbginfo, "Registering net_device...\n"); + if ((result = register_netdev(netdev)) != 0) { + DBG_ERROR(et131x_dbginfo, "register_netdev() failed\n"); + goto err_mem_free; + } + + /* Register the net_device struct with the PCI subsystem. Save a copy + * of the PCI config space for this device now that the device has + * been initialized, just in case it needs to be quickly restored. + */ + pci_set_drvdata(pdev, netdev); + + pci_save_state(adapter->pdev); + +out: + DBG_LEAVE(et131x_dbginfo); + return result; + +err_mem_free: + et131x_adapter_memory_free(adapter); +err_iounmap: + iounmap(adapter->CSRAddress); +err_free_dev: + free_netdev(netdev); +err_release_res: + pci_release_regions(pdev); +err_disable: + pci_disable_device(pdev); + goto out; +} diff --git a/src/et131x/et131x_initpci.h b/src/et131x/et131x_initpci.h new file mode 100644 index 0000000..bbacb62 --- /dev/null +++ b/src/et131x/et131x_initpci.h @@ -0,0 +1,73 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_initpci.h - Header which includes common data and function prototypes + * related to the driver's PCI (and PCI Express) information. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#ifndef __ET131X_INITPCI_H__ +#define __ET131X_INITPCI_H__ + +/* Function Prototypes */ +void et131x_align_allocated_memory(struct et131x_adapter *adapter, + u64 *phys_addr, + u64 *offset, u64 mask); + +int et131x_adapter_setup(struct et131x_adapter *adapter); +int et131x_adapter_memory_alloc(struct et131x_adapter *adapter); +void et131x_adapter_memory_free(struct et131x_adapter *adapter); +void et131x_setup_hardware_properties(struct et131x_adapter *adapter); +void et131x_soft_reset(struct et131x_adapter *adapter); + +#endif /* __ET131X_INITPCI_H__ */ diff --git a/src/et131x/et131x_isr.c b/src/et131x/et131x_isr.c new file mode 100644 index 0000000..00afad1 --- /dev/null +++ b/src/et131x/et131x_isr.c @@ -0,0 +1,488 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_isr.c - File which contains the ISR, ISR handler, and related routines + * for processing interrupts from the device. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#include "et131x_version.h" +#include "et131x_debug.h" +#include "et131x_defs.h" + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> + +#include <linux/sched.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/ctype.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/in.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/bitops.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/if_arp.h> +#include <linux/ioport.h> + +#include "et1310_phy.h" +#include "et1310_pm.h" +#include "et1310_jagcore.h" +#include "et1310_mac.h" + +#include "et131x_adapter.h" + +/* Data for debugging facilities */ +#ifdef CONFIG_ET131X_DEBUG +extern dbg_info_t *et131x_dbginfo; +#endif /* CONFIG_ET131X_DEBUG */ + +/** + * et131x_isr - The Interrupt Service Routine for the driver. + * @irq: the IRQ on which the interrupt was received. + * @dev_id: device-specific info (here a pointer to a net_device struct) + * + * Returns a value indicating if the interrupt was handled. + */ +irqreturn_t et131x_isr(int irq, void *dev_id) +{ + bool handled = true; + struct net_device *netdev = (struct net_device *)dev_id; + struct et131x_adapter *adapter = NULL; + INTERRUPT_t status; + + if (netdev == NULL || !netif_device_present(netdev)) { + DBG_WARNING(et131x_dbginfo, + "No net_device struct or device not present\n"); + handled = false; + goto out; + } + + adapter = netdev_priv(netdev); + + /* If the adapter is in low power state, then it should not + * recognize any interrupt + */ + + /* Disable Device Interrupts */ + et131x_disable_interrupts(adapter); + + /* Get a copy of the value in the interrupt status register + * so we can process the interrupting section + */ + status.value = readl(&adapter->CSRAddress->global.int_status.value); + + if (adapter->FlowControl == TxOnly || + adapter->FlowControl == Both) { + status.value &= ~INT_MASK_ENABLE; + } else { + status.value &= ~INT_MASK_ENABLE_NO_FLOW; + } + + /* Make sure this is our interrupt */ + if (!status.value) { +#ifdef CONFIG_ET131X_DEBUG + adapter->Stats.UnhandledInterruptsPerSec++; +#endif + handled = false; + DBG_VERBOSE(et131x_dbginfo, "NOT OUR INTERRUPT\n"); + et131x_enable_interrupts(adapter); + goto out; + } + + /* This is our interrupt, so process accordingly */ +#ifdef CONFIG_ET131X_DEBUG + if (status.bits.rxdma_xfr_done) { + adapter->Stats.RxDmaInterruptsPerSec++; + } + + if (status.bits.txdma_isr) { + adapter->Stats.TxDmaInterruptsPerSec++; + } +#endif + + if (status.bits.watchdog_interrupt) { + PMP_TCB pMpTcb = adapter->TxRing.CurrSendHead; + + if (pMpTcb) { + if (++pMpTcb->PacketStaleCount > 1) { + status.bits.txdma_isr = 1; + } + } + + if (adapter->RxRing.UnfinishedReceives) { + status.bits.rxdma_xfr_done = 1; + } else if (pMpTcb == NULL) { + writel(0, &adapter->CSRAddress->global.watchdog_timer); + } + + status.bits.watchdog_interrupt = 0; +#ifdef CONFIG_ET131X_DEBUG + adapter->Stats.WatchDogInterruptsPerSec++; +#endif + } + + if (status.value == 0) { + /* This interrupt has in some way been "handled" by + * the ISR. Either it was a spurious Rx interrupt, or + * it was a Tx interrupt that has been filtered by + * the ISR. + */ + et131x_enable_interrupts(adapter); + goto out; + } + + /* We need to save the interrupt status value for use in our + * DPC. We will clear the software copy of that in that + * routine. + */ + adapter->Stats.InterruptStatus = status; + + /* Schedule the ISR handler as a bottom-half task in the + * kernel's tq_immediate queue, and mark the queue for + * execution + */ + schedule_work(&adapter->task); + +out: + return IRQ_RETVAL(handled); +} + +/** + * et131x_isr_handler - The ISR handler + * @p_adapter, a pointer to the device's private adapter structure + * + * scheduled to run in a deferred context by the ISR. This is where the ISR's + * work actually gets done. + */ +void et131x_isr_handler(struct work_struct *work) +{ + struct et131x_adapter *pAdapter = + container_of(work, struct et131x_adapter, task); + INTERRUPT_t GlobStatus = pAdapter->Stats.InterruptStatus; + ADDRESS_MAP_t __iomem *iomem = pAdapter->CSRAddress; + + /* + * These first two are by far the most common. Once handled, we clear + * their two bits in the status word. If the word is now zero, we + * exit. + */ + /* Handle all the completed Transmit interrupts */ + if (GlobStatus.bits.txdma_isr) { + DBG_TX(et131x_dbginfo, "TXDMA_ISR interrupt\n"); + et131x_handle_send_interrupt(pAdapter); + } + + /* Handle all the completed Receives interrupts */ + if (GlobStatus.bits.rxdma_xfr_done) { + DBG_RX(et131x_dbginfo, "RXDMA_XFR_DONE interrupt\n"); + et131x_handle_recv_interrupt(pAdapter); + } + + GlobStatus.value &= 0xffffffd7; + + if (GlobStatus.value) { + /* Handle the TXDMA Error interrupt */ + if (GlobStatus.bits.txdma_err) { + TXDMA_ERROR_t TxDmaErr; + + /* Following read also clears the register (COR) */ + TxDmaErr.value = readl(&iomem->txdma.TxDmaError.value); + + DBG_WARNING(et131x_dbginfo, + "TXDMA_ERR interrupt, error = %d\n", + TxDmaErr.value); + } + + /* Handle Free Buffer Ring 0 and 1 Low interrupt */ + if (GlobStatus.bits.rxdma_fb_ring0_low || + GlobStatus.bits.rxdma_fb_ring1_low) { + /* + * This indicates the number of unused buffers in + * RXDMA free buffer ring 0 is <= the limit you + * programmed. Free buffer resources need to be + * returned. Free buffers are consumed as packets + * are passed from the network to the host. The host + * becomes aware of the packets from the contents of + * the packet status ring. This ring is queried when + * the packet done interrupt occurs. Packets are then + * passed to the OS. When the OS is done with the + * packets the resources can be returned to the + * ET1310 for re-use. This interrupt is one method of + * returning resources. + */ + DBG_WARNING(et131x_dbginfo, + "RXDMA_FB_RING0_LOW or " + "RXDMA_FB_RING1_LOW interrupt\n"); + + /* If the user has flow control on, then we will + * send a pause packet, otherwise just exit + */ + if (pAdapter->FlowControl == TxOnly || + pAdapter->FlowControl == Both) { + PM_CSR_t pm_csr; + + /* Tell the device to send a pause packet via + * the back pressure register + */ + pm_csr.value = readl(&iomem->global.pm_csr.value); + if (pm_csr.bits.pm_phy_sw_coma == 0) { + TXMAC_BP_CTRL_t bp_ctrl = { 0 }; + + bp_ctrl.bits.bp_req = 1; + bp_ctrl.bits.bp_xonxoff = 1; + writel(bp_ctrl.value, + &iomem->txmac.bp_ctrl.value); + } + } + } + + /* Handle Packet Status Ring Low Interrupt */ + if (GlobStatus.bits.rxdma_pkt_stat_ring_low) { + DBG_WARNING(et131x_dbginfo, + "RXDMA_PKT_STAT_RING_LOW interrupt\n"); + + /* + * Same idea as with the two Free Buffer Rings. + * Packets going from the network to the host each + * consume a free buffer resource and a packet status + * resource. These resoures are passed to the OS. + * When the OS is done with the resources, they need + * to be returned to the ET1310. This is one method + * of returning the resources. + */ + } + + /* Handle RXDMA Error Interrupt */ + if (GlobStatus.bits.rxdma_err) { + /* + * The rxdma_error interrupt is sent when a time-out + * on a request issued by the JAGCore has occurred or + * a completion is returned with an un-successful + * status. In both cases the request is considered + * complete. The JAGCore will automatically re-try the + * request in question. Normally information on events + * like these are sent to the host using the "Advanced + * Error Reporting" capability. This interrupt is + * another way of getting similar information. The + * only thing required is to clear the interrupt by + * reading the ISR in the global resources. The + * JAGCore will do a re-try on the request. Normally + * you should never see this interrupt. If you start + * to see this interrupt occurring frequently then + * something bad has occurred. A reset might be the + * thing to do. + */ + // TRAP(); + + pAdapter->TxMacTest.value = + readl(&iomem->txmac.tx_test.value); + DBG_WARNING(et131x_dbginfo, + "RxDMA_ERR interrupt, error %x\n", + pAdapter->TxMacTest.value); + } + + /* Handle the Wake on LAN Event */ + if (GlobStatus.bits.wake_on_lan) { + /* + * This is a secondary interrupt for wake on LAN. + * The driver should never see this, if it does, + * something serious is wrong. We will TRAP the + * message when we are in DBG mode, otherwise we + * will ignore it. + */ + DBG_ERROR(et131x_dbginfo, "WAKE_ON_LAN interrupt\n"); + } + + /* Handle the PHY interrupt */ + if (GlobStatus.bits.phy_interrupt) { + PM_CSR_t pm_csr; + MI_BMSR_t BmsrInts, BmsrData; + MI_ISR_t myIsr; + + DBG_VERBOSE(et131x_dbginfo, "PHY interrupt\n"); + + /* If we are in coma mode when we get this interrupt, + * we need to disable it. + */ + pm_csr.value = readl(&iomem->global.pm_csr.value); + if (pm_csr.bits.pm_phy_sw_coma == 1) { + /* + * Check to see if we are in coma mode and if + * so, disable it because we will not be able + * to read PHY values until we are out. + */ + DBG_VERBOSE(et131x_dbginfo, + "Device is in COMA mode, " + "need to wake up\n"); + DisablePhyComa(pAdapter); + } + + /* Read the PHY ISR to clear the reason for the + * interrupt. + */ + MiRead(pAdapter, (uint8_t) offsetof(MI_REGS_t, isr), + &myIsr.value); + + if (!pAdapter->ReplicaPhyLoopbk) { + MiRead(pAdapter, + (uint8_t) offsetof(MI_REGS_t, bmsr), + &BmsrData.value); + + BmsrInts.value = + pAdapter->Bmsr.value ^ BmsrData.value; + pAdapter->Bmsr.value = BmsrData.value; + + DBG_VERBOSE(et131x_dbginfo, + "Bmsr.value = 0x%04x," + "Bmsr_ints.value = 0x%04x\n", + BmsrData.value, BmsrInts.value); + + /* Do all the cable in / cable out stuff */ + et131x_Mii_check(pAdapter, BmsrData, BmsrInts); + } + } + + /* Let's move on to the TxMac */ + if (GlobStatus.bits.txmac_interrupt) { + pAdapter->TxRing.TxMacErr.value = + readl(&iomem->txmac.err.value); + + /* + * When any of the errors occur and TXMAC generates + * an interrupt to report these errors, it usually + * means that TXMAC has detected an error in the data + * stream retrieved from the on-chip Tx Q. All of + * these errors are catastrophic and TXMAC won't be + * able to recover data when these errors occur. In + * a nutshell, the whole Tx path will have to be reset + * and re-configured afterwards. + */ + DBG_WARNING(et131x_dbginfo, + "TXMAC interrupt, error 0x%08x\n", + pAdapter->TxRing.TxMacErr.value); + + /* If we are debugging, we want to see this error, + * otherwise we just want the device to be reset and + * continue + */ + //DBG_TRAP(); + } + + /* Handle RXMAC Interrupt */ + if (GlobStatus.bits.rxmac_interrupt) { + /* + * These interrupts are catastrophic to the device, + * what we need to do is disable the interrupts and + * set the flag to cause us to reset so we can solve + * this issue. + */ + // MP_SET_FLAG( pAdapter, fMP_ADAPTER_HARDWARE_ERROR ); + + DBG_WARNING(et131x_dbginfo, + "RXMAC interrupt, error 0x%08x. Requesting reset\n", + readl(&iomem->rxmac.err_reg.value)); + + DBG_WARNING(et131x_dbginfo, + "Enable 0x%08x, Diag 0x%08x\n", + readl(&iomem->rxmac.ctrl.value), + readl(&iomem->rxmac.rxq_diag.value)); + + /* + * If we are debugging, we want to see this error, + * otherwise we just want the device to be reset and + * continue + */ + // TRAP(); + } + + /* Handle MAC_STAT Interrupt */ + if (GlobStatus.bits.mac_stat_interrupt) { + /* + * This means at least one of the un-masked counters + * in the MAC_STAT block has rolled over. Use this + * to maintain the top, software managed bits of the + * counter(s). + */ + DBG_VERBOSE(et131x_dbginfo, "MAC_STAT interrupt\n"); + HandleMacStatInterrupt(pAdapter); + } + + /* Handle SLV Timeout Interrupt */ + if (GlobStatus.bits.slv_timeout) { + /* + * This means a timeout has occured on a read or + * write request to one of the JAGCore registers. The + * Global Resources block has terminated the request + * and on a read request, returned a "fake" value. + * The most likely reasons are: Bad Address or the + * addressed module is in a power-down state and + * can't respond. + */ + DBG_VERBOSE(et131x_dbginfo, "SLV_TIMEOUT interrupt\n"); + } + } + + if (pAdapter->PoMgmt.PowerState == NdisDeviceStateD0) { + et131x_enable_interrupts(pAdapter); + } +} diff --git a/src/et131x/et131x_isr.h b/src/et131x/et131x_isr.h new file mode 100644 index 0000000..76a51d5 --- /dev/null +++ b/src/et131x/et131x_isr.h @@ -0,0 +1,65 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_isr.h - Defines, structs, enums, prototypes, etc. pertaining to the + * ISR processing code. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#ifndef __ET131X_ISR_H__ +#define __ET131X_ISR_H__ + +irqreturn_t et131x_isr(int irq, void *dev_id); +void et131x_isr_handler(struct work_struct *work); + +#endif /* __ET131X_ISR_H__ */ diff --git a/src/et131x/et131x_netdev.c b/src/et131x/et131x_netdev.c new file mode 100644 index 0000000..de65972 --- /dev/null +++ b/src/et131x/et131x_netdev.c @@ -0,0 +1,856 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_netdev.c - Routines and data required by all Linux network devices. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#include "et131x_version.h" +#include "et131x_debug.h" +#include "et131x_defs.h" + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> + +#include <linux/sched.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/ctype.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/in.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/bitops.h> + +#include <linux/mii.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/if_arp.h> +#include <linux/ioport.h> + +#include "et1310_phy.h" +#include "et1310_pm.h" +#include "et1310_jagcore.h" +#include "et1310_mac.h" +#include "et1310_tx.h" + +#include "et131x_adapter.h" +#include "et131x_isr.h" +#include "et131x_initpci.h" + +/* Data for debugging facilities */ +#ifdef CONFIG_ET131X_DEBUG +extern dbg_info_t *et131x_dbginfo; +#endif /* CONFIG_ET131X_DEBUG */ + +struct net_device_stats *et131x_stats(struct net_device *netdev); +int et131x_open(struct net_device *netdev); +int et131x_close(struct net_device *netdev); +int et131x_ioctl(struct net_device *netdev, struct ifreq *reqbuf, int cmd); +void et131x_multicast(struct net_device *netdev); +int et131x_tx(struct sk_buff *skb, struct net_device *netdev); +void et131x_tx_timeout(struct net_device *netdev); +int et131x_change_mtu(struct net_device *netdev, int new_mtu); +int et131x_set_mac_addr(struct net_device *netdev, void *new_mac); +void et131x_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp); +void et131x_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid); +void et131x_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid); + +/** + * et131x_device_alloc + * + * Returns pointer to the allocated and initialized net_device struct for + * this device. + * + * Create instances of net_device and wl_private for the new adapter and + * register the device's entry points in the net_device structure. + */ +struct net_device *et131x_device_alloc(void) +{ + struct net_device *netdev; + + DBG_ENTER(et131x_dbginfo); + + /* Alloc net_device and adapter structs */ + netdev = alloc_etherdev(sizeof(struct et131x_adapter)); + + if (netdev == NULL) { + DBG_ERROR(et131x_dbginfo, + "Alloc of net_device struct failed\n"); + DBG_LEAVE(et131x_dbginfo); + return NULL; + } + + /* Setup the function registration table (and other data) for a + * net_device + */ + //netdev->init = &et131x_init; + //netdev->set_config = &et131x_config; + netdev->get_stats = &et131x_stats; + netdev->open = &et131x_open; + netdev->stop = &et131x_close; + netdev->do_ioctl = &et131x_ioctl; + netdev->set_multicast_list = &et131x_multicast; + netdev->hard_start_xmit = &et131x_tx; + netdev->tx_timeout = &et131x_tx_timeout; + netdev->watchdog_timeo = ET131X_TX_TIMEOUT; + netdev->change_mtu = &et131x_change_mtu; + netdev->set_mac_address = &et131x_set_mac_addr; + + //netdev->ethtool_ops = &et131x_ethtool_ops; + + // Poll? + //netdev->poll = &et131x_poll; + //netdev->poll_controller = &et131x_poll_controller; + + DBG_LEAVE(et131x_dbginfo); + return netdev; +} + +/** + * et131x_stats - Return the current device statistics. + * @netdev: device whose stats are being queried + * + * Returns 0 on success, errno on failure (as defined in errno.h) + */ +struct net_device_stats *et131x_stats(struct net_device *netdev) +{ + struct et131x_adapter *adapter = netdev_priv(netdev); + struct net_device_stats *stats = &adapter->net_stats; + CE_STATS_t *devstat = &adapter->Stats; + + DBG_ENTER(et131x_dbginfo); + + stats->rx_packets = devstat->ipackets; + stats->tx_packets = devstat->opackets; + stats->rx_errors = devstat->length_err + devstat->alignment_err + + devstat->crc_err + devstat->code_violations + devstat->other_errors; + stats->tx_errors = devstat->max_pkt_error; + stats->multicast = devstat->multircv; + stats->collisions = devstat->collisions; + + stats->rx_length_errors = devstat->length_err; + stats->rx_over_errors = devstat->rx_ov_flow; + stats->rx_crc_errors = devstat->crc_err; + + // NOTE: These stats don't have corresponding values in CE_STATS, so we're + // going to have to update these directly from within the TX/RX code + //stats->rx_bytes = 20; //devstat->; + //stats->tx_bytes = 20; //devstat->; + //stats->rx_dropped = devstat->; + //stats->tx_dropped = devstat->; + + // NOTE: Not used, can't find analogous statistics + //stats->rx_frame_errors = devstat->; + //stats->rx_fifo_errors = devstat->; + //stats->rx_missed_errors = devstat->; + + //stats->tx_aborted_errors = devstat->; + //stats->tx_carrier_errors = devstat->; + //stats->tx_fifo_errors = devstat->; + //stats->tx_heartbeat_errors = devstat->; + //stats->tx_window_errors = devstat->; + + DBG_LEAVE(et131x_dbginfo); + return stats; +} + +/** + * et131x_open - Open the device for use. + * @netdev: device to be opened + * + * Returns 0 on success, errno on failure (as defined in errno.h) + */ +int et131x_open(struct net_device *netdev) +{ + int result = 0; + struct et131x_adapter *adapter = netdev_priv(netdev); + + DBG_ENTER(et131x_dbginfo); + + /* Start the timer to track NIC errors */ + add_timer(&adapter->ErrorTimer); + + /* Register our ISR */ + DBG_TRACE(et131x_dbginfo, "Registering ISR...\n"); + + result = + request_irq(netdev->irq, et131x_isr, IRQF_SHARED, netdev->name, + netdev); + if (result) { + DBG_ERROR(et131x_dbginfo, "Could not register ISR\n"); + DBG_LEAVE(et131x_dbginfo); + return result; + } + + /* Enable the Tx and Rx DMA engines (if not already enabled) */ + et131x_rx_dma_enable(adapter); + et131x_tx_dma_enable(adapter); + + /* Enable device interrupts */ + et131x_enable_interrupts(adapter); + + MP_SET_FLAG(adapter, fMP_ADAPTER_INTERRUPT_IN_USE); + + /* We're ready to move some data, so start the queue */ + netif_start_queue(netdev); + + DBG_LEAVE(et131x_dbginfo); + return result; +} + +/** + * et131x_close - Close the device + * @netdev: device to be closed + * + * Returns 0 on success, errno on failure (as defined in errno.h) + */ +int et131x_close(struct net_device *netdev) +{ + struct et131x_adapter *adapter = netdev_priv(netdev); + + DBG_ENTER(et131x_dbginfo); + + /* First thing is to stop the queue */ + netif_stop_queue(netdev); + + /* Stop the Tx and Rx DMA engines */ + et131x_rx_dma_disable(adapter); + et131x_tx_dma_disable(adapter); + + /* Disable device interrupts */ + et131x_disable_interrupts(adapter); + + /* Deregistering ISR */ + MP_CLEAR_FLAG(adapter, fMP_ADAPTER_INTERRUPT_IN_USE); + + DBG_TRACE(et131x_dbginfo, "Deregistering ISR...\n"); + free_irq(netdev->irq, netdev); + + /* Stop the error timer */ + del_timer_sync(&adapter->ErrorTimer); + + DBG_LEAVE(et131x_dbginfo); + return 0; +} + +/** + * et131x_ioctl_mii - The function which handles MII IOCTLs + * @netdev: device on which the query is being made + * @reqbuf: the request-specific data buffer + * @cmd: the command request code + * + * Returns 0 on success, errno on failure (as defined in errno.h) + */ +int et131x_ioctl_mii(struct net_device *netdev, struct ifreq *reqbuf, int cmd) +{ + int status = 0; + struct et131x_adapter *pAdapter = netdev_priv(netdev); + struct mii_ioctl_data *data = if_mii(reqbuf); + + DBG_ENTER(et131x_dbginfo); + + switch (cmd) { + case SIOCGMIIPHY: + DBG_VERBOSE(et131x_dbginfo, "SIOCGMIIPHY\n"); + data->phy_id = pAdapter->Stats.xcvr_addr; + break; + + case SIOCGMIIREG: + DBG_VERBOSE(et131x_dbginfo, "SIOCGMIIREG\n"); + if (!capable(CAP_NET_ADMIN)) { + status = -EPERM; + } else { + status = MiRead(pAdapter, + data->reg_num, &data->val_out); + } + break; + + case SIOCSMIIREG: + DBG_VERBOSE(et131x_dbginfo, "SIOCSMIIREG\n"); + if (!capable(CAP_NET_ADMIN)) { + status = -EPERM; + } else { + status = MiWrite(pAdapter, data->reg_num, + data->val_in); + } + break; + + default: + status = -EOPNOTSUPP; + } + + DBG_LEAVE(et131x_dbginfo); + return status; +} + +/** + * et131x_ioctl - The I/O Control handler for the driver + * @netdev: device on which the control request is being made + * @reqbuf: a pointer to the IOCTL request buffer + * @cmd: the IOCTL command code + * + * Returns 0 on success, errno on failure (as defined in errno.h) + */ +int et131x_ioctl(struct net_device *netdev, struct ifreq *reqbuf, int cmd) +{ + int status = 0; + + DBG_ENTER(et131x_dbginfo); + + switch (cmd) { + case SIOCGMIIPHY: + case SIOCGMIIREG: + case SIOCSMIIREG: + status = et131x_ioctl_mii(netdev, reqbuf, cmd); + break; + + default: + DBG_WARNING(et131x_dbginfo, "Unhandled IOCTL Code: 0x%04x\n", + cmd); + status = -EOPNOTSUPP; + } + + DBG_LEAVE(et131x_dbginfo); + return status; +} + +/** + * et131x_set_packet_filter - Configures the Rx Packet filtering on the device + * @adapter: pointer to our private adapter structure + * + * Returns 0 on success, errno on failure + */ +int et131x_set_packet_filter(struct et131x_adapter *adapter) +{ + int status = 0; + uint32_t filter = adapter->PacketFilter; + RXMAC_CTRL_t ctrl; + RXMAC_PF_CTRL_t pf_ctrl; + + DBG_ENTER(et131x_dbginfo); + + ctrl.value = readl(&adapter->CSRAddress->rxmac.ctrl.value); + pf_ctrl.value = readl(&adapter->CSRAddress->rxmac.pf_ctrl.value); + + /* Default to disabled packet filtering. Enable it in the individual + * case statements that require the device to filter something + */ + ctrl.bits.pkt_filter_disable = 1; + + /* Set us to be in promiscuous mode so we receive everything, this + * is also true when we get a packet filter of 0 + */ + if ((filter & ET131X_PACKET_TYPE_PROMISCUOUS) || filter == 0) { + pf_ctrl.bits.filter_broad_en = 0; + pf_ctrl.bits.filter_multi_en = 0; + pf_ctrl.bits.filter_uni_en = 0; + } else { + /* + * Set us up with Multicast packet filtering. Three cases are + * possible - (1) we have a multi-cast list, (2) we receive ALL + * multicast entries or (3) we receive none. + */ + if (filter & ET131X_PACKET_TYPE_ALL_MULTICAST) { + DBG_VERBOSE(et131x_dbginfo, + "Multicast filtering OFF (Rx ALL MULTICAST)\n"); + pf_ctrl.bits.filter_multi_en = 0; + } else { + DBG_VERBOSE(et131x_dbginfo, "Multicast filtering ON\n"); + SetupDeviceForMulticast(adapter); + pf_ctrl.bits.filter_multi_en = 1; + ctrl.bits.pkt_filter_disable = 0; + } + + /* Set us up with Unicast packet filtering */ + if (filter & ET131X_PACKET_TYPE_DIRECTED) { + DBG_VERBOSE(et131x_dbginfo, "Unicast Filtering ON\n"); + SetupDeviceForUnicast(adapter); + pf_ctrl.bits.filter_uni_en = 1; + ctrl.bits.pkt_filter_disable = 0; + } + + /* Set us up with Broadcast packet filtering */ + if (filter & ET131X_PACKET_TYPE_BROADCAST) { + DBG_VERBOSE(et131x_dbginfo, "Broadcast Filtering ON\n"); + pf_ctrl.bits.filter_broad_en = 1; + ctrl.bits.pkt_filter_disable = 0; + } else { + DBG_VERBOSE(et131x_dbginfo, + "Broadcast Filtering OFF\n"); + pf_ctrl.bits.filter_broad_en = 0; + } + + /* Setup the receive mac configuration registers - Packet + * Filter control + the enable / disable for packet filter + * in the control reg. + */ + writel(pf_ctrl.value, + &adapter->CSRAddress->rxmac.pf_ctrl.value); + writel(ctrl.value, &adapter->CSRAddress->rxmac.ctrl.value); + } + + DBG_LEAVE(et131x_dbginfo); + return status; +} + +/** + * et131x_multicast - The handler to configure multicasting on the interface + * @netdev: a pointer to a net_device struct representing the device + */ +void et131x_multicast(struct net_device *netdev) +{ + struct et131x_adapter *adapter = netdev_priv(netdev); + uint32_t PacketFilter = 0; + uint32_t count; + unsigned long lockflags; + struct dev_mc_list *mclist = netdev->mc_list; + + DBG_ENTER(et131x_dbginfo); + + spin_lock_irqsave(&adapter->Lock, lockflags); + + /* Before we modify the platform-independent filter flags, store them + * locally. This allows us to determine if anything's changed and if + * we even need to bother the hardware + */ + PacketFilter = adapter->PacketFilter; + + /* Clear the 'multicast' flag locally; becuase we only have a single + * flag to check multicast, and multiple multicast addresses can be + * set, this is the easiest way to determine if more than one + * multicast address is being set. + */ + PacketFilter &= ~ET131X_PACKET_TYPE_MULTICAST; + + /* Check the net_device flags and set the device independent flags + * accordingly + */ + DBG_VERBOSE(et131x_dbginfo, + "MULTICAST ADDR COUNT: %d\n", netdev->mc_count); + + if (netdev->flags & IFF_PROMISC) { + DBG_VERBOSE(et131x_dbginfo, "Request: PROMISCUOUS MODE ON\n"); + adapter->PacketFilter |= ET131X_PACKET_TYPE_PROMISCUOUS; + } else { + DBG_VERBOSE(et131x_dbginfo, "Request: PROMISCUOUS MODE OFF\n"); + adapter->PacketFilter &= ~ET131X_PACKET_TYPE_PROMISCUOUS; + } + + if (netdev->flags & IFF_ALLMULTI) { + DBG_VERBOSE(et131x_dbginfo, "Request: ACCEPT ALL MULTICAST\n"); + adapter->PacketFilter |= ET131X_PACKET_TYPE_ALL_MULTICAST; + } + + if (netdev->mc_count > NIC_MAX_MCAST_LIST) { + DBG_WARNING(et131x_dbginfo, + "ACCEPT ALL MULTICAST for now, as there's more Multicast " + "addresses than the HW supports\n"); + + adapter->PacketFilter |= ET131X_PACKET_TYPE_ALL_MULTICAST; + } + + if (netdev->mc_count < 1) { + DBG_VERBOSE(et131x_dbginfo, "Request: REJECT ALL MULTICAST\n"); + adapter->PacketFilter &= ~ET131X_PACKET_TYPE_ALL_MULTICAST; + adapter->PacketFilter &= ~ET131X_PACKET_TYPE_MULTICAST; + } else { + DBG_VERBOSE(et131x_dbginfo, + "Request: SET MULTICAST FILTER(S)\n"); + adapter->PacketFilter |= ET131X_PACKET_TYPE_MULTICAST; + } + + /* Set values in the private adapter struct */ + adapter->MCAddressCount = netdev->mc_count; + + if (netdev->mc_count) { + if (mclist->dmi_addrlen != ETH_ALEN) { + DBG_WARNING(et131x_dbginfo, + "Multicast addrs are not ETH_ALEN in size\n"); + } else { + count = netdev->mc_count - 1; + memcpy(adapter->MCList[count], mclist->dmi_addr, + ETH_ALEN); + } + } + + /* Are the new flags different from the previous ones? If not, then no + * action is required + * + * NOTE - This block will always update the MCList with the hardware, + * even if the addresses aren't the same. + */ + if (PacketFilter != adapter->PacketFilter) { + /* Call the device's filter function */ + DBG_VERBOSE(et131x_dbginfo, "UPDATE REQUIRED, FLAGS changed\n"); + + et131x_set_packet_filter(adapter); + } else { + DBG_VERBOSE(et131x_dbginfo, + "NO UPDATE REQUIRED, FLAGS didn't change\n"); + } + + spin_unlock_irqrestore(&adapter->Lock, lockflags); + + DBG_LEAVE(et131x_dbginfo); +} + +/** + * et131x_tx - The handler to tx a packet on the device + * @skb: data to be Tx'd + * @netdev: device on which data is to be Tx'd + * + * Returns 0 on success, errno on failure (as defined in errno.h) + */ +int et131x_tx(struct sk_buff *skb, struct net_device *netdev) +{ + int status = 0; + + DBG_TX_ENTER(et131x_dbginfo); + + /* Save the timestamp for the TX timeout watchdog */ + netdev->trans_start = jiffies; + + /* Call the device-specific data Tx routine */ + status = et131x_send_packets(skb, netdev); + + /* Check status and manage the netif queue if necessary */ + if (status != 0) { + if (status == -ENOMEM) { + DBG_VERBOSE(et131x_dbginfo, + "OUT OF TCBs; STOP NETIF QUEUE\n"); + + /* Put the queue to sleep until resources are + * available + */ + netif_stop_queue(netdev); + status = 1; + } else { + DBG_WARNING(et131x_dbginfo, + "Misc error; drop packet\n"); + status = 0; + } + } + + DBG_TX_LEAVE(et131x_dbginfo); + return status; +} + +/** + * et131x_tx_timeout - Timeout handler + * @netdev: a pointer to a net_device struct representing the device + * + * The handler called when a Tx request times out. The timeout period is + * specified by the 'tx_timeo" element in the net_device structure (see + * et131x_alloc_device() to see how this value is set). + */ +void et131x_tx_timeout(struct net_device *netdev) +{ + struct et131x_adapter *pAdapter = netdev_priv(netdev); + PMP_TCB pMpTcb; + unsigned long lockflags; + + DBG_WARNING(et131x_dbginfo, "TX TIMEOUT\n"); + + /* Just skip this part if the adapter is doing link detection */ + if (MP_TEST_FLAG(pAdapter, fMP_ADAPTER_LINK_DETECTION)) { + DBG_ERROR(et131x_dbginfo, "Still doing link detection\n"); + return; + } + + /* Any nonrecoverable hardware error? + * Checks adapter->flags for any failure in phy reading + */ + if (MP_TEST_FLAG(pAdapter, fMP_ADAPTER_NON_RECOVER_ERROR)) { + DBG_WARNING(et131x_dbginfo, "Non recoverable error - remove\n"); + return; + } + + /* Hardware failure? */ + if (MP_TEST_FLAG(pAdapter, fMP_ADAPTER_HARDWARE_ERROR)) { + DBG_WARNING(et131x_dbginfo, "hardware error - reset\n"); + return; + } + + /* Is send stuck? */ + spin_lock_irqsave(&pAdapter->TCBSendQLock, lockflags); + + pMpTcb = pAdapter->TxRing.CurrSendHead; + + if (pMpTcb != NULL) { + pMpTcb->Count++; + + if (pMpTcb->Count > NIC_SEND_HANG_THRESHOLD) { +#ifdef CONFIG_ET131X_DEBUG + TX_STATUS_BLOCK_t txDmaComplete = + *(pAdapter->TxRing.pTxStatusVa); + PTX_DESC_ENTRY_t pDesc = + pAdapter->TxRing.pTxDescRingVa + + pMpTcb->WrIndex.bits.val; +#endif + TX_DESC_ENTRY_t StuckDescriptors[10]; + + if (pMpTcb->WrIndex.bits.val > 7) { + memcpy(StuckDescriptors, + pAdapter->TxRing.pTxDescRingVa + + pMpTcb->WrIndex.bits.val - 6, + sizeof(TX_DESC_ENTRY_t) * 10); + } + + spin_unlock_irqrestore(&pAdapter->TCBSendQLock, + lockflags); + + DBG_WARNING(et131x_dbginfo, + "Send stuck - reset. pMpTcb->WrIndex %x, Flags 0x%08x\n", + pMpTcb->WrIndex.bits.val, + pMpTcb->Flags); + + DBG_WARNING(et131x_dbginfo, + "pDesc 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", + pDesc->DataBufferPtrHigh, + pDesc->DataBufferPtrLow, pDesc->word2.value, + pDesc->word3.value); + + DBG_WARNING(et131x_dbginfo, + "WbStatus 0x%08x\n", txDmaComplete.value); + +#ifdef CONFIG_ET131X_DEBUG + DumpDeviceBlock(DBG_WARNING_ON, pAdapter, 0); + DumpDeviceBlock(DBG_WARNING_ON, pAdapter, 1); + DumpDeviceBlock(DBG_WARNING_ON, pAdapter, 3); + DumpDeviceBlock(DBG_WARNING_ON, pAdapter, 5); +#endif + et131x_close(netdev); + et131x_open(netdev); + + return; + } + } + + spin_unlock_irqrestore(&pAdapter->TCBSendQLock, lockflags); +} + +/** + * et131x_change_mtu - The handler called to change the MTU for the device + * @netdev: device whose MTU is to be changed + * @new_mtu: the desired MTU + * + * Returns 0 on success, errno on failure (as defined in errno.h) + */ +int et131x_change_mtu(struct net_device *netdev, int new_mtu) +{ + int result = 0; + struct et131x_adapter *adapter = netdev_priv(netdev); + + DBG_ENTER(et131x_dbginfo); + + /* Make sure the requested MTU is valid */ + if (new_mtu == 0 || new_mtu > 9216) { + DBG_LEAVE(et131x_dbginfo); + return -EINVAL; + } + + /* Stop the netif queue */ + netif_stop_queue(netdev); + + /* Stop the Tx and Rx DMA engines */ + et131x_rx_dma_disable(adapter); + et131x_tx_dma_disable(adapter); + + /* Disable device interrupts */ + et131x_disable_interrupts(adapter); + et131x_handle_send_interrupt(adapter); + et131x_handle_recv_interrupt(adapter); + + /* Set the new MTU */ + netdev->mtu = new_mtu; + + /* Free Rx DMA memory */ + et131x_adapter_memory_free(adapter); + + /* Set the config parameter for Jumbo Packet support */ + adapter->RegistryJumboPacket = new_mtu + 14; + et131x_soft_reset(adapter); + + /* Alloc and init Rx DMA memory */ + result = et131x_adapter_memory_alloc(adapter); + if (result != 0) { + DBG_WARNING(et131x_dbginfo, + "Change MTU failed; couldn't re-alloc DMA memory\n"); + return result; + } + + et131x_init_send(adapter); + + et131x_setup_hardware_properties(adapter); + memcpy(netdev->dev_addr, adapter->CurrentAddress, ETH_ALEN); + + /* Init the device with the new settings */ + et131x_adapter_setup(adapter); + + /* Enable interrupts */ + if (MP_TEST_FLAG(adapter, fMP_ADAPTER_INTERRUPT_IN_USE)) { + et131x_enable_interrupts(adapter); + } + + /* Restart the Tx and Rx DMA engines */ + et131x_rx_dma_enable(adapter); + et131x_tx_dma_enable(adapter); + + /* Restart the netif queue */ + netif_wake_queue(netdev); + + DBG_LEAVE(et131x_dbginfo); + return result; +} + +/** + * et131x_set_mac_addr - handler to change the MAC address for the device + * @netdev: device whose MAC is to be changed + * @new_mac: the desired MAC address + * + * Returns 0 on success, errno on failure (as defined in errno.h) + * + * IMPLEMENTED BY : blux http://berndlux.de 22.01.2007 21:14 + */ +int et131x_set_mac_addr(struct net_device *netdev, void *new_mac) +{ + int result = 0; + struct et131x_adapter *adapter = netdev_priv(netdev); + struct sockaddr *address = new_mac; + + DBG_ENTER(et131x_dbginfo); + // begin blux + // DBG_VERBOSE( et131x_dbginfo, "Function not implemented!!\n" ); + + if (adapter == NULL) { + DBG_LEAVE(et131x_dbginfo); + return -ENODEV; + } + + /* Make sure the requested MAC is valid */ + if (!is_valid_ether_addr(address->sa_data)) { + DBG_LEAVE(et131x_dbginfo); + return -EINVAL; + } + + /* Stop the netif queue */ + netif_stop_queue(netdev); + + /* Stop the Tx and Rx DMA engines */ + et131x_rx_dma_disable(adapter); + et131x_tx_dma_disable(adapter); + + /* Disable device interrupts */ + et131x_disable_interrupts(adapter); + et131x_handle_send_interrupt(adapter); + et131x_handle_recv_interrupt(adapter); + + /* Set the new MAC */ + // netdev->set_mac_address = &new_mac; + // netdev->mtu = new_mtu; + + memcpy(netdev->dev_addr, address->sa_data, netdev->addr_len); + + printk("%s: Setting MAC address to %02x:%02x:%02x:%02x:%02x:%02x\n", + netdev->name, netdev->dev_addr[0], netdev->dev_addr[1], + netdev->dev_addr[2], netdev->dev_addr[3], netdev->dev_addr[4], + netdev->dev_addr[5]); + + /* Free Rx DMA memory */ + et131x_adapter_memory_free(adapter); + + /* Set the config parameter for Jumbo Packet support */ + // adapter->RegistryJumboPacket = new_mtu + 14; + // blux: not needet here, w'll change the MAC + + et131x_soft_reset(adapter); + + /* Alloc and init Rx DMA memory */ + result = et131x_adapter_memory_alloc(adapter); + if (result != 0) { + DBG_WARNING(et131x_dbginfo, + "Change MAC failed; couldn't re-alloc DMA memory\n"); + return result; + } + + et131x_init_send(adapter); + + et131x_setup_hardware_properties(adapter); + // memcpy( netdev->dev_addr, adapter->CurrentAddress, ETH_ALEN ); + // blux: no, do not override our nice address + + /* Init the device with the new settings */ + et131x_adapter_setup(adapter); + + /* Enable interrupts */ + if (MP_TEST_FLAG(adapter, fMP_ADAPTER_INTERRUPT_IN_USE)) { + et131x_enable_interrupts(adapter); + } + + /* Restart the Tx and Rx DMA engines */ + et131x_rx_dma_enable(adapter); + et131x_tx_dma_enable(adapter); + + /* Restart the netif queue */ + netif_wake_queue(netdev); + + DBG_LEAVE(et131x_dbginfo); + return result; +} diff --git a/src/et131x/et131x_netdev.h b/src/et131x/et131x_netdev.h new file mode 100644 index 0000000..b8acd14 --- /dev/null +++ b/src/et131x/et131x_netdev.h @@ -0,0 +1,64 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_netdev.h - Defines, structs, enums, prototypes, etc. related to the + * driver's net_device support. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#ifndef __ET131X_NETDEV_H__ +#define __ET131X_NETDEV_H__ + +struct net_device *et131x_device_alloc(void); + +#endif /* __ET131X_NETDEV_H__ */ diff --git a/src/et131x/et131x_version.h b/src/et131x/et131x_version.h new file mode 100644 index 0000000..2ea645e --- /dev/null +++ b/src/et131x/et131x_version.h @@ -0,0 +1,81 @@ +/* + * Agere Systems Inc. + * 10/100/1000 Base-T Ethernet Driver for the ET1301 and ET131x series MACs + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + *------------------------------------------------------------------------------ + * + * et131x_version.h - This file provides system and device version information. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2005 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +#ifndef __ET131X_VERSION_H__ +#define __ET131X_VERSION_H__ + +#define DRIVER_AUTHOR "Victor Soriano (vjsoriano@agere.com)" +#define DRIVER_LICENSE "Dual BSD/GPL" +#define DRIVER_DEVICE_STRING "ET1310" +#define DRIVER_NAME "et131x" +#define DRIVER_MAJOR_VERSION 1 +#define DRIVER_MINOR_VERSION 2 +#define DRIVER_PATCH_VERSION 3 +#define DRIVER_VERSION_STRING "1.2.3" +#define DRIVER_VENDOR "Agere Systems, http://www.agere.com" +#define DRIVER_DESC "10/100/1000 Base-T Ethernet Driver" + +#define STRUCT_MODULE "net" /* blux: missed by the kernel */ + +#define DRIVER_INFO DRIVER_DESC " for the "\ + DRIVER_DEVICE_STRING ", v" \ + DRIVER_VERSION_STRING " by " \ + DRIVER_VENDOR + +#define DRIVER_NAME_EXT "et131x.ko" + +#endif /* __ET131X_VERSION_H__ */
hooks/post-receive -- IPFire 2.x development tree