From 5f84bfe465818d9bfab537ac73d57c2e0d63a2dd Mon Sep 17 00:00:00 2001 From: Avik Sil Date: Mon, 23 Sep 2013 14:07:36 +0530 Subject: Add bcm57xx network driver in libbcm Signed-off-by: Avik Sil Signed-off-by: Nikunj A Dadhania --- board-js2x/Makefile | 2 +- board-js2x/slof/Makefile | 10 +- board-js2x/slof/bcm57xx.fs | 75 + board-js2x/slof/pci-device_14e4_16a8.fs | 23 + clients/net-snk/kernel/modules.c | 1 - lib/Makefile | 2 +- lib/libbcm/Makefile | 51 + lib/libbcm/bcm.code | 57 + lib/libbcm/bcm.in | 20 + lib/libbcm/bcm57xx.c | 3461 +++++++++++++++++++++++++++++++ lib/libbcm/bcm57xx.h | 323 +++ 11 files changed, 4019 insertions(+), 6 deletions(-) create mode 100644 board-js2x/slof/bcm57xx.fs create mode 100644 board-js2x/slof/pci-device_14e4_16a8.fs create mode 100644 lib/libbcm/Makefile create mode 100644 lib/libbcm/bcm.code create mode 100644 lib/libbcm/bcm.in create mode 100644 lib/libbcm/bcm57xx.c create mode 100644 lib/libbcm/bcm57xx.h diff --git a/board-js2x/Makefile b/board-js2x/Makefile index 2f6e79a..4747f41 100644 --- a/board-js2x/Makefile +++ b/board-js2x/Makefile @@ -13,7 +13,7 @@ BOARD_TARGETS = tools_build romfs_build clients_build netdrivers stage1 subdirs SUBDIRS = slof rtas -COMMON_LIBS = libc libipmi libbootmsg libbases libnvram libelf libusb +COMMON_LIBS = libc libipmi libbootmsg libbases libnvram libelf libusb libbcm all: $(BOARD_TARGETS) $(MAKE) boot_rom.bin diff --git a/board-js2x/slof/Makefile b/board-js2x/slof/Makefile index 1dd9be5..5be9f07 100644 --- a/board-js2x/slof/Makefile +++ b/board-js2x/slof/Makefile @@ -20,19 +20,21 @@ include $(TOPCMNDIR)/make.rules all: Makefile.dep OF.ffs paflof $(SLOFCMNDIR)/xvect.bin CPPFLAGS = -I$(LIBCMNDIR)/libbootmsg -I$(LIBCMNDIR)/libnvram \ - -I$(LIBCMNDIR)/libusb + -I$(LIBCMNDIR)/libusb -I$(LIBCMNDIR)/libbcm SLOF_LIBS = \ $(LIBCMNDIR)/libbootmsg.a \ $(LIBCMNDIR)/libelf.a \ $(LIBCMNDIR)/libusb.a \ - $(LIBCMNDIR)/libnvram.a + $(LIBCMNDIR)/libnvram.a \ + $(LIBCMNDIR)/libbcm.a BOARD_SLOF_IN = \ $(LIBCMNDIR)/libbootmsg/bootmsg.in \ $(LIBCMNDIR)/libelf/libelf.in \ $(LIBCMNDIR)/libusb/usb.in \ $(LIBCMNDIR)/libbases/libbases.in \ $(LIBCMNDIR)/libnvram/libnvram.in \ - $(LIBCMNDIR)/libnativeio/nativeio.in + $(LIBCMNDIR)/libnativeio/nativeio.in \ + $(LIBCMNDIR)/libbcm/bcm.in BOARD_SLOF_CODE = $(BOARD_SLOF_IN:%.in=%.code) include $(SLOFCMNDIR)/Makefile.inc @@ -61,6 +63,8 @@ OF_FFS_FILES = \ $(SLOFBRDDIR)/pci-device_1022_7468.fs \ $(SLOFBRDDIR)/pci-device_1022_7469.fs \ $(SLOFBRDDIR)/pci-device_1022_7451.fs \ + $(SLOFBRDDIR)/pci-device_14e4_16a8.fs \ + $(SLOFBRDDIR)/bcm57xx.fs \ $(SLOFBRDDIR)/pci-class_03.fs \ $(SLOFBRDDIR)/vga-display.fs \ $(SLOFBRDDIR)/freq.fs \ diff --git a/board-js2x/slof/bcm57xx.fs b/board-js2x/slof/bcm57xx.fs new file mode 100644 index 0000000..e4f8776 --- /dev/null +++ b/board-js2x/slof/bcm57xx.fs @@ -0,0 +1,75 @@ +\ ***************************************************************************** +\ * Copyright (c) 2013 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 +\ ****************************************************************************/ + +\ Handle bcm57xx device + +s" network" device-type + +my-space pci-alias-net + +VARIABLE obp-tftp-package + +0 VALUE bcm57xx-priv +0 VALUE open-count + +: open ( -- okay? ) + open-count 0= IF + open IF + my-args s" obp-tftp" $open-package obp-tftp-package ! + bcm57xx-open dup not IF ." bcm57xx-open failed" EXIT THEN + drop dup TO bcm57xx-priv + 6 encode-bytes s" local-mac-address" property + true + ELSE + false + THEN + ELSE + true + THEN + open-count 1 + to open-count +; + + +: close ( -- ) + open-count 0> IF + open-count 1 - dup to open-count + 0= IF + s" close" obp-tftp-package @ $call-method + bcm57xx-priv bcm57xx-close + close + THEN + THEN +; + +: read ( buf len -- actual ) + dup IF + bcm57xx-read + ELSE + nip + THEN +; + +: write ( buf len -- actual ) + dup IF + bcm57xx-write + ELSE + nip + THEN +; + +: load ( addr -- len ) + s" load" obp-tftp-package @ $call-method +; + +: ping ( -- ) + s" ping" obp-tftp-package @ $call-method +; diff --git a/board-js2x/slof/pci-device_14e4_16a8.fs b/board-js2x/slof/pci-device_14e4_16a8.fs new file mode 100644 index 0000000..ef782c9 --- /dev/null +++ b/board-js2x/slof/pci-device_14e4_16a8.fs @@ -0,0 +1,23 @@ +\ ***************************************************************************** +\ * Copyright (c) 2013 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 +\ ****************************************************************************/ + +\ Handle bcm57xx device + +s" bcm57xx [ net ]" type cr + +my-space pci-device-generic-setup + +pci-io-enable + +s" bcm57xx.fs" included + +pci-device-disable diff --git a/clients/net-snk/kernel/modules.c b/clients/net-snk/kernel/modules.c index dc34b39..398b246 100644 --- a/clients/net-snk/kernel/modules.c +++ b/clients/net-snk/kernel/modules.c @@ -36,7 +36,6 @@ typedef struct { } mod_descriptor_t; static const mod_descriptor_t modules[] = { - { "net_bcm", MOD_TYPE_NETWORK }, { NULL, 0 } }; diff --git a/lib/Makefile b/lib/Makefile index 6654f9d..ed8a359 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -11,7 +11,7 @@ # ****************************************************************************/ SUBDIRS = libc libipmi libbootmsg libbases libnvram libelf libhvcall libvirtio \ - libusb libveth libe1k + libusb libveth libe1k libbcm all: subdirs diff --git a/lib/libbcm/Makefile b/lib/libbcm/Makefile new file mode 100644 index 0000000..b17e588 --- /dev/null +++ b/lib/libbcm/Makefile @@ -0,0 +1,51 @@ +# ***************************************************************************** +# * Copyright (c) 2004, 2008, 2013 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 +# ****************************************************************************/ + +TOPCMNDIR ?= ../.. + +CPPFLAGS = -I../libc/include $(CPUARCHDEF) -I$(INCLBRDDIR) \ + -I$(INCLCMNDIR) -I$(INCLCMNDIR)/$(CPUARCH) + +#CFLAGS += -O2 -I. -I../common -I$(TOP)/clients/net-snk/include -I$(TOP)/lib/libc/include -fno-builtin -ffreestanding -msoft-float -Wall -nostdinc + +LDFLAGS = -nostdlib + +TARGET = ../libbcm.a + + +all: $(TARGET) Makefile.dep + +SRCS = bcm57xx.c + +OBJS = $(SRCS:%.c=%.o) + +$(TARGET): $(OBJS) + $(AR) -rc $@ $(OBJS) + $(RANLIB) $@ + +clean: + $(RM) $(TARGET) $(OBJS) + +distclean: clean + $(RM) Makefile.dep + + +# Rules for creating the dependency file: +depend: + $(RM) Makefile.dep + $(MAKE) Makefile.dep + +Makefile.dep: Makefile + $(CC) -M $(CPPFLAGS) $(CFLAGS) $(SRCS) $(SRCSS) > Makefile.dep + +# Include dependency file if available: +-include Makefile.dep diff --git a/lib/libbcm/bcm.code b/lib/libbcm/bcm.code new file mode 100644 index 0000000..308ebba --- /dev/null +++ b/lib/libbcm/bcm.code @@ -0,0 +1,57 @@ +/****************************************************************************** + * Copyright (c) 2013 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 + *****************************************************************************/ + +/* + * libbcm Forth wrapper + */ + +#include + +// : bcm57xx-open ( -- false | [ driver true ] ) +PRIM(BCM57XX_X2d_OPEN) +{ + net_driver_t *net_driver = bcm57xx_open(); + if (net_driver) { + PUSH; + TOS.u = (unsigned long)net_driver; PUSH; + TOS.n = -1; + } else { + PUSH; + TOS.n = 0; + } +} +MIRP + +// : bcm57xx-close ( driver -- ) +PRIM(BCM57XX_X2d_CLOSE) +{ + net_driver_t *driver = TOS.a; POP; + bcm57xx_close(driver); +} +MIRP + + +// : bcm57xx-read ( addr len -- actual ) +PRIM(BCM57XX_X2d_READ) +{ + int len = TOS.u; POP; + TOS.n = bcm57xx_read(TOS.a, len); +} +MIRP + +// : bcm57xx-write ( addr len -- actual ) +PRIM(BCM57XX_X2d_WRITE) +{ + int len = TOS.u; POP; + TOS.n = bcm57xx_write(TOS.a, len); +} +MIRP diff --git a/lib/libbcm/bcm.in b/lib/libbcm/bcm.in new file mode 100644 index 0000000..ee50a6e --- /dev/null +++ b/lib/libbcm/bcm.in @@ -0,0 +1,20 @@ +/****************************************************************************** + * Copyright (c) 2013 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 + *****************************************************************************/ + +/* + * libbcm bindings for Forth - definitions + */ + +cod(BCM57XX-OPEN) +cod(BCM57XX-CLOSE) +cod(BCM57XX-READ) +cod(BCM57XX-WRITE) diff --git a/lib/libbcm/bcm57xx.c b/lib/libbcm/bcm57xx.c new file mode 100644 index 0000000..2ecb517 --- /dev/null +++ b/lib/libbcm/bcm57xx.c @@ -0,0 +1,3461 @@ +/****************************************************************************** + * 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 +#include +#include +#include +#include +#include +#include "bcm57xx.h" + +/* + * local defines + ****************************************************************************** + */ + + +// #define BCM_VLAN_TAG ( (uint32_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 ( (uint16_t) 0x0530 ) + +// offset of NIC memory start address from base address +#define BCM_MEMORY_OFFS ( (uint64_t) 0x8000 ) + +// offset of statistics block in NIC memory +#define BCM_STATISTIC_OFFS ( (uint64_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 ( (uint16_t) 0x4000 ) +#define BCM_NIC_RX_OFFS ( (uint16_t) 0x6000 ) +#define BCM_NIC_TX_SIZE ( (uint16_t) ( ( BCM_TX_RING_SIZE * BCM_RCB_SIZE_u16 ) / 4 ) ) + +// device mailboxes +#define BCM_FW_MBX ( (uint16_t) 0x0b50 ) +#define BCM_FW_MBX_CMD ( (uint16_t) 0x0b78 ) +#define BCM_FW_MBX_LEN ( (uint16_t) 0x0b7c ) +#define BCM_FW_MBX_DATA ( (uint16_t) 0x0b80 ) +#define BCM_NICDRV_STATE_MBX ( (uint16_t) 0x0c04 ) + +// device mailbox commands +#define BCM_NICDRV_ALIVE ( (uint32_t) 0x00000001 ) +#define BCM_NICDRV_PAUSE_FW ( (uint32_t) 0x00000002 ) + +// device values +#define BCM_MAGIC_NUMBER ( (uint32_t) 0x4b657654 ) + +// device states +#define NIC_FWDRV_STATE_START ( (uint32_t) 0x00000001 ) +#define NIC_FWDRV_STATE_START_DONE ( (uint32_t) 0x80000001 ) +#define NIC_FWDRV_STATE_UNLOAD ( (uint32_t) 0x00000002 ) +#define NIC_FWDRV_STATE_UNLOAD_DONE ( (uint32_t) 0x80000002 ) +#define NIC_FWDRV_STATE_SUSPEND ( (uint32_t) 0x00000004 ) + +// timer prescaler value +#define BCM_TMR_PRESCALE ( (uint32_t) 0x41 ) + +// offset of transmit rcb's in NIC memory +#define BCM_TX_RCB_OFFS ( (uint16_t) 0x0100 ) +// offset of receive return rcb's in NIC memory +#define BCM_RXRET_RCB_OFFS ( (uint16_t) 0x0200 ) + +// register offsets for ring indices +#define TX_PROD_IND ( (uint16_t) 0x0304 ) +#define TX_CONS_IND ( (uint16_t) 0x3cc0 ) +#define RXPROD_PROD_IND ( (uint16_t) 0x026c ) +#define RXPROD_CONS_IND ( (uint16_t) 0x3c54 ) +#define RXRET_PROD_IND ( (uint16_t) 0x3c80 ) +#define RXRET_CONS_IND ( (uint16_t) 0x0284 ) +// NIC producer index only needed for initialization +#define TX_NIC_PROD_IND ( (uint16_t) 0x0384 ) + +/* + * predefined register values used during initialization + * may be adapted by user + */ +#define DMA_RW_CTRL_VAL_5714 ( (uint32_t) 0x76144000 ) +#define DMA_RW_CTRL_VAL ( (uint32_t) 0x760F0000 ) +#define TX_MAC_LEN_VAL ( (uint32_t) 0x00002620 ) + +#define RX_LST_PLC_CFG_VAL ( (uint32_t) 0x00000109 ) +#define RX_LST_PLC_STAT_EN_VAL ( (uint32_t) 0x007e000f ) +#define NVM_ADDR_MSK ( (uint32_t) 0x000fffff ) + +// Number of Receive Rules /w or /wo SOL enabled +#define RX_RULE_CFG_VAL ( (uint32_t) 0x00000008 ) +#define NUM_RX_RULE ( (uint32_t) 16 ) +#define NUM_RX_RULE_ASF ( (uint32_t) ( NUM_RX_RULE - 4 ) ) + +// RCB register offsets +#define BCM_RXPROD_RCB_JUM ( (uint16_t) 0x2440 ) +#define BCM_RXPROD_RCB_STD ( (uint16_t) 0x2450 ) +#define BCM_RXPROD_RCB_MIN ( (uint16_t) 0x2460 ) + +// macros needed for new addressing method +#define BCM_RCB_HOSTADDR_HI_u16( rcb ) ( (uint16_t) rcb + 0x00 ) +#define BCM_RCB_HOSTADDR_LOW_u16( rcb ) ( (uint16_t) rcb + 0x04 ) +#define BCM_RCB_LENFLAG_u16( rcb ) ( (uint16_t) rcb + 0x08 ) +#define BCM_RCB_NICADDR_u16( rcb ) ( (uint16_t) rcb + 0x0c ) +#define BCM_RCB_SIZE_u16 ( (uint16_t) 0x0010 ) + +// RCB flags +#define RCB_FLAG_RING_DISABLED BIT32( 1 ) + +// BCM device ID masks +#define BCM_DEV_5714 ( (uint64_t) 0x1 ) +#define BCM_DEV_5704 ( (uint64_t) 0x2 ) +#define BCM_DEV_5703 ( (uint64_t) 0x4 ) +#define BCM_DEV_SERDES ( (uint64_t) 0x80000000 ) +#define BCM_DEV_COPPER ( (uint64_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 ((<pci_config_write( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + REG_BASE_ADDR_REG, + f_offs_u16 );*/ + return bswap_32(SLOF_pci_config_read32(REG_DATA_REG)); + /*return (uint32_t) bswap_32( snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + REG_DATA_REG ) ) ;*/ +} + +static uint32_t +bcm_read_reg32( uint16_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 + (uint64_t) f_offs_u16 ); +} + +static uint16_t +bcm_read_reg16( uint16_t f_offs_u16 ) +{ // caution: shall only be used after initialization! + return rd16( bcm_baseaddr_u64 + (uint64_t) f_offs_u16 ); +} +/* not used so far +static uint8_t +bcm_read_reg08( uint16_t f_offs_u16 ) +{ // caution: shall only be used after initialization! + return rd08( bcm_baseaddr_u64 + (uint64_t) f_offs_u16 ); +}*/ + +static void +bcm_write_mem32_indirect( uint16_t f_offs_u16, uint32_t f_val_u32 ) +{ // caution: shall only be used after initialization! + SLOF_pci_config_write32(MEM_BASE_ADDR_REG, f_offs_u16); + /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + MEM_BASE_ADDR_REG, + f_offs_u16 );*/ + SLOF_pci_config_write32(MEM_DATA_REG, bswap_32(f_val_u32)); + /*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( uint16_t f_offs_u16, uint32_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 + (uint64_t) f_offs_u16, f_val_u32 ); +} +/* not used so far +static void +bcm_write_mem16( uint16_t f_offs_u16, uint16_t f_val_u16 ) +{ // caution: shall only be used after initialization! + wr16( bcm_memaddr_u64 + (uint64_t) f_offs_u16, f_val_u16 ); +}*/ +/* not used so far +static void +bcm_write_mem08( uint16_t f_offs_u16, uint8_t f_val_u08 ) +{ // caution: shall only be used after initialization! + wr08( bcm_memaddr_u64 + (uint64_t) f_offs_u16, f_val_u08 ); +}*/ + +static void +bcm_write_reg32_indirect( uint16_t f_offs_u16, uint32_t f_val_u32 ) +{ // caution: shall only be used after initialization! + SLOF_pci_config_write32(REG_BASE_ADDR_REG, f_offs_u16); + /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + REG_BASE_ADDR_REG, + f_offs_u16 );*/ + SLOF_pci_config_write32(REG_DATA_REG, bswap_32(f_val_u32)); + /*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( uint16_t f_offs_u16, uint32_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 + (uint64_t) f_offs_u16, f_val_u32 ); +} + +static void +bcm_write_reg16( uint16_t f_offs_u16, uint16_t f_val_u16 ) +{ // caution: shall only be used after initialization! + wr16( bcm_baseaddr_u64 + (uint64_t) f_offs_u16, f_val_u16 ); +} +/* not used so far +static void +bcm_write_reg08( uint16_t f_offs_u16, uint8_t f_val_u08 ) +{ // caution: shall only be used after initialization! + wr08( bcm_baseaddr_u64 + (uint64_t) f_offs_u16, f_val_u08 ); +}*/ + +static void +bcm_setb_reg32( uint16_t f_offs_u16, uint32_t f_mask_u32 ) +{ + uint32_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( uint16_t f_offs_u16, uint16_t f_mask_u16 ) +{ + uint16_t v; + v = rd16( bcm_baseaddr_u64 + (uint64_t) f_offs_u16 ); + v |= f_mask_u16; + wr16( bcm_baseaddr_u64 + (uint64_t) f_offs_u16, v ); +}*/ +/* not used so far +static void +bcm_setb_reg08( uint16_t f_offs_u16, uint8_t f_mask_u08 ) +{ + uint8_t v; + v = rd08( bcm_baseaddr_u64 + (uint64_t) f_offs_u16 ); + v |= f_mask_u08; + wr08( bcm_baseaddr_u64 + (uint64_t) f_offs_u16, v ); +}*/ + +static void +bcm_clrb_reg32( uint16_t f_offs_u16, uint32_t f_mask_u32 ) +{ + uint32_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( uint16_t f_offs_u16, uint16_t f_mask_u16 ) +{ + uint16_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( uint16_t f_offs_u16, uint8_t f_mask_u08 ) +{ + uint8_t v; + v = rd08( bcm_baseaddr_u64 + (uint64_t) f_offs_u16 ); + v &= ~f_mask_u32; + wr08( bcm_baseaddr_u64 + (uint64_t) f_offs_u16, v ); +}*/ + +static void +bcm_clr_wait_bit32( uint16_t r, uint32_t b ) +{ + uint32_t i; + + bcm_clrb_reg32( r, b ); + + i = 1000; + while( --i ) { + + if( ( bcm_read_reg32( r ) & b ) == 0 ) { + break; + } + + SLOF_usleep( 10 ); + } +#ifdef BCM_DEBUG + if( ( bcm_read_reg32( r ) & b ) != 0 ) { + printf( "bcm57xx: bcm_clear_wait_bit32 failed (0x%04X)!\n", r ); + } +#endif +} + +/* + * (g)mii bus access + */ +#if 0 +// not used so far +static int32_t +bcm_mii_write16( uint32_t f_reg_u32, uint16_t f_value_u16 ) +{ + static const uint32_t WR_VAL = ( ( ((uint32_t) 0x1) << 21 ) | BIT32( 29 ) | BIT32( 26 ) ); + int32_t l_autopoll_i32 = 0; + uint32_t l_wrval_u32; + uint32_t i; + + /* + * only 0x00-0x1f are valid registers + */ + if( f_reg_u32 > (uint32_t) 0x1f ) { + return -1; + } + + /* + * disable auto polling if enabled + */ + if( ( bcm_read_reg32( MI_MODE_R ) & BIT32( 4 ) ) != 0 ) { + l_autopoll_i32 = (int32_t) !0; + bcm_clrb_reg32( MI_MODE_R, BIT32( 4 ) ); + SLOF_usleep( 40 ); + } + + /* + * construct & write mi com register value + */ + l_wrval_u32 = ( WR_VAL | ( f_reg_u32 << 16 ) | (uint32_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 ) ) { + SLOF_usleep( 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 int32_t +bcm_mii_read16( uint32_t f_reg_u32, uint16_t *f_value_pu16 ) +{ + static const uint32_t RD_VAL = ( ( ((uint32_t) 0x1) << 21 ) | BIT32( 29 ) | BIT32( 27 ) ); + int32_t l_autopoll_i32 = 0; + uint32_t l_rdval_u32; + uint32_t i; + uint16_t first_not_busy; + + /* + * only 0x00-0x1f are valid registers + */ + if( f_reg_u32 > (uint32_t) 0x1f ) { + return -1; + } + + /* + * disable auto polling if enabled + */ + if( ( bcm_read_reg32( MI_MODE_R ) & BIT32( 4 ) ) != 0 ) { + l_autopoll_i32 = ( int32_t ) !0; + bcm_clrb_reg32( MI_MODE_R, BIT32( 4 ) ); + SLOF_usleep( 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++; + SLOF_usleep( 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 = (uint16_t) ( l_rdval_u32 & (uint32_t) 0xffff ); + + return 0; +} + +/* + * ht2000 dump (not complete) + */ +#if 0 +static void +bcm_dump( void ) +{ + uint32_t i, j; + + printf( "*** DUMP ***********************************************************************\n\n" ); + + printf( "* PCI Configuration Registers:\n" ); + for( i = 0, j = 0; i < 0x40; i += 4 ) { + + printf( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printf( "\n" ); + } + + } + + printf( "\n* Private PCI Configuration Registers:\n" ); + for( i = 0x68, j = 0; i < 0x88; i += 4 ) { + + printf( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printf( "\n" ); + } + + } + + printf( "\n* VPD Config:\n" ); + printf( "%04X: %08X \n", 0x94, bcm_read_reg32( 0x94 ) ); + + printf( "\n* Dual MAC Control Registers:\n" ); + for( i = 0xb8, j = 0; i < 0xd0; i += 4 ) { + + printf( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printf( "\n" ); + } + + } + + printf( "\n* Ethernet MAC Control Registers:\n" ); + for( i = 0x400, j = 0; i < 0x590; i += 4 ) { + + printf( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printf( "\n" ); + } + + } + + printf( "\n* Send Data Initiator Control:\n" ); + for( i = 0xc00, j = 0; i < 0xc10; i += 4 ) { + + printf( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printf( "\n" ); + } + + } + + printf( "\n* Send Data Completion Control:\n" ); + printf( "%04X: %08X ", 0x1000, bcm_read_reg32( 0x1000 ) ); + printf( "%04X: %08X \n", 0x1008, bcm_read_reg32( 0x1008 ) ); + + printf( "\n* Send BD Ring Selector Control:\n" ); + printf( "%04X: %08X ", 0x1400, bcm_read_reg32( 0x1400 ) ); + printf( "%04X: %08X ", 0x1404, bcm_read_reg32( 0x1404 ) ); + printf( "%04X: %08X \n", 0x1408, bcm_read_reg32( 0x1408 ) ); + + printf( "\n* Send BD Initiator Control:\n" ); + printf( "%04X: %08X ", 0x1800, bcm_read_reg32( 0x1800 ) ); + printf( "%04X: %08X \n", 0x1804, bcm_read_reg32( 0x1804 ) ); + + printf( "\n* Send BD Completion Control:\n" ); + printf( "%04X: %08X ", 0x1c00, bcm_read_reg32( 0x1c00 ) ); + + printf( "\n* Receive List Placement Control:\n" ); + for( i = 0x2000, j = 0; i < 0x2020; i += 4 ) { + + printf( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printf( "\n" ); + } + + } + + printf( "\n* Receive Data & Receive BD Initiator Control:\n" ); + printf( "%04X: %08X ", 0x2400, bcm_read_reg32( 0x2400 ) ); + printf( "%04X: %08X \n", 0x2404, bcm_read_reg32( 0x2404 ) ); + + printf( "\n* Jumbo Receive BD Ring RCB:\n" ); + for( i = 0x2440, j = 0; i < 0x2450; i += 4 ) { + + printf( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printf( "\n" ); + } + + } + + printf( "\n* Standard Receive BD Ring RCB:\n" ); + for( i = 0x2450, j = 0; i < 0x2460; i += 4 ) { + + printf( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printf( "\n" ); + } + + } + + printf( "\n* Mini Receive BD Ring RCB:\n" ); + for( i = 0x2460, j = 0; i < 0x2470; i += 4 ) { + + printf( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printf( "\n" ); + } + + } + + printf( "\nRDI Timer Mode Register:\n" ); + printf( "%04X: %08X \n", 0x24f0, bcm_read_reg32( 0x24f0 ) ); + + printf( "\n* Receive BD Initiator Control:\n" ); + for( i = 0x2c00, j = 0; i < 0x2c20; i += 4 ) { + + printf( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printf( "\n" ); + } + + } + + printf( "\n* Receive BD Completion Control:\n" ); + for( i = 0x3000, j = 0; i < 0x3014; i += 4 ) { + + printf( "%04X: %08X ", i, bcm_read_reg32( i ) ); + + if( ( ++j & 0x3 ) == 0 ) { + printf( "\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 ) { + SLOF_msleep( 1 ); + } + + // return on error + if( i == 0 ) { +#ifdef BCM_DEBUG + printf("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 int32_t +bcm_nvram_read( uint32_t f_addr_u32, uint32_t *f_val_pu32, uint32_t lock ) +{ + uint32_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 ) ) { + SLOF_msleep( 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 + printf("bcm57xx: reading from NVRAM failed\n"); +#endif + return -1; + } + + // success + return 0; +} + +static int32_t +bcm_nvram_write( uint32_t f_addr_u32, uint32_t f_value_u32, uint32_t lock ) +{ + uint32_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 ) ) { + SLOF_msleep( 1 ); + } + + /* + * release NVRam lock (CLR0) + */ + if(lock) + bcm_nvram_unlock(); + + // error + if( i == 0 ) { +#ifdef BCM_DEBUG + printf("bcm57xx: writing to NVRAM failed\n"); +#endif + return -1; + } + + // success + return 0; +} + +/* + * PHY initialization + */ +static int32_t +bcm_mii_phy_init( void ) +{ + static const uint32_t PHY_STAT_R = (uint32_t) 0x01; + static const uint32_t AUX_STAT_R = (uint32_t) 0x19; + static const uint32_t MODE_GMII = BIT32( 3 ); + static const uint32_t MODE_MII = BIT32( 2 ); + static const uint32_t NEG_POLARITY = BIT32( 10 ); + static const uint32_t MII_MSK = ( MODE_GMII | MODE_MII ); + static const uint16_t GIGA_ETH = ( BIT16( 10 ) | BIT16( 9 ) ); + int32_t i; + uint16_t v; + + /* + * enable MDI communication + */ + bcm_write_reg32( MDI_CTRL_R, (uint32_t) 0x0 ); + + /* + * check link up + */ + i = 2500; + do { + SLOF_msleep( 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 + printf( "bcm57xx: link is down\n" ); +#endif + return -1; + } + +#ifdef BCM_DEBUG + printf( "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 + printf( "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 + printf( "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 + printf( "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 int32_t +bcm_tbi_phy_init( void ) +{ + int32_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, (uint32_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 ) ); + + SLOF_usleep( 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; + } + + SLOF_usleep( 20 ); + } + + if( ( bcm_read_reg32( ETH_MAC_STAT_R ) & BIT32( 0 ) ) == 0) { +#ifdef BCM_DEBUG + printf( "bcm57xx: link is down\n" ); +#endif + return -1; + } +#if 0 + /* + * clear all attentions + */ + bcm_write_reg32( ETH_MAC_STAT_R, (uint32_t) ~0 ); +#endif + +#ifdef BCM_DEBUG + printf( "bcm57xx: link is up\n" ); +#endif + return 0; +} + +static int32_t +bcm_phy_init( void ) +{ + static const uint16_t SRAM_HW_CFG = (uint16_t) 0x0b58; + uint32_t l_val_u32; + int32_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 + printf( "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 + printf( "bcm57xx: fiber PHY detected\n" ); + #endif + + if( !IS_SERDES ) { + #ifdef BCM_DEBUG + printf( "bcm57xx: running PHY in gmii/mii mode\n" ); + #endif + l_ret_i32 = bcm_mii_phy_init(); + } else { + #ifdef BCM_DEBUG + printf( "bcm57xx: running PHY in tbi mode\n" ); + #endif + l_ret_i32 = bcm_tbi_phy_init(); + } + + } break; + + default: { + #ifdef BCM_DEBUG + printf( "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 ) +{ + uint32_t v; + uint32_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 = + (uint32_t) ( (uint64_t) &bcm_rx_buffer_pu08[i] >> 32 ); + bcm_rxprod_ring[i].m_hostaddr_st.m_lo_u32 = + (uint32_t) ( (uint64_t) &bcm_rx_buffer_pu08[i] & + (uint64_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 ), + (uint32_t) ( (uint64_t) &bcm_rxprod_ring >> 32 ) ); + bcm_write_reg32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXPROD_RCB_STD ), + (uint32_t) ( (uint64_t) &bcm_rxprod_ring & (uint64_t) 0xffffffff ) ); + bcm_write_reg32( BCM_RCB_NICADDR_u16( BCM_RXPROD_RCB_STD ), + (uint32_t) BCM_NIC_RX_OFFS ); + + if( IS_5704 || IS_5703 ) { + // 5704: length field = max buffer len + v = (uint32_t) BCM_BUF_SIZE << 16; + } else { + // 5714: length field = number of ring entries + v = (uint32_t) BCM_RXPROD_RING_SIZE << 16; + } + + v &= (uint32_t) ~RCB_FLAG_RING_DISABLED; + bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXPROD_RCB_STD ), v ); +} + +static void +bcm_init_rxret_ring( void ) +{ + uint32_t i; + uint16_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 ), + (uint32_t) ( (uint64_t) &bcm_rxret_ring >> 32 ) ); + bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( BCM_RXRET_RCB_OFFS ), + (uint32_t) ( (uint64_t) &bcm_rxret_ring & + (uint64_t) 0xffffffff ) ); + bcm_write_mem32( BCM_RCB_NICADDR_u16( BCM_RXRET_RCB_OFFS ), 0 ); + + i = bcm_rxret_ring_sz; + i <<= 16; + i &= (uint32_t) ~RCB_FLAG_RING_DISABLED; + bcm_write_reg32( BCM_RCB_LENFLAG_u16( BCM_RXRET_RCB_OFFS ), i ); +} + +static void +bcm_init_tx_ring( void ) +{ + uint32_t i; + uint16_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 = + (uint32_t) ( (uint64_t) &bcm_tx_buffer_pu08[i] >> 32 ); + bcm_tx_ring[i].m_hostaddr_st.m_lo_u32 = + (uint32_t) ( (uint64_t) &bcm_tx_buffer_pu08[i] & + (uint64_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 = (uint32_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 ), + (uint32_t) ( (uint64_t) &bcm_tx_ring >> 32 ) ); + bcm_write_mem32( BCM_RCB_HOSTADDR_LOW_u16( BCM_TX_RCB_OFFS ), + (uint32_t) ( (uint64_t) &bcm_tx_ring & + (uint64_t) 0xffffffff ) ); + bcm_write_mem32( BCM_RCB_NICADDR_u16( BCM_TX_RCB_OFFS ), + (uint32_t) BCM_NIC_TX_OFFS ); + + if( IS_5704 || IS_5703 ) { + // 5704: length field = max buffer len + i = (uint32_t) BCM_BUF_SIZE << 16; + } else { + // 5714: length field = number of ring entries + i = (uint32_t) BCM_TX_RING_SIZE << 16; + } + + i &= ( uint32_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 int32_t +bcm_mac_init( uint8_t *f_mac_pu08 ) +{ + static const uint16_t MEM_MAC_LO = (uint16_t) 0x0c18; + static const uint16_t MEM_MAC_HI = (uint16_t) 0x0c14; + + uint32_t NVR_MAC_LO = (uint16_t) 0x80; + uint32_t NVR_MAC_HI = (uint16_t) 0x7c; + + bcm_addr64_t l_mac_st; + uint32_t i; + uint32_t v; + + /* + * Use MAC address from device tree if possible + */ + for( i = 0, v = 0; i < 6; i++ ) { + v += (uint32_t) f_mac_pu08[i]; + } + + if( v != 0 ) { + l_mac_st.m_hi_u32 = ( ( (uint32_t) f_mac_pu08[0]) << 8 ); + l_mac_st.m_hi_u32 |= ( ( (uint32_t) f_mac_pu08[1]) << 0 ); + l_mac_st.m_lo_u32 = ( ( (uint32_t) f_mac_pu08[2]) << 24 ); + l_mac_st.m_lo_u32 |= ( ( (uint32_t) f_mac_pu08[3]) << 16 ); + l_mac_st.m_lo_u32 |= ( ( (uint32_t) f_mac_pu08[4]) << 8 ); + l_mac_st.m_lo_u32 |= ( ( (uint32_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 ) == (uint32_t) 0x484b ) { + l_mac_st.m_hi_u32 &= (uint32_t) 0xffff; + l_mac_st.m_lo_u32 = bcm_read_mem32( MEM_MAC_LO ); + } else { + int32_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 + printf( "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( uint32_t ); + bcm_write_reg32( v, l_mac_st.m_lo_u32 ); + v += sizeof( uint32_t ); + } + + } + */ + + /* + * return MAC address as string + */ + f_mac_pu08[0] = (uint8_t) ( ( l_mac_st.m_hi_u32 >> 8 ) & (uint32_t) 0xff ); + f_mac_pu08[1] = (uint8_t) ( ( l_mac_st.m_hi_u32 ) & (uint32_t) 0xff ); + f_mac_pu08[2] = (uint8_t) ( ( l_mac_st.m_lo_u32 >> 24 ) & (uint32_t) 0xff ); + f_mac_pu08[3] = (uint8_t) ( ( l_mac_st.m_lo_u32 >> 16 ) & (uint32_t) 0xff ); + f_mac_pu08[4] = (uint8_t) ( ( l_mac_st.m_lo_u32 >> 8 ) & (uint32_t) 0xff ); + f_mac_pu08[5] = (uint8_t) ( ( l_mac_st.m_lo_u32 ) & (uint32_t) 0xff ); + +#ifdef BCM_DEBUG + do { + int32_t i; + printf( "bcm57xx: retrieved MAC address " ); + + for( i = 0; i < 6; i++ ) { + printf( "%02X", f_mac_pu08[i] ); + + if( i != 5 ) { + printf( ":" ); + } + + } + + printf( "\n" ); + } while( 0 ); +#endif + + return 0; +} + + +/* + ****************************************************************************** + * ASF Firmware + ****************************************************************************** + */ + + +#ifdef BCM_DEBUG +#ifdef BCM_SHOW_ASF_REGS +static void +bcm_asf_check_register( void ) +{ + uint32_t i; + + i = bcm_read_reg32( ASF_CTRL_R ); + printf( "bcm57xx: ASF control : %x\n", i ); + + i = bcm_read_reg32( ASF_WATCHDOG_TIMER_R ); + printf( "bcm57xx: ASF Watchdog Timer : %x\n", i ); + + i = bcm_read_reg32( ASF_HEARTBEAT_TIMER_R ); + printf( "bcm57xx: ASF Heartbeat Timer : %x\n", i ); + + i = bcm_read_reg32( ASF_POLL_TIMER_R ); + printf( "bcm57xx: ASF Poll Timer : %x\n", i ); + + i = bcm_read_reg32( POLL_LEGACY_TIMER_R ); + printf( "bcm57xx: Poll Legacy Timer : %x\n", i ); + + i = bcm_read_reg32( RETRANSMISSION_TIMER_R ); + printf( "bcm57xx: Retransmission Timer : %x\n", i ); + + i = bcm_read_reg32( TIME_STAMP_COUNTER_R ); + printf( "bcm57xx: Time Stamp Counter : %x\n", i ); + + i = bcm_read_reg32( RX_CPU_MODE_R ); + printf( "bcm57xx: RX RISC Mode : %x\n", i ); + + i = bcm_read_reg32( RX_CPU_STATE_R ); + printf( "bcm57xx: RX RISC State : %x\n", i ); + + i = bcm_read_reg32( RX_CPU_PC_R ); + printf( "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; + SLOF_msleep(1); + } + if( i>= 100) + return -1; + return 0; +} + + +#ifdef BCM_SW_AUTONEG +static void +bcm_sw_autoneg( void ) { + uint32_t i, j, k; + uint32_t SerDesCfg; + uint32_t SgDigControl; + uint32_t SgDigStatus; + uint32_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 ) ); + SLOF_usleep(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 + printf("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 + SLOF_usleep( 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); + SLOF_usleep( 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 ) { + printf("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 ); + + SLOF_usleep( 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 + printf("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; + SLOF_msleep(1); + } + if( i == 0) { +#ifdef BCM_DEBUG + printf( "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 ) +{ + uint32_t l_rxret_prod_u32 = bcm_read_reg32( RXRET_PROD_IND ); + uint32_t l_rxret_cons_u32 = bcm_read_reg32( RXRET_CONS_IND ); + uint32_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 + printf( "bcm57xx: erroneous frame received\n" ); + printf( " : 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 & + (uint32_t) 0xffff ) - (int) 4; + + /* + * discard oversized packets + */ + if( l_ret_i > f_len_i ) { +#ifdef BCM_DEBUG + printf( "bcm57xx: receive packet length error:\n" ); + printf( " : incoming 0x%X bytes, available buffer 0x%X bytes\n", l_ret_i, f_len_i ); + printf( " : frame discarded\n" ); +#endif + l_ret_i = 0; + } + + } + + /* + * copy & update data & indices + */ + if( l_ret_i != 0 ) { + uint64_t l_cpyaddr_u64; + + l_cpyaddr_u64 = + ( (uint64_t) bcm_rxret_ring[l_rxret_cons_u32].m_hostaddr_st.m_hi_u32 << 32 ); + l_cpyaddr_u64 += + ( (uint64_t) bcm_rxret_ring[l_rxret_cons_u32].m_hostaddr_st.m_lo_u32 ); + +// FIXME: + if(l_cpyaddr_u64 == 0) { +#ifdef BCM_DEBUG + printf("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 += + (uint32_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 ) { + printf( "bcm57xx: received bytes: %d\n", l_ret_i ); + } +#ifdef BCM_SHOW_RCV_DATA + for( i = 0, j = 0; i < l_ret_i; i++ ) { + printf( "%02X ", ( uint32_t ) f_buffer_pc[i] ); + + if( ( ++j % 0x18 ) == 0 ) { + printf( "\n" ); + } + } + + if( ( i % 0x18 ) != 0 ) { + printf( "\n" ); + } +#endif +#endif +#endif + + /* + * return packet length + */ + return l_ret_i; +} + +static int +bcm_xmit( char *f_buffer_pc, int f_len_i ) +{ + uint32_t l_tx_cons_u32 = bcm_read_reg32( TX_CONS_IND ); + uint32_t l_tx_prod_u32 = bcm_read_reg32( TX_PROD_IND ); + uint64_t l_cpyaddr_u64; + +#ifdef BCM_DEBUG +#ifdef BCM_SHOW_XMIT_DATA + int i, j; +#endif +#ifdef BCM_SHOW_IDX + printf( "\n" ); + printf( "bcm57xx: TX_PROD_IND : 0x%03X\n", l_tx_prod_u32 ); + printf( "bcm57xx: TX_CONS_IND : 0x%03X\n", l_tx_cons_u32 ); + printf( "bcm57xx: RXPROD_PROD_IND: 0x%03X\n", bcm_read_reg32( RXPROD_PROD_IND ) ); + printf( "bcm57xx: RXPROD_CONS_IND: 0x%03X\n", bcm_read_reg32( RXPROD_CONS_IND ) ); + printf( "bcm57xx: RXRET_PROD_IND : 0x%03X\n", bcm_read_reg32( RXRET_PROD_IND ) ); + printf( "bcm57xx: RXRET_CONS_IND : 0x%03X\n", bcm_read_reg32( RXRET_CONS_IND ) ); + printf( "bcm57xx: available txb : 0x%03X\n", bcm_tx_bufavail_u32 ); +#endif +#ifdef BCM_SHOW_STATS + printf( "bcm57xx: bcm_status.m_st_word_u32: %08X\n", bcm_status.m_st_word_u32 ); + printf( "bcm57xx: bcm_status.m_st_tag_u32 : %08X\n", bcm_status.m_st_tag_u32 ); + printf( "bcm57xx: bcm_status.m_rxprod_cons_u16: %04X\n", ( uint32_t ) bcm_status.m_rxprod_cons_u16 ); + printf( "bcm57xx: bcm_status.m_unused_u16: %04X\n", ( uint32_t ) bcm_status.m_unused_u16 ); + printf( "bcm57xx: bcm_status.m_unused_u32: %08X\n", bcm_status.m_unused_u32 ); + printf( "bcm57xx: bcm_status.m_tx_cons_u16: %04X\n", ( uint32_t ) bcm_status.m_tx_cons_u16 ); + printf( "bcm57xx: bcm_status.m_rxret_prod_u16: %04X\n", ( uint32_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 + printf( "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 += ( (uint32_t) f_len_i << 16 ); +// bcm_tx_ring[l_tx_prod_u32].m_VLANtag_u32 = BCM_VLAN_TAG; + + l_cpyaddr_u64 = ( (uint64_t) bcm_tx_ring[l_tx_prod_u32].m_hostaddr_st.m_hi_u32 << 32 ); + l_cpyaddr_u64 += ( (uint64_t) bcm_tx_ring[l_tx_prod_u32].m_hostaddr_st.m_lo_u32 ); + +#ifdef BCM_DEBUG +#ifdef BCM_SHOW_XMIT_STATS + printf("bcm57xx: xmit: l_cpyaddr_u64: 0x%lx\n", l_cpyaddr_u64 ); + printf(" f_buffer_pc : 0x%lx\n", f_buffer_pc ); + printf(" 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 + printf( "bcm57xx: sent bytes: %d\n", f_len_i ); +#ifdef BCM_SHOW_XMIT_DATA + for( i = 0, j = 0; i < f_len_i; i++ ) { + printf( "%02X ", ( uint32_t ) f_buffer_pc[i] ); + + if( ( ++j % 0x18 ) == 0 ) { + printf( "\n" ); + } + + } + if( ( i % 0x18 ) != 0 ) { + printf( "\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; +} + +static int +check_driver( uint16_t vendor_id, uint16_t device_id ) +{ + uint64_t i; + + /* + * checks whether the driver is handling this device + * by verifying vendor & device id + * vendor id 0x14e4 == Broadcom + */ + if( vendor_id != 0x14e4 ) { +#ifdef BCM_DEBUG + printf( "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 == (uint32_t) device_id ) { + // success + break; + } + } + + if(bcm_dev[i].m_dev_u32 == 0) { +#ifdef BCM_DEBUG + printf( "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; + + return 0; +} + +static void +bcm_wol_activate(void) +{ +#ifdef BCM_DEBUG + uint16_t reg_pwr_cap; +#endif + uint16_t reg_pwr_crtl; + uint32_t wol_mode; + + wol_mode = bcm_read_reg32( WOL_MODE_R ); + bcm_write_reg32( WOL_MODE_R, wol_mode | BIT32(0) ); + +#ifdef BCM_DEBUG + printf( "bcm57xx: WOL activating..." ); +#endif + +// bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_WOL ); +// SLOF_msleep( 100 ); + +#ifdef BCM_DEBUG + reg_pwr_cap = SLOF_pci_config_read16(0x4a); + /*reg_pwr_cap = snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, + 2, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + 0x4a );*/ + printf( "bcm57xx: PM Capability Register: %04X\n", reg_pwr_cap ); +#endif + /* get curretn power control register */ + reg_pwr_crtl = SLOF_pci_config_read16(0x4c); + /*reg_pwr_crtl = snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, + 2, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + 0x4c );*/ + +#ifdef BCM_DEBUG + printf( "bcm57xx: PM Control/Status Register: %04X\n", reg_pwr_crtl ); +#endif + + /* switch to power state D0 */ + reg_pwr_crtl |= 0x8000; + reg_pwr_crtl &= ~(0x0003); + SLOF_pci_config_write16(0x4c, reg_pwr_crtl); + /*snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 2, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + 0x4c, + reg_pwr_crtl );*/ + SLOF_msleep(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; + SLOF_pci_config_write16(0x4c, reg_pwr_crtl); + snk_kernel_interface->pci_config_write( bcm_pcicfg_puid, + 2, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + 0x4c, + reg_pwr_crtl ); + SLOF_msleep(10); +*/ + +#ifdef BCM_DEBUG + reg_pwr_crtl = SLOF_pci_config_read16(0x4c); + /*reg_pwr_crtl = snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, + 2, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + 0x4c );*/ + + printf( "bcm57xx: PM Control/Status Register: %04X\n", reg_pwr_crtl ); +#endif + +#ifdef BCM_DEBUG + printf( "bcm57xx: WOL activated" ); +#endif +} + +static int +bcm_init( net_driver_t *driver ) +{ + static const uint32_t lc_Maxwait_u32 = (uint32_t) 1000; + uint32_t l_baseaddrL_u32; + uint32_t l_baseaddrH_u32; + uint32_t i; + uint8_t *mac_addr = driver->mac_addr; + + if(driver->running != 0) { + return 0; + } +#ifdef BCM_DEBUG + printf( "bcm57xx: detected device " ); + if( IS_5703 ) { + printf( "5703S\n" ); + } else if( IS_5704 ) { + printf( "5704" ); + + if( IS_SERDES ) { + printf( "S\n" ); + } else { + printf( "C\n" ); + } + + } else if( IS_5714 ) { + printf( "5714\n" ); + } +#endif + /* + * setup register & memory base addresses of NIC + */ + l_baseaddrL_u32 = (uint32_t) ~0xf & + (uint32_t) SLOF_pci_config_read32(PCI_BAR1_R); + /*l_baseaddrL_u32 = ( (uint32_t) ~0xf & + (uint32_t) snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_BAR1_R ) );*/ + + l_baseaddrH_u32 = (uint32_t) SLOF_pci_config_read32(PCI_BAR2_R); + /*l_baseaddrH_u32 = + (uint32_t) snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_BAR2_R );*/ + bcm_baseaddr_u64 = (uint64_t) l_baseaddrH_u32; + bcm_baseaddr_u64 <<= 32; + bcm_baseaddr_u64 += (uint64_t) l_baseaddrL_u32; + bcm_baseaddr_u64 = + (uint64_t) SLOF_translate_my_address((void *)bcm_baseaddr_u64); + /*snk_kernel_interface->translate_addr(((void *)&(bcm_baseaddr_u64)));*/ + bcm_memaddr_u64 = bcm_baseaddr_u64 + BCM_MEMORY_OFFS; + +#ifdef BCM_DEBUG + printf( "bcm57xx: device's register base high address = 0x%08X\n", l_baseaddrH_u32 ); + printf( "bcm57xx: device's register base low address = 0x%08X\n", l_baseaddrL_u32 ); + printf( "bcm57xx: device's register address = 0x%llx\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 ) ); + SLOF_pci_config_write16(PCI_COM_R, i); + /*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 ) ); + + SLOF_pci_config_write32(PCI_MISC_HCTRL_R, i); + /*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 + printf( "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 ) ); + SLOF_pci_config_write32(PCI_MISC_HCTRL_R, i); + /*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 + SLOF_msleep( 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 ) ); + SLOF_pci_config_write32(PCI_MISC_HCTRL_R, i); + /*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 ) ); + SLOF_pci_config_write16(PCI_COM_R, i); + /*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 ) ); + SLOF_pci_config_write32(PCI_MISC_HCTRL_R, i); + /*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 + printf( "." ); +#endif + SLOF_msleep( 1 ); + } + + // return on error + if( bcm_read_mem32( BCM_FW_MBX ) != ~BCM_MAGIC_NUMBER ) { + printf( "bootcode not loaded: %x\n", bcm_read_mem32( BCM_FW_MBX ) ); +#ifdef BCM_DEBUG + printf( "failed\n" ); +#endif + return -1; + } + + + // if ASF Firmware enabled + bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_START ); + SLOF_msleep( 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, (uint32_t) 0xc ); + } else { + bcm_write_reg32( ETH_MAC_MODE_R, (uint32_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 { + uint32_t l_PCIState_u32 = bcm_read_reg32( PCI_STATE_R ); + uint32_t l_DMAVal_u32 = DMA_RW_CTRL_VAL; + + if( ( l_PCIState_u32 & BIT32( 2 ) ) != 0 ) { // PCI + l_DMAVal_u32 |= (uint32_t) 0x300000; + } else { // PCI-X + l_DMAVal_u32 |= (uint32_t) 0x900000; + + if( ( bcm_read_reg32( PCI_CLK_CTRL_R ) & (uint32_t) 0x1f ) + >= (uint32_t) 6 ) { + l_DMAVal_u32 |= (uint32_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 &= (uint32_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, (uint32_t) 0x8000 ); + bcm_write_reg32( MBUF_POOL_LEN_R, (uint32_t) 0x18000 ); + } else { + bcm_write_reg32( MBUF_POOL_ADDR_R, (uint32_t) 0x10000 ); + bcm_write_reg32( MBUF_POOL_LEN_R, (uint32_t) 0x10000 ); + } + + bcm_write_reg32( DMA_DESC_POOL_ADDR_R, (uint32_t) 0x2000 ); + bcm_write_reg32( DMA_DESC_POOL_LEN_R, (uint32_t) 0x2000 ); + + bcm_write_reg32( DMA_RMBUF_LOW_WMARK_R, (uint32_t) 0x50 ); + bcm_write_reg32( MAC_RXMBUF_LOW_WMARK_R, (uint32_t) 0x20 ); + bcm_write_reg32( MBUF_HIGH_WMARK_R, (uint32_t) 0x60 ); + + bcm_write_reg32( DMA_DESC_LOW_WM_R, (uint32_t) 5 ); + bcm_write_reg32( DMA_DESC_HIGH_WM_R, (uint32_t) 10 ); + } else { + bcm_write_reg32( DMA_RMBUF_LOW_WMARK_R, (uint32_t) 0x00 ); + bcm_write_reg32( MAC_RXMBUF_LOW_WMARK_R, (uint32_t) 0x10 ); + bcm_write_reg32( MBUF_HIGH_WMARK_R, (uint32_t) 0x60 ); + } + + // step 35: omitted + // step 36: Configure flow control behaviour + // using recommended settings (hard coded) + bcm_write_reg32( LOW_WMARK_MAX_RXFRAM_R, (uint32_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 ) ) { + SLOF_usleep( 10 ); + } + + // return on error + if( i == 0 ) { +#ifdef BCM_DEBUG + printf( "bcm57xx: init step 38: enable buffer manager failed\n" ); +#endif + return -1; + } + + // step 39: enable internal hardware queues + bcm_write_reg32( FTQ_RES_R, (uint32_t) ~0 ); + bcm_write_reg32( FTQ_RES_R, (uint32_t) 0 ); + + // step 40/41/42: initialize rx producer ring + bcm_init_rxprod_ring(); + + // step 43: set rx producer ring replenish threshold + // using recommended setting of maximum allocated BD's/8 + bcm_write_reg32( STD_RXPR_REP_THR_R, (uint32_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( (uint8_t *) mac_addr ) < 0 ) { +#ifdef BCM_DEBUG + printf( "bcm57xx: init step 51: configure MAC unicast address failed\n" ); +#endif + return -1; + } + memcpy(driver->mac_addr, mac_addr, 6); + + // step 52: configure backoff random seed for transmit + // using recommended algorithm + i = (uint32_t) mac_addr[0] + (uint32_t) mac_addr[1] + + (uint32_t) mac_addr[2] + (uint32_t) mac_addr[3] + + (uint32_t) mac_addr[4] + (uint32_t) mac_addr[5]; + i &= (uint32_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, (uint32_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 ), + (uint32_t) 0xffff0000 | + ( bcm_read_reg32( MAC_ADDR_OFFS_HI(0) ) & + (uint32_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 ), + (uint32_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 ), + (uint32_t) ~0 ); +*/ + for( i=0; i> 32 ); + bcm_write_reg32( STB_HOST_ADDR_HI_R, i ); + i = (uint32_t) ( (uint64_t) &bcm_status & (uint64_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, (uint32_t) 0x300 ); + // step 71: 5704 configure status block address in NIC memory + // using recommended values (hard coded) + bcm_write_reg32( STB_NIC_ADDR_R, (uint32_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 ) ); + SLOF_usleep( 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 + printf( "bcm57xx: init step 99: PHY initialization failed\n" ); +#endif + return -1; + } + + // step 100: setup multicast filters + bcm_write_reg32( MAC_HASH0_R, (uint32_t) 0 ); + bcm_write_reg32( MAC_HASH1_R, (uint32_t) 0 ); + bcm_write_reg32( MAC_HASH2_R, (uint32_t) 0 ); + bcm_write_reg32( MAC_HASH3_R, (uint32_t) 0 ); +/* + // accept all multicast frames + bcm_write_reg32( MAC_HASH0_R, (uint32_t) 0xffffffff ); + bcm_write_reg32( MAC_HASH1_R, (uint32_t) 0xffffffff ); + bcm_write_reg32( MAC_HASH2_R, (uint32_t) 0xffffffff ); + bcm_write_reg32( MAC_HASH3_R, (uint32_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 ); + SLOF_msleep( 10 ); + + // enable heartbeat timer + + bcm_write_reg32( ASF_HEARTBEAT_TIMER_R, 0x5 ); + + driver->running = 1; + // off we go.. + return 0; +} + +static int +bcm_reset( void ) +{ + uint32_t i; + +#ifdef BCM_DEBUG + printf( "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 ) ); + } + + SLOF_msleep( 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 ) ); + SLOF_pci_config_write16(PCI_COM_R, i); + /*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 ) ); + SLOF_pci_config_write32(PCI_MISC_HCTRL_R, i); + /*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 + printf( "." ); +#else + SLOF_msleep( 1 ); +#endif + } + + // return on error + if( bcm_read_mem32( BCM_FW_MBX ) != ~BCM_MAGIC_NUMBER ) { +#ifdef BCM_DEBUG + printf( "failed\n" ); +#endif + return -1; + } + +#ifdef BCM_DEBUG + printf( "done\n" ); +#endif + return 0; +} + +static int +bcm_term( void ) +{ + uint32_t i; + uint16_t v; + +#ifdef BCM_DEBUG + printf( "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, (uint32_t) ~0 ); + bcm_write_reg32( FTQ_RES_R, (uint32_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 + printf( "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 ); + SLOF_msleep( 10 ); + bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_UNLOAD_DONE ); + SLOF_msleep( 100 ); + bcm_write_mem32( BCM_NICDRV_STATE_MBX, NIC_FWDRV_STATE_START ); + SLOF_msleep( 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 ) ); + + SLOF_pci_config_write32(PCI_COM_R, BIT32(8) | BIT32(6)); + /*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... + return 0; +} + +static int +bcm_getmac(uint32_t addr, char mac[6]) +{ + uint32_t t1, t2; + uint64_t t3; + + if (bcm_nvram_read(addr, &t1, 1) != 0) + return -1; + if (bcm_nvram_read(addr+4, &t2, 1) != 0) + return -1; + t3 = ((uint64_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, uint32_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) +{ + uint32_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 uint32_t +util_gen_crc( char *pcDatabuf, uint32_t ulDatalen, uint32_t ulCrc_in) +{ + unsigned char data; + uint32_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]) +{ + uint64_t mac1 = 0, mac2 = 0; + uint32_t manu[MANUFACTURING_INFO_SIZE/4]; + int addr, i; + uint32_t crc, val1, val2, val3, val4; + +#ifdef BCM_DEBUG + printf("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); + + printf("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 |= ((uint64_t) mac_addr1[0]) & 0xFF; mac1 = mac1 << 8; + mac1 |= ((uint64_t) mac_addr1[1]) & 0xFF; mac1 = mac1 << 8; + mac1 |= ((uint64_t) mac_addr1[2]) & 0xFF; mac1 = mac1 << 8; + mac1 |= ((uint64_t) mac_addr1[3]) & 0xFF; mac1 = mac1 << 8; + mac1 |= ((uint64_t) mac_addr1[4]) & 0xFF; mac1 = mac1 << 8; + mac1 |= ((uint64_t) mac_addr1[5]) & 0xFF; + + mac2 |= ((uint64_t) mac_addr2[0]) & 0xFF; mac2 = mac2 << 8; + mac2 |= ((uint64_t) mac_addr2[1]) & 0xFF; mac2 = mac2 << 8; + mac2 |= ((uint64_t) mac_addr2[2]) & 0xFF; mac2 = mac2 << 8; + mac2 |= ((uint64_t) mac_addr2[3]) & 0xFF; mac2 = mac2 << 8; + mac2 |= ((uint64_t) mac_addr2[4]) & 0xFF; mac2 = mac2 << 8; + mac2 |= ((uint64_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) { + printf("\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 + printf("failed to write MAC address\n"); +#endif + return -1; + } + + /* Success !!!! */ + return 0; +} + +static int +bcm_ioctl( int request, void* data ) +{ + uint32_t l_baseaddrL_u32; + uint32_t l_baseaddrH_u32; + uint32_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 + printf( "bcm57xx: detected device " ); + if( IS_5703 ) { + printf( "5703S" ); + } else if( IS_5704 ) { + printf( "5704" ); + if( IS_SERDES ) { + printf( "S\n" ); + } else { + printf( "C\n" ); + } + } else if( IS_5714 ) { + printf( "5714\n" ); + } +#endif + /* + * setup register & memory base addresses of NIC + */ + l_baseaddrL_u32 = (uint32_t) ~0xf & + SLOF_pci_config_read32(PCI_BAR1_R); + /*l_baseaddrL_u32 = ( (uint32_t) ~0xf & + (uint32_t) snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_BAR1_R ) );*/ + + l_baseaddrH_u32 = SLOF_pci_config_read32(PCI_BAR2_R); + /*l_baseaddrH_u32 = + (uint32_t) snk_kernel_interface->pci_config_read( bcm_pcicfg_puid, + 4, + bcm_pcicfg_bus, + bcm_pcicfg_devfn, + PCI_BAR2_R );*/ + + bcm_baseaddr_u64 = (uint64_t) l_baseaddrH_u32; + bcm_baseaddr_u64 <<= 32; + bcm_baseaddr_u64 += (uint64_t) l_baseaddrL_u32; + bcm_baseaddr_u64 = + (uint64_t)SLOF_translate_my_address((void *)bcm_baseaddr_u64); + /*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 ) ); + SLOF_pci_config_write16(PCI_COM_R, i); + /*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 ) ); + SLOF_pci_config_write32(PCI_MISC_HCTRL_R, i); + /*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; + } + + bcm_term(); + return ret_val; +} + +net_driver_t *bcm57xx_open(void) +{ + net_driver_t *driver; + uint16_t vendor_id, device_id; + + vendor_id = SLOF_pci_config_read16(0); + device_id = SLOF_pci_config_read16(2); + if (check_driver(vendor_id, device_id)) + return NULL; + + driver = SLOF_alloc_mem(sizeof(*driver)); + if (!driver) { + printf("Unable to allocate virtio-net driver\n"); + return NULL; + } + memset(driver, 0, sizeof(*driver)); + + if (bcm_init(driver)) + goto FAIL; + + return driver; + +FAIL: SLOF_free_mem(driver, sizeof(*driver)); + return NULL; + + return 0; +} + +void bcm57xx_close(net_driver_t *driver) +{ + if (driver->running == 0) + return; + + bcm_term(); + driver->running = 0; + SLOF_free_mem(driver, sizeof(*driver)); +} + +int bcm57xx_read(char *buf, int len) +{ + if (buf) + return bcm_receive(buf, len); + return -1; +} + +int bcm57xx_write(char *buf, int len) +{ + if (buf) + return bcm_xmit(buf, len); + return -1; +} diff --git a/lib/libbcm/bcm57xx.h b/lib/libbcm/bcm57xx.h new file mode 100644 index 0000000..efaba60 --- /dev/null +++ b/lib/libbcm/bcm57xx.h @@ -0,0 +1,323 @@ +/****************************************************************************** + * 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 +#include + +// 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 ( (uint16_t) 0x0004 ) +// PCI Cache Line Size register +#define PCI_CACHELS_R ( (uint16_t) 0x000c ) +// PCI bar1 register +#define PCI_BAR1_R ( (uint16_t) 0x0010 ) +// PCI bar2 register +#define PCI_BAR2_R ( (uint16_t) 0x0014 ) +// PCI bar1 register +#define PCI_SUBID_R ( (uint16_t) 0x002e ) +// PCI-X Comand register +#define PCI_X_COM_R ( (uint16_t) 0x0042 ) +// Message Data Register +#define MSG_DATA_R ( (uint16_t) 0x0064 ) +// PCI misc host contrl register +#define PCI_MISC_HCTRL_R ( (uint16_t) 0x0068 ) +// DMA Read/Write Control register +#define DMA_RW_CTRL_R ( (uint16_t) 0x006c ) +// PCI State register +#define PCI_STATE_R ( (uint16_t) 0x0070 ) +// PCI_Clock Control register +#define PCI_CLK_CTRL_R ( (uint16_t) 0x0074 ) +// Register Base Address Register +#define REG_BASE_ADDR_REG ( (uint16_t) 0x0078 ) +// Memory Window Base Address Register +#define MEM_BASE_ADDR_REG ( (uint16_t) 0x007c ) +// Register Data Register +#define REG_DATA_REG ( (uint16_t) 0x0080 ) +// Memory Window Data Register +#define MEM_DATA_REG ( (uint16_t) 0x0084 ) +// MAC Function register +#define MAC_FUNC_R ( (uint16_t) 0x00b8 ) +// Interrupt Mailbox 0 register +#define INT_MBX0_R ( (uint16_t) 0x0204 ) +// Ethernet MAC Mode register +#define ETH_MAC_MODE_R ( (uint16_t) 0x0400 ) +// Ethernet MAC Addresses registers +#define MAC_ADDR_OFFS_HI( idx ) ( (uint16_t) ( (idx*2 + 0)*sizeof( uint32_t ) + 0x0410 ) ) +#define MAC_ADDR_OFFS_LO( idx ) ( (uint16_t) ( (idx*2 + 1)*sizeof( uint32_t ) + 0x0410 ) ) +// Ethernet MAC Status register +#define ETH_MAC_STAT_R ( (uint16_t) 0x0404 ) +// Ethernet MAC Event Enable register +#define ETH_MAC_EVT_EN_R ( (uint16_t) 0x0408 ) +// Ethernet Transmit Random Backoff register +#define ETH_TX_RND_BO_R ( (uint16_t) 0x0438 ) +// Receive MTU Size register +#define RX_MTU_SIZE_R ( (uint16_t) 0x043c ) +// Transmit 1000BASE-X Auto Negotiation register +#define TX_1000BX_AUTONEG_R ( (uint16_t) 0x0444 ) +// Receive 1000BASE-X Auto Negotiation register +#define RX_1000BX_AUTONEG_R ( (uint16_t) 0x0448 ) +// MI Communication register +#define MI_COM_R ( (uint16_t) 0x044c ) +// MI Status Register +#define MI_STATUS_R ( (uint16_t) 0x0450 ) +// MI Mode register +#define MI_MODE_R ( (uint16_t) 0x0454 ) +// Transmit MAC Mode register +#define TX_MAC_MODE_R ( (uint16_t) 0x045c ) +// Transmit MAC Length register +#define TX_MAC_LEN_R ( (uint16_t) 0x0464 ) +// Receive MAC Mode register +#define RX_MAC_MODE_R ( (uint16_t) 0x0468 ) +// MAC Hash 0 register* VPD Config: +#define MAC_HASH0_R ( (uint16_t) 0x0470 ) +// MAC Hash 1 register +#define MAC_HASH1_R ( (uint16_t) 0x0474 ) +// MAC Hash 2 register +#define MAC_HASH2_R ( (uint16_t) 0x0478 ) +// MAC Hash 3 register +#define MAC_HASH3_R ( (uint16_t) 0x047c ) +// Receive Rules Control register +#define RX_RULE_CTRL_R( idx ) ( (uint16_t) ( idx*8 + 0x0480 ) ) +// Receive Rules Value register +#define RX_RULE_VAL_R( idx ) ( (uint16_t) ( idx*8 + 0x0484 ) ) +// Receive Rules Configuration register +#define RX_RULE_CFG_R ( (uint16_t) 0x0500 ) +// Low Watermark Max Receive Frames register +#define LOW_WMARK_MAX_RXFRAM_R ( (uint16_t) 0x0504 ) +// SerDes Control Register +#define SERDES_CTRL_R ( (uint16_t) 0x0590 ) +// Hardware Auto Negotiation Control Register +#define HW_AUTONEG_CTRL_R ( (uint16_t) 0x05B0 ) +// Hardware Auto Negotiation Status Register +#define HW_AUTONEG_STAT_R ( (uint16_t) 0x05B4 ) +// Send Data Initiator Mode register +#define TX_DAT_INIT_MODE_R ( (uint16_t) 0x0c00 ) +// Send Data Completion Mode register +#define TX_DAT_COMPL_MODE_R ( (uint16_t) 0x1000 ) +// Send BD Ring Selector Mode register +#define TX_BD_RING_SEL_MODE_R ( (uint16_t) 0x1400 ) +// Send BD Initiator Mode register +#define TX_BD_INIT_MODE_R ( (uint16_t) 0x1800 ) +// Send BD Completion Mode register +#define TX_BD_COMPL_MODE_R ( (uint16_t) 0x1c00 ) +// Receive List Placement Mode register +#define RX_LST_PLACE_MODE_R ( (uint16_t) 0x2000 ) +// Receive List Placement Configuration register +#define RX_LST_PLACE_CFG_R ( (uint16_t) 0x2010 ) +// Receive List Placement Statistics Enable Mask register +#define RX_LST_PLACE_STAT_EN_R ( (uint16_t) 0x2018 ) +// Receive Data & Receive BD Initiator Mode register +#define RX_DAT_BD_INIT_MODE_R ( (uint16_t) 0x2400 ) +// Receive Data Completion Mode register +#define RX_DAT_COMPL_MODE_R ( (uint16_t) 0x2800 ) +// Receive BD Initiator Mode register +#define RX_BD_INIT_MODE_R ( (uint16_t) 0x2c00 ) +// Standard Receive Producer Ring Replenish Threshold register +#define STD_RXPR_REP_THR_R ( (uint16_t) 0x2c18 ) +// Receive BD Completion Mode register +#define RX_BD_COMPL_MODE_R ( (uint16_t) 0x3000 ) +// Receive List Selector Mode register +#define RX_LST_SEL_MODE_R ( (uint16_t) 0x3400 ) +// MBUF Cluster Free Mode register +#define MBUF_CLSTR_FREE_MODE_R ( (uint16_t) 0x3800 ) +// Host Coalescing Mode register +#define HOST_COAL_MODE_R ( (uint16_t) 0x3c00 ) +// Receive Coalescing Ticks register +#define RX_COAL_TICKS_R ( (uint16_t) 0x3c08 ) +// Send Coalescing Ticks register +#define TX_COAL_TICKS_R ( (uint16_t) 0x3c0c ) +// Receive Max Coalesced BD Count register +#define RX_COAL_MAX_BD_R ( (uint16_t) 0x3c10 ) +// Send Max Coalesced BD Count register +#define TX_COAL_MAX_BD_R ( (uint16_t) 0x3c14 ) +// Receive Coalescing Ticks During Int register +#define RX_COAL_TICKS_INT_R ( (uint16_t) 0x3c18 ) +// Send Coalescing Ticks During Int register +#define TX_COAL_TICKS_INT_R ( (uint16_t) 0x3c1c ) +// Receive Max Coalesced BD Count During Int register +#define RX_COAL_MAX_BD_INT_R ( (uint16_t) 0x3c18 ) +// Send Max Coalesced BD Count During Int register +#define TX_COAL_MAX_BD_INT_R ( (uint16_t) 0x3c1c ) +// Statistics Ticks Counter register +#define STAT_TICK_CNT_R ( (uint16_t) 0x3c28 ) +// Status Block Host Address Low register +#define STB_HOST_ADDR_HI_R ( (uint16_t) 0x3c38 ) +// Status Block Host Address High register +#define STB_HOST_ADDR_LO_R ( (uint16_t) 0x3c3c ) +// Statistics Base Address register +#define STAT_NIC_ADDR_R ( (uint16_t) 0x3c40 ) +// Status Block Base Address register +#define STB_NIC_ADDR_R ( (uint16_t) 0x3c44 ) +// Memory Arbiter Mode register +#define MEMARB_MODE_R ( (uint16_t) 0x4000 ) +// Buffer Manager Mode register +#define BUF_MAN_MODE_R ( (uint16_t) 0x4400 ) +// MBuf Pool Address register +#define MBUF_POOL_ADDR_R ( (uint16_t) 0x4408 ) +// MBuf Pool Length register +#define MBUF_POOL_LEN_R ( (uint16_t) 0x440c ) +// Read DMA Mbuf Low Watermark register +#define DMA_RMBUF_LOW_WMARK_R ( (uint16_t) 0x4410 ) +// MAC Rx Mbuf Low Watermark register +#define MAC_RXMBUF_LOW_WMARK_R ( (uint16_t) 0x4414 ) +// Mbuf High Watermark register +#define MBUF_HIGH_WMARK_R ( (uint16_t) 0x4418 ) +// DMA Descriptor Pool Address register +#define DMA_DESC_POOL_ADDR_R ( (uint16_t) 0x442c ) +// DMA Descriptor Pool Length register +#define DMA_DESC_POOL_LEN_R ( (uint16_t) 0x4430 ) +// DMA Descriptor Low Watermark register +#define DMA_DESC_LOW_WM_R ( (uint16_t) 0x4434 ) +// DMA Descriptor HIGH Watermark register +#define DMA_DESC_HIGH_WM_R ( (uint16_t) 0x4438 ) +// Read DMA Mode register +#define RD_DMA_MODE_R ( (uint16_t) 0x4800 ) +// Write DMA Mode register +#define WR_DMA_MODE_R ( (uint16_t) 0x4c00 ) +// FTQ Reset register +#define FTQ_RES_R ( (uint16_t) 0x5c00 ) +// MSI Mode register +#define MSI_MODE_R ( (uint16_t) 0x6000 ) +// DMA completion Mode register +#define DMA_COMPL_MODE_R ( (uint16_t) 0x6400 ) +// Mode Control register +#define MODE_CTRL_R ( (uint16_t) 0x6800 ) +// Misc Configuration register +#define MISC_CFG_R ( (uint16_t) 0x6804 ) +// Misc Local Control register +#define MISC_LOCAL_CTRL_R ( (uint16_t) 0x6808 ) +// RX-Risc Mode Register +#define RX_CPU_MODE_R ( (uint16_t) 0x5000 ) +// RX-Risc State Register +#define RX_CPU_STATE_R ( (uint16_t) 0x5004 ) +// RX-Risc Program Counter +#define RX_CPU_PC_R ( (uint16_t) 0x501c ) +// RX-Risc Event Register +#define RX_CPU_EVENT_R ( (uint16_t) 0x6810 ) +// MDI Control register +#define MDI_CTRL_R ( (uint16_t) 0x6844 ) +// WOL Mode register +#define WOL_MODE_R ( (uint16_t) 0x6880 ) +// WOL Config register +#define WOL_CFG_R ( (uint16_t) 0x6884 ) +// WOL Status register +#define WOL_STATUS_R ( (uint16_t) 0x6888 ) + +// ASF Control register +#define ASF_CTRL_R ( (uint16_t) 0x6c00 ) +// ASF Watchdog Timer register +#define ASF_WATCHDOG_TIMER_R ( (uint16_t) 0x6c0c ) +// ASF Heartbeat Timer register +#define ASF_HEARTBEAT_TIMER_R ( (uint16_t) 0x6c10 ) +// Poll ASF Timer register +#define ASF_POLL_TIMER_R ( (uint16_t) 0x6c14 ) +// Poll Legacy Timer register +#define POLL_LEGACY_TIMER_R ( (uint16_t) 0x6c18 ) +// Retransmission Timer register +#define RETRANSMISSION_TIMER_R ( (uint16_t) 0x6c1c ) +// Time Stamp Counter register +#define TIME_STAMP_COUNTER_R ( (uint16_t) 0x6c20 ) + +// NVM Command register +#define NVM_COM_R ( (uint16_t) 0x7000 ) +// NVM Write register +#define NVM_WRITE_R ( (uint16_t) 0x7008 ) +// NVM Address register +#define NVM_ADDR_R ( (uint16_t) 0x700c ) +// NVM Read registertg3_phy_copper_begin +#define NVM_READ_R ( (uint16_t) 0x7010 ) +// NVM Access register +#define NVM_ACC_R ( (uint16_t) 0x7024 ) +// NVM Config 1 register +#define NVM_CFG1_R ( (uint16_t) 0x7014 ) +// Software arbitration register +#define SW_ARB_R ( (uint16_t) 0x7020 ) + +/* + * useful def's + */ +#define rd08(a) ci_read_8((uint8_t *)(a)) +#define rd16(a) ci_read_16((uint16_t *)(a)) +#define rd32(a) ci_read_32((uint32_t *)(a)) +#define wr08(a,v) ci_write_8((uint8_t *)(a), (v)) +#define wr16(a,v) ci_write_16((uint16_t *)(a), (v)) +#define wr32(a,v) ci_write_32((uint32_t *)(a), (v)) + +#define BIT08( bit ) ( (uint8_t) 0x1 << (bit) ) +#define BIT16( bit ) ( (uint16_t) 0x1 << (bit) ) +#define BIT32( bit ) ( (uint32_t) 0x1 << (bit) ) + +/* + * type definition + */ + +/* + * Constants for different kinds of IOCTL requests + */ + +#define SIOCETHTOOL 0x1000 + +/* + * special structure and constants for IOCTL requests of type ETHTOOL + */ + +#define ETHTOOL_GMAC 0x03 +#define ETHTOOL_SMAC 0x04 +#define ETHTOOL_VERSION 0x05 + +typedef struct { + int idx; + char address[6]; +} ioctl_ethtool_mac_t; + +typedef struct { + unsigned int length; + char *text; +} ioctl_ethtool_version_t; + + +/* + * default structure and constants for IOCTL requests + */ + +#define IF_NAME_SIZE 0xFF + +typedef struct { + char if_name[IF_NAME_SIZE]; + int subcmd; + union { + ioctl_ethtool_mac_t mac; + ioctl_ethtool_version_t version; + } data; +} ioctl_net_data_t; + +extern net_driver_t *bcm57xx_open(void); +extern void bcm57xx_close(net_driver_t *driver); +extern int bcm57xx_read(char *buf, int len); +extern int bcm57xx_write(char *buf, int len); -- cgit v1.1