diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2010-12-01 09:51:44 +1100 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2010-12-01 09:51:44 +1100 |
commit | aaad509cdca2ed5f2c92a26f5279ec0e89c4fd5f (patch) | |
tree | dfffc0d8f3d21f6736b7f09219c95e2370052d8a /other-licence | |
download | SLOF-aaad509cdca2ed5f2c92a26f5279ec0e89c4fd5f.zip SLOF-aaad509cdca2ed5f2c92a26f5279ec0e89c4fd5f.tar.gz SLOF-aaad509cdca2ed5f2c92a26f5279ec0e89c4fd5f.tar.bz2 |
Initial import of slof-JX-1.7.0-4
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'other-licence')
-rw-r--r-- | other-licence/Makefile | 31 | ||||
-rw-r--r-- | other-licence/bcm/Makefile | 57 | ||||
-rw-r--r-- | other-licence/bcm/bcm57xx.c | 3428 | ||||
-rw-r--r-- | other-licence/bcm/bcm57xx.h | 296 | ||||
-rw-r--r-- | other-licence/bcm/types.h | 26 | ||||
-rw-r--r-- | other-licence/common/Makefile | 44 | ||||
-rw-r--r-- | other-licence/common/module.lds | 39 | ||||
-rw-r--r-- | other-licence/common/module_entry.c | 64 | ||||
-rw-r--r-- | other-licence/x86emu/Makefile | 46 | ||||
-rw-r--r-- | other-licence/x86emu/x86emu_changes.diff | 893 | ||||
-rwxr-xr-x | other-licence/x86emu/x86emu_download.sh | 60 |
11 files changed, 4984 insertions, 0 deletions
diff --git a/other-licence/Makefile b/other-licence/Makefile new file mode 100644 index 0000000..fb5397d --- /dev/null +++ b/other-licence/Makefile @@ -0,0 +1,31 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +ifndef TOP + TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd) + export TOP +endif +include $(TOP)/make.rules + +SUBDIRS=common bcm +ifeq ($(SNK_BIOSEMU_APPS), 1) +SUBDIRS += x86emu +endif +CLEANSUBDIRS = $(SUBDIRS) + + +all : + for subdir in $(SUBDIRS) ; do $(MAKE) -C $${subdir} || exit 1 ; done + +# Common targets for all subdirectories: +clean distclean depend: + for subdir in $(CLEANSUBDIRS) ; do $(MAKE) -C $${subdir} $@ ; done diff --git a/other-licence/bcm/Makefile b/other-licence/bcm/Makefile new file mode 100644 index 0000000..b7b386d --- /dev/null +++ b/other-licence/bcm/Makefile @@ -0,0 +1,57 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +ifndef TOP + TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd) + export TOP +endif +include $(TOP)/make.rules + +CFLAGS = -O2 -I. -I../common -I$(TOP)/clients/net-snk/include -I$(TOP)/lib/libc/include -fno-builtin -ffreestanding -msoft-float -Wall -nostdinc + +SRCS = bcm57xx.c + +COMMONOBJS = ../common/module_entry.o + +OBJS += $(COMMONOBJS) $(SRCS:.c=.o) + + +all: Makefile.dep net_bcm57xx.bin + +bcm57xx_net.o: $(OBJS) + $(LD) $(LDFLAGS) $^ -o $@ -T ../common/module.lds -N + +net_bcm57xx.bin: bcm57xx_net.o + $(OBJCOPY) -O binary $^ $@ + +# A rule for making the object files in the common directory: +../common/%.o: ../common/%.c + $(MAKE) -C ../common all + + +clean: + $(RM) -f *.o *.a *.i *.bin + +distclean : clean + rm -f Makefile.dep + + +# Rules for creating the dependency file: +depend: + $(CC) -MM $(CFLAGS) $(SRCS) > Makefile.dep +Makefile.dep: + $(MAKE) depend + +# Include dependency file if available: +ifneq (,$(wildcard Makefile.dep)) +include Makefile.dep +endif diff --git a/other-licence/bcm/bcm57xx.c b/other-licence/bcm/bcm57xx.c new file mode 100644 index 0000000..65b319b --- /dev/null +++ b/other-licence/bcm/bcm57xx.c @@ -0,0 +1,3428 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/* + * + ****************************************************************************** + * reference: + * Broadcom 57xx + * Host Programmer Interface Specification for the + * NetXtreme Family of Highly-Integrated Media Access Controlers + */ +#include "types.h" +#include "bcm57xx.h" + + +/* + * local defines + ****************************************************************************** + */ + + +// #define BCM_VLAN_TAG ( (u32_t) 0x1 ) + +// number of tx/rx rings +// NOTE: 5714 only uses 1 rx/tx ring, but memory +// for the other rings is cleaned anyways for +// sanity & future use +#define BCM_MAX_TX_RING 16 +#define BCM_MAX_RXRET_RING 16 +#define BCM_MAX_RXPROD_RCB 3 + +// bd descriptions +#define BCM_RXPROD_RING_SIZE 512 // don't change +#define BCM_RXRET_RING_SIZE 512 // don't change +#define BCM_TX_RING_SIZE 512 // don't change +#define BCM_BUF_SIZE 1536 // don't change +#define BCM_MTU_MAX_LEN 1522 +#define BCM_MAX_RX_BUF 64 +#define BCM_MAX_TX_BUF 16 + +// number of MAC addresses in NIC +#define BCM_NUM_MAC_ADDR 4 +#define BCM_NUM_MAC5704_ADDR 12 +// offset of mac address field(s) in bcm register space +#define MAC5704_ADDR_OFFS ( (u16_t) 0x0530 ) + +// offset of NIC memory start address from base address +#define BCM_MEMORY_OFFS ( (u64_t) 0x8000 ) + +// offset of statistics block in NIC memory +#define BCM_STATISTIC_OFFS ( (u64_t) 0x0300 ) +// size of statistic block in NIC memory +#define BCM_STATISTIC_SIZE 0x800 + +// offsets of NIC rx/tx rings in NIC memory +#define BCM_NIC_TX_OFFS ( (u16_t) 0x4000 ) +#define BCM_NIC_RX_OFFS ( (u16_t) 0x6000 ) +#define BCM_NIC_TX_SIZE ( (u16_t) ( ( BCM_TX_RING_SIZE * BCM_RCB_SIZE_u16 ) / 4 ) ) + +// device mailboxes +#define BCM_FW_MBX ( (u16_t) 0x0b50 ) +#define BCM_FW_MBX_CMD ( (u16_t) 0x0b78 ) +#define BCM_FW_MBX_LEN ( (u16_t) 0x0b7c ) +#define BCM_FW_MBX_DATA ( (u16_t) 0x0b80 ) +#define BCM_NICDRV_STATE_MBX ( (u16_t) 0x0c04 ) + +// device mailbox commands +#define BCM_NICDRV_ALIVE ( (u32_t) 0x00000001 ) +#define BCM_NICDRV_PAUSE_FW ( (u32_t) 0x00000002 ) + +// device values +#define BCM_MAGIC_NUMBER ( (u32_t) 0x4b657654 ) + +// device states +#define NIC_FWDRV_STATE_START ( (u32_t) 0x00000001 ) +#define NIC_FWDRV_STATE_START_DONE ( (u32_t) 0x80000001 ) +#define NIC_FWDRV_STATE_UNLOAD ( (u32_t) 0x00000002 ) +#define NIC_FWDRV_STATE_UNLOAD_DONE ( (u32_t) 0x80000002 ) +#define NIC_FWDRV_STATE_SUSPEND ( (u32_t) 0x00000004 ) + +// timer prescaler value +#define BCM_TMR_PRESCALE ( (u32_t) 0x41 ) + +// offset of transmit rcb's in NIC memory +#define BCM_TX_RCB_OFFS ( (u16_t) 0x0100 ) +// offset of receive return rcb's in NIC memory +#define BCM_RXRET_RCB_OFFS ( (u16_t) 0x0200 ) + +// register offsets for ring indices +#define TX_PROD_IND ( (u16_t) 0x0304 ) +#define TX_CONS_IND ( (u16_t) 0x3cc0 ) +#define RXPROD_PROD_IND ( (u16_t) 0x026c ) +#define RXPROD_CONS_IND ( (u16_t) 0x3c54 ) +#define RXRET_PROD_IND ( (u16_t) 0x3c80 ) +#define RXRET_CONS_IND ( (u16_t) 0x0284 ) +// NIC producer index only needed for initialization +#define TX_NIC_PROD_IND ( (u16_t) 0x0384 ) + +/* + * predefined register values used during initialization + * may be adapted by user + */ +#define DMA_RW_CTRL_VAL_5714 ( (u32_t) 0x76144000 ) +#define DMA_RW_CTRL_VAL ( (u32_t) 0x760F0000 ) +#define TX_MAC_LEN_VAL ( (u32_t) 0x00002620 ) + +#define RX_LST_PLC_CFG_VAL ( (u32_t) 0x00000109 ) +#define RX_LST_PLC_STAT_EN_VAL ( (u32_t) 0x007e000f ) +#define NVM_ADDR_MSK ( (u32_t) 0x000fffff ) + +// Number of Receive Rules /w or /wo SOL enabled +#define RX_RULE_CFG_VAL ( (u32_t) 0x00000008 ) +#define NUM_RX_RULE ( (u32_t) 16 ) +#define NUM_RX_RULE_ASF ( (u32_t) ( NUM_RX_RULE - 4 ) ) + +// RCB register offsets +#define BCM_RXPROD_RCB_JUM ( (u16_t) 0x2440 ) +#define BCM_RXPROD_RCB_STD ( (u16_t) 0x2450 ) +#define BCM_RXPROD_RCB_MIN ( (u16_t) 0x2460 ) + +// macros needed for new addressing method +#define BCM_RCB_HOSTADDR_HI_u16( rcb ) ( (u16_t) rcb + 0x00 ) +#define BCM_RCB_HOSTADDR_LOW_u16( rcb ) ( (u16_t) rcb + 0x04 ) +#define BCM_RCB_LENFLAG_u16( rcb ) ( (u16_t) rcb + 0x08 ) +#define BCM_RCB_NICADDR_u16( rcb ) ( (u16_t) rcb + 0x0c ) +#define BCM_RCB_SIZE_u16 ( (u16_t) 0x0010 ) + +// RCB flags +#define RCB_FLAG_RING_DISABLED BIT32( 1 ) + +// BCM device ID masks +#define BCM_DEV_5714 ( (u64_t) 0x1 ) +#define BCM_DEV_5704 ( (u64_t) 0x2 ) +#define BCM_DEV_5703 ( (u64_t) 0x4 ) +#define BCM_DEV_SERDES ( (u64_t) 0x80000000 ) +#define BCM_DEV_COPPER ( (u64_t) 0x40000000 ) + +#define IS_5714 ( ( bcm_device_u64 & BCM_DEV_5714 ) != 0 ) +#define IS_5704 ( ( bcm_device_u64 & BCM_DEV_5704 ) != 0 ) +#define IS_5703 ( ( bcm_device_u64 & BCM_DEV_5703 ) != 0 ) +#define IS_SERDES ( ( bcm_device_u64 & BCM_DEV_SERDES ) != 0 ) +#define IS_COPPER_PHY ( ( bcm_device_u64 & BCM_DEV_COPPER ) != 0 ) + +#define BUFFERED_FLASH_PAGE_POS 9 +#define BUFFERED_FLASH_BYTE_ADDR_MASK ((<<BUFFERED_FLASH_PAGE_POS) - 1) +#define BUFFERED_FLASH_PAGE_SIZE 264 +#define BUFFERED_FLASH_PHY_SIZE 512 +#define MANUFACTURING_INFO_SIZE 140 +#define CRC32_POLYNOMIAL 0xEDB88320 + +/* + * local types + ****************************************************************************** + */ +typedef struct { + u32_t m_dev_u32; + u64_t m_devmsk_u64; +} bcm_dev_t; + +/* + * BCM common data structures + * BCM57xx Programmer's Guide: Section 5 + */ + +/* + * 64bit host address in a way the NIC is able to understand it + */ +typedef struct { + u32_t m_hi_u32; + u32_t m_lo_u32; +} bcm_addr64_t; +/* + * ring control block + */ +typedef struct { + bcm_addr64_t m_hostaddr_st; + u32_t m_lenflags_u32; // upper 16b: len, lower 16b: flags + u32_t m_nicaddr_u32; +} bcm_rcb_t; + +/* + * tx buffer descriptor + */ +typedef struct { + bcm_addr64_t m_hostaddr_st; + u32_t m_lenflags_u32; // upper 16b: len, lower 16b: flags + u32_t m_VLANtag_u32; // lower 16b: vtag +} bcm_txbd_t; + +/* + * rx buffer descriptor + */ +typedef struct { + bcm_addr64_t m_hostaddr_st; + u32_t m_idxlen_u32; // upper 16b: idx, lower 16b: len + u32_t m_typeflags_u32; // upper 16b: type, lower 16b: flags + u32_t m_chksum_u32; // upper 16b: ip, lower 16b: tcp/udp + u32_t m_errvlan_u32; // upper 16b: err, lower 16b: vlan tag + u32_t m_reserved_u32; + u32_t m_opaque_u32; +} bcm_rxbd_t; + +/* + * bcm status block + * NOTE: in fact the status block is not used and configured + * so that it is not updated by the NIC. Still it has to be + * set up so the NIC is satisfied + */ +typedef struct { + u32_t m_st_word_u32; + u32_t m_st_tag_u32; + u16_t m_rxprod_cons_u16; + u16_t m_unused_u16; + u32_t m_unused_u32; + u16_t m_tx_cons_u16; + u16_t m_rxret_prod_u16; +} bcm_status_t; + +/* + * local constants + ****************************************************************************** + */ +static const bcm_dev_t bcm_dev[] = { + { 0x166b, BCM_DEV_5714 }, + { 0x1668, BCM_DEV_5714 }, + { 0x1669, BCM_DEV_5714 }, + { 0x166a, BCM_DEV_5714 }, + { 0x1648, BCM_DEV_5704 }, + { 0x1649, BCM_DEV_5704 | BCM_DEV_SERDES }, + { 0x16a8, BCM_DEV_5704 | BCM_DEV_SERDES }, + { 0x16a7, BCM_DEV_5703 | BCM_DEV_SERDES }, + { 0x16c7, BCM_DEV_5703 | BCM_DEV_SERDES }, + { 0 , 0 } +}; + +/* + * local variables + ****************************************************************************** + */ +static u64_t bcm_device_u64; +static u32_t bcm_rxret_ring_sz; +static u64_t bcm_baseaddr_u64; +static u64_t bcm_memaddr_u64; + +/* + * rings & their buffers + */ +// the rings made of buffer descriptors +static bcm_txbd_t bcm_tx_ring[BCM_TX_RING_SIZE]; +static bcm_rxbd_t bcm_rxprod_ring[BCM_RXPROD_RING_SIZE]; +static bcm_rxbd_t bcm_rxret_ring[BCM_RXRET_RING_SIZE*2]; + +// the buffers used in the rings +static u08_t bcm_tx_buffer_pu08[BCM_MAX_TX_BUF][BCM_BUF_SIZE]; +static u08_t bcm_rx_buffer_pu08[BCM_MAX_RX_BUF][BCM_BUF_SIZE]; + +// tx ring index of first/last bd +static u32_t bcm_tx_start_u32; +static u32_t bcm_tx_stop_u32; +static u32_t bcm_tx_bufavail_u32; + +// PCI device location needed for indirect addressing +static u64_t bcm_pcicfg_puid; +static u08_t bcm_pcicfg_bus; +static u08_t bcm_pcicfg_devfn; + +/* + * status block + */ +static bcm_status_t bcm_status; + +/* + * snk module interface + ****************************************************************************** + */ +static int bcm_init ( void ); +static int bcm_term ( void ); +static int bcm_xmit ( char *f_buffer_pc, int f_len_i ); +static int bcm_receive( char *f_buffer_pc, int f_len_i ); +static int bcm_ioctl ( int request, void* data ); + +snk_module_t snk_module_interface = { + .version = 1, + .type = MOD_TYPE_NETWORK, + .running = 0, + .init = bcm_init, + .term = bcm_term, + .write = bcm_xmit, + .read = bcm_receive, + .ioctl = bcm_ioctl +}; + +/* + * implementation + ****************************************************************************** + */ + + +/* + * global functions + ****************************************************************************** + */ +int +check_driver( pci_config_t *pci_conf ); + + +/* + * local helper functions + ****************************************************************************** + */ +static char * +memcpy( char *dest, const char *src, size_t n ) +{ + char *ret = dest; + while( n-- ) { + *dest++ = *src++; + } + + return( ret ); +} + +static char * +memset_ci( char *dest, int c, size_t n ) +{ + char *ret = dest; + + while( n-- ) { + wr08( dest, c ); + dest++; + } + + return( ret ); +} + +static char * +memset( char *dest, int c, size_t n ) +{ + char *ret = dest; + while( n-- ) { + *dest++ = (char) c; + } + + return( ret ); +} + +static u32_t +bcm_nvram_logical_to_physical_address(u32_t address) +{ + u32_t page_no = address / BUFFERED_FLASH_PAGE_SIZE; + u32_t page_addr = address % BUFFERED_FLASH_PAGE_SIZE; + + return (page_no << BUFFERED_FLASH_PAGE_POS) + page_addr; +} + + +/* + * local inline functions for endian swapping + ****************************************************************************** + */ + +static u16_t +bswap_16 (u16_t x) { + return ((x&0xff00) >> 8) + | ((x&0x00ff) << 8); +} + +u32_t +static bswap_32 (u32_t x) { + return bswap_16((x&0xffff0000) >> 16) + | (bswap_16(x&0x0000ffff) << 16); +} + +/* + * read/write functions to access NIC registers & memory + * NOTE: all functions are executed with cache inhibitation (dead slow :-) ) + */ +static u32_t +bcm_read_mem32( u16_t f_offs_u16 ) +{ // caution: shall only be used after initialization! + return rd32( bcm_memaddr_u64 + (u64_t) f_offs_u16 ); +} + +/* not used so far +static u16_t +bcm_read_mem16( u16_t f_offs_u16 ) +{ // caution: shall only be used after initialization! + return rd16( bcm_memaddr_u64 + (u64_t) f_offs_u16 ); +}*/ +/* not used so far +static u08_t +bcm_read_mem08( u16_t f_offs_u16 ) +{ // caution: shall only be used after initialization! + return rd08( bcm_memaddr_u64 + (u64_t) f_offs_u16 ); +}*/ + +static u32_t +bcm_read_reg32_indirect( u16_t f_offs_u16 ) +{ // caution: shall only be used after initialization! + snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + REG_BASE_ADDR_REG, + f_offs_u16 ); + return (u32_t) bswap_32( snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + REG_DATA_REG ) ) ; +} + +static u32_t +bcm_read_reg32( u16_t f_offs_u16 ) +{ // caution: shall only be used after initialization! + if(f_offs_u16 >= 0x200 && f_offs_u16 <0x400) + return bcm_read_reg32_indirect( f_offs_u16 + 0x5600 ); + return rd32( bcm_baseaddr_u64 + (u64_t) f_offs_u16 ); +} + +static u16_t +bcm_read_reg16( u16_t f_offs_u16 ) +{ // caution: shall only be used after initialization! + return rd16( bcm_baseaddr_u64 + (u64_t) f_offs_u16 ); +} +/* not used so far +static u08_t +bcm_read_reg08( u16_t f_offs_u16 ) +{ // caution: shall only be used after initialization! + return rd08( bcm_baseaddr_u64 + (u64_t) f_offs_u16 ); +}*/ + +static void +bcm_write_mem32_indirect( u16_t f_offs_u16, u32_t f_val_u32 ) +{ // caution: shall only be used after initialization! + snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + MEM_BASE_ADDR_REG, + f_offs_u16 ); + snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + MEM_DATA_REG, + bswap_32 ( f_val_u32 ) ); +} + +static void +bcm_write_mem32( u16_t f_offs_u16, u32_t f_val_u32 ) +{ // caution: shall only be used after initialization! + if(f_offs_u16 >= BCM_RXRET_RCB_OFFS && + f_offs_u16 < BCM_RXRET_RCB_OFFS + (BCM_MAX_RXRET_RING*BCM_RCB_SIZE_u16)) + bcm_write_mem32_indirect( f_offs_u16, f_val_u32 ); + else if(f_offs_u16 >= BCM_TX_RCB_OFFS && + f_offs_u16 < BCM_TX_RCB_OFFS + (BCM_MAX_TX_RING*BCM_RCB_SIZE_u16)) + bcm_write_mem32_indirect( f_offs_u16, f_val_u32 ); + else + wr32( bcm_memaddr_u64 + (u64_t) f_offs_u16, f_val_u32 ); +} +/* not used so far +static void +bcm_write_mem16( u16_t f_offs_u16, u16_t f_val_u16 ) +{ // caution: shall only be used after initialization! + wr16( bcm_memaddr_u64 + (u64_t) f_offs_u16, f_val_u16 ); +}*/ +/* not used so far +static void +bcm_write_mem08( u16_t f_offs_u16, u08_t f_val_u08 ) +{ // caution: shall only be used after initialization! + wr08( bcm_memaddr_u64 + (u64_t) f_offs_u16, f_val_u08 ); +}*/ + +static void +bcm_write_reg32_indirect( u16_t f_offs_u16, u32_t f_val_u32 ) +{ // caution: shall only be used after initialization! + snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + REG_BASE_ADDR_REG, + f_offs_u16 ); + snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + REG_DATA_REG, + bswap_32 ( f_val_u32 ) ); +} + +static void +bcm_write_reg32( u16_t f_offs_u16, u32_t f_val_u32 ) +{ // caution: shall only be used after initialization! + if(f_offs_u16 >= 0x200 && f_offs_u16 <0x400) + bcm_write_reg32_indirect( f_offs_u16 + 0x5600, f_val_u32 ); + else + wr32( bcm_baseaddr_u64 + (u64_t) f_offs_u16, f_val_u32 ); +} + +static void +bcm_write_reg16( u16_t f_offs_u16, u16_t f_val_u16 ) +{ // caution: shall only be used after initialization! + wr16( bcm_baseaddr_u64 + (u64_t) f_offs_u16, f_val_u16 ); +} +/* not used so far +static void +bcm_write_reg08( u16_t f_offs_u16, u08_t f_val_u08 ) +{ // caution: shall only be used after initialization! + wr08( bcm_baseaddr_u64 + (u64_t) f_offs_u16, f_val_u08 ); +}*/ + +static void +bcm_setb_reg32( u16_t f_offs_u16, u32_t f_mask_u32 ) +{ + u32_t v; + + v = bcm_read_reg32( f_offs_u16 ); + v |= f_mask_u32; + bcm_write_reg32( f_offs_u16, v ); +} +/* not used so far +static void +bcm_setb_reg16( u16_t f_offs_u16, u16_t f_mask_u16 ) +{ + u16_t v; + v = rd16( bcm_baseaddr_u64 + (u64_t) f_offs_u16 ); + v |= f_mask_u16; + wr16( bcm_baseaddr_u64 + (u64_t) f_offs_u16, v ); +}*/ +/* not used so far +static void +bcm_setb_reg08( u16_t f_offs_u16, u08_t f_mask_u08 ) +{ + u08_t v; + v = rd08( bcm_baseaddr_u64 + (u64_t) f_offs_u16 ); + v |= f_mask_u08; + wr08( bcm_baseaddr_u64 + (u64_t) f_offs_u16, v ); +}*/ + +static void +bcm_clrb_reg32( u16_t f_offs_u16, u32_t f_mask_u32 ) +{ + u32_t v; + + v = bcm_read_reg32( f_offs_u16 ); + v &= ~f_mask_u32; + bcm_write_reg32( f_offs_u16, v ); +} + +static void +bcm_clrb_reg16( u16_t f_offs_u16, u16_t f_mask_u16 ) +{ + u16_t v; + + v = bcm_read_reg16( f_offs_u16 ); + v &= ~f_mask_u16; + bcm_write_reg16( f_offs_u16, v ); +} +/* not used so far +static void +bcm_clrb_reg08( u16_t f_offs_u16, u08_t f_mask_u08 ) +{ + u08_t v; + v = rd08( bcm_baseaddr_u64 + (u64_t) f_offs_u16 ); + v &= ~f_mask_u32; + wr08( bcm_baseaddr_u64 + (u64_t) f_offs_u16, v ); +}*/ + +static void +bcm_clr_wait_bit32( u16_t r, u32_t b ) +{ + u32_t i; + + bcm_clrb_reg32( r, b ); + + i = 1000; + while( --i ) { + + if( ( bcm_read_reg32( r ) & b ) == 0 ) { + break; + } + + us_delay( 10 ); + } +#ifdef BCM_DEBUG + if( ( bcm_read_reg32( r ) & b ) != 0 ) { + printk( "bcm57xx: bcm_clear_wait_bit32 failed (0x%04X)!\n", r ); + } +#endif +} + +/* + * (g)mii bus access + */ +#if 0 +// not used so far +static i32_t +bcm_mii_write16( u32_t f_reg_u32, u16_t f_value_u16 ) +{ + static const u32_t WR_VAL = ( ( ((u32_t) 0x1) << 21 ) | BIT32( 29 ) | BIT32( 26 ) ); + i32_t l_autopoll_i32 = 0; + u32_t l_wrval_u32; + u32_t i; + + /* + * only 0x00-0x1f are valid registers + */ + if( f_reg_u32 > (u32_t) 0x1f ) { + return -1; + } + + /* + * disable auto polling if enabled + */ + if( ( bcm_read_reg32( MI_MODE_R ) & BIT32( 4 ) ) != 0 ) { + l_autopoll_i32 = (i32_t) !0; + bcm_clrb_reg32( MI_MODE_R, BIT32( 4 ) ); + us_delay( 40 ); + } + + /* + * construct & write mi com register value + */ + l_wrval_u32 = ( WR_VAL | ( f_reg_u32 << 16 ) | (u32_t) f_value_u16 ); + bcm_write_reg32( MI_COM_R, l_wrval_u32 ); + + /* + * wait for transaction to complete + */ + i = 25; + while( ( --i ) && + ( ( bcm_read_reg32( MI_COM_R ) & BIT32( 29 ) ) != 0 ) ) { + us_delay( 10 ); + } + + /* + * re-enable auto polling if necessary + */ + if( l_autopoll_i32 ) { + bcm_setb_reg32( MI_MODE_R, BIT32( 4 ) ); + } + + // return on error + if( i == 0 ) { + return -1; + } + + return 0; +} +#endif + +static i32_t +bcm_mii_read16( u32_t f_reg_u32, u16_t *f_value_pu16 ) +{ + static const u32_t RD_VAL = ( ( ((u32_t) 0x1) << 21 ) | BIT32( 29 ) | BIT32( 27 ) ); + i32_t l_autopoll_i32 = 0; + u32_t l_rdval_u32; + u32_t i; + u16_t first_not_busy; + + /* + * only 0x00-0x1f are valid registers + */ + if( f_reg_u32 > (u32_t) 0x1f ) { + return -1; + } + + /* + * disable auto polling if enabled + */ + if( ( bcm_read_reg32( MI_MODE_R ) & BIT32( 4 ) ) != 0 ) { + l_autopoll_i32 = ( i32_t ) !0; + bcm_clrb_reg32( MI_MODE_R, BIT32( 4 ) ); + us_delay( 40 ); + } + + /* + * construct & write mi com register value + */ + l_rdval_u32 = ( RD_VAL | ( f_reg_u32 << 16 ) ); + bcm_write_reg32( MI_COM_R, l_rdval_u32 ); + + /* + * wait for transaction to complete + * ERRATA workaround: must read two "not busy" states to indicate transaction complete + */ + i = 25; + first_not_busy = 0; + l_rdval_u32 = bcm_read_reg32( MI_COM_R ); + while( ( --i ) && + ( (first_not_busy == 0) || ( ( l_rdval_u32 & BIT32( 29 ) ) != 0 ) ) ) { + /* Is this the first clear BUSY state? */ + if ( ( l_rdval_u32 & BIT32( 29 ) ) == 0 ) + first_not_busy++; + us_delay( 10 ); + l_rdval_u32 = bcm_read_reg32( MI_COM_R ); + } + + /* + * re-enable autopolling if necessary + */ + if( l_autopoll_i32 ) { + bcm_setb_reg32( MI_MODE_R, BIT32( 4 ) ); + } + + /* + * return on read transaction error + * (check read failed bit) + */ + if( ( i == 0 ) || + ( ( l_rdval_u32 & BIT32( 28 ) ) != 0 ) ) { + return -1; + } + + /* + * return read value + */ + *f_value_pu16 = (u16_t) ( l_rdval_u32 & (u32_t) 0xffff ); + + return 0; +} + +/* + * ht2000 dump (not complete) + */ +#if 0 +static void +bcm_dump( void ) +{ + u32_t i, j; + + printk( "*** DUMP ***********************************************************************\n\n" ); + + printk( "* PCI Configuration Registers:\n" ); + for( i = 0, j = 0; i < 0x40; i += 4 ) { + + printk( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printk( "\n" ); + } + + } + + printk( "\n* Private PCI Configuration Registers:\n" ); + for( i = 0x68, j = 0; i < 0x88; i += 4 ) { + + printk( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printk( "\n" ); + } + + } + + printk( "\n* VPD Config:\n" ); + printk( "%04X: %08X \n", 0x94, bcm_read_reg32( 0x94 ) ); + + printk( "\n* Dual MAC Control Registers:\n" ); + for( i = 0xb8, j = 0; i < 0xd0; i += 4 ) { + + printk( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printk( "\n" ); + } + + } + + printk( "\n* Ethernet MAC Control Registers:\n" ); + for( i = 0x400, j = 0; i < 0x590; i += 4 ) { + + printk( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printk( "\n" ); + } + + } + + printk( "\n* Send Data Initiator Control:\n" ); + for( i = 0xc00, j = 0; i < 0xc10; i += 4 ) { + + printk( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printk( "\n" ); + } + + } + + printk( "\n* Send Data Completion Control:\n" ); + printk( "%04X: %08X ", 0x1000, bcm_read_reg32( 0x1000 ) ); + printk( "%04X: %08X \n", 0x1008, bcm_read_reg32( 0x1008 ) ); + + printk( "\n* Send BD Ring Selector Control:\n" ); + printk( "%04X: %08X ", 0x1400, bcm_read_reg32( 0x1400 ) ); + printk( "%04X: %08X ", 0x1404, bcm_read_reg32( 0x1404 ) ); + printk( "%04X: %08X \n", 0x1408, bcm_read_reg32( 0x1408 ) ); + + printk( "\n* Send BD Initiator Control:\n" ); + printk( "%04X: %08X ", 0x1800, bcm_read_reg32( 0x1800 ) ); + printk( "%04X: %08X \n", 0x1804, bcm_read_reg32( 0x1804 ) ); + + printk( "\n* Send BD Completion Control:\n" ); + printk( "%04X: %08X ", 0x1c00, bcm_read_reg32( 0x1c00 ) ); + + printk( "\n* Receive List Placement Control:\n" ); + for( i = 0x2000, j = 0; i < 0x2020; i += 4 ) { + + printk( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printk( "\n" ); + } + + } + + printk( "\n* Receive Data & Receive BD Initiator Control:\n" ); + printk( "%04X: %08X ", 0x2400, bcm_read_reg32( 0x2400 ) ); + printk( "%04X: %08X \n", 0x2404, bcm_read_reg32( 0x2404 ) ); + + printk( "\n* Jumbo Receive BD Ring RCB:\n" ); + for( i = 0x2440, j = 0; i < 0x2450; i += 4 ) { + + printk( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printk( "\n" ); + } + + } + + printk( "\n* Standard Receive BD Ring RCB:\n" ); + for( i = 0x2450, j = 0; i < 0x2460; i += 4 ) { + + printk( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printk( "\n" ); + } + + } + + printk( "\n* Mini Receive BD Ring RCB:\n" ); + for( i = 0x2460, j = 0; i < 0x2470; i += 4 ) { + + printk( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printk( "\n" ); + } + + } + + printk( "\nRDI Timer Mode Register:\n" ); + printk( "%04X: %08X \n", 0x24f0, bcm_read_reg32( 0x24f0 ) ); + + printk( "\n* Receive BD Initiator Control:\n" ); + for( i = 0x2c00, j = 0; i < 0x2c20; i += 4 ) { + + printk( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printk( "\n" ); + } + + } + + printk( "\n* Receive BD Completion Control:\n" ); + for( i = 0x3000, j = 0; i < 0x3014; i += 4 ) { + + printk( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printk( "\n" ); + } + + } +} +#endif + + + +/* + * NVRAM access + */ + +static int +bcm_nvram_lock( void ) +{ + int i; + + /* + * Acquire NVRam lock (REQ0) & wait for arbitration won (ARB0_WON) + */ +// bcm_setb_reg32( SW_ARB_R, BIT32( 0 ) ); + bcm_setb_reg32( SW_ARB_R, BIT32( 1 ) ); + + i = 2000; + while( ( --i ) && +// ( bcm_read_reg32( SW_ARB_R ) & BIT32( 8 ) ) == 0 ) { + ( bcm_read_reg32( SW_ARB_R ) & BIT32( 9 ) ) == 0 ) { + ms_delay( 1 ); + } + + // return on error + if( i == 0 ) { +#ifdef BCM_DEBUG + printk("bcm57xx: failed to lock nvram"); +#endif + return -1; + } + + return 0; +} + +static void +bcm_nvram_unlock( void ) +{ + /* + * release NVRam lock (CLR0) + */ +// bcm_setb_reg32( SW_ARB_R, BIT32( 4 ) ); + bcm_setb_reg32( SW_ARB_R, BIT32( 5 ) ); +} + +static void +bcm_nvram_init( void ) +{ + /* + * enable access to NVRAM registers + */ + if(IS_5714) { + bcm_setb_reg32( NVM_ACC_R, BIT32( 1 ) | BIT32( 0 ) ); + } + + /* + * disable bit-bang method 19& disable interface bypass + */ + bcm_clrb_reg32( NVM_CFG1_R, BIT32( 31 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 14 ) | BIT32( 16 ) ); + bcm_setb_reg32( NVM_CFG1_R, BIT32 ( 13 ) | BIT32 ( 17 )); + + /* + * enable Auto SEEPROM Access + */ + bcm_setb_reg32( MISC_LOCAL_CTRL_R, BIT32 ( 24 ) ); + + /* + * NVRAM write enable + */ + bcm_setb_reg32( MODE_CTRL_R, BIT32 ( 21 ) ); +} + +static i32_t +bcm_nvram_read( u32_t f_addr_u32, u32_t *f_val_pu32, u32_t lock ) +{ + u32_t i; + + /* + * parameter check + */ + if( f_addr_u32 > NVM_ADDR_MSK ) { + return -1; + } + + /* + * Acquire NVRam lock (REQ0) & wait for arbitration won (ARB0_WON) + */ + if( lock && (bcm_nvram_lock() == -1) ) { + return -1; + } + + /* + * setup address to read + */ + bcm_write_reg32( NVM_ADDR_R, + bcm_nvram_logical_to_physical_address(f_addr_u32) ); +// bcm_write_reg32( NVM_ADDR_R, f_addr_u32 ); + + /* + * get the command going + */ + bcm_write_reg32( NVM_COM_R, BIT32( 8 ) | BIT32( 7 ) | + BIT32( 4 ) | BIT32( 3 ) ); + + /* + * wait for command completion + */ + i = 2000; + while( ( --i ) && + ( ( bcm_read_reg32( NVM_COM_R ) & BIT32( 3 ) ) == 0 ) ) { + ms_delay( 1 ); + } + + /* + * read back data if no error + */ + if( i != 0 ) { + /* + * read back data + */ + *f_val_pu32 = bcm_read_reg32( NVM_READ_R ); + } + + if(lock) + bcm_nvram_unlock(); + + // error + if( i == 0 ) { +#ifdef BCM_DEBUG + printk("bcm57xx: reading from NVRAM failed\n"); +#endif + return -1; + } + + // success + return 0; +} + +static i32_t +bcm_nvram_write( u32_t f_addr_u32, u32_t f_value_u32, u32_t lock ) +{ + u32_t i; + + /* + * parameter check + */ + if( f_addr_u32 > NVM_ADDR_MSK ) { + return -1; + } + + /* + * Acquire NVRam lock (REQ0) & wait for arbitration won (ARB0_WON) + */ + if( lock && (bcm_nvram_lock() == -1) ) { + return -1; + } + + /* + * setup address to write + */ + bcm_write_reg32( NVM_ADDR_R, bcm_nvram_logical_to_physical_address( f_addr_u32 ) ); + + /* + * setup write data + */ + bcm_write_reg32( NVM_WRITE_R, f_value_u32 ); + + /* + * get the command going + */ + bcm_write_reg32( NVM_COM_R, BIT32( 8 ) | BIT32( 7 ) | + BIT32( 5 ) | BIT32( 4 ) | BIT32( 3 ) ); + + /* + * wait for command completion + */ + i = 2000; + while( ( --i ) && + ( ( bcm_read_reg32( NVM_COM_R ) & BIT32( 3 ) ) == 0 ) ) { + ms_delay( 1 ); + } + + /* + * release NVRam lock (CLR0) + */ + if(lock) + bcm_nvram_unlock(); + + // error + if( i == 0 ) { +#ifdef BCM_DEBUG + printk("bcm57xx: writing to NVRAM failed\n"); +#endif + return -1; + } + + // success + return 0; +} + +/* + * PHY initialization + */ +static i32_t +bcm_mii_phy_init( void ) +{ + static const u32_t PHY_STAT_R = (u32_t) 0x01; + static const u32_t AUX_STAT_R = (u32_t) 0x19; + static const u32_t MODE_GMII = BIT32( 3 ); + static const u32_t MODE_MII = BIT32( 2 ); + static const u32_t NEG_POLARITY = BIT32( 10 ); + static const u32_t MII_MSK = ( MODE_GMII | MODE_MII ); + static const u16_t GIGA_ETH = ( BIT16( 10 ) | BIT16( 9 ) ); + i32_t i; + u16_t v; + + /* + * enable MDI communication + */ + bcm_write_reg32( MDI_CTRL_R, (u32_t) 0x0 ); + + /* + * check link up + */ + i = 2500; + do { + ms_delay( 1 ); + // register needs to be read twice! + bcm_mii_read16( PHY_STAT_R, &v ); + bcm_mii_read16( PHY_STAT_R, &v ); + } while( ( --i ) && + ( ( v & BIT16( 2 ) ) == 0 ) ); + + if( i == 0 ) { +#ifdef BCM_DEBUG + printk( "bcm57xx: link is down\n" ); +#endif + return -1; + } + +#ifdef BCM_DEBUG + printk( "bcm57xx: link is up\n" ); +#endif + if( !IS_COPPER_PHY ) { + return 0; + } + + /* + * setup GMII or MII interface + */ + i = bcm_read_reg32( ETH_MAC_MODE_R ); + /* + * read status register twice, since the first + * read fails once between here and the moon... + */ + bcm_mii_read16( AUX_STAT_R, &v ); + bcm_mii_read16( AUX_STAT_R, &v ); + + if( ( v & GIGA_ETH ) == GIGA_ETH ) { +#ifdef BCM_DEBUG + printk( "bcm57xx: running PHY in GMII mode (1000BaseT)\n" ); +#endif + // GMII device + if( ( i & MII_MSK ) != MODE_GMII ) { + i &= ~MODE_MII; + i |= MODE_GMII; + } + + } else { +#ifdef BCM_DEBUG + printk( "bcm57xx: running PHY in MII mode (10/100BaseT)\n" ); +#endif + // MII device + if( ( i & MII_MSK ) != MODE_MII ) { + i &= ~MODE_GMII; + i |= MODE_MII; + } + + } + + if( IS_5704 && !IS_SERDES ) { +#ifdef BCM_DEBUG + printk( "bcm57xx: set the link ready signal for 5704C to negative polarity\n" ); +#endif + i |= NEG_POLARITY; // set the link ready signal for 5704C to negative polarity + } + + bcm_write_reg32( ETH_MAC_MODE_R, i ); + + return 0; +} + +static i32_t +bcm_tbi_phy_init( void ) +{ + i32_t i; +#if 0 + /* + * set TBI mode full duplex + */ + bcm_clrb_reg32( ETH_MAC_MODE_R, BIT32( 1 ) ); + bcm_setb_reg32( ETH_MAC_MODE_R, BIT32( 2 ) | BIT32( 3 ) ); + + /* + * enable MDI communication + */ + bcm_write_reg32( MDI_CTRL_R, (u32_t) 0x0 ); + + /* Disable link change interrupt. */ + bcm_write_reg32( ETH_MAC_EVT_EN_R, 0 ); + + /* + * set link polarity + */ + bcm_clrb_reg32( ETH_MAC_MODE_R, BIT32( 10 ) ); + + /* + * wait for sync/config changes + */ + for( i = 0; i < 100; i++ ) { + bcm_write_reg32( ETH_MAC_STAT_R, + BIT32( 3 ) | BIT32( 4 ) ); + + us_delay( 20 ); + + if( ( bcm_read_reg32( ETH_MAC_STAT_R ) & + ( BIT32( 3 ) | BIT32( 4 ) ) ) == 0 ) { + break; + } + + } +#endif + /* + * wait for sync to come up + */ + for( i = 0; i < 100; i++ ) { + + if( ( bcm_read_reg32( ETH_MAC_STAT_R ) & BIT32( 0 ) ) != 0 ) { + break; + } + + us_delay( 20 ); + } + + if( ( bcm_read_reg32( ETH_MAC_STAT_R ) & BIT32( 0 ) ) == 0) { +#ifdef BCM_DEBUG + printk( "bcm57xx: link is down\n" ); +#endif + return -1; + } +#if 0 + /* + * clear all attentions + */ + bcm_write_reg32( ETH_MAC_STAT_R, (u32_t) ~0 ); +#endif + +#ifdef BCM_DEBUG + printk( "bcm57xx: link is up\n" ); +#endif + return 0; +} + +static i32_t +bcm_phy_init( void ) +{ + static const u16_t SRAM_HW_CFG = (u16_t) 0x0b58; + u32_t l_val_u32; + i32_t l_ret_i32 = 0; + + /* + * get HW configuration from SRAM + */ + l_val_u32 = bcm_read_mem32( SRAM_HW_CFG ); + l_val_u32 &= ( BIT32( 5 ) | BIT32( 4 ) ); + + switch( l_val_u32 ) { + case 0x10: { + #ifdef BCM_DEBUG + printk( "bcm57xx: copper PHY detected\n" ); + #endif + + bcm_device_u64 |= BCM_DEV_COPPER; + l_ret_i32 = bcm_mii_phy_init(); + } break; + + case 0x20: { + #ifdef BCM_DEBUG + printk( "bcm57xx: fiber PHY detected\n" ); + #endif + + if( !IS_SERDES ) { + #ifdef BCM_DEBUG + printk( "bcm57xx: running PHY in gmii/mii mode\n" ); + #endif + l_ret_i32 = bcm_mii_phy_init(); + } else { + #ifdef BCM_DEBUG + printk( "bcm57xx: running PHY in tbi mode\n" ); + #endif + l_ret_i32 = bcm_tbi_phy_init(); + } + + } break; + + default: { + #ifdef BCM_DEBUG + printk( "bcm57xx: unknown PHY type detected, terminating\n" ); + #endif + l_ret_i32 = -1; + } + + } + + return l_ret_i32; +} + +/* + * ring initialization + */ +static void +bcm_init_rxprod_ring( void ) +{ + u32_t v; + u32_t i; + + /* + * clear out the whole rx prod ring for sanity + */ + memset( (void *) &bcm_rxprod_ring, + 0, + BCM_RXPROD_RING_SIZE * sizeof( bcm_rxbd_t ) ); + mb(); + + /* + * assign buffers & indices to the ring members + */ + for( i = 0; i < BCM_MAX_RX_BUF; i++ ) { + bcm_rxprod_ring[i].m_hostaddr_st.m_hi_u32 = + (u32_t) ( (u64_t) &bcm_rx_buffer_pu08[i] >> 32 ); + bcm_rxprod_ring[i].m_hostaddr_st.m_lo_u32 = + (u32_t) ( (u64_t) &bcm_rx_buffer_pu08[i] & + (u64_t) 0xffffffff ); + bcm_rxprod_ring[i].m_idxlen_u32 = ( i << 16 ); + bcm_rxprod_ring[i].m_idxlen_u32 += BCM_BUF_SIZE; + } + + /* + * clear rcb registers & disable rings + * NOTE: mini & jumbo rings are not supported, + * still rcb's are cleaned out for sanity + */ + bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXPROD_RCB_JUM ), RCB_FLAG_RING_DISABLED ); + bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXPROD_RCB_JUM ), 0 ); + bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_JUM ), 0 ); + bcm_write_reg32( BCM_RCB_NICADDR_u16( BCM_RXPROD_RCB_JUM ), 0 ); + + bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXPROD_RCB_STD ), RCB_FLAG_RING_DISABLED ); + bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXPROD_RCB_STD ), 0 ); + bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_STD ), 0 ); + bcm_write_reg32( BCM_RCB_NICADDR_u16( BCM_RXPROD_RCB_STD ), 0 ); + + bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXPROD_RCB_MIN ), RCB_FLAG_RING_DISABLED ); + bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXPROD_RCB_MIN ), 0 ); + bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_MIN ), 0 ); + bcm_write_reg32( BCM_RCB_NICADDR_u16( BCM_RXPROD_RCB_MIN ), 0 ); + + /* + * clear rx producer index of std producer ring + */ + bcm_write_reg32( RXPROD_PROD_IND, 0 ); + + /* + * setup rx standard rcb using recommended NIC addr (hard coded) + */ + bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXPROD_RCB_STD ), + (u32_t) ( (u64_t) &bcm_rxprod_ring >> 32 ) ); + bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_STD ), + (u32_t) ( (u64_t) &bcm_rxprod_ring & (u64_t) 0xffffffff ) ); + bcm_write_reg32( BCM_RCB_NICADDR_u16( BCM_RXPROD_RCB_STD ), + (u32_t) BCM_NIC_RX_OFFS ); + + if( IS_5704 || IS_5703 ) { + // 5704: length field = max buffer len + v = (u32_t) BCM_BUF_SIZE << 16; + } else { + // 5714: length field = number of ring entries + v = (u32_t) BCM_RXPROD_RING_SIZE << 16; + } + + v &= (u32_t) ~RCB_FLAG_RING_DISABLED; + bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXPROD_RCB_STD ), v ); +} + +static void +bcm_init_rxret_ring( void ) +{ + u32_t i; + u16_t v; + + /* + * clear out the whole rx ret ring for sanity + */ + memset( (void *) &bcm_rxret_ring, + 0, + 2 * BCM_RXRET_RING_SIZE * sizeof( bcm_rxbd_t ) ); + mb(); + + /* + * setup return ring size dependent on installed device + */ + bcm_rxret_ring_sz = BCM_RXRET_RING_SIZE; + if( IS_5704 || IS_5703 ) { + bcm_rxret_ring_sz *= 2; + } + + /* + * clear rcb memory & disable rings + * NOTE: 5714 only supports one return ring, + * still all possible rcb's are cleaned out for sanity + */ + v = BCM_RXRET_RCB_OFFS; + for( i = 0; i < BCM_MAX_RXRET_RING; i++ ) { + bcm_write_mem32( BCM_RCB_LENFLAG_u16( v ), RCB_FLAG_RING_DISABLED ); + bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( v ), 0 ); + bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( v ), 0 ); + bcm_write_mem32( BCM_RCB_NICADDR_u16( v ), 0 ); + + v += BCM_RCB_SIZE_u16; + } + + /* + * clear rx consumer index of return ring + */ + bcm_write_reg32( RXRET_CONS_IND, 0 ); + + /* + * setup rx ret rcb + * NOTE: NIC address not aplicable in return rings + */ + bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXRET_RCB_OFFS ), + (u32_t) ( (u64_t) &bcm_rxret_ring >> 32 ) ); + bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXRET_RCB_OFFS ), + (u32_t) ( (u64_t) &bcm_rxret_ring & + (u64_t) 0xffffffff ) ); + bcm_write_mem32( BCM_RCB_NICADDR_u16( BCM_RXRET_RCB_OFFS ), 0 ); + + i = bcm_rxret_ring_sz; + i <<= 16; + i &= (u32_t) ~RCB_FLAG_RING_DISABLED; + bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXRET_RCB_OFFS ), i ); +} + +static void +bcm_init_tx_ring( void ) +{ + u32_t i; + u16_t v; + + /* + * clear out the whole tx ring for sanity + */ + memset( (void *) &bcm_tx_ring, + 0, + BCM_TX_RING_SIZE * sizeof( bcm_txbd_t ) ); + mb(); + + /* + * assign buffers to the ring members & setup invariant flags + */ + for( i = 0; i < BCM_MAX_TX_BUF; i++ ) { + bcm_tx_ring[i].m_hostaddr_st.m_hi_u32 = + (u32_t) ( (u64_t) &bcm_tx_buffer_pu08[i] >> 32 ); + bcm_tx_ring[i].m_hostaddr_st.m_lo_u32 = + (u32_t) ( (u64_t) &bcm_tx_buffer_pu08[i] & + (u64_t) 0xffffffff ); + // flags: indicate last packet & coal now + // -last packet is always true (only one send packet supported) + // -coal now needed to always get the consumed bd's (since + // only a few bd's are set up which permanently are recycled) + bcm_tx_ring[i].m_lenflags_u32 = ( BIT32( 2 ) | BIT32( 7 ) ); + bcm_tx_ring[i].m_VLANtag_u32 = (u32_t) 0; // not used + } + + /* + * clear rcb memory & disable rings + * NOTE: 5714 only supports one send ring, + * still all possible rcb's are cleaned out for sanity + */ + v = BCM_TX_RCB_OFFS; + for( i = 0; i < BCM_MAX_TX_RING; i++ ) { + bcm_write_mem32( BCM_RCB_LENFLAG_u16( v ), RCB_FLAG_RING_DISABLED ); + bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( v ), 0 ); + bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( v ), 0 ); + bcm_write_mem32( BCM_RCB_NICADDR_u16( v ), 0 ); + + v += BCM_RCB_SIZE_u16; + } + + /* + * clear host/nic producer indices + */ + bcm_write_reg32( TX_NIC_PROD_IND, 0 ); + bcm_write_reg32( TX_PROD_IND, 0 ); + + /* + * setup tx rcb using recommended NIC addr (hard coded) + */ + bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( BCM_TX_RCB_OFFS ), + (u32_t) ( (u64_t) &bcm_tx_ring >> 32 ) ); + bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( BCM_TX_RCB_OFFS ), + (u32_t) ( (u64_t) &bcm_tx_ring & + (u64_t) 0xffffffff ) ); + bcm_write_mem32( BCM_RCB_NICADDR_u16( BCM_TX_RCB_OFFS ), + (u32_t) BCM_NIC_TX_OFFS ); + + if( IS_5704 || IS_5703 ) { + // 5704: length field = max buffer len + i = (u32_t) BCM_BUF_SIZE << 16; + } else { + // 5714: length field = number of ring entries + i = (u32_t) BCM_TX_RING_SIZE << 16; + } + + i &= ( u32_t ) ~RCB_FLAG_RING_DISABLED; + bcm_write_mem32( BCM_RCB_LENFLAG_u16( BCM_TX_RCB_OFFS ), i ); + + /* + * remember the next bd index to be used + * & number of available buffers + */ + bcm_tx_stop_u32 = BCM_MAX_TX_BUF; + bcm_tx_bufavail_u32 = BCM_MAX_TX_BUF; +} + +static i32_t +bcm_mac_init( u08_t *f_mac_pu08 ) +{ + static const u16_t MEM_MAC_LO = (u16_t) 0x0c18; + static const u16_t MEM_MAC_HI = (u16_t) 0x0c14; + + u32_t NVR_MAC_LO = (u16_t) 0x80; + u32_t NVR_MAC_HI = (u16_t) 0x7c; + + bcm_addr64_t l_mac_st; + u32_t i; + u32_t v; + + /* + * Use MAC address from device tree if possible + */ + for( i = 0, v = 0; i < 6; i++ ) { + v += (u32_t) f_mac_pu08[i]; + } + + if( v != 0 ) { + l_mac_st.m_hi_u32 = ( ( (u32_t) f_mac_pu08[0]) << 8 ); + l_mac_st.m_hi_u32 |= ( ( (u32_t) f_mac_pu08[1]) << 0 ); + l_mac_st.m_lo_u32 = ( ( (u32_t) f_mac_pu08[2]) << 24 ); + l_mac_st.m_lo_u32 |= ( ( (u32_t) f_mac_pu08[3]) << 16 ); + l_mac_st.m_lo_u32 |= ( ( (u32_t) f_mac_pu08[4]) << 8 ); + l_mac_st.m_lo_u32 |= ( ( (u32_t) f_mac_pu08[5]) << 0 ); + } else { + /* + * try to read MAC address from MAC mailbox + */ + l_mac_st.m_hi_u32 = bcm_read_mem32( MEM_MAC_HI ); + + if( ( l_mac_st.m_hi_u32 >> 16 ) == (u32_t) 0x484b ) { + l_mac_st.m_hi_u32 &= (u32_t) 0xffff; + l_mac_st.m_lo_u32 = bcm_read_mem32( MEM_MAC_LO ); + } else { + i32_t l_err_i32; + + /* + * otherwise retrieve MAC address from NVRam + */ + if( ( bcm_read_reg32( MAC_FUNC_R ) & BIT32( 2 ) ) != 0 ) { + // secondary MAC is in use, address in NVRAM changes + NVR_MAC_LO += 0x50; + NVR_MAC_HI += 0x50; + } + + l_err_i32 = bcm_nvram_read( NVR_MAC_LO, &l_mac_st.m_lo_u32, 1 ); + l_err_i32 += bcm_nvram_read( NVR_MAC_HI, &l_mac_st.m_hi_u32, 1 ); + + // return on read error + if( l_err_i32 < 0 ) { +#ifdef BCM_DEBUG + printk( "bcm57xx: failed to retrieve MAC address\n" ); +#endif + return -1; + } + } + } + + /* + * write the mac addr into the NIC's register area + */ + bcm_write_reg32( MAC_ADDR_OFFS_HI(0), l_mac_st.m_hi_u32 ); + bcm_write_reg32( MAC_ADDR_OFFS_LO(0), l_mac_st.m_lo_u32 ); + for( i = 1; i < BCM_NUM_MAC_ADDR; i++ ) { + bcm_write_reg32( MAC_ADDR_OFFS_HI(i), 0 ); + bcm_write_reg32( MAC_ADDR_OFFS_LO(i), 0 ); + } + + /* + * WY 26.01.07 + * not needed anymore, s.a. + if( IS_5704 != 0 ) { + + v = MAC5704_ADDR_OFFS; + for( i = 0; i < BCM_NUM_MAC5704_ADDR; i++ ) { + bcm_write_reg32( v, l_mac_st.m_hi_u32 ); + v += sizeof( u32_t ); + bcm_write_reg32( v, l_mac_st.m_lo_u32 ); + v += sizeof( u32_t ); + } + + } + */ + + /* + * return MAC address as string + */ + f_mac_pu08[0] = (u08_t) ( ( l_mac_st.m_hi_u32 >> 8 ) & (u32_t) 0xff ); + f_mac_pu08[1] = (u08_t) ( ( l_mac_st.m_hi_u32 ) & (u32_t) 0xff ); + f_mac_pu08[2] = (u08_t) ( ( l_mac_st.m_lo_u32 >> 24 ) & (u32_t) 0xff ); + f_mac_pu08[3] = (u08_t) ( ( l_mac_st.m_lo_u32 >> 16 ) & (u32_t) 0xff ); + f_mac_pu08[4] = (u08_t) ( ( l_mac_st.m_lo_u32 >> 8 ) & (u32_t) 0xff ); + f_mac_pu08[5] = (u08_t) ( ( l_mac_st.m_lo_u32 ) & (u32_t) 0xff ); + +#ifdef BCM_DEBUG + do { + i32_t i; + printk( "bcm57xx: retrieved MAC address " ); + + for( i = 0; i < 6; i++ ) { + printk( "%02X", f_mac_pu08[i] ); + + if( i != 5 ) { + printk( ":" ); + } + + } + + printk( "\n" ); + } while( 0 ); +#endif + + return 0; +} + + +/* + ****************************************************************************** + * ASF Firmware + ****************************************************************************** + */ + + +#ifdef BCM_DEBUG +#ifdef BCM_SHOW_ASF_REGS +static void +bcm_asf_check_register( void ) +{ + u32_t i; + + i = bcm_read_reg32( ASF_CTRL_R ); + printk( "bcm57xx: ASF control : %x\n", i ); + + i = bcm_read_reg32( ASF_WATCHDOG_TIMER_R ); + printk( "bcm57xx: ASF Watchdog Timer : %x\n", i ); + + i = bcm_read_reg32( ASF_HEARTBEAT_TIMER_R ); + printk( "bcm57xx: ASF Heartbeat Timer : %x\n", i ); + + i = bcm_read_reg32( ASF_POLL_TIMER_R ); + printk( "bcm57xx: ASF Poll Timer : %x\n", i ); + + i = bcm_read_reg32( POLL_LEGACY_TIMER_R ); + printk( "bcm57xx: Poll Legacy Timer : %x\n", i ); + + i = bcm_read_reg32( RETRANSMISSION_TIMER_R ); + printk( "bcm57xx: Retransmission Timer : %x\n", i ); + + i = bcm_read_reg32( TIME_STAMP_COUNTER_R ); + printk( "bcm57xx: Time Stamp Counter : %x\n", i ); + + i = bcm_read_reg32( RX_CPU_MODE_R ); + printk( "bcm57xx: RX RISC Mode : %x\n", i ); + + i = bcm_read_reg32( RX_CPU_STATE_R ); + printk( "bcm57xx: RX RISC State : %x\n", i ); + + i = bcm_read_reg32( RX_CPU_PC_R ); + printk( "bcm57xx: RX RISC Prg. Counter : %x\n", i ); +} +#endif +#endif + +static int +bcm_fw_halt( void ) +{ + int i; + + bcm_write_mem32( BCM_FW_MBX_CMD, BCM_NICDRV_PAUSE_FW ); + bcm_setb_reg32( RX_CPU_EVENT_R, BIT32( 14 ) ); + + /* Wait for RX cpu to ACK the event. */ + for (i = 0; i < 100; i++) { + if(bcm_read_reg32( RX_CPU_EVENT_R ) & BIT32( 14 )) + break; + ms_delay(1); + } + if( i>= 100) + return -1; + return 0; +} + + +#ifdef BCM_SW_AUTONEG +static void +bcm_sw_autoneg( void ) { + u32_t i, j, k; + u32_t SerDesCfg; + u32_t SgDigControl; + u32_t SgDigStatus; + u32_t ExpectedSgDigControl; + int AutoNegJustInitiated = 0; + + // step 1: init TX 1000BX Autoneg. Register to zero + bcm_write_reg32(TX_1000BX_AUTONEG_R, 0); + + // step 2&3: set TBI mode + bcm_setb_reg32( ETH_MAC_MODE_R, BIT32( 2 ) | BIT32( 3 ) ); + us_delay(10); + + // step 4: enable link attention + bcm_setb_reg32( ETH_MAC_EVT_EN_R, BIT32( 12 ) ); + + // step 5: preserve voltage regulator bits + SerDesCfg = bcm_read_reg32(SERDES_CTRL_R) & ( BIT32( 20 ) | BIT32( 21 ) + | BIT32( 22 ) | BIT32( 23 ) ); + + // step 6: preserve voltage regulator bits + SgDigControl = bcm_read_reg32(HW_AUTONEG_CTRL_R); + + // step 7: if device is NOT set-up for auto negotiation, then go to step 26 + // goto bcm_setup_phy_step26; + + // We want to use auto negotiation + + // step 8: we don't want to use flow control + ExpectedSgDigControl = 0x81388400; // no flow control + + // step 9: compare SgDigControl with 0x81388400 + if(SgDigControl == ExpectedSgDigControl) { + goto bcm_setup_phy_step17; + } +#ifdef BCM_DEBUG + printk("bcm57xx: SgDigControl = %08X\n", SgDigControl); +#endif + // step 10 + bcm_write_reg32(SERDES_CTRL_R, SerDesCfg | 0xC011880); + + // step 11: restart auto negotiation + bcm_write_reg32(HW_AUTONEG_CTRL_R, ExpectedSgDigControl | BIT32( 30 ) ); + + // step 12: read back HW_AUTONEG_CTRL_R + bcm_read_reg32(HW_AUTONEG_CTRL_R); + + // step 13 + us_delay( 5 ); + + // step 14,15,16: same as step 11, but don't restart auto neg. + bcm_write_reg32(HW_AUTONEG_CTRL_R, ExpectedSgDigControl); + AutoNegJustInitiated = 1; + goto bcm_setup_phy_step30; + + // step 17: + bcm_setup_phy_step17: + if( ( bcm_read_reg32(ETH_MAC_STAT_R) & ( BIT32( 1 ) | BIT32( 0 ) ) ) == 0 ) { + goto bcm_setup_phy_step30; + } + + // step 18: Get HW Autoneg. Status + SgDigStatus = bcm_read_reg32(HW_AUTONEG_STAT_R); + + // step 19: + if( ( SgDigStatus & BIT32(1) ) + && ( bcm_read_reg32(ETH_MAC_STAT_R) & BIT32(0) ) ) { + // resolve the current flow control? + AutoNegJustInitiated = 0; + goto bcm_setup_phy_step30; + } + + // step 20 + if( SgDigStatus & BIT32(1) ) { + goto bcm_setup_phy_step30; + } + if( AutoNegJustInitiated != 0) { + AutoNegJustInitiated = 0; + goto bcm_setup_phy_step29; + } + + // step 21, 22, 23, 24: fallback to 1000Mbps-FullDuplex forced mode + if( ( bcm_read_reg32( MAC_FUNC_R ) & BIT32( 2 ) ) == 0 ) { + // port 0 + bcm_write_reg32( SERDES_CTRL_R, 0xC010880 ); + } + else { // port 1 + bcm_write_reg32( SERDES_CTRL_R, 0x4010880 ); + } + // set to 1000Mbps-FullDuplex + bcm_write_reg32(HW_AUTONEG_CTRL_R, 0x1388400); + // read back + bcm_read_reg32(HW_AUTONEG_CTRL_R); + us_delay( 40 ); + + // step 25: a little bit reduces... + goto bcm_setup_phy_step30; + + // step 26: check if auto negotiation bit is NOT set +// bcm_setup_phy_step26: + if( ( SgDigControl & BIT32(31) )== 0 ) { + printk("No autoneg.\n"); + goto bcm_setup_phy_step29; + } + + // step 27: + if( ( bcm_read_reg32( MAC_FUNC_R ) & BIT32( 2 ) ) == 0 ) { + // port 0 + bcm_write_reg32( SERDES_CTRL_R, 0xC010880 ); + } + else { // port 1 + bcm_write_reg32( SERDES_CTRL_R, 0x4010880 ); + } + + // step 28: disable auto neg. and force 1000FD mode + bcm_write_reg32(HW_AUTONEG_CTRL_R, 0x1388400); + + // step 29-31: omitted for 5704S + bcm_setup_phy_step29: + bcm_setup_phy_step30: + + // step 32: clear link attentions + i = bcm_read_reg32( ETH_MAC_STAT_R ) | BIT32( 3 ) | BIT32( 4 ); + k = 100; + do { + bcm_write_reg32( ETH_MAC_STAT_R, i ); + j = bcm_read_reg32( ETH_MAC_STAT_R ); + if( ( j & BIT32( 3 ) ) != 0 ) + i = i & ~(BIT32( 3 )); + if( ( j & BIT32( 4 ) ) != 0 ) + i = i & ~(BIT32( 4 )); + --k; + } while( i & k); + + // step 33 + if( ( bcm_read_reg32( ETH_MAC_STAT_R ) & BIT32( 0 ) ) == 0 ) { + goto bcm_setup_phy_step35; + } + + // step 34 + i = bcm_read_reg32( ETH_MAC_MODE_R ); + i|= BIT32( 17 ); + bcm_write_reg32( ETH_MAC_MODE_R, i ); + + us_delay( 1 ); + + i = bcm_read_reg32( ETH_MAC_STAT_R ); + i&= ~BIT32( 17 ); + bcm_write_reg32( ETH_MAC_STAT_R, i ); + + // step 35 & 36: done + bcm_setup_phy_step35: +#ifdef BCM_DEBUG + printk("bcm57xx: SetupPhy\n"); +#endif + return; +} +#endif + +static int +bcm_handle_events( void ) { +#ifdef BCM_DEBUG +#ifdef BCM_SHOW_ASF_REGS + // ASF REGISTER CHECK + // ------------------ + // check if watchdog timer expired + if( bcm_read_reg32( ASF_WATCHDOG_TIMER_R ) == 0 ) { + // Show ASF registers + bcm_asf_check_register(); + + // rearm watchdog timer + bcm_write_reg32( ASF_WATCHDOG_TIMER_R, 5 ); + } +#endif +#endif + +#ifdef BCM_SW_AUTONEG + // AUTO NEGOTIATION + // ---------------- + + // Check event for Auto Negotiation + if( ( bcm_read_reg32( ETH_MAC_STAT_R ) & + ( BIT32( 12 ) | BIT32( 3 ) | BIT32( 0 ) ) ) != 0 ) { + // link timer procedure + bcm_sw_autoneg(); + } +#endif + + // ASF FW HEARTBEAT + // ---------------- + + // check if heartsbeat timer expired + if( bcm_read_reg32( ASF_HEARTBEAT_TIMER_R ) <= 2) { + int i; + + // Send heartbeat event + bcm_write_mem32( BCM_FW_MBX_CMD, BCM_NICDRV_ALIVE ); + bcm_write_mem32( BCM_FW_MBX_LEN, 4 ); + bcm_write_mem32( BCM_FW_MBX_DATA, 5 ); + bcm_setb_reg32( RX_CPU_EVENT_R, BIT32( 14 ) ); + + // Wait for RX cpu to ACK the event. + for (i = 100; i > 0; i--) { + if(bcm_read_reg32( RX_CPU_EVENT_R ) & BIT32( 14 )) + break; + ms_delay(1); + } + if( i == 0) { +#ifdef BCM_DEBUG + printk( "bcm57xx: RX cpu did not acknowledge heartbeat event\n" ); +#endif + return -1; + } + + // rearm heartbeat timer + bcm_write_reg32( ASF_HEARTBEAT_TIMER_R, 5 ); + } + return 0; +} + +/* + * interface + ****************************************************************************** + */ + +/* + * bcm_receive + */ +static int +bcm_receive( char *f_buffer_pc, int f_len_i ) +{ + u32_t l_rxret_prod_u32 = bcm_read_reg32( RXRET_PROD_IND ); + u32_t l_rxret_cons_u32 = bcm_read_reg32( RXRET_CONS_IND ); + u32_t l_rxprod_prod_u32 = bcm_read_reg32( RXPROD_PROD_IND ); + int l_ret_i; +#ifdef BCM_DEBUG +#ifdef BCM_SHOW_RCV_DATA + int i, j; +#endif +#endif + + /* + * NOTE: dummy read to ensure data has already been DMA'd is + * done by the indice reads + */ + + bcm_handle_events(); + + /* + * if producer index == consumer index then nothing was received + */ + if( l_rxret_prod_u32 == l_rxret_cons_u32 ) { + return 0; + } + + /* + * discard erroneous packets + */ + if( ( bcm_rxret_ring[l_rxret_cons_u32].m_typeflags_u32 & BIT32( 10 ) ) != 0 ) { +#ifdef BCM_DEBUG + printk( "bcm57xx: erroneous frame received\n" ); + printk( " : frame discarded\n" ); +#endif + l_ret_i = 0; + } else { + /* + * get packet length, throw away checksum (last 4 bytes) + */ + l_ret_i = (int) ( bcm_rxret_ring[l_rxret_cons_u32].m_idxlen_u32 & + (u32_t) 0xffff ) - (int) 4; + + /* + * discard oversized packets + */ + if( l_ret_i > f_len_i ) { +#ifdef BCM_DEBUG + printk( "bcm57xx: receive packet length error:\n" ); + printk( " : incoming 0x%X bytes, available buffer 0x%X bytes\n", l_ret_i, f_len_i ); + printk( " : frame discarded\n" ); +#endif + l_ret_i = 0; + } + + } + + /* + * copy & update data & indices + */ + if( l_ret_i != 0 ) { + u64_t l_cpyaddr_u64; + + l_cpyaddr_u64 = + ( (u64_t) bcm_rxret_ring[l_rxret_cons_u32].m_hostaddr_st.m_hi_u32 << 32 ); + l_cpyaddr_u64 += + ( (u64_t) bcm_rxret_ring[l_rxret_cons_u32].m_hostaddr_st.m_lo_u32 ); + +// FIXME: + if(l_cpyaddr_u64 == 0) { +#ifdef BCM_DEBUG + printk("bcm57xx: NULL address\n"); +#endif + return 0; + } +// + memcpy( (void *) f_buffer_pc, + (void *) l_cpyaddr_u64, + (size_t) l_ret_i ); + + } + + /* + * replenish bd to producer ring + */ + bcm_rxprod_ring[l_rxprod_prod_u32] = + bcm_rxret_ring[l_rxret_cons_u32]; + bcm_rxprod_ring[l_rxprod_prod_u32].m_idxlen_u32 = + ( l_rxprod_prod_u32 << 16 ); + bcm_rxprod_ring[l_rxprod_prod_u32].m_idxlen_u32 += + (u32_t) BCM_BUF_SIZE; + + /* + * update producer ring's producer index + */ + l_rxprod_prod_u32 = ( l_rxprod_prod_u32 + 1 ) & ( BCM_RXPROD_RING_SIZE - 1 ); + + /* + * move to the next bd in return ring + */ + l_rxret_cons_u32 = ( l_rxret_cons_u32 + 1 ) & ( bcm_rxret_ring_sz - 1 ); + + /* + * synchronize before new indices are send to NIC + */ + mb(); + + /* + * write back new indices + */ + bcm_write_reg32( RXRET_CONS_IND, l_rxret_cons_u32 ); + bcm_write_reg32( RXPROD_PROD_IND, l_rxprod_prod_u32 ); + +#ifdef BCM_DEBUG +#ifdef BCM_SHOW_RCV + if( l_ret_i != 0 ) { + printk( "bcm57xx: received bytes: %d\n", l_ret_i ); + } +#ifdef BCM_SHOW_RCV_DATA + for( i = 0, j = 0; i < l_ret_i; i++ ) { + printk( "%02X ", ( u32_t ) f_buffer_pc[i] ); + + if( ( ++j % 0x18 ) == 0 ) { + printk( "\n" ); + } + } + + if( ( i % 0x18 ) != 0 ) { + printk( "\n" ); + } +#endif +#endif +#endif + + /* + * return packet length + */ + return l_ret_i; +} + +static int +bcm_xmit( char *f_buffer_pc, int f_len_i ) +{ + u32_t l_tx_cons_u32 = bcm_read_reg32( TX_CONS_IND ); + u32_t l_tx_prod_u32 = bcm_read_reg32( TX_PROD_IND ); + u64_t l_cpyaddr_u64; + +#ifdef BCM_DEBUG +#ifdef BCM_SHOW_XMIT_DATA + int i, j; +#endif +#ifdef BCM_SHOW_IDX + printk( "\n" ); + printk( "bcm57xx: TX_PROD_IND : 0x%03X\n", l_tx_prod_u32 ); + printk( "bcm57xx: TX_CONS_IND : 0x%03X\n", l_tx_cons_u32 ); + printk( "bcm57xx: RXPROD_PROD_IND: 0x%03X\n", bcm_read_reg32( RXPROD_PROD_IND ) ); + printk( "bcm57xx: RXPROD_CONS_IND: 0x%03X\n", bcm_read_reg32( RXPROD_CONS_IND ) ); + printk( "bcm57xx: RXRET_PROD_IND : 0x%03X\n", bcm_read_reg32( RXRET_PROD_IND ) ); + printk( "bcm57xx: RXRET_CONS_IND : 0x%03X\n", bcm_read_reg32( RXRET_CONS_IND ) ); + printk( "bcm57xx: available txb : 0x%03X\n", bcm_tx_bufavail_u32 ); +#endif +#ifdef BCM_SHOW_STATS + printk( "bcm57xx: bcm_status.m_st_word_u32: %08X\n", bcm_status.m_st_word_u32 ); + printk( "bcm57xx: bcm_status.m_st_tag_u32 : %08X\n", bcm_status.m_st_tag_u32 ); + printk( "bcm57xx: bcm_status.m_rxprod_cons_u16: %04X\n", ( u32_t ) bcm_status.m_rxprod_cons_u16 ); + printk( "bcm57xx: bcm_status.m_unused_u16: %04X\n", ( u32_t ) bcm_status.m_unused_u16 ); + printk( "bcm57xx: bcm_status.m_unused_u32: %08X\n", bcm_status.m_unused_u32 ); + printk( "bcm57xx: bcm_status.m_tx_cons_u16: %04X\n", ( u32_t ) bcm_status.m_tx_cons_u16 ); + printk( "bcm57xx: bcm_status.m_rxret_prod_u16: %04X\n", ( u32_t ) bcm_status.m_rxret_prod_u16 ); +#endif +#endif + + bcm_handle_events(); + + /* + * make all consumed bd's available in the ring again + * this way only a few buffers are needed instead of + * having 512 buffers allocated + */ + while( bcm_tx_start_u32 != l_tx_cons_u32 ) { + bcm_tx_ring[bcm_tx_stop_u32] = bcm_tx_ring[bcm_tx_start_u32]; + bcm_tx_stop_u32 = ( bcm_tx_stop_u32 + 1 ) & ( BCM_TX_RING_SIZE - 1 ); + bcm_tx_start_u32 = ( bcm_tx_start_u32 + 1 ) & ( BCM_TX_RING_SIZE - 1 ); + bcm_tx_bufavail_u32++; + } + + /* + * check for tx buffer availability + */ + if( bcm_tx_bufavail_u32 == 0 ) { +#ifdef BCM_DEBUG + printk( "bcm57xx: no more transmit buffers available\n" ); +#endif + return 0; + } + + /* + * setup next available bd in tx ring + */ + bcm_tx_ring[l_tx_prod_u32].m_lenflags_u32 = ( BIT32( 2 ) | BIT32( 7 ) /*| BIT32( 6 )*/ ); + bcm_tx_ring[l_tx_prod_u32].m_lenflags_u32 += ( (u32_t) f_len_i << 16 ); +// bcm_tx_ring[l_tx_prod_u32].m_VLANtag_u32 = BCM_VLAN_TAG; + + l_cpyaddr_u64 = ( (u64_t) bcm_tx_ring[l_tx_prod_u32].m_hostaddr_st.m_hi_u32 << 32 ); + l_cpyaddr_u64 += ( (u64_t) bcm_tx_ring[l_tx_prod_u32].m_hostaddr_st.m_lo_u32 ); + +#ifdef BCM_DEBUG +#ifdef BCM_SHOW_XMIT_STATS + printk("bcm57xx: xmit: l_cpyaddr_u64: 0x%lx\n", l_cpyaddr_u64 ); + printk(" f_buffer_pc : 0x%lx\n", f_buffer_pc ); + printk(" f_len_i : %d\n", f_len_i ); +#endif +#endif + memcpy( (void *) l_cpyaddr_u64, (void *) f_buffer_pc, (size_t) f_len_i ); + + /* + * update tx producer index & available buffers + */ + l_tx_prod_u32 = ( l_tx_prod_u32 + 1 ) & ( BCM_TX_RING_SIZE - 1 ); + bcm_tx_bufavail_u32--; + + /* + * synchronize before new index is send to NIC + */ + mb(); + + bcm_write_reg32( TX_PROD_IND, l_tx_prod_u32 ); + +#ifdef BCM_DEBUG +#ifdef BCM_SHOW_XMIT + printk( "bcm57xx: sent bytes: %d\n", f_len_i ); +#ifdef BCM_SHOW_XMIT_DATA + for( i = 0, j = 0; i < f_len_i; i++ ) { + printk( "%02X ", ( u32_t ) f_buffer_pc[i] ); + + if( ( ++j % 0x18 ) == 0 ) { + printk( "\n" ); + } + + } + if( ( i % 0x18 ) != 0 ) { + printk( "\n" ); + } +#endif +#endif + +#ifdef BCM_SHOW_STATS + // coalesce status block now + bcm_setb_reg32( HOST_COAL_MODE_R, BIT32( 3 ) | BIT32( 1 ) ); +#endif + +#endif + return f_len_i; +} + +int +check_driver( pci_config_t *pci_conf ) +{ + u64_t i; + + /* + * checks whether the driver is handling this device + * by verifying vendor & device id + * vendor id 0x14e4 == Broadcom + */ + if( pci_conf->vendor_id != 0x14e4 ) { +#ifdef BCM_DEBUG + printk( "bcm57xx: netdevice not supported, illegal vendor id\n" ); +#endif + return -1; + } + + for( i = 0; bcm_dev[i].m_dev_u32 != 0; i++ ) { + if( bcm_dev[i].m_dev_u32 == (u32_t) pci_conf->device_id ) { + // success + break; + } + } + + if(bcm_dev[i].m_dev_u32 == 0) { +#ifdef BCM_DEBUG + printk( "bcm57xx: netdevice not supported, illegal device ID\n" ); +#endif + return -1; + } + + /* + * initialize static variables + */ + bcm_device_u64 = bcm_dev[i].m_devmsk_u64; + bcm_rxret_ring_sz = 0; + bcm_baseaddr_u64 = 0; + bcm_memaddr_u64 = 0; + + bcm_tx_start_u32 = 0; + bcm_tx_stop_u32 = 0; + bcm_tx_bufavail_u32 = 0; + + bcm_pcicfg_puid = pci_conf->puid; + bcm_pcicfg_bus = pci_conf->bus; + bcm_pcicfg_devfn = pci_conf->devfn; + + return 0; +} + +static void +bcm_wol_activate(void) +{ +#ifdef BCM_DEBUG + u16_t reg_pwr_cap; +#endif + u16_t reg_pwr_crtl; + u32_t wol_mode; + + wol_mode = bcm_read_reg32( WOL_MODE_R ); + bcm_write_reg32( WOL_MODE_R, wol_mode | BIT32(0) ); + +#ifdef BCM_DEBUG + printk( "bcm57xx: WOL activating..." ); +#endif + +// bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_WOL ); +// ms_delay( 100 ); + +#ifdef BCM_DEBUG + reg_pwr_cap = snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, + 2, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + 0x4a ); + printk( "bcm57xx: PM Capability Register: %04X\n", reg_pwr_cap ); +#endif + /* get curretn power control register */ + reg_pwr_crtl = snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, + 2, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + 0x4c ); + +#ifdef BCM_DEBUG + printk( "bcm57xx: PM Control/Status Register: %04X\n", reg_pwr_crtl ); +#endif + + /* switch to power state D0 */ + reg_pwr_crtl |= 0x8000; + reg_pwr_crtl &= ~(0x0003); + snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 2, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + 0x4c, + reg_pwr_crtl ); + ms_delay(10); + +/* + bcm_write_mem32( BCM_NICDRV_WOL_MBX, BCM_WOL_MAGIC_NUMBER | + NIC_WOLDRV_STATE_SHUTDOWN | + NIC_WOLDRV_WOL | + NIC_WOLDRV_SET_MAGIC_PKT ); +*/ + + /* switch to power state D3hot */ +/* + reg_pwr_crtl |= 0x0103; + snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 2, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + 0x4c, + reg_pwr_crtl ); + ms_delay(10); +*/ + +#ifdef BCM_DEBUG + reg_pwr_crtl = snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, + 2, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + 0x4c ); + + printk( "bcm57xx: PM Control/Status Register: %04X\n", reg_pwr_crtl ); +#endif + +#ifdef BCM_DEBUG + printk( "bcm57xx: WOL activated" ); +#endif +} + +static int +bcm_init( void ) +{ + static const u32_t lc_Maxwait_u32 = (u32_t) 1000; + u32_t l_baseaddrL_u32; + u32_t l_baseaddrH_u32; + u32_t i; + char *mac_addr = snk_module_interface.mac_addr; + + if(snk_module_interface.running != 0) { + return 0; + } +#ifdef BCM_DEBUG + printk( "bcm57xx: detected device " ); + if( IS_5703 ) { + printk( "5703S\n" ); + } else if( IS_5704 ) { + printk( "5704" ); + + if( IS_SERDES ) { + printk( "S\n" ); + } else { + printk( "C\n" ); + } + + } else if( IS_5714 ) { + printk( "5714\n" ); + } +#endif + /* + * setup register & memory base addresses of NIC + */ + l_baseaddrL_u32 = ( (u32_t) ~0xf & + (u32_t) snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_BAR1_R ) ); + + l_baseaddrH_u32 = + (u32_t) snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_BAR2_R ); + bcm_baseaddr_u64 = (u64_t) l_baseaddrH_u32; + bcm_baseaddr_u64 <<= 32; + bcm_baseaddr_u64 += (u64_t) l_baseaddrL_u32; + snk_kernel_interface->translate_addr(((void *)&(bcm_baseaddr_u64))); + bcm_memaddr_u64 = bcm_baseaddr_u64 + BCM_MEMORY_OFFS; + +#ifdef BCM_DEBUG + printk( "bcm57xx: PCI-Puid = 0x%X\n", bcm_pcicfg_puid ); + printk( "bcm57xx: PCI-Bus = 0x%X\n", bcm_pcicfg_bus ); + printk( "bcm57xx: PCI-DevFn = 0x%X\n", bcm_pcicfg_devfn ); + printk( "bcm57xx: device's register base high address = 0x%08X\n", l_baseaddrH_u32 ); + printk( "bcm57xx: device's register base low address = 0x%08X\n", l_baseaddrL_u32 ); + printk( "bcm57xx: device's register address = 0x%lx\n", bcm_baseaddr_u64 ); +#endif + + /* + * 57xx hardware initialization + * BCM57xx Programmer's Guide: Section 8, "Initialization" + * steps 1 through 101 + */ + + // step 1: enable bus master & memory space in command reg + i = ( BIT32( 10 ) | BIT32( 2 ) | BIT32( 1 ) ); + snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 2, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_COM_R, + ( int ) i ); + // step 2: disable & mask interrupts & enable pci byte/word swapping & enable indirect addressing mode + i = ( BIT32( 8 ) | BIT32( 7 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) ); + + snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_MISC_HCTRL_R, + ( int ) i ); + + /* + * from now on access may be made through the local + * read/write functions + */ + + // step 3: Save ahche line size register + // omitted, because register is not used for 5704 + + // step 4: acquire the nvram lock + if( bcm_nvram_lock() != 0 ) { +#ifdef BCM_DEBUG + printk( "bcm57xx: locking NVRAM failed\n" ); +#endif + return -1; + } + + // step 5: prepare the chip for writing TG3_MAGIC_NUMBER + bcm_setb_reg32( MEMARB_MODE_R, BIT32( 1 ) ); + i = ( BIT32( 8 ) | BIT32( 7 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) ); + snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_MISC_HCTRL_R, + ( int ) i ); + bcm_write_reg32( MODE_CTRL_R, BIT32( 23 ) | BIT32( 20 ) | + BIT32( 17 ) | BIT32( 16 ) | + BIT32( 14 ) | BIT32( 13 ) | + BIT32( 5 ) | BIT32( 4 ) | + BIT32( 2 ) | BIT32( 1 ) ); + + // step 6: write TG3_MAGIC_NUMBER + bcm_write_mem32( BCM_FW_MBX, BCM_MAGIC_NUMBER ); + + // step 7: reset core clocks + + if( IS_5714 ) { + bcm_setb_reg32( MISC_CFG_R, BIT32( 26 ) | BIT32( 0 ) ); + } else { + bcm_setb_reg32( MISC_CFG_R, BIT32( 0 ) ); + } + // step 8 + ms_delay( 20 ); + + // step 9: disable & mask interrupts & enable indirect addressing mode & + // enable pci byte/word swapping initialize the misc host control register + i = ( BIT32( 8 ) | BIT32( 7 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) ); + snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_MISC_HCTRL_R, + ( int ) i ); + + // step 10: set but master et cetera + i = ( BIT32( 10 ) | BIT32( 2 ) | BIT32( 1 ) ); + snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 2, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_COM_R, + ( int ) i ); + + // step 11: disable PCI-X relaxed ordering + bcm_clrb_reg16( PCI_X_COM_R, BIT16( 1 ) ); + + // step 12: enable the MAC memory arbiter + bcm_setb_reg32( MEMARB_MODE_R, BIT32( 1 ) ); + + // step 13: omitted, only for BCM5700 + // step 14: s. step 10 + i = ( BIT32( 8 ) | BIT32( 7 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) ); + snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_MISC_HCTRL_R, + ( int ) i ); + // step 15: set byte swapping (incl. step 27/28/29/30) + // included prohibition of tx/rx interrupts + bcm_write_reg32( MODE_CTRL_R, BIT32( 23 ) | BIT32( 20 ) | + BIT32( 17 ) | BIT32( 16 ) | + BIT32( 14 ) | BIT32( 13 ) | + BIT32( 5 ) | BIT32( 4 ) | + BIT32( 2 ) | BIT32( 1 ) ); + // step 16: omitted + i = 1000; + while( ( --i ) && + ( bcm_read_mem32( BCM_FW_MBX ) != ~BCM_MAGIC_NUMBER ) ) { +#ifdef BCM_DEBUG + printk( "." ); +#endif + ms_delay( 1 ); + } + + // return on error + if( bcm_read_mem32( BCM_FW_MBX ) != ~BCM_MAGIC_NUMBER ) { + printk( "bootcode not loaded: %x\n", bcm_read_mem32( BCM_FW_MBX ) ); +#ifdef BCM_DEBUG + printk( "failed\n" ); +#endif + return -1; + } + + + // if ASF Firmware enabled + bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_START ); + ms_delay( 10 ); + + // step 17: write ethernet mac mode register + /* + * WY 07.02.07 + * omitted for correct SOL function + */ + /* + if( IS_SERDES ) { + bcm_write_reg32( ETH_MAC_MODE_R, (u32_t) 0xc ); + } else { + bcm_write_reg32( ETH_MAC_MODE_R, (u32_t) 0x0 ); + } + */ + + // step 18/19: omitted + // step 20: enable hw bugfix for 5704 + if( IS_5704 || IS_5703 ) { + bcm_setb_reg32( MSG_DATA_R, BIT32( 26 ) | + BIT32( 28 ) | + BIT32( 29 ) ); + } + + // step 21: omitted + // step 22: omitted + // step 23: 5704 clear statistics block + if( IS_5703 || IS_5704 ) { + memset_ci( (void *) ( bcm_memaddr_u64 + BCM_STATISTIC_OFFS ), + 0, + BCM_STATISTIC_SIZE ); + } + + // step 24/25: omitted + // step 26: set DMA Read/Write Control register + // NOTE: recommended values from the spec are used here + if( IS_5714 ) { + bcm_write_reg32( DMA_RW_CTRL_R, DMA_RW_CTRL_VAL_5714 ); + } else { + u32_t l_PCIState_u32 = bcm_read_reg32( PCI_STATE_R ); + u32_t l_DMAVal_u32 = DMA_RW_CTRL_VAL; + + if( ( l_PCIState_u32 & BIT32( 2 ) ) != 0 ) { // PCI + l_DMAVal_u32 |= (u32_t) 0x300000; + } else { // PCI-X + l_DMAVal_u32 |= (u32_t) 0x900000; + + if( ( bcm_read_reg32( PCI_CLK_CTRL_R ) & (u32_t) 0x1f ) + >= (u32_t) 6 ) { + l_DMAVal_u32 |= (u32_t) 0x4000; + } + + } + + bcm_write_reg32( DMA_RW_CTRL_R, l_DMAVal_u32 ); + } + + // step 27/28/29: s. step 14 + + // step 30: Configure TCP/UDP pseudo header checksum offloading + // already done in step 14: offloading disabled + + // step 31: setup timer prescaler + i = bcm_read_reg32( MISC_CFG_R ); + i &= (u32_t) ~0xfe; // clear bits 7-1 first + i |= ( BCM_TMR_PRESCALE << 1 ); + bcm_write_reg32( MISC_CFG_R, i ); + + // step 32: 5703/4 configure Mbuf pool address/length + // step 33: 5703/4 configure MAC DMA resource pool + // step 34: configure MAC memory pool watermarks + // step 35: 5703/4 configure DMA resource watermarks + // using recommended settings (hard coded) + if( IS_5703 || IS_5704 ) { + + if( IS_5703 ) { + bcm_write_reg32( MBUF_POOL_ADDR_R, (u32_t) 0x8000 ); + bcm_write_reg32( MBUF_POOL_LEN_R, (u32_t) 0x18000 ); + } else { + bcm_write_reg32( MBUF_POOL_ADDR_R, (u32_t) 0x10000 ); + bcm_write_reg32( MBUF_POOL_LEN_R, (u32_t) 0x10000 ); + } + + bcm_write_reg32( DMA_DESC_POOL_ADDR_R, (u32_t) 0x2000 ); + bcm_write_reg32( DMA_DESC_POOL_LEN_R, (u32_t) 0x2000 ); + + bcm_write_reg32( DMA_RMBUF_LOW_WMARK_R, (u32_t) 0x50 ); + bcm_write_reg32( MAC_RXMBUF_LOW_WMARK_R, (u32_t) 0x20 ); + bcm_write_reg32( MBUF_HIGH_WMARK_R, (u32_t) 0x60 ); + + bcm_write_reg32( DMA_DESC_LOW_WM_R, (u32_t) 5 ); + bcm_write_reg32( DMA_DESC_HIGH_WM_R, (u32_t) 10 ); + } else { + bcm_write_reg32( DMA_RMBUF_LOW_WMARK_R, (u32_t) 0x00 ); + bcm_write_reg32( MAC_RXMBUF_LOW_WMARK_R, (u32_t) 0x10 ); + bcm_write_reg32( MBUF_HIGH_WMARK_R, (u32_t) 0x60 ); + } + + // step 35: omitted + // step 36: Configure flow control behaviour + // using recommended settings (hard coded) + bcm_write_reg32( LOW_WMARK_MAX_RXFRAM_R, (u32_t) 0x02 ); + + // step 37/38: enable buffer manager & wait for successful start + bcm_setb_reg32( BUF_MAN_MODE_R, BIT32( 2 ) | BIT32( 1 ) ); + + i = lc_Maxwait_u32; + while( ( --i ) && + ( ( bcm_read_reg32( BUF_MAN_MODE_R ) & BIT32( 1 ) ) == 0 ) ) { + us_delay( 10 ); + } + + // return on error + if( i == 0 ) { +#ifdef BCM_DEBUG + printk( "bcm57xx: init step 38: enable buffer manager failed\n" ); +#endif + return -1; + } + + // step 39: enable internal hardware queues + bcm_write_reg32( FTQ_RES_R, (u32_t) ~0 ); + bcm_write_reg32( FTQ_RES_R, (u32_t) 0 ); + + // step 40/41/42: initialize rx producer ring + bcm_init_rxprod_ring(); + + // step 43: set rx producer ring replenish threshhold + // using recommended setting of maximum allocated BD's/8 + bcm_write_reg32( STD_RXPR_REP_THR_R, (u32_t) BCM_MAX_RX_BUF / 8 ); + + // step 44/45/46: initialize send rings + bcm_init_tx_ring(); + bcm_init_rxret_ring(); + + // steps 47-50 done in ring init functions + // step 51: configure MAC unicast address + bcm_nvram_init(); + if( bcm_mac_init( (u08_t *) mac_addr ) < 0 ) { +#ifdef BCM_DEBUG + printk( "bcm57xx: init step 51: configure MAC unicast address failed\n" ); +#endif + return -1; + } + + // step 52: configure backoff random seed for transmit + // using recommended algorithm + i = (u32_t) mac_addr[0] + (u32_t) mac_addr[1] + + (u32_t) mac_addr[2] + (u32_t) mac_addr[3] + + (u32_t) mac_addr[4] + (u32_t) mac_addr[5]; + i &= (u32_t) 0x03ff; + bcm_write_reg32( ETH_TX_RND_BO_R, i ); + + // step 53: configure message transfer unit MTU size + bcm_write_reg32( RX_MTU_SIZE_R, (u32_t) BCM_MTU_MAX_LEN ); + + // step 54: configure IPG for transmit + // using recommended value (through #define) + bcm_write_reg32( TX_MAC_LEN_R, TX_MAC_LEN_VAL ); + + // step 55: configure receive rules + + // set RX rule default class + bcm_write_reg32( RX_RULE_CFG_R, RX_RULE_CFG_VAL ); + + // step 56: configure the number of receive lists + bcm_write_reg32( RX_LST_PLACE_CFG_R, RX_LST_PLC_CFG_VAL ); + bcm_write_reg32( RX_LST_PLACE_STAT_EN_R, RX_LST_PLC_STAT_EN_VAL ); + +/* + // rule 1: accept frames for our MAC address + bcm_write_reg32( RX_RULE_CTRL_R ( 0 ), + BIT32( 31 ) | // enable rule + BIT32( 30 ) | // and with next + BIT32( 26 ) | // split value register + BIT32( 8 ) ); // class 1 + bcm_write_reg32( RX_RULE_VAL_R ( 0 ), + (u32_t) 0xffff0000 | + ( bcm_read_reg32( MAC_ADDR_OFFS_HI(0) ) & + (u32_t) 0xffff ) ); + + bcm_write_reg32( RX_RULE_CTRL_R ( 1 ), + BIT32( 31 ) | // enable rule + BIT32( 8 ) | // class 1 + BIT32( 1 ) ); // offset 2 + bcm_write_reg32( RX_RULE_VAL_R ( 1 ), + bcm_read_reg32( MAC_ADDR_OFFS_LO(0) ) ); + + // rule 2: accept broadcast frames + bcm_write_reg32( RX_RULE_CTRL_R ( 2 ), + BIT32( 31 ) | // enable rule + BIT32( 30 ) | // and with next + BIT32( 26 ) | // split value register + BIT32( 8 ) ); // class 1 + bcm_write_reg32( RX_RULE_VAL_R ( 2 ), + (u32_t) ~0 ); + + bcm_write_reg32( RX_RULE_CTRL_R ( 3 ), + BIT32( 31 ) | // enable rule + BIT32( 8 ) | // class 1 + BIT32( 1 ) ); // offset 2 + bcm_write_reg32( RX_RULE_VAL_R ( 3 ), + (u32_t) ~0 ); +*/ + for( i=0; i<NUM_RX_RULE_ASF; ++i) { + bcm_write_reg32( RX_RULE_CTRL_R ( i ), 0 ); + bcm_write_reg32( RX_RULE_VAL_R ( i ), 0 ); + } + + // step 57-60: enable rx/tx statistics + // omitted, no need for statistics (so far) + + // step 61/62: disable host coalescing engine/wait 20ms + bcm_write_reg32( HOST_COAL_MODE_R, (u32_t) 0 ); + + i = lc_Maxwait_u32 * 2; + while( ( --i ) && + ( bcm_read_reg32( HOST_COAL_MODE_R ) != 0 ) ) { + us_delay( 10 ); + } + + // return on error + if( i == 0 ) { +#ifdef BCM_DEBUG + printk( "bcm57xx: init step 62: disable host coal. engine failed\n" ); +#endif + return -1; + } + + // step 63-66: initialize coalescing engine + // NOTE: status block is unused in this driver, + // therefore the coal. engine status block + // automatic update is disabled (by writing + // 0 to every counter + bcm_write_reg32( RX_COAL_TICKS_R, 0 ); + bcm_write_reg32( TX_COAL_TICKS_R, 0 ); + bcm_write_reg32( RX_COAL_MAX_BD_R, 0 ); + bcm_write_reg32( TX_COAL_MAX_BD_R, 0 ); + bcm_write_reg32( RX_COAL_TICKS_INT_R, 0 ); + bcm_write_reg32( TX_COAL_TICKS_INT_R, 0 ); + bcm_write_reg32( RX_COAL_MAX_BD_INT_R, 0 ); + bcm_write_reg32( TX_COAL_MAX_BD_INT_R, 0 ); + + // step 67: initialize host status block address + // NOTE: status block is not needed in this driver, + // still it needs to be set up + i = (u32_t) ( (u64_t) &bcm_status >> 32 ); + bcm_write_reg32( STB_HOST_ADDR_HI_R, i ); + i = (u32_t) ( (u64_t) &bcm_status & (u64_t) 0xffffffff ); + bcm_write_reg32( STB_HOST_ADDR_LO_R, i ); + + // 5704/3 adaption + if( IS_5703 || IS_5704 ) { + // step 68: 5704, for now omitted + // step 69: 5704 set the statistics coalescing tick counter + bcm_write_reg32( STAT_TICK_CNT_R, 0 ); + // step 70: 5704 configure statistics block address in NIC memory + // using recommended values (hard coded) + bcm_write_reg32( STAT_NIC_ADDR_R, (u32_t) 0x300 ); + // step 71: 5704 configure status block address in NIC memory + // using recommended values (hard coded) + bcm_write_reg32( STB_NIC_ADDR_R, (u32_t) 0xb00 ); + } + + // step 72: enable host coalescing engine + bcm_setb_reg32( HOST_COAL_MODE_R, BIT32( 12 ) | BIT32( 11 ) | BIT32( 1 ) ); + + // step 73: enable rx bd completion functional block + bcm_write_reg32( RX_BD_COMPL_MODE_R, BIT32( 1 ) | BIT32( 2 ) ); + + // step 74: enable rx list placement functional block + bcm_write_reg32( RX_LST_PLACE_MODE_R, BIT32( 1 ) ); + // 5704/3 adaption + if( IS_5703 || IS_5704 ) { + // step 75: 5704/3 enable receive list selector func block + bcm_write_reg32( RX_LST_SEL_MODE_R, BIT32( 1 ) | BIT32( 2 ) ); + } + + // step 76: enable DMA engines + bcm_setb_reg32( ETH_MAC_MODE_R, BIT32( 23 ) | BIT32( 22 ) | BIT32( 21 ) ); + /* + * WY 26.10.07 This is wrong for 5714, better leave it alone + if( IS_5714 ) { + bcm_setb_reg32( ETH_MAC_MODE_R, BIT32( 20 ) ); + } + */ + + // step 77: omitted, statistics are not used + // step 78: Configure the General Misc Local Control register + // NOTE: as known so far nothing needs to be done here, + // default values should work fine + //bcm_setb_reg32( MISC_LOCAL_CTRL_R, 0 ); + + // step 79: clear interrupts in INT_MBX0_R low word + bcm_write_reg32( INT_MBX0_R, 0 ); + // 5704/3 adaption + // step 80: 5704/3 enable DMA completion functional block + if( IS_5703 || IS_5704 ) { + bcm_write_reg32( DMA_COMPL_MODE_R, BIT32( 1 ) ); + } + + // step 81/82: configure write/read DMA mode registers + // disable MSI + bcm_write_reg32( RD_DMA_MODE_R, BIT32( 10 ) | BIT32( 9 ) | BIT32( 8 ) | + BIT32( 7 ) | BIT32( 6 ) | BIT32( 5 ) | + BIT32( 4 ) | BIT32( 3 ) | BIT32( 2 ) | + BIT32( 1 ) ); + bcm_write_reg32( WR_DMA_MODE_R, BIT32( 9 ) | BIT32( 8 ) | BIT32( 7 ) | + BIT32( 6 ) | BIT32( 5 ) | BIT32( 4 ) | + BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) ); + bcm_clrb_reg32( MSI_MODE_R, BIT32( 1 ) ); + us_delay( 100 ); + + // step 83-91: enable all these functional blocks... + bcm_write_reg32( RX_DAT_COMPL_MODE_R, BIT32( 1 ) | BIT32( 2 ) ); + + if( IS_5703 || IS_5704 ) { + bcm_write_reg32( MBUF_CLSTR_FREE_MODE_R, BIT32( 1 ) ); + } + + bcm_write_reg32( TX_DAT_COMPL_MODE_R, BIT32( 1 ) ); + bcm_write_reg32( TX_BD_COMPL_MODE_R, BIT32( 1 ) | BIT32( 2 ) ); + bcm_write_reg32( RX_BD_INIT_MODE_R, BIT32( 1 ) | BIT32( 2 ) ); + bcm_write_reg32( RX_DAT_BD_INIT_MODE_R, BIT32( 1 ) ); + bcm_write_reg32( TX_DAT_INIT_MODE_R, BIT32( 1 ) | BIT32( 3 ) ); + bcm_write_reg32( TX_BD_INIT_MODE_R, BIT32( 1 ) | BIT32( 2 ) ); + bcm_write_reg32( TX_BD_RING_SEL_MODE_R, BIT32( 1 ) | BIT32( 2 ) ); + + // step 92: omitted + // step 93/94: Enable Tx/Rx MAC + bcm_setb_reg32( TX_MAC_MODE_R, BIT32( 1 ) ); +// bcm_setb_reg32( RX_MAC_MODE_R, BIT32( 1 ) | BIT32( 2 ) ); // set BIT32( 8 ) for promiscious mode! + bcm_setb_reg32( RX_MAC_MODE_R, BIT32( 1 ) ); // set BIT32( 8 ) for promiscious mode! + // set BIT32( 10) for VLAN + + // step 95: disable auto polling: + // bcm_phy_init takes care of this + // step 96: omitted + // step 97: omitted, may change though, but is not important + // step 98: activate link & enable MAC functional block + // NOTE autopolling is enabled so bit 0 needs not to be set + //bcm_setb_reg32( MI_STATUS_R, BIT32( 0 ) ); + + // step 99: setup PHY + // return if link is down + if( bcm_phy_init() < 0 ) { +#ifdef BCM_DEBUG + printk( "bcm57xx: init step 99: PHY initialization failed\n" ); +#endif + return -1; + } + + // step 100: setup multicast filters + bcm_write_reg32( MAC_HASH0_R, (u32_t) 0 ); + bcm_write_reg32( MAC_HASH1_R, (u32_t) 0 ); + bcm_write_reg32( MAC_HASH2_R, (u32_t) 0 ); + bcm_write_reg32( MAC_HASH3_R, (u32_t) 0 ); +/* + // accept all multicast frames + bcm_write_reg32( MAC_HASH0_R, (u32_t) 0xffffffff ); + bcm_write_reg32( MAC_HASH1_R, (u32_t) 0xffffffff ); + bcm_write_reg32( MAC_HASH2_R, (u32_t) 0xffffffff ); + bcm_write_reg32( MAC_HASH3_R, (u32_t) 0xffffffff ); +*/ + // step 101: omitted, no interrupts used + + // make initial receive buffers available for NIC + // this step has to be done here after RX DMA engine has started (step 94) + bcm_write_reg32( RXPROD_PROD_IND, BCM_MAX_RX_BUF ); + + // if ASF Firmware enabled + bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_START_DONE ); + ms_delay( 10 ); + + // enable heartbeat timer + + bcm_write_reg32( ASF_HEARTBEAT_TIMER_R, 0x5 ); + + snk_module_interface.running = 1; + // off we go.. + return 0; +} + +static int +bcm_reset( void ) +{ + u32_t i; + +#ifdef BCM_DEBUG + printk( "bcm57xx: resetting controller.." ); +#endif + + bcm_write_mem32( BCM_FW_MBX, BCM_MAGIC_NUMBER ); + + if( IS_5714 ) { + bcm_setb_reg32( MISC_CFG_R, BIT32( 26 ) | BIT32( 0 ) ); + } else { + bcm_setb_reg32( MISC_CFG_R, BIT32( 0 ) ); + } + + ms_delay( 20 ); + + /* + * after reset local read/write functions cannot be used annymore + * until bus master & stuff is set up again + */ + + i = ( BIT32( 10 ) | BIT32( 2 ) | BIT32( 1 ) ); + snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 2, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_COM_R, + ( int ) i ); + + // step 9 & 13: disable & mask interrupts & enable indirect addressing mode & + // enable pci byte/word swapping initialize the misc host control register + i = ( BIT32( 7 ) | BIT32( 5 ) | BIT32( 4 ) | + BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) ); + snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_MISC_HCTRL_R, + ( int ) i ); + + // step 16: poll for bootcode completion by waiting for the one's + // complement of the magic number previously written + i = 1000; + while( ( --i ) && + ( bcm_read_mem32( BCM_FW_MBX ) != ~BCM_MAGIC_NUMBER ) ) { +#ifdef BCM_DEBUG + printk( "." ); +#else + ms_delay( 1 ); +#endif + } + + // return on error + if( bcm_read_mem32( BCM_FW_MBX ) != ~BCM_MAGIC_NUMBER ) { +#ifdef BCM_DEBUG + printk( "failed\n" ); +#endif + return -1; + } + +#ifdef BCM_DEBUG + printk( "done\n" ); +#endif + return 0; +} + +static int +bcm_term( void ) +{ + u32_t i; + u16_t v; + + if(snk_module_interface.running == 0) { + return 0; + } + +#ifdef BCM_DEBUG + printk( "bcm57xx: driver shutdown.." ); +#endif + + /* + * halt ASF firmware + */ + bcm_fw_halt(); + + /* + * unload ASF firmware + */ + bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_UNLOAD ); + + /* + * disable RX producer rings + */ + bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXPROD_RCB_JUM ), RCB_FLAG_RING_DISABLED ); + bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXPROD_RCB_JUM ), 0 ); + bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_JUM ), 0 ); + bcm_write_reg32( BCM_RCB_NICADDR_u16( BCM_RXPROD_RCB_JUM ), 0 ); + + bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXPROD_RCB_STD ), RCB_FLAG_RING_DISABLED ); + bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXPROD_RCB_STD ), 0 ); + bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_STD ), 0 ); + bcm_write_reg32( BCM_RCB_NICADDR_u16( BCM_RXPROD_RCB_STD ), 0 ); + + bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXPROD_RCB_MIN ), RCB_FLAG_RING_DISABLED ); + bcm_write_reg32( BCM_RCB_HOSTADDR_HI_u16( BCM_RXPROD_RCB_MIN ), 0 ); + bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_MIN ), 0 ); + bcm_write_reg32( BCM_RCB_NICADDR_u16( BCM_RXPROD_RCB_MIN ), 0 ); + + /* + * disable RX return rings + */ + v = BCM_RXRET_RCB_OFFS; + for( i = 0; i < BCM_MAX_RXRET_RING; i++ ) { + bcm_write_mem32( BCM_RCB_LENFLAG_u16( v ), RCB_FLAG_RING_DISABLED ); + bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( v ), 0 ); + bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( v ), 0 ); + bcm_write_mem32( BCM_RCB_NICADDR_u16( v ), 0 ); + + v += BCM_RCB_SIZE_u16; + } + + /* + * disable TX rings + */ + v = BCM_TX_RCB_OFFS; + for( i = 0; i < BCM_MAX_TX_RING; i++ ) { + bcm_write_mem32( BCM_RCB_LENFLAG_u16( v ), RCB_FLAG_RING_DISABLED ); + bcm_write_mem32( BCM_RCB_HOSTADDR_HI_u16( v ), 0 ); + bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( v ), 0 ); + bcm_write_mem32( BCM_RCB_NICADDR_u16( v ), 0 ); + + v += BCM_RCB_SIZE_u16; + } + + /* + * remove receive rules + */ + bcm_write_reg32( RX_RULE_CTRL_R ( 0 ), 0 ); + bcm_write_reg32( RX_RULE_VAL_R ( 0 ), 0 ); + bcm_write_reg32( RX_RULE_CTRL_R ( 1 ), 0 ); + bcm_write_reg32( RX_RULE_VAL_R ( 1 ), 0 ); + + /* + * shutdown sequence + * BCM57xx Programmer's Guide: Section 8, "Shutdown" + * the enable bit of every state machine of the 57xx + * has to be reset. + */ + + /* + * receive path shutdown sequence + */ + bcm_clr_wait_bit32( RX_MAC_MODE_R, BIT32( 1 ) ); + bcm_clr_wait_bit32( RX_LST_PLACE_MODE_R, BIT32( 1 ) ); + bcm_clr_wait_bit32( RX_BD_INIT_MODE_R, BIT32( 1 ) ); + bcm_clr_wait_bit32( RX_DAT_BD_INIT_MODE_R, BIT32( 1 ) ); + bcm_clr_wait_bit32( RX_DAT_COMPL_MODE_R, BIT32( 1 ) ); + bcm_clr_wait_bit32( RX_BD_COMPL_MODE_R, BIT32( 1 ) ); + + if( IS_5704 || IS_5703 ) { + bcm_clr_wait_bit32( RX_LST_SEL_MODE_R, BIT32( 1 ) ); + } + + /* + * transmit path & memory shutdown sequence + */ + bcm_clr_wait_bit32( TX_BD_RING_SEL_MODE_R, BIT32( 1 ) ); + bcm_clr_wait_bit32( TX_BD_INIT_MODE_R, BIT32( 1 ) ); + bcm_clr_wait_bit32( TX_DAT_INIT_MODE_R, BIT32( 1 ) ); + bcm_clr_wait_bit32( RD_DMA_MODE_R, BIT32( 1 ) ); + bcm_clr_wait_bit32( TX_DAT_COMPL_MODE_R, BIT32( 1 ) ); + + if( IS_5704 ) { + bcm_clr_wait_bit32( DMA_COMPL_MODE_R, BIT32( 1 ) ); + } + + bcm_clr_wait_bit32( TX_BD_COMPL_MODE_R, BIT32( 1 ) ); + bcm_clr_wait_bit32( ETH_MAC_MODE_R, BIT32( 21 ) ); + bcm_clr_wait_bit32( TX_MAC_MODE_R, BIT32( 1 ) ); + + bcm_clr_wait_bit32( HOST_COAL_MODE_R, BIT32( 1 ) ); + bcm_clr_wait_bit32( WR_DMA_MODE_R, BIT32( 1 ) ); + + if( IS_5704 || IS_5703 ) { + bcm_clr_wait_bit32( MBUF_CLSTR_FREE_MODE_R, BIT32( 1 ) ); + } + + bcm_write_reg32( FTQ_RES_R, (u32_t) ~0 ); + bcm_write_reg32( FTQ_RES_R, (u32_t) 0 ); + + if( IS_5704 || IS_5703 ) { + bcm_clr_wait_bit32( BUF_MAN_MODE_R, BIT32( 1 ) ); + bcm_clr_wait_bit32( MEMARB_MODE_R, BIT32( 1 ) ); + } + +#ifdef BCM_DEBUG + printk( "done.\n" ); +#endif + /* + * controller reset + */ + if( bcm_reset() != 0 ) { + return -1; + } + + /* + * restart ASF firmware + */ + bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_UNLOAD ); + ms_delay( 10 ); + bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_UNLOAD_DONE ); + ms_delay( 100 ); + bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_START ); + ms_delay( 10 ); + bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_START_DONE ); + + /* + * activate Wake-on-LAN + */ + bcm_wol_activate(); + + /* + * PCI shutdown + */ + bcm_clrb_reg32( PCI_MISC_HCTRL_R, BIT32( 3 ) | BIT32( 2 ) ); + + /* + * from now on local rw functions cannot be used anymore + */ + +// bcm_clrb_reg32( PCI_COM_R, BIT32( 10 ) | BIT32( 2 ) | BIT32( 1 ) ); + + snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 2, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_COM_R, + BIT32(8) | BIT32(6) ); + + // no more networking... + snk_module_interface.running = 0; + return 0; +} + +static int +bcm_getmac(u32_t addr, char mac[6]) +{ + u32_t t1, t2; + u64_t t3; + + if (bcm_nvram_read(addr, &t1, 1) != 0) + return -1; + if (bcm_nvram_read(addr+4, &t2, 1) != 0) + return -1; + t3 = ((u64_t)t1 << 32) + t2; + + mac[0] = (t3 >> 40) & 0xFF; + mac[1] = (t3 >> 32) & 0xFF; + mac[2] = (t3 >> 24) & 0xFF; + mac[3] = (t3 >> 16) & 0xFF; + mac[4] = (t3 >> 8) & 0xFF; + mac[5] = (t3 >> 0) & 0xFF; + + return 0; +} + +static char* +print_itoa(char *text, u32_t value) +{ + if(value >= 10) + text = print_itoa(text, value / 10); + *text = '0' + (value % 10); + ++text; + return text; +} + +static int +bcm_get_version(char *text) +{ + u32_t t1; + + if (bcm_nvram_read(0x94, &t1, 1) != 0) + return -1; + + text = print_itoa(text, (t1 >> 8) & 0xFF); + text[0] = '.'; + text = print_itoa(&text[1], t1 & 0xFF); + text[0] = '\n'; + return 0; +} + +static u32_t +util_gen_crc( char *pcDatabuf, u32_t ulDatalen, u32_t ulCrc_in) +{ + unsigned char data; + u32_t idx, bit, crc = ulCrc_in; + + for(idx = 0; idx < ulDatalen; idx++) { + data = *pcDatabuf++; + for(bit = 0; bit < 8; bit++, data >>= 1) { + crc = (crc >> 1) ^ (((crc ^ data) & 1) ? + CRC32_POLYNOMIAL : 0); + } + } + return bswap_32(~crc); +} + +static int +bcm_setmac(char mac_addr1[6], char mac_addr2[6]) +{ + u64_t mac1 = 0, mac2 = 0; + u32_t manu[MANUFACTURING_INFO_SIZE/4]; + int addr, i; + u32_t crc, val1, val2, val3, val4; + +#ifdef BCM_DEBUG + printk("Flashing MAC 1: %02X:%02X:%02X:%02X:%02X:%02X\n", + ((unsigned int) mac_addr1[0]) & 0xFF, + ((unsigned int) mac_addr1[1]) & 0xFF, + ((unsigned int) mac_addr1[2]) & 0xFF, + ((unsigned int) mac_addr1[3]) & 0xFF, + ((unsigned int) mac_addr1[4]) & 0xFF, + ((unsigned int) mac_addr1[5]) & 0xFF); + + printk("Flashing MAC 2: %02X:%02X:%02X:%02X:%02X:%02X\n", + ((unsigned int) mac_addr2[0]) & 0xFF, + ((unsigned int) mac_addr2[1]) & 0xFF, + ((unsigned int) mac_addr2[2]) & 0xFF, + ((unsigned int) mac_addr2[3]) & 0xFF, + ((unsigned int) mac_addr2[4]) & 0xFF, + ((unsigned int) mac_addr2[5]) & 0xFF); +#endif + + mac1 |= ((u64_t) mac_addr1[0]) & 0xFF; mac1 = mac1 << 8; + mac1 |= ((u64_t) mac_addr1[1]) & 0xFF; mac1 = mac1 << 8; + mac1 |= ((u64_t) mac_addr1[2]) & 0xFF; mac1 = mac1 << 8; + mac1 |= ((u64_t) mac_addr1[3]) & 0xFF; mac1 = mac1 << 8; + mac1 |= ((u64_t) mac_addr1[4]) & 0xFF; mac1 = mac1 << 8; + mac1 |= ((u64_t) mac_addr1[5]) & 0xFF; + + mac2 |= ((u64_t) mac_addr2[0]) & 0xFF; mac2 = mac2 << 8; + mac2 |= ((u64_t) mac_addr2[1]) & 0xFF; mac2 = mac2 << 8; + mac2 |= ((u64_t) mac_addr2[2]) & 0xFF; mac2 = mac2 << 8; + mac2 |= ((u64_t) mac_addr2[3]) & 0xFF; mac2 = mac2 << 8; + mac2 |= ((u64_t) mac_addr2[4]) & 0xFF; mac2 = mac2 << 8; + mac2 |= ((u64_t) mac_addr2[5]) & 0xFF; + + /* Extract the manufacturing data, starts at 0x74 */ + if(bcm_nvram_lock() == -1) { + return -1; + } + + addr = 0x74; + for (i = 0; i < (MANUFACTURING_INFO_SIZE/4); i++) { + if (bcm_nvram_read(addr, &manu[i], 0) != 0) { + printk("\nREAD FAILED\n"); + bcm_nvram_unlock(); + return -1; + } + addr+=4; + } + bcm_nvram_unlock(); + + /* Store the new MAC address in the manufacturing data */ + val1 = mac1 >> 32; + val2 = mac1 & 0xFFFFFFFF; + val3 = mac2 >> 32; + val4 = mac2 & 0xFFFFFFFF; + manu[(0x7C-0x74)/4] = val1; + manu[(0x80-0x74)/4] = val2; + manu[(0xCC-0x74)/4] = val3; + manu[(0xD0-0x74)/4] = val4; + + /* Calculate the new manufacturing datas CRC */ + crc = util_gen_crc(((char *)manu), + MANUFACTURING_INFO_SIZE - 4, 0xFFFFFFFF); + + /* Now write the new MAC addresses and CRC */ + if ((bcm_nvram_write(0x7C, val1, 1) != 0) || + (bcm_nvram_write(0x80, val2, 1) != 0) || + (bcm_nvram_write(0xCC, val3, 1) != 0) || + (bcm_nvram_write(0xD0, val4, 1) != 0) || + (bcm_nvram_write(0xFC, crc, 1) != 0) ) + { + /* Disastor ! */ +#ifdef BCM_DEBUG + printk("failed to write MAC address\n"); +#endif + return -1; + } + + /* Success !!!! */ + return 0; +} + +static int +bcm_ioctl( int request, void* data ) +{ + u32_t l_baseaddrL_u32; + u32_t l_baseaddrH_u32; + u32_t i; + int ret_val = 0; + char mac_addr[6]; + ioctl_net_data_t *ioctl_data = (ioctl_net_data_t*) data; + + if(request != SIOCETHTOOL) { + return -1; + } + +#ifdef BCM_DEBUG + printk( "bcm57xx: detected device " ); + if( IS_5703 ) { + printk( "5703S" ); + } else if( IS_5704 ) { + printk( "5704" ); + if( IS_SERDES ) { + printk( "S\n" ); + } else { + printk( "C\n" ); + } + } else if( IS_5714 ) { + printk( "5714\n" ); + } +#endif + /* + * setup register & memory base addresses of NIC + */ + l_baseaddrL_u32 = ( (u32_t) ~0xf & + (u32_t) snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_BAR1_R ) ); + + l_baseaddrH_u32 = + (u32_t) snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_BAR2_R ); + + bcm_baseaddr_u64 = (u64_t) l_baseaddrH_u32; + bcm_baseaddr_u64 <<= 32; + bcm_baseaddr_u64 += (u64_t) l_baseaddrL_u32; + snk_kernel_interface->translate_addr(((void *)&(bcm_baseaddr_u64))); + bcm_memaddr_u64 = bcm_baseaddr_u64 + BCM_MEMORY_OFFS; + + /* + * 57xx hardware initialization + * BCM57xx Programmer's Guide: Section 8, "Initialization" + * steps 1 through 101 + */ + + // step 1: enable bus master & memory space in command reg + i = ( BIT32( 10 ) | BIT32( 2 ) | BIT32( 1 ) ); + snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 2, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_COM_R, + ( int ) i ); + + // step 2: disable & mask interrupts & enable pci byte/word swapping & enable indirect addressing mode + i = ( BIT32( 7 ) | BIT32( 3 ) | BIT32( 2 ) | BIT32( 1 ) | BIT32( 0 ) ); + snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_MISC_HCTRL_R, + ( int ) i ); + + bcm_nvram_init(); + + switch(ioctl_data->subcmd) { + case ETHTOOL_GMAC: + switch(ioctl_data->data.mac.idx) { + case 0: + ret_val = bcm_getmac(0x7C, ioctl_data->data.mac.address); + break; + case 1: + ret_val = bcm_getmac(0xCC, ioctl_data->data.mac.address); + break; + default: + ret_val = -1; + break; + } + break; + case ETHTOOL_SMAC: + switch(ioctl_data->data.mac.idx) { + case 0: + ret_val = bcm_getmac(0xCC, mac_addr); + if(ret_val == 0) + ret_val = bcm_setmac(ioctl_data->data.mac.address, mac_addr); + break; + case 1: + ret_val = bcm_getmac(0x7C, mac_addr); + if(ret_val == 0) + ret_val = bcm_setmac(mac_addr, ioctl_data->data.mac.address); + break; + default: + ret_val = -1; + break; + } + break; + case ETHTOOL_VERSION: { + char *text = ioctl_data->data.version.text; + memcpy(text, " BCM57xx Boot code level: ", 27); + ret_val = bcm_get_version(&text[27]); + break; + } + default: + ret_val = -1; + break; + } + + snk_module_interface.running = 1; + bcm_term(); + return ret_val; +} + diff --git a/other-licence/bcm/bcm57xx.h b/other-licence/bcm/bcm57xx.h new file mode 100644 index 0000000..d968313 --- /dev/null +++ b/other-licence/bcm/bcm57xx.h @@ -0,0 +1,296 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include "netdriver_int.h" +#include "types.h" + +// compiler switches + +// Debug switches +//#define BCM_DEBUG // main debug switch, w/o it the other ones don't work +//#define BCM_SHOW_RCV +//#define BCM_SHOW_RCV_DATA +//#define BCM_SHOW_XMIT +//#define BCM_SHOW_XMIT_DATA +//#define BCM_SHOW_XMIT_STATS +//#define BCM_SHOW_IDX +//#define BCM_SHOW_STATS +//#define BCM_SHOW_ASF_REGS + +// Switch to enable SW AUTO-NEG +// don't try, it's still incomplete +//#define BCM_SW_AUTONEG + +/* + * used register offsets + */ +// PCI command register +#define PCI_COM_R ( (u16_t) 0x0004 ) +// PCI Cache Line Size register +#define PCI_CACHELS_R ( (u16_t) 0x000c ) +// PCI bar1 register +#define PCI_BAR1_R ( (u16_t) 0x0010 ) +// PCI bar2 register +#define PCI_BAR2_R ( (u16_t) 0x0014 ) +// PCI bar1 register +#define PCI_SUBID_R ( (u16_t) 0x002e ) +// PCI-X Comand register +#define PCI_X_COM_R ( (u16_t) 0x0042 ) +// Message Data Register +#define MSG_DATA_R ( (u16_t) 0x0064 ) +// PCI misc host contrl register +#define PCI_MISC_HCTRL_R ( (u16_t) 0x0068 ) +// DMA Read/Write Control register +#define DMA_RW_CTRL_R ( (u16_t) 0x006c ) +// PCI State register +#define PCI_STATE_R ( (u16_t) 0x0070 ) +// PCI_Clock Control register +#define PCI_CLK_CTRL_R ( (u16_t) 0x0074 ) +// Register Base Address Register +#define REG_BASE_ADDR_REG ( (u16_t) 0x0078 ) +// Memory Window Base Address Register +#define MEM_BASE_ADDR_REG ( (u16_t) 0x007c ) +// Register Data Register +#define REG_DATA_REG ( (u16_t) 0x0080 ) +// Memory Window Data Register +#define MEM_DATA_REG ( (u16_t) 0x0084 ) +// MAC Function register +#define MAC_FUNC_R ( (u16_t) 0x00b8 ) +// Interrupt Mailbox 0 register +#define INT_MBX0_R ( (u16_t) 0x0204 ) +// Ethernet MAC Mode register +#define ETH_MAC_MODE_R ( (u16_t) 0x0400 ) +// Ethernet MAC Addresses registers +#define MAC_ADDR_OFFS_HI( idx ) ( (u16_t) ( (idx*2 + 0)*sizeof( u32_t ) + 0x0410 ) ) +#define MAC_ADDR_OFFS_LO( idx ) ( (u16_t) ( (idx*2 + 1)*sizeof( u32_t ) + 0x0410 ) ) +// Ethernet MAC Status register +#define ETH_MAC_STAT_R ( (u16_t) 0x0404 ) +// Ethernet MAC Event Enable register +#define ETH_MAC_EVT_EN_R ( (u16_t) 0x0408 ) +// Ethernet Transmit Random Backoff register +#define ETH_TX_RND_BO_R ( (u16_t) 0x0438 ) +// Receive MTU Size register +#define RX_MTU_SIZE_R ( (u16_t) 0x043c ) +// Transmit 1000BASE-X Auto Negotiation register +#define TX_1000BX_AUTONEG_R ( (u16_t) 0x0444 ) +// Receive 1000BASE-X Auto Negotiation register +#define RX_1000BX_AUTONEG_R ( (u16_t) 0x0448 ) +// MI Communication register +#define MI_COM_R ( (u16_t) 0x044c ) +// MI Status Register +#define MI_STATUS_R ( (u16_t) 0x0450 ) +// MI Mode register +#define MI_MODE_R ( (u16_t) 0x0454 ) +// Transmit MAC Mode register +#define TX_MAC_MODE_R ( (u16_t) 0x045c ) +// Transmit MAC Length register +#define TX_MAC_LEN_R ( (u16_t) 0x0464 ) +// Receive MAC Mode register +#define RX_MAC_MODE_R ( (u16_t) 0x0468 ) +// MAC Hash 0 register* VPD Config: +#define MAC_HASH0_R ( (u16_t) 0x0470 ) +// MAC Hash 1 register +#define MAC_HASH1_R ( (u16_t) 0x0474 ) +// MAC Hash 2 register +#define MAC_HASH2_R ( (u16_t) 0x0478 ) +// MAC Hash 3 register +#define MAC_HASH3_R ( (u16_t) 0x047c ) +// Receive Rules Control register +#define RX_RULE_CTRL_R( idx ) ( (u16_t) ( idx*8 + 0x0480 ) ) +// Receive Rules Value register +#define RX_RULE_VAL_R( idx ) ( (u16_t) ( idx*8 + 0x0484 ) ) +// Receive Rules Configuration register +#define RX_RULE_CFG_R ( (u16_t) 0x0500 ) +// Low Watermark Max Receive Frames register +#define LOW_WMARK_MAX_RXFRAM_R ( (u16_t) 0x0504 ) +// SerDes Control Register +#define SERDES_CTRL_R ( (u16_t) 0x0590 ) +// Hardware Auto Negotiation Control Register +#define HW_AUTONEG_CTRL_R ( (u16_t) 0x05B0 ) +// Hardware Auto Negotiation Status Register +#define HW_AUTONEG_STAT_R ( (u16_t) 0x05B4 ) +// Send Data Initiator Mode register +#define TX_DAT_INIT_MODE_R ( (u16_t) 0x0c00 ) +// Send Data Completion Mode register +#define TX_DAT_COMPL_MODE_R ( (u16_t) 0x1000 ) +// Send BD Ring Selector Mode register +#define TX_BD_RING_SEL_MODE_R ( (u16_t) 0x1400 ) +// Send BD Initiator Mode register +#define TX_BD_INIT_MODE_R ( (u16_t) 0x1800 ) +// Send BD Completion Mode register +#define TX_BD_COMPL_MODE_R ( (u16_t) 0x1c00 ) +// Receive List Placement Mode register +#define RX_LST_PLACE_MODE_R ( (u16_t) 0x2000 ) +// Receive List Placement Configuration register +#define RX_LST_PLACE_CFG_R ( (u16_t) 0x2010 ) +// Receive List Placement Statistics Enable Mask register +#define RX_LST_PLACE_STAT_EN_R ( (u16_t) 0x2018 ) +// Receive Data & Receive BD Initiator Mode register +#define RX_DAT_BD_INIT_MODE_R ( (u16_t) 0x2400 ) +// Receive Data Completion Mode register +#define RX_DAT_COMPL_MODE_R ( (u16_t) 0x2800 ) +// Receive BD Initiator Mode register +#define RX_BD_INIT_MODE_R ( (u16_t) 0x2c00 ) +// Standard Receive Producer Ring Replenish Threshhold register +#define STD_RXPR_REP_THR_R ( (u16_t) 0x2c18 ) +// Receive BD Completion Mode register +#define RX_BD_COMPL_MODE_R ( (u16_t) 0x3000 ) +// Receive List Selector Mode register +#define RX_LST_SEL_MODE_R ( (u16_t) 0x3400 ) +// MBUF Cluster Free Mode register +#define MBUF_CLSTR_FREE_MODE_R ( (u16_t) 0x3800 ) +// Host Coalescing Mode register +#define HOST_COAL_MODE_R ( (u16_t) 0x3c00 ) +// Receive Coalescing Ticks register +#define RX_COAL_TICKS_R ( (u16_t) 0x3c08 ) +// Send Coalescing Ticks register +#define TX_COAL_TICKS_R ( (u16_t) 0x3c0c ) +// Receive Max Coalesced BD Count register +#define RX_COAL_MAX_BD_R ( (u16_t) 0x3c10 ) +// Send Max Coalesced BD Count register +#define TX_COAL_MAX_BD_R ( (u16_t) 0x3c14 ) +// Receive Coalescing Ticks During Int register +#define RX_COAL_TICKS_INT_R ( (u16_t) 0x3c18 ) +// Send Coalescing Ticks During Int register +#define TX_COAL_TICKS_INT_R ( (u16_t) 0x3c1c ) +// Receive Max Coalesced BD Count During Int register +#define RX_COAL_MAX_BD_INT_R ( (u16_t) 0x3c18 ) +// Send Max Coalesced BD Count During Int register +#define TX_COAL_MAX_BD_INT_R ( (u16_t) 0x3c1c ) +// Statistics Ticks Counter register +#define STAT_TICK_CNT_R ( (u16_t) 0x3c28 ) +// Status Block Host Address Low register +#define STB_HOST_ADDR_HI_R ( (u16_t) 0x3c38 ) +// Status Block Host Address High register +#define STB_HOST_ADDR_LO_R ( (u16_t) 0x3c3c ) +// Statistsics Base Adress register +#define STAT_NIC_ADDR_R ( (u16_t) 0x3c40 ) +// Status Block Base Address register +#define STB_NIC_ADDR_R ( (u16_t) 0x3c44 ) +// Memory Arbiter Mode register +#define MEMARB_MODE_R ( (u16_t) 0x4000 ) +// Buffer Manager Mode register +#define BUF_MAN_MODE_R ( (u16_t) 0x4400 ) +// MBuf Pool Address register +#define MBUF_POOL_ADDR_R ( (u16_t) 0x4408 ) +// MBuf Pool Length register +#define MBUF_POOL_LEN_R ( (u16_t) 0x440c ) +// Read DMA Mbuf Low Watermark register +#define DMA_RMBUF_LOW_WMARK_R ( (u16_t) 0x4410 ) +// MAC Rx Mbuf Low Watermark register +#define MAC_RXMBUF_LOW_WMARK_R ( (u16_t) 0x4414 ) +// Mbuf High Watermark register +#define MBUF_HIGH_WMARK_R ( (u16_t) 0x4418 ) +// DMA Descriptor Pool Address register +#define DMA_DESC_POOL_ADDR_R ( (u16_t) 0x442c ) +// DMA Descriptor Pool Length register +#define DMA_DESC_POOL_LEN_R ( (u16_t) 0x4430 ) +// DMA Descriptor Low Watermark register +#define DMA_DESC_LOW_WM_R ( (u16_t) 0x4434 ) +// DMA Descriptor HIGH Watermark register +#define DMA_DESC_HIGH_WM_R ( (u16_t) 0x4438 ) +// Read DMA Mode register +#define RD_DMA_MODE_R ( (u16_t) 0x4800 ) +// Write DMA Mode register +#define WR_DMA_MODE_R ( (u16_t) 0x4c00 ) +// FTQ Reset register +#define FTQ_RES_R ( (u16_t) 0x5c00 ) +// MSI Mode register +#define MSI_MODE_R ( (u16_t) 0x6000 ) +// DMA completion Mode register +#define DMA_COMPL_MODE_R ( (u16_t) 0x6400 ) +// Mode Control register +#define MODE_CTRL_R ( (u16_t) 0x6800 ) +// Misc Configuration register +#define MISC_CFG_R ( (u16_t) 0x6804 ) +// Misc Local Control register +#define MISC_LOCAL_CTRL_R ( (u16_t) 0x6808 ) +// RX-Risc Mode Register +#define RX_CPU_MODE_R ( (u16_t) 0x5000 ) +// RX-Risc State Register +#define RX_CPU_STATE_R ( (u16_t) 0x5004 ) +// RX-Risc Program Counter +#define RX_CPU_PC_R ( (u16_t) 0x501c ) +// RX-Risc Event Register +#define RX_CPU_EVENT_R ( (u16_t) 0x6810 ) +// MDI Control register +#define MDI_CTRL_R ( (u16_t) 0x6844 ) +// WOL Mode register +#define WOL_MODE_R ( (u16_t) 0x6880 ) +// WOL Config register +#define WOL_CFG_R ( (u16_t) 0x6884 ) +// WOL Status register +#define WOL_STATUS_R ( (u16_t) 0x6888 ) + +// ASF Control register +#define ASF_CTRL_R ( (u16_t) 0x6c00 ) +// ASF Watchdog Timer register +#define ASF_WATCHDOG_TIMER_R ( (u16_t) 0x6c0c ) +// ASF Heartbeat Timer register +#define ASF_HEARTBEAT_TIMER_R ( (u16_t) 0x6c10 ) +// Poll ASF Timer register +#define ASF_POLL_TIMER_R ( (u16_t) 0x6c14 ) +// Poll Legacy Timer register +#define POLL_LEGACY_TIMER_R ( (u16_t) 0x6c18 ) +// Retransmission Timer register +#define RETRANSMISSION_TIMER_R ( (u16_t) 0x6c1c ) +// Time Stamp Counter register +#define TIME_STAMP_COUNTER_R ( (u16_t) 0x6c20 ) + +// NVM Command register +#define NVM_COM_R ( (u16_t) 0x7000 ) +// NVM Write register +#define NVM_WRITE_R ( (u16_t) 0x7008 ) +// NVM Address register +#define NVM_ADDR_R ( (u16_t) 0x700c ) +// NVM Read registertg3_phy_copper_begin +#define NVM_READ_R ( (u16_t) 0x7010 ) +// NVM Access register +#define NVM_ACC_R ( (u16_t) 0x7024 ) +// NVM Config 1 register +#define NVM_CFG1_R ( (u16_t) 0x7014 ) +// Software arbitration register +#define SW_ARB_R ( (u16_t) 0x7020 ) + +/* + * useful def's + */ +#define rd08(a) (u08_t) snk_kernel_interface->io_read((void*)(a),1) +#define rd16(a) (u16_t) snk_kernel_interface->io_read((void*)(a),2) +#define rd32(a) (u32_t) snk_kernel_interface->io_read((void*)(a),4) +#define wr08(a,v) snk_kernel_interface->io_write((void*)(a),(u32_t)(v),1) +#define wr16(a,v) snk_kernel_interface->io_write((void*)(a),(u32_t)(v),2) +#define wr32(a,v) snk_kernel_interface->io_write((void*)(a),(u32_t)(v),4) +#define printk snk_kernel_interface->print +#define us_delay snk_kernel_interface->us_delay +#define ms_delay snk_kernel_interface->ms_delay + +#define BIT08( bit ) ( (u08_t) 0x1 << (bit) ) +#define BIT16( bit ) ( (u16_t) 0x1 << (bit) ) +#define BIT32( bit ) ( (u32_t) 0x1 << (bit) ) + +/* + * type definition + */ + +extern snk_kernel_t *snk_kernel_interface; + + +/* + * inline functions + */ +// memory barrier function implementation +static inline void +mb() +{ + asm volatile( "sync;" ); +} diff --git a/other-licence/bcm/types.h b/other-licence/bcm/types.h new file mode 100644 index 0000000..fb562d7 --- /dev/null +++ b/other-licence/bcm/types.h @@ -0,0 +1,26 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _TYPES_H_ +#define _TYPES_H_ + +typedef unsigned char u08_t; +typedef unsigned short u16_t; +typedef unsigned int u32_t; +typedef unsigned long long u64_t; + +typedef signed char i08_t; +typedef signed short i16_t; +typedef signed int i32_t; +typedef signed long long i64_t; + +#endif diff --git a/other-licence/common/Makefile b/other-licence/common/Makefile new file mode 100644 index 0000000..8b3ebe1 --- /dev/null +++ b/other-licence/common/Makefile @@ -0,0 +1,44 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +ifndef TOP + TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd) + export TOP +endif +include $(TOP)/make.rules + +CFLAGS = -O2 -I./ -I$(TOP)/clients/net-snk/include/ -I$(TOP)/lib/libc/include/ -fno-builtin -ffreestanding -msoft-float -nostdinc -Wall + +SRCS = module_entry.c + +OBJS = $(SRCS:.c=.o) + +all: Makefile.dep $(OBJS) + + +clean: + $(RM) -f *.o *.a *.i *.bin + +distclean : clean + rm -f Makefile.dep + + +# Rules for creating the dependency file: +depend: + $(CC) -MM $(CFLAGS) $(SRCS) > Makefile.dep +Makefile.dep: + $(MAKE) depend + +# Include dependency file if available: +ifneq (,$(wildcard Makefile.dep)) +include Makefile.dep +endif diff --git a/other-licence/common/module.lds b/other-licence/common/module.lds new file mode 100644 index 0000000..c17a055 --- /dev/null +++ b/other-licence/common/module.lds @@ -0,0 +1,39 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", "elf64-powerpc") +OUTPUT_ARCH(powerpc:common64) +ENTRY(module_init) + +SECTIONS { + .code 0xF800000: + { + ../common/module_entry.o(.opd) + *(.text .stub .text.* .gnu.linkonce.t.*) + *(.sfpr .glink) + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.data .data.* .gnu.linkonce.d.*) + *(.opd) + } + .got : + { + _got = .; + *(.got .toc) + } + .bss : { + __bss_start = .; + *(*COM* .bss .gnu.linkonce.b.*) + __bss_end = .; + } + __bss_size = (__bss_end - __bss_start); + __end = .; +} diff --git a/other-licence/common/module_entry.c b/other-licence/common/module_entry.c new file mode 100644 index 0000000..423d908 --- /dev/null +++ b/other-licence/common/module_entry.c @@ -0,0 +1,64 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#include "netdriver_int.h" + +extern snk_module_t snk_module_interface; + +snk_kernel_t *snk_kernel_interface = 0; + +extern int +check_driver( pci_config_t *pci_conf ); + + +static void* +memset( void *dest, int c, size_t n ) +{ + while( n-- ) { + *( char * ) dest++ = ( char ) c; + } + return dest; +} + + +extern char __bss_start; +extern char __bss_size; + +snk_module_t* +module_init(snk_kernel_t *snk_kernel_int, pci_config_t *pciconf) +{ + /* Need to clear bss, heavy linker script dependency, expert change only */ + char *bss = &__bss_start; + unsigned long long bss_size = (unsigned long long) &__bss_size; + + if (((unsigned long long) bss) + bss_size >= 0xFF00000 + || bss_size >= 0x2000000) { + snk_kernel_int->print("BSS size (%llu bytes) is too big!\n", bss_size); + return 0; + } + + memset(bss, 0, bss_size); + + if (snk_kernel_int->version != snk_module_interface.version) { + return 0; + } + + snk_kernel_interface = snk_kernel_int; + + /* Check if this is the right driver */ + if (check_driver(pciconf) < 0) { + return 0; + } + + snk_module_interface.link_addr = module_init; + return &snk_module_interface; +} diff --git a/other-licence/x86emu/Makefile b/other-licence/x86emu/Makefile new file mode 100644 index 0000000..5f1fac4 --- /dev/null +++ b/other-licence/x86emu/Makefile @@ -0,0 +1,46 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ + +ifndef TOP + TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd) + export TOP +endif +include $(TOP)/make.rules + +ROOTDIR ?= ../.. + +LDFLAGS = +ASFLAGS = -I./include -Wa,-mregnames + +#NOTE: -DDEBUG only needed for debugging/tracing... +#CFLAGS = -DDEBUG -I. -I./include -I./include/x86emu -I$(ROOTDIR)/include -I$(ROOTDIR)/lib/libc/include -g -O2 -msoft-float -Wall -save-temps -nostdinc -fno-builtin -ffreestanding +CFLAGS = -UDEBUG -m64 -I. -I./include -I./include/x86emu -I$(TOP)/clients/net-snk/include -I$(ROOTDIR)/include -I$(ROOTDIR)/lib/libc/include -O3 -Wall -nostdinc -fno-builtin -ffreestanding + +X86EMU_OBJS = debug.o decode.o fpu.o ops2.o ops.o prim_ops.o sys.o + +%.o: %.S + $(CC) $(ASFLAGS) -c -o $@ $^ + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $^ + +all: libx86emu.a + +libx86emu.a: $(X86EMU_OBJS) + $(AR) -rc $@ $^ + $(RANLIB) $@ + +clean: + $(RM) *.o *.i *.s libx86emu.a + +distclean: clean + diff --git a/other-licence/x86emu/x86emu_changes.diff b/other-licence/x86emu/x86emu_changes.diff new file mode 100644 index 0000000..aa1a359 --- /dev/null +++ b/other-licence/x86emu/x86emu_changes.diff @@ -0,0 +1,893 @@ +Index: debug.c +=================================================================== +RCS file: /cvs/osdf/cvs/host/other-licence/x86emu/debug.c,v +retrieving revision 1.1 +retrieving revision 1.3 +diff -u -u -r1.1 -r1.3 +--- debug.c 7 Sep 2007 10:01:21 -0000 1.1 ++++ debug.c 15 Jan 2008 13:49:25 -0000 1.3 +@@ -52,7 +52,11 @@ + void X86EMU_trace_regs (void) + { + if (DEBUG_TRACE()) { +- x86emu_dump_regs(); ++ if (M.x86.mode & (SYSMODE_PREFIX_DATA | SYSMODE_PREFIX_ADDR)) { ++ x86emu_dump_xregs(); ++ } else { ++ x86emu_dump_regs(); ++ } + } + if (DEBUG_DECODE() && ! DEBUG_DECODE_NOPRINT()) { + printk("%04x:%04x ",M.x86.saved_cs, M.x86.saved_ip); +@@ -185,7 +189,7 @@ + for (i=0; i< M.x86.enc_pos; i++) { + sprintf(buf1+2*i,"%02x", fetch_data_byte_abs(s,o+i)); + } +- printk("%-20s",buf1); ++ printk("%-20s ",buf1); + } + + static void print_decoded_instruction (void) +Index: ops2.c +=================================================================== +RCS file: /cvs/osdf/cvs/host/other-licence/x86emu/ops2.c,v +retrieving revision 1.1 +retrieving revision 1.3 +diff -u -u -r1.1 -r1.3 +--- ops2.c 7 Sep 2007 10:01:21 -0000 1.1 ++++ ops2.c 20 Mar 2008 15:48:34 -0000 1.3 +@@ -149,8 +149,69 @@ + target += (s16) M.x86.R_IP; + DECODE_PRINTF2("%04x\n", target); + TRACE_AND_STEP(); +- if (cond) ++ if (cond) { + M.x86.R_IP = (u16)target; ++ JMP_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, M.x86.R_IP, " LONG COND "); ++ } ++ DECODE_CLEAR_SEGOVR(); ++ END_OF_INSTR(); ++} ++ ++/**************************************************************************** ++REMARKS: ++Handles opcode 0x0f,0xC8-0xCF ++****************************************************************************/ ++s32 x86emu_bswap(s32 reg) ++{ ++ // perform the byte swap ++ s32 temp = reg; ++ reg = (temp & 0xFF000000) >> 24; ++ reg |= (temp & 0xFF0000) >> 8; ++ reg |= (temp & 0xFF00) << 8; ++ reg |= (temp & 0xFF) << 24; ++ return reg; ++} ++ ++void x86emuOp2_bswap(u8 op2) ++{ ++ /* byte swap 32 bit register */ ++ START_OF_INSTR(); ++ DECODE_PRINTF("BSWAP\t"); ++ switch (op2) { ++ case 0xc8: ++ DECODE_PRINTF("EAX\n"); ++ M.x86.R_EAX = x86emu_bswap(M.x86.R_EAX); ++ break; ++ case 0xc9: ++ DECODE_PRINTF("ECX\n"); ++ M.x86.R_ECX = x86emu_bswap(M.x86.R_ECX); ++ break; ++ case 0xca: ++ DECODE_PRINTF("EDX\n"); ++ M.x86.R_EDX = x86emu_bswap(M.x86.R_EDX); ++ break; ++ case 0xcb: ++ DECODE_PRINTF("EBX\n"); ++ M.x86.R_EBX = x86emu_bswap(M.x86.R_EBX); ++ break; ++ case 0xcc: ++ DECODE_PRINTF("ESP\n"); ++ M.x86.R_ESP = x86emu_bswap(M.x86.R_ESP); ++ break; ++ case 0xcd: ++ DECODE_PRINTF("EBP\n"); ++ M.x86.R_EBP = x86emu_bswap(M.x86.R_EBP); ++ break; ++ case 0xce: ++ DECODE_PRINTF("ESI\n"); ++ M.x86.R_ESI = x86emu_bswap(M.x86.R_ESI); ++ break; ++ case 0xcf: ++ DECODE_PRINTF("EDI\n"); ++ M.x86.R_EDI = x86emu_bswap(M.x86.R_EDI); ++ break; ++ } ++ TRACE_AND_STEP(); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); + } +@@ -1702,14 +1763,14 @@ + /* 0xc5 */ x86emuOp2_illegal_op, + /* 0xc6 */ x86emuOp2_illegal_op, + /* 0xc7 */ x86emuOp2_illegal_op, +-/* 0xc8 */ x86emuOp2_illegal_op, /* TODO: bswap */ +-/* 0xc9 */ x86emuOp2_illegal_op, /* TODO: bswap */ +-/* 0xca */ x86emuOp2_illegal_op, /* TODO: bswap */ +-/* 0xcb */ x86emuOp2_illegal_op, /* TODO: bswap */ +-/* 0xcc */ x86emuOp2_illegal_op, /* TODO: bswap */ +-/* 0xcd */ x86emuOp2_illegal_op, /* TODO: bswap */ +-/* 0xce */ x86emuOp2_illegal_op, /* TODO: bswap */ +-/* 0xcf */ x86emuOp2_illegal_op, /* TODO: bswap */ ++/* 0xc8 */ x86emuOp2_bswap, ++/* 0xc9 */ x86emuOp2_bswap, ++/* 0xca */ x86emuOp2_bswap, ++/* 0xcb */ x86emuOp2_bswap, ++/* 0xcc */ x86emuOp2_bswap, ++/* 0xcd */ x86emuOp2_bswap, ++/* 0xce */ x86emuOp2_bswap, ++/* 0xcf */ x86emuOp2_bswap, + + /* 0xd0 */ x86emuOp2_illegal_op, + /* 0xd1 */ x86emuOp2_illegal_op, +Index: ops.c +=================================================================== +RCS file: /cvs/osdf/cvs/host/other-licence/x86emu/ops.c,v +retrieving revision 1.1 +diff -u -u -r1.1 ops.c +--- ops.c 7 Sep 2007 10:01:21 -0000 1.1 ++++ ops.c 20 Mar 2008 16:52:00 -0000 +@@ -1061,7 +1061,11 @@ + imm = (s8)fetch_byte_imm(); + DECODE_PRINTF2("PUSH\t%d\n", imm); + TRACE_AND_STEP(); +- push_word(imm); ++ if (M.x86.mode & SYSMODE_PREFIX_DATA) { ++ push_long(imm); ++ } else { ++ push_word(imm); ++ } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); + } +@@ -1256,8 +1260,10 @@ + target = (u16)(M.x86.R_IP + (s16)offset); + DECODE_PRINTF2("%x\n", target); + TRACE_AND_STEP(); +- if (cond) ++ if (cond) { + M.x86.R_IP = target; ++ JMP_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, M.x86.R_IP, " NEAR COND "); ++ } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); + } +@@ -2516,9 +2522,11 @@ + count = 1; + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ +- /* move them until CX is ZERO. */ +- count = M.x86.R_CX; ++ /* move them until (E)CX is ZERO. */ ++ count = (M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX; + M.x86.R_CX = 0; ++ if (M.x86.mode & SYSMODE_32BIT_REP) ++ M.x86.R_ECX = 0; + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } + while (count--) { +@@ -2526,6 +2534,8 @@ + store_data_byte_abs(M.x86.R_ES, M.x86.R_DI, val); + M.x86.R_SI += inc; + M.x86.R_DI += inc; ++ if (M.x86.intr & INTR_HALTED) ++ break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +@@ -2559,9 +2569,11 @@ + count = 1; + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ +- /* move them until CX is ZERO. */ +- count = M.x86.R_CX; ++ /* move them until (E)CX is ZERO. */ ++ count = (M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX; + M.x86.R_CX = 0; ++ if (M.x86.mode & SYSMODE_32BIT_REP) ++ M.x86.R_ECX = 0; + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } + while (count--) { +@@ -2574,6 +2586,8 @@ + } + M.x86.R_SI += inc; + M.x86.R_DI += inc; ++ if (M.x86.intr & INTR_HALTED) ++ break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +@@ -2598,16 +2612,21 @@ + + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* REPE */ +- /* move them until CX is ZERO. */ +- while (M.x86.R_CX != 0) { ++ /* move them until (E)CX is ZERO. */ ++ while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) { + val1 = fetch_data_byte(M.x86.R_SI); + val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI); + cmp_byte(val1, val2); +- M.x86.R_CX -= 1; ++ if (M.x86.mode & SYSMODE_32BIT_REP) ++ M.x86.R_ECX -= 1; ++ else ++ M.x86.R_CX -= 1; + M.x86.R_SI += inc; + M.x86.R_DI += inc; + if ( (M.x86.mode & SYSMODE_PREFIX_REPE) && (ACCESS_FLAG(F_ZF) == 0) ) break; + if ( (M.x86.mode & SYSMODE_PREFIX_REPNE) && ACCESS_FLAG(F_ZF) ) break; ++ if (M.x86.intr & INTR_HALTED) ++ break; + } + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } else { +@@ -2644,8 +2663,8 @@ + TRACE_AND_STEP(); + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* REPE */ +- /* move them until CX is ZERO. */ +- while (M.x86.R_CX != 0) { ++ /* move them until (E)CX is ZERO. */ ++ while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) { + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + val1 = fetch_data_long(M.x86.R_SI); + val2 = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI); +@@ -2655,11 +2674,16 @@ + val2 = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI); + cmp_word((u16)val1, (u16)val2); + } +- M.x86.R_CX -= 1; ++ if (M.x86.mode & SYSMODE_32BIT_REP) ++ M.x86.R_ECX -= 1; ++ else ++ M.x86.R_CX -= 1; + M.x86.R_SI += inc; + M.x86.R_DI += inc; + if ( (M.x86.mode & SYSMODE_PREFIX_REPE) && ACCESS_FLAG(F_ZF) == 0 ) break; + if ( (M.x86.mode & SYSMODE_PREFIX_REPNE) && ACCESS_FLAG(F_ZF) ) break; ++ if (M.x86.intr & INTR_HALTED) ++ break; + } + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } else { +@@ -2741,11 +2765,16 @@ + TRACE_AND_STEP(); + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ +- /* move them until CX is ZERO. */ +- while (M.x86.R_CX != 0) { ++ /* move them until (E)CX is ZERO. */ ++ while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) { + store_data_byte_abs(M.x86.R_ES, M.x86.R_DI, M.x86.R_AL); +- M.x86.R_CX -= 1; ++ if (M.x86.mode & SYSMODE_32BIT_REP) ++ M.x86.R_ECX -= 1; ++ else ++ M.x86.R_CX -= 1; + M.x86.R_DI += inc; ++ if (M.x86.intr & INTR_HALTED) ++ break; + } + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } else { +@@ -2783,9 +2812,11 @@ + count = 1; + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ +- /* move them until CX is ZERO. */ +- count = M.x86.R_CX; ++ /* move them until (E)CX is ZERO. */ ++ count = (M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX; + M.x86.R_CX = 0; ++ if (M.x86.mode & SYSMODE_32BIT_REP) ++ M.x86.R_ECX = 0; + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } + while (count--) { +@@ -2795,6 +2826,8 @@ + store_data_word_abs(M.x86.R_ES, M.x86.R_DI, M.x86.R_AX); + } + M.x86.R_DI += inc; ++ if (M.x86.intr & INTR_HALTED) ++ break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +@@ -2817,11 +2850,16 @@ + inc = 1; + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ +- /* move them until CX is ZERO. */ +- while (M.x86.R_CX != 0) { ++ /* move them until (E)CX is ZERO. */ ++ while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) { + M.x86.R_AL = fetch_data_byte(M.x86.R_SI); +- M.x86.R_CX -= 1; ++ if (M.x86.mode & SYSMODE_32BIT_REP) ++ M.x86.R_ECX -= 1; ++ else ++ M.x86.R_CX -= 1; + M.x86.R_SI += inc; ++ if (M.x86.intr & INTR_HALTED) ++ break; + } + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } else { +@@ -2859,9 +2897,11 @@ + count = 1; + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ +- /* move them until CX is ZERO. */ +- count = M.x86.R_CX; ++ /* move them until (E)CX is ZERO. */ ++ count = (M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX; + M.x86.R_CX = 0; ++ if (M.x86.mode & SYSMODE_32BIT_REP) ++ M.x86.R_ECX = 0; + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } + while (count--) { +@@ -2871,6 +2911,8 @@ + M.x86.R_AX = fetch_data_word(M.x86.R_SI); + } + M.x86.R_SI += inc; ++ if (M.x86.intr & INTR_HALTED) ++ break; + } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +@@ -2894,26 +2936,36 @@ + inc = 1; + if (M.x86.mode & SYSMODE_PREFIX_REPE) { + /* REPE */ +- /* move them until CX is ZERO. */ +- while (M.x86.R_CX != 0) { ++ /* move them until (E)CX is ZERO. */ ++ while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) { + val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI); + cmp_byte(M.x86.R_AL, val2); +- M.x86.R_CX -= 1; ++ if (M.x86.mode & SYSMODE_32BIT_REP) ++ M.x86.R_ECX -= 1; ++ else ++ M.x86.R_CX -= 1; + M.x86.R_DI += inc; + if (ACCESS_FLAG(F_ZF) == 0) + break; ++ if (M.x86.intr & INTR_HALTED) ++ break; + } + M.x86.mode &= ~SYSMODE_PREFIX_REPE; + } else if (M.x86.mode & SYSMODE_PREFIX_REPNE) { + /* REPNE */ +- /* move them until CX is ZERO. */ +- while (M.x86.R_CX != 0) { ++ /* move them until (E)CX is ZERO. */ ++ while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) { + val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI); + cmp_byte(M.x86.R_AL, val2); +- M.x86.R_CX -= 1; ++ if (M.x86.mode & SYSMODE_32BIT_REP) ++ M.x86.R_ECX -= 1; ++ else ++ M.x86.R_CX -= 1; + M.x86.R_DI += inc; + if (ACCESS_FLAG(F_ZF)) + break; /* zero flag set means equal */ ++ if (M.x86.intr & INTR_HALTED) ++ break; + } + M.x86.mode &= ~SYSMODE_PREFIX_REPNE; + } else { +@@ -2951,8 +3003,8 @@ + TRACE_AND_STEP(); + if (M.x86.mode & SYSMODE_PREFIX_REPE) { + /* REPE */ +- /* move them until CX is ZERO. */ +- while (M.x86.R_CX != 0) { ++ /* move them until (E)CX is ZERO. */ ++ while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) { + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + val = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI); + cmp_long(M.x86.R_EAX, val); +@@ -2960,16 +3012,21 @@ + val = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI); + cmp_word(M.x86.R_AX, (u16)val); + } +- M.x86.R_CX -= 1; ++ if (M.x86.mode & SYSMODE_32BIT_REP) ++ M.x86.R_ECX -= 1; ++ else ++ M.x86.R_CX -= 1; + M.x86.R_DI += inc; + if (ACCESS_FLAG(F_ZF) == 0) + break; ++ if (M.x86.intr & INTR_HALTED) ++ break; + } + M.x86.mode &= ~SYSMODE_PREFIX_REPE; + } else if (M.x86.mode & SYSMODE_PREFIX_REPNE) { + /* REPNE */ +- /* move them until CX is ZERO. */ +- while (M.x86.R_CX != 0) { ++ /* move them until (E)CX is ZERO. */ ++ while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) { + if (M.x86.mode & SYSMODE_PREFIX_DATA) { + val = fetch_data_long_abs(M.x86.R_ES, M.x86.R_DI); + cmp_long(M.x86.R_EAX, val); +@@ -2977,10 +3034,15 @@ + val = fetch_data_word_abs(M.x86.R_ES, M.x86.R_DI); + cmp_word(M.x86.R_AX, (u16)val); + } +- M.x86.R_CX -= 1; ++ if (M.x86.mode & SYSMODE_32BIT_REP) ++ M.x86.R_ECX -= 1; ++ else ++ M.x86.R_CX -= 1; + M.x86.R_DI += inc; + if (ACCESS_FLAG(F_ZF)) + break; /* zero flag set means equal */ ++ if (M.x86.intr & INTR_HALTED) ++ break; + } + M.x86.mode &= ~SYSMODE_PREFIX_REPNE; + } else { +@@ -3238,9 +3300,9 @@ + DECODE_PRINTF("RET\t"); + imm = fetch_word_imm(); + DECODE_PRINTF2("%x\n", imm); +- RETURN_TRACE("RET",M.x86.saved_cs,M.x86.saved_ip); + TRACE_AND_STEP(); + M.x86.R_IP = pop_word(); ++ RETURN_TRACE(M.x86.saved_cs,M.x86.saved_ip, M.x86.R_CS, M.x86.R_IP, "NEAR"); + M.x86.R_SP += imm; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +@@ -3254,9 +3316,9 @@ + { + START_OF_INSTR(); + DECODE_PRINTF("RET\n"); +- RETURN_TRACE("RET",M.x86.saved_cs,M.x86.saved_ip); + TRACE_AND_STEP(); + M.x86.R_IP = pop_word(); ++ RETURN_TRACE(M.x86.saved_cs,M.x86.saved_ip, M.x86.R_CS, M.x86.R_IP, "NEAR"); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); + } +@@ -3471,10 +3533,10 @@ + DECODE_PRINTF("RETF\t"); + imm = fetch_word_imm(); + DECODE_PRINTF2("%x\n", imm); +- RETURN_TRACE("RETF",M.x86.saved_cs,M.x86.saved_ip); + TRACE_AND_STEP(); + M.x86.R_IP = pop_word(); + M.x86.R_CS = pop_word(); ++ RETURN_TRACE(M.x86.saved_cs,M.x86.saved_ip, M.x86.R_CS, M.x86.R_IP, "FAR"); + M.x86.R_SP += imm; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +@@ -3488,10 +3550,10 @@ + { + START_OF_INSTR(); + DECODE_PRINTF("RETF\n"); +- RETURN_TRACE("RETF",M.x86.saved_cs,M.x86.saved_ip); + TRACE_AND_STEP(); + M.x86.R_IP = pop_word(); + M.x86.R_CS = pop_word(); ++ RETURN_TRACE(M.x86.saved_cs,M.x86.saved_ip, M.x86.R_CS, M.x86.R_IP, "FAR"); + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); + } +@@ -4020,8 +4082,11 @@ + ip += (s16) M.x86.R_IP; + DECODE_PRINTF2("%04x\n", ip); + TRACE_AND_STEP(); +- M.x86.R_CX -= 1; +- if (M.x86.R_CX != 0 && !ACCESS_FLAG(F_ZF)) /* CX != 0 and !ZF */ ++ if (M.x86.mode & SYSMODE_PREFIX_ADDR) ++ M.x86.R_ECX -= 1; ++ else ++ M.x86.R_CX -= 1; ++ if (((M.x86.mode & SYSMODE_PREFIX_ADDR) ? M.x86.R_ECX : M.x86.R_CX) != 0 && !ACCESS_FLAG(F_ZF)) /* (E)CX != 0 and !ZF */ + M.x86.R_IP = ip; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +@@ -4041,8 +4106,11 @@ + ip += (s16) M.x86.R_IP; + DECODE_PRINTF2("%04x\n", ip); + TRACE_AND_STEP(); +- M.x86.R_CX -= 1; +- if (M.x86.R_CX != 0 && ACCESS_FLAG(F_ZF)) /* CX != 0 and ZF */ ++ if (M.x86.mode & SYSMODE_PREFIX_ADDR) ++ M.x86.R_ECX -= 1; ++ else ++ M.x86.R_CX -= 1; ++ if (((M.x86.mode & SYSMODE_PREFIX_ADDR) ? M.x86.R_ECX : M.x86.R_CX) != 0 && ACCESS_FLAG(F_ZF)) /* (E)CX != 0 and ZF */ + M.x86.R_IP = ip; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +@@ -4062,8 +4130,11 @@ + ip += (s16) M.x86.R_IP; + DECODE_PRINTF2("%04x\n", ip); + TRACE_AND_STEP(); +- M.x86.R_CX -= 1; +- if (M.x86.R_CX != 0) ++ if (M.x86.mode & SYSMODE_PREFIX_ADDR) ++ M.x86.R_ECX -= 1; ++ else ++ M.x86.R_CX -= 1; ++ if (((M.x86.mode & SYSMODE_PREFIX_ADDR) ? M.x86.R_ECX : M.x86.R_CX) != 0) /* (E)CX != 0 */ + M.x86.R_IP = ip; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); +@@ -4085,8 +4156,10 @@ + target = (u16)(M.x86.R_IP + offset); + DECODE_PRINTF2("%x\n", target); + TRACE_AND_STEP(); +- if (M.x86.R_CX == 0) ++ if (M.x86.R_CX == 0) { + M.x86.R_IP = target; ++ JMP_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, M.x86.R_IP, " CXZ "); ++ } + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); + } +@@ -4213,6 +4286,7 @@ + ip = (s16)fetch_word_imm(); + ip += (s16)M.x86.R_IP; + DECODE_PRINTF2("%04x\n", ip); ++ JMP_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, ip, " NEAR "); + TRACE_AND_STEP(); + M.x86.R_IP = (u16)ip; + DECODE_CLEAR_SEGOVR(); +@@ -4233,6 +4307,7 @@ + cs = fetch_word_imm(); + DECODE_PRINTF2("%04x:", cs); + DECODE_PRINTF2("%04x\n", ip); ++ JMP_TRACE(M.x86.saved_cs, M.x86.saved_ip, cs, ip, " FAR "); + TRACE_AND_STEP(); + M.x86.R_IP = ip; + M.x86.R_CS = cs; +@@ -4254,6 +4329,7 @@ + offset = (s8)fetch_byte_imm(); + target = (u16)(M.x86.R_IP + offset); + DECODE_PRINTF2("%x\n", target); ++ JMP_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, target, " BYTE "); + TRACE_AND_STEP(); + M.x86.R_IP = target; + DECODE_CLEAR_SEGOVR(); +@@ -4357,6 +4433,8 @@ + DECODE_PRINTF("REPNE\n"); + TRACE_AND_STEP(); + M.x86.mode |= SYSMODE_PREFIX_REPNE; ++ if (M.x86.mode & SYSMODE_PREFIX_ADDR) ++ M.x86.mode |= SYSMODE_32BIT_REP; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); + } +@@ -4371,6 +4449,8 @@ + DECODE_PRINTF("REPE\n"); + TRACE_AND_STEP(); + M.x86.mode |= SYSMODE_PREFIX_REPE; ++ if (M.x86.mode & SYSMODE_PREFIX_ADDR) ++ M.x86.mode |= SYSMODE_32BIT_REP; + DECODE_CLEAR_SEGOVR(); + END_OF_INSTR(); + } +@@ -5013,12 +5093,14 @@ + break; + case 4: /* jmp word ptr ... */ + destval = fetch_data_word(destoffset); ++ JMP_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, destval, " WORD "); + TRACE_AND_STEP(); + M.x86.R_IP = destval; + break; + case 5: /* jmp far ptr ... */ + destval = fetch_data_word(destoffset); + destval2 = fetch_data_word(destoffset + 2); ++ JMP_TRACE(M.x86.saved_cs, M.x86.saved_ip, destval2, destval, " FAR "); + TRACE_AND_STEP(); + M.x86.R_IP = destval; + M.x86.R_CS = destval2; +Index: prim_ops.c +=================================================================== +RCS file: /cvs/osdf/cvs/host/other-licence/x86emu/prim_ops.c,v +retrieving revision 1.1 +retrieving revision 1.3 +diff -u -u -r1.1 -r1.3 +--- prim_ops.c 7 Sep 2007 10:01:21 -0000 1.1 ++++ prim_ops.c 16 Jan 2008 14:18:15 -0000 1.3 +@@ -1921,7 +1921,7 @@ + void imul_long_direct(u32 *res_lo, u32* res_hi,u32 d, u32 s) + { + #ifdef __HAS_LONG_LONG__ +- s64 res = (s64)d * (s64)s; ++ s64 res = (s64)(s32)d * (s64)(s32)s; + + *res_lo = (u32)res; + *res_hi = (u32)(res >> 32); +@@ -2013,7 +2013,7 @@ + void mul_long(u32 s) + { + #ifdef __HAS_LONG_LONG__ +- u64 res = (u32)M.x86.R_EAX * (u32)s; ++ u64 res = (u64)M.x86.R_EAX * s; + + M.x86.R_EAX = (u32)res; + M.x86.R_EDX = (u32)(res >> 32); +@@ -2312,16 +2312,15 @@ + } + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ +- /* in until CX is ZERO. */ +- u32 count = ((M.x86.mode & SYSMODE_PREFIX_DATA) ? ++ /* in until (E)CX is ZERO. */ ++ u32 count = ((M.x86.mode & SYSMODE_32BIT_REP) ? + M.x86.R_ECX : M.x86.R_CX); +- + while (count--) { + single_in(size); + M.x86.R_DI += inc; + } + M.x86.R_CX = 0; +- if (M.x86.mode & SYSMODE_PREFIX_DATA) { ++ if (M.x86.mode & SYSMODE_32BIT_REP) { + M.x86.R_ECX = 0; + } + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); +@@ -2355,15 +2354,15 @@ + } + if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { + /* dont care whether REPE or REPNE */ +- /* out until CX is ZERO. */ +- u32 count = ((M.x86.mode & SYSMODE_PREFIX_DATA) ? ++ /* out until (E)CX is ZERO. */ ++ u32 count = ((M.x86.mode & SYSMODE_32BIT_REP) ? + M.x86.R_ECX : M.x86.R_CX); + while (count--) { + single_out(size); + M.x86.R_SI += inc; + } + M.x86.R_CX = 0; +- if (M.x86.mode & SYSMODE_PREFIX_DATA) { ++ if (M.x86.mode & SYSMODE_32BIT_REP) { + M.x86.R_ECX = 0; + } + M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); +Index: sys.c +=================================================================== +RCS file: /cvs/osdf/cvs/host/other-licence/x86emu/sys.c,v +retrieving revision 1.1 +retrieving revision 1.2 +diff -u -u -r1.1 -r1.2 +--- sys.c 7 Sep 2007 10:01:21 -0000 1.1 ++++ sys.c 7 Sep 2007 10:03:13 -0000 1.2 +@@ -45,11 +45,6 @@ + #include <x86emu/regs.h> + #include "debug.h" + #include "prim_ops.h" +-#ifdef LINUXBIOS_VERSION +-#include "io.h" +-#else +-#include <sys/io.h> +-#endif + + #ifdef IN_MODULE + #include "xf86_ansic.h" +@@ -220,7 +215,7 @@ + { + DB(if (DEBUG_IO_TRACE()) + printk("inb %#04x \n", addr);) +- return inb(addr); ++ return 0; + } + + /**************************************************************************** +@@ -235,7 +230,7 @@ + { + DB(if (DEBUG_IO_TRACE()) + printk("inw %#04x \n", addr);) +- return inw(addr); ++ return 0; + } + + /**************************************************************************** +@@ -250,7 +245,7 @@ + { + DB(if (DEBUG_IO_TRACE()) + printk("inl %#04x \n", addr);) +- return inl(addr); ++ return 0; + } + + /**************************************************************************** +@@ -264,7 +259,6 @@ + { + DB(if (DEBUG_IO_TRACE()) + printk("outb %#02x -> %#04x \n", val, addr);) +- outb(val, addr); + return; + } + +@@ -279,7 +273,6 @@ + { + DB(if (DEBUG_IO_TRACE()) + printk("outw %#04x -> %#04x \n", val, addr);) +- outw(val, addr); + return; + } + +@@ -295,7 +288,6 @@ + DB(if (DEBUG_IO_TRACE()) + printk("outl %#08x -> %#04x \n", val, addr);) + +- outl(val, addr); + return; + } + +@@ -405,6 +397,6 @@ + + void X86EMU_setMemBase(void *base, size_t size) + { +- M.mem_base = (int) base; ++ M.mem_base = (unsigned long) base; + M.mem_size = size; + } +Index: include/x86emu/debug.h +=================================================================== +RCS file: /cvs/osdf/cvs/host/other-licence/x86emu/include/x86emu/debug.h,v +retrieving revision 1.1 +retrieving revision 1.4 +diff -u -u -r1.1 -r1.4 +--- include/x86emu/debug.h 7 Sep 2007 10:01:21 -0000 1.1 ++++ include/x86emu/debug.h 20 Mar 2008 15:25:27 -0000 1.4 +@@ -40,8 +40,6 @@ + #ifndef __X86EMU_DEBUG_H + #define __X86EMU_DEBUG_H + +-//#define DEBUG 0 +-#undef DEBUG + /*---------------------- Macros and type definitions ----------------------*/ + + /* checks to be enabled for "runtime" */ +@@ -78,6 +76,8 @@ + # define DEBUG_SYSINT() (M.x86.debug & DEBUG_SYSINT_F) + # define DEBUG_TRACECALL() (M.x86.debug & DEBUG_TRACECALL_F) + # define DEBUG_TRACECALLREGS() (M.x86.debug & DEBUG_TRACECALL_REGS_F) ++# define DEBUG_TRACEJMP() (M.x86.debug & DEBUG_TRACEJMP_F) ++# define DEBUG_TRACEJMPREGS() (M.x86.debug & DEBUG_TRACEJMP_REGS_F) + # define DEBUG_SYS() (M.x86.debug & DEBUG_SYS_F) + # define DEBUG_MEM_TRACE() (M.x86.debug & DEBUG_MEM_TRACE_F) + # define DEBUG_IO_TRACE() (M.x86.debug & DEBUG_IO_TRACE_F) +@@ -96,6 +96,8 @@ + # define DEBUG_SYSINT() 0 + # define DEBUG_TRACECALL() 0 + # define DEBUG_TRACECALLREGS() 0 ++# define DEBUG_TRACEJMP() 0 ++# define DEBUG_TRACEJMPREGS() 0 + # define DEBUG_SYS() 0 + # define DEBUG_MEM_TRACE() 0 + # define DEBUG_IO_TRACE() 0 +@@ -169,14 +171,20 @@ + x86emu_dump_regs(); \ + if (DEBUG_TRACECALL()) \ + printk("%04x:%04x: CALL %s%04x:%04x\n", u , v, s, w, x); +-# define RETURN_TRACE(n,u,v) \ ++# define RETURN_TRACE(u,v,w,x,s) \ + if (DEBUG_TRACECALLREGS()) \ + x86emu_dump_regs(); \ + if (DEBUG_TRACECALL()) \ +- printk("%04x:%04x: %s\n",u,v,n); ++ printk("%04x:%04x: RET %s %04x:%04x\n",u,v,s,w,x); ++# define JMP_TRACE(u,v,w,x,s) \ ++ if (DEBUG_TRACEJMPREGS()) \ ++ x86emu_dump_regs(); \ ++ if (DEBUG_TRACEJMP()) \ ++ printk("%04x:%04x: JMP %s%04x:%04x\n", u , v, s, w, x); + #else + # define CALL_TRACE(u,v,w,x,s) +-# define RETURN_TRACE(n,u,v) ++# define RETURN_TRACE(u,v,w,x,s) ++# define JMP_TRACE(u,v,w,x,s) + #endif + + #ifdef DEBUG +Index: include/x86emu/regs.h +=================================================================== +RCS file: /cvs/osdf/cvs/host/other-licence/x86emu/include/x86emu/regs.h,v +retrieving revision 1.1 +retrieving revision 1.4 +diff -u -u -r1.1 -r1.4 +--- include/x86emu/regs.h 7 Sep 2007 10:01:21 -0000 1.1 ++++ include/x86emu/regs.h 15 Jan 2008 13:46:40 -0000 1.4 +@@ -231,6 +231,9 @@ + #define SYSMODE_PREFIX_REPNE 0x00000100 + #define SYSMODE_PREFIX_DATA 0x00000200 + #define SYSMODE_PREFIX_ADDR 0x00000400 ++//phueper: for REP(E|NE) Instructions, we need to decide wether it should be using ++//the 32bit ECX register as or the 16bit CX register as count register ++#define SYSMODE_32BIT_REP 0x00000800 + #define SYSMODE_INTR_PENDING 0x10000000 + #define SYSMODE_EXTRN_INTR 0x20000000 + #define SYSMODE_HALTED 0x40000000 +@@ -250,7 +253,8 @@ + SYSMODE_SEGOVR_GS | \ + SYSMODE_SEGOVR_SS | \ + SYSMODE_PREFIX_DATA | \ +- SYSMODE_PREFIX_ADDR) ++ SYSMODE_PREFIX_ADDR | \ ++ SYSMODE_32BIT_REP) + + #define INTR_SYNCH 0x1 + #define INTR_ASYNCH 0x2 +@@ -274,9 +278,9 @@ + */ + u32 mode; + volatile int intr; /* mask of pending interrupts */ +- int debug; ++ volatile int debug; + #ifdef DEBUG +- int check; ++ int check; + u16 saved_ip; + u16 saved_cs; + int enc_pos; +@@ -366,7 +370,7 @@ + + /* Function to log information at runtime */ + +-//void printk(const char *fmt, ...); ++void printk(const char *fmt, ...); + + #ifdef __cplusplus + } /* End of "C" linkage for C++ */ +Index: include/x86emu/x86emu.h +=================================================================== +RCS file: /cvs/osdf/cvs/host/other-licence/x86emu/include/x86emu/x86emu.h,v +retrieving revision 1.1 +retrieving revision 1.3 +diff -u -u -r1.1 -r1.3 +--- include/x86emu/x86emu.h 7 Sep 2007 10:01:21 -0000 1.1 ++++ include/x86emu/x86emu.h 19 Oct 2007 08:42:15 -0000 1.3 +@@ -42,14 +42,6 @@ + #ifndef __X86EMU_X86EMU_H + #define __X86EMU_X86EMU_H + +-/* FIXME: undefine printk for the moment */ +-#ifdef LINUXBIOS_VERSION +-#include <console.h> +-#define printk(x...) printk(BIOS_DEBUG, x) +-#else +-#define printk printf +-#endif +- + #ifdef SCITECH + #include "scitech.h" + #define X86API _ASMAPI +@@ -189,6 +181,8 @@ + #define DEBUG_TRACECALL_REGS_F 0x004000 + #define DEBUG_DECODE_NOPRINT_F 0x008000 + #define DEBUG_SAVE_IP_CS_F 0x010000 ++#define DEBUG_TRACEJMP_F 0x020000 ++#define DEBUG_TRACEJMP_REGS_F 0x040000 + #define DEBUG_SYS_F (DEBUG_SVC_F|DEBUG_FS_F|DEBUG_PROC_F) + + void X86EMU_trace_regs(void); +@@ -200,5 +194,4 @@ + #ifdef __cplusplus + } /* End of "C" linkage for C++ */ + #endif +- + #endif /* __X86EMU_X86EMU_H */ diff --git a/other-licence/x86emu/x86emu_download.sh b/other-licence/x86emu/x86emu_download.sh new file mode 100755 index 0000000..36b1e10 --- /dev/null +++ b/other-licence/x86emu/x86emu_download.sh @@ -0,0 +1,60 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008 IBM Corporation +# * All rights reserved. +# * This program and the accompanying materials +# * are made available under the terms of the BSD License +# * which accompanies this distribution, and is available at +# * http://www.opensource.org/licenses/bsd-license.php +# * +# * Contributors: +# * IBM Corporation - initial implementation +# ****************************************************************************/ +#!/bin/bash + +#set -x +#set -e + +SVN=`which svn` +PATCH=`which patch` +DIFF_FILE=./x86emu_changes.diff + +# check wether svn, patch, ... is available... + +if [ ! -x $SVN ]; then + echo "subversion executable not found!" + exit -1 +fi +if [ ! -x $PATCH ]; then + echo "patch executable not found!" + exit -1 +fi +if [ ! -r $DIFF_FILE ]; then + echo "diff file $DIFF_FILE not found!" + exit -1 +fi + +# download the x86emu sources from LinuxBIOS subversion + +#revision known to work... +REV=496 + +echo "Checking out x86emu from coreboot-v3 repository revision $REV" +$SVN co svn://coreboot.org/repository/coreboot-v3/util/x86emu -r $REV + +echo "Copying files..." + +cp -v x86emu/x86emu/*.c . +cp -v x86emu/x86emu/*.h include/x86emu +cp -v x86emu/include/x86emu/*.h include/x86emu + +echo "Removing checkedout subversion director..." + +rm -rf x86emu + +echo "Patching files..." + +$PATCH -p0 < x86emu_changes.diff + + +echo "done" +exit 0 |