diff --git a/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet.mdd b/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet.mdd new file mode 100755 index 00000000..24f0b94e --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet.mdd @@ -0,0 +1,48 @@ +############################################################################### +# +# Copyright (C) 2010 - 2014 Xilinx, Inc. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# Use of the Software is limited solely to applications: +# (a) running on a Xilinx device, or +# (b) that interact with a Xilinx device through a bus or interconnect. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +# OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# Except as contained in this notice, the name of the Xilinx shall not be used +# in advertising or otherwise to promote the sale, use or other dealings in +# this Software without prior written authorization from Xilinx. +# +# MODIFICATION HISTORY: +# +# 05/12/10 asa First Release +# 02/01/13 srt Added support for IPI designs (CR 698249) +# +############################################################################### + +OPTION psf_version = 2.1; + +BEGIN driver axiethernet + + OPTION supported_peripherals = (axi_ethernet_v[3-9]_[0-9][1-9]_[a-z] axi_ethernet_v[3-9]_[0-9] axi_ethernet_buffer); + OPTION driver_state = ACTIVE; + OPTION copyfiles = all; + OPTION VERSION = 5.0; + OPTION NAME = axiethernet; + +END driver diff --git a/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet.tcl b/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet.tcl new file mode 100755 index 00000000..6daa1bae --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet.tcl @@ -0,0 +1,700 @@ +############################################################################### +# +# Copyright (C) 2010 - 2014 Xilinx, Inc. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# Use of the Software is limited solely to applications: +# (a) running on a Xilinx device, or +# (b) that interact with a Xilinx device through a bus or interconnect. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +# OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# Except as contained in this notice, the name of the Xilinx shall not be used +# in advertising or otherwise to promote the sale, use or other dealings in +# this Software without prior written authorization from Xilinx. +# +# MODIFICATION HISTORY: +# +# 05/12/10 asa First Release based on the LL TEMAC driver tcl +# 01/07/13 srt Added C_PHYADDR configuration parameter to support SGMII mode +# 02/03/13 srt Added support for IPI designs (CR 698249) +# 02/14/13 srt Added support for Zynq (CR 681136) +# 04/24/13 srt Modified parameter *_SGMII_PHYADDR to *_PHYADDR, the config +# parameter C_PHYADDR applies to SGMII/1000BaseX modes of +# operation (CR 704195) +# 08/06/13 srt Added support to handle multiple instances of AxiEthernet +# FIFO interface (CR 721141) +# 06/08/14 adk Modified the driver tcl to handle the open/close of files +# properly (CR 810643) +# 29/10/14 adk Added support for generating parameters for SGMII/1000BaseX modes +# When IP is configured with the PCS/PMA core (CR 828796) +# 8/1/15 adk Fixed TCL errors when axiethernet is configured with the +# Axi stream fifo (CR 835605). +# +############################################################################### +#uses "xillib.tcl" + +set periph_config_params 0 +set periph_ninstances 0 + +proc init_periph_config_struct { deviceid } { + global periph_config_params + set periph_config_params($deviceid) [list] +} + +proc get_periph_config_struct_fields { deviceid } { + global periph_config_params + return $periph_config_params($deviceid) +} +proc add_field_to_periph_config_struct { deviceid fieldval } { + global periph_config_params + lappend periph_config_params($deviceid) $fieldval +} +proc display_avb_warning_if_applicable { periph } { + set avb_param_val "" + set avb_param_val [::hsi::utils::get_param_value $periph C_AVB] + if { $avb_param_val == 1 } { + puts "*******************************************************************************\r\n" + puts "WARNING: Audio Video Bridging (AVB) functionality is ENABLED in the AXI Ethernet core." + puts "The AXI Ethernet driver does not support AVB functionality." + puts "Please refer to the System Integration section of the Ethernet AVB User Guide" + puts "http://www.xilinx.com/support/documentation/ip_documentation/eth_avb_endpoint_ug492.pdf for information on AXI-Ethernet AVB Driver integration.\r\n" + puts "*******************************************************************************\r\n" + } +} + +# ------------------------------------------------------------------ +# Given an Axi Ethernet peripheral, generate all the stuff required in +# the system include file. +# +# Given an Axi Ethernet which is an initiator on a +# Axi4 Stream interface, traverse the Axi4 Stream to the target side, +# figure out the peripheral type that is connected and +# put in appropriate defines. The peripheral on the other side +# can be AXI DMA or AXI Streaming FIFO. +# +# ------------------------------------------------------------------ +proc xdefine_axiethernet_include_file {drv_handle file_name drv_string} { + global periph_ninstances + + # Open include file + set file_handle [::hsi::utils::open_include_file $file_name] + + # Get all peripherals connected to this driver + set periphs [::hsi::utils::get_common_driver_ips $drv_handle] + + # ---------------------------------------------- + # PART 1 - AXI Ethernet related parameters + # ---------------------------------------------- + + # Handle NUM_INSTANCES + set periph_ninstances 0 + puts $file_handle "/* Definitions for driver [string toupper [get_property NAME $drv_handle]] */" + foreach periph $periphs { + init_periph_config_struct $periph_ninstances + incr periph_ninstances 1 + } + puts $file_handle "\#define [::hsi::utils::get_driver_param_name $drv_string NUM_INSTANCES] $periph_ninstances" + + close $file_handle + # Now print all useful parameters for all peripherals + set device_id 0 + foreach periph $periphs { + #puts $file_handle "" + + ::hsi::utils::define_include_file $drv_handle "xparameters.h" "XAxiEthernet" "NUM_INSTANCES" "DEVICE_ID" "C_BASEADDR" "C_HIGHADDR" "C_TYPE" "C_TXCSUM" "C_RXCSUM" "C_PHY_TYPE" "C_TXVLAN_TRAN" "C_RXVLAN_TRAN" "C_TXVLAN_TAG" "C_RXVLAN_TAG" "C_TXVLAN_STRP" "C_RXVLAN_STRP" "C_MCAST_EXTEND" "C_STATS" "C_AVB" "C_PHYADDR" + + set file_handle [::hsi::utils::open_include_file $file_name] + # Create canonical definitions + xdefine_temac_params_canonical $file_handle $periph $device_id + + # Interrupt ID (canonical) + xdefine_temac_interrupt $file_handle $periph $device_id + + generate_sgmii_params $drv_handle "xparameters.h" + + display_avb_warning_if_applicable $periph + + incr device_id + puts $file_handle "\n" + close $file_handle + + } + # ------------------------------------------------------- + # PART 2 -- AXIFIFO/AXIDMA Connection related parameters + # ------------------------------------------------------- + set file_handle [::hsi::utils::open_include_file $file_name] + xdefine_axi_target_params $periphs $file_handle + + puts $file_handle "\n/******************************************************************/\n" + close $file_handle +} +# ------------------------------------------------------------------ +# Main generate function - called by the tools +# ------------------------------------------------------------------ +proc generate {drv_handle} { + + xdefine_axiethernet_include_file $drv_handle "xparameters.h" "XAxiEthernet" + xdefine_axiethernet_config_file "xaxiethernet_g.c" "XAxiEthernet" +} + +# --------------------------------------------------------------------------- +# Given each AXI4 Stream peripheral which is an initiator on a AXI4 +# Stream interface, traverse to the target side, figure out the peripheral +# type that is connected and put in appropriate defines. +# The peripheral on the other side can be AXI DMA or AXi Streaming FIFO. +# +# NOTE: This procedure assumes that each AXI4 Stream on each peripheral +# corresponds to a unique device id in the system and populates +# the global device config params structure accordingly. +# --------------------------------------------------------------------------- +proc xdefine_axi_target_params {periphs file_handle} { + + global periph_ninstances + + # + # First dump some enumerations on AXI_TYPE + # + puts $file_handle "/* AxiEthernet TYPE Enumerations */" + puts $file_handle "#define XPAR_AXI_FIFO 1" + puts $file_handle "#define XPAR_AXI_DMA 2" + puts $file_handle "" + + set device_id 0 + set validentry 0 + + # Get unique list of p2p peripherals + foreach periph $periphs { + set p2p_periphs [list] + set periph_name [string toupper [get_property NAME $periph]] + # Get all point2point buses for periph + set p2p_busifs_i [get_intf_pins -of_objects $periph -filter "TYPE==INITIATOR"] + + puts $file_handle "" + puts $file_handle "/* Canonical Axi parameters for $periph_name */" + + # Add p2p periphs + foreach p2p_busif $p2p_busifs_i { + + set busif_name [string toupper [get_property NAME $p2p_busif]] + set conn_busif_handle [::hsi::utils::get_connected_intf $periph $busif_name] + if { [string compare -nocase $conn_busif_handle ""] == 0} { + continue + } else { + # if there is a single match, we know if it is FIFO or DMA + # no need for further iterations + set conn_busif_name [get_property NAME $conn_busif_handle] + set target_periph [get_cells -of_objects $conn_busif_handle] + set target_periph_type [get_property IP_NAME $target_periph] + if { [string compare -nocase $target_periph_type "tri_mode_ethernet_mac"] == 0 } { + continue + } + set tartget_per_name [get_property NAME $target_periph] + set target_periph_name [string toupper [get_property NAME $target_periph]] + set canonical_tag [string toupper [format "AXIETHERNET_%d" $device_id ]] + set validentry 1 + break + } + } + if {$validentry == 1} { + if {$target_periph_type == "axi_fifo_mm_s"} { + # + # Handle the connection type (FIFO in this case) + # + set canonical_name [format "XPAR_%s_CONNECTED_TYPE" $canonical_tag] + puts $file_handle "#define $canonical_name XPAR_AXI_FIFO" + add_field_to_periph_config_struct $device_id $canonical_name + + set axi_fifo_baseaddr [get_property CONFIG.C_BASEADDR $target_periph] + set canonical_name [format "XPAR_%s_CONNECTED_BASEADDR" $canonical_tag] + puts $file_handle [format "#define $canonical_name %s" $axi_fifo_baseaddr] + add_field_to_periph_config_struct $device_id $canonical_name + # FIFO Interrupts Handling + set int_pin [get_pins -of_objects [get_cells $tartget_per_name] INTERRUPT] + set intc_periph_type [::hsi::utils::get_connected_intr_cntrl $tartget_per_name $int_pin] + set intc_name [get_property IP_NAME $intc_periph_type] + if { $intc_name != [format "ps7_scugic"] } { + set int_id [::hsi::utils::get_port_intr_id [get_cells $tartget_per_name] $int_pin] + set canonical_name [format "XPAR_%s_CONNECTED_FIFO_INTR" $canonical_tag] + puts $file_handle [format "#define $canonical_name %d" $int_id] + add_field_to_periph_config_struct $device_id $canonical_name + puts $file_handle [format "#define XPAR_%s_CONNECTED_DMARX_INTR 0xFF" $canonical_tag] + puts $file_handle [format "#define XPAR_%s_CONNECTED_DMATX_INTR 0xFF" $canonical_tag] + add_field_to_periph_config_struct $device_id 0xFF + add_field_to_periph_config_struct $device_id 0xFF + } else { + set canonical_name [format "XPAR_%s_CONNECTED_FIFO_INTR" $canonical_tag] + set temp [string toupper $int_pin] + puts $file_handle [format "#define $canonical_name XPAR_FABRIC_%s_%s_INTR" $target_periph_name $temp] + add_field_to_periph_config_struct $device_id $canonical_name + puts $file_handle [format "#define XPAR_%s_CONNECTED_DMARX_INTR 0xFF" $canonical_tag] + puts $file_handle [format "#define XPAR_%s_CONNECTED_DMATX_INTR 0xFF" $canonical_tag] + add_field_to_periph_config_struct $device_id 0xFF + add_field_to_periph_config_struct $device_id 0xFF + } + } + if {$target_periph_type == "axi_dma"} { + set axi_dma_baseaddr [get_property CONFIG.C_BASEADDR $target_periph] + # Handle base address and connection type + set canonical_name [format "XPAR_%s_CONNECTED_TYPE" $canonical_tag] + puts $file_handle "#define $canonical_name XPAR_AXI_DMA" + add_field_to_periph_config_struct $device_id $canonical_name + set canonical_name [format "XPAR_%s_CONNECTED_BASEADDR" $canonical_tag] + puts $file_handle [format "#define $canonical_name %s" $axi_dma_baseaddr] + add_field_to_periph_config_struct $device_id $canonical_name + + puts $file_handle [format "#define XPAR_%s_CONNECTED_FIFO_INTR 0xFF" $canonical_tag] + add_field_to_periph_config_struct $device_id 0xFF + set dmarx_signal [format "s2mm_introut"] + set dmatx_signal [format "mm2s_introut"] + xdefine_dma_interrupts $file_handle $target_periph $device_id $canonical_tag $dmarx_signal $dmatx_signal + } + incr device_id + + } + + if {$validentry !=1} { + puts "*******************************************************************************\r\n" + puts "The target Peripheral(Axi DMA or AXI FIFO) is not connected properly to the AXI Ethernet core." + puts "*******************************************************************************\r\n" + } + } +} +# ------------------------------------------------------------------ +# This procedure creates XPARs that are canonical/normalized for the +# hardware design parameters. It also adds these to the Config table. +# ------------------------------------------------------------------ +proc xdefine_temac_params_canonical {file_handle periph device_id} { + + puts $file_handle "\n/* Canonical definitions for peripheral [string toupper [get_property NAME $periph]] */" + + set canonical_tag [string toupper [format "XPAR_AXIETHERNET_%d" $device_id]] + + # Handle device ID + set canonical_name [format "%s_DEVICE_ID" $canonical_tag] + puts $file_handle "\#define $canonical_name $device_id" + add_field_to_periph_config_struct $device_id $canonical_name + + # Handle BASEADDR specially + set canonical_name [format "%s_BASEADDR" $canonical_tag] + puts $file_handle "\#define $canonical_name [::hsi::utils::get_param_value $periph C_BASEADDR]" + add_field_to_periph_config_struct $device_id $canonical_name + + # Handle HIGHADDR specially + set canonical_name [format "%s_HIGHADDR" $canonical_tag] + puts $file_handle "\#define $canonical_name [::hsi::utils::get_param_value $periph C_HIGHADDR]" + + set canonical_name [format "%s_TEMAC_TYPE" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_TYPE] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + + set canonical_name [format "%s_TXCSUM" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_TXCSUM] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + + set canonical_name [format "%s_RXCSUM" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_RXCSUM] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + + set canonical_name [format "%s_PHY_TYPE" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_PHY_TYPE] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + + set canonical_name [format "%s_TXVLAN_TRAN" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_TXVLAN_TRAN] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + + set canonical_name [format "%s_RXVLAN_TRAN" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_RXVLAN_TRAN] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + + set canonical_name [format "%s_TXVLAN_TAG" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_TXVLAN_TAG] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + + set canonical_name [format "%s_RXVLAN_TAG" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_RXVLAN_TAG] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + + set canonical_name [format "%s_TXVLAN_STRP" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_TXVLAN_STRP] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + + set canonical_name [format "%s_RXVLAN_STRP" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_RXVLAN_STRP] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + + set canonical_name [format "%s_MCAST_EXTEND" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_MCAST_EXTEND] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + + set canonical_name [format "%s_STATS" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_STATS] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + + set canonical_name [format "%s_AVB" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_AVB] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + set canonical_name [format "%s_ENABLE_SGMII_OVER_LVDS" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_ENABLE_LVDS] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + set canonical_name [format "%s_PHYADDR" $canonical_tag] + set phyaddr [::hsi::utils::get_param_value $periph C_PHYADDR] + set value [::hsi::utils::convert_binary_to_decimal $phyaddr] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + +} + +# ------------------------------------------------------------------ +# Create configuration C file as required by Xilinx drivers +# Use the config field list technique +# ------------------------------------------------------------------ +proc xdefine_axiethernet_config_file {file_name drv_string} { + global periph_ninstances + + set filename [file join "src" $file_name] + file delete $filename + set config_file [open $filename w] + ::hsi::utils::write_c_header $config_file "Driver configuration" + puts $config_file "\#include \"xparameters.h\"" + puts $config_file "\#include \"[string tolower $drv_string].h\"" + puts $config_file "\n/*" + puts $config_file "* The configuration table for devices" + puts $config_file "*/\n" + puts $config_file [format "%s_Config %s_ConfigTable\[\] =" $drv_string $drv_string] + puts $config_file "\{" + + set start_comma "" + for {set i 0} {$i < $periph_ninstances} {incr i} { + + puts $config_file [format "%s\t\{" $start_comma] + set comma "" + foreach field [get_periph_config_struct_fields $i] { + puts -nonewline $config_file [format "%s\t\t%s" $comma $field] + set comma ",\n" + } + + puts -nonewline $config_file "\n\t\}" + set start_comma ",\n" + } + puts $config_file "\n\};\n" + close $config_file +} + +# ------------------------------------------------------------------ +# Find the two LocalLink DMA interrupts (RX and TX), and define +# the canonical constants in xparameters.h and the config table +# ------------------------------------------------------------------ +proc xdefine_dma_interrupts {file_handle target_periph deviceid canonical_tag dmarx_signal dmatx_signal} { + + set target_periph_name [string toupper [get_property NAME $target_periph]] + + # First get the interrupt ports on this AXI peripheral + set interrupt_port [get_pins -of_objects $target_periph -filter {TYPE==INTERRUPT&&DIRECTION==O}] + if {$interrupt_port == ""} { + puts "Info: There are no AXIDMA Interrupt ports" + puts $file_handle [format "#define XPAR_%s_CONNECTED_DMARX_INTR 0xFF" $canonical_tag] + add_field_to_periph_config_struct $deviceid 0xFF + puts $file_handle [format "#define XPAR_%s_CONNECTED_DMATX_INTR 0xFF" $canonical_tag] + add_field_to_periph_config_struct $deviceid 0xFF + return + } + # For each interrupt port, find out the ordinal of the interrupt line + # as connected to an interrupt controller + set addentry 0 + set dmarx "null" + set dmatx "null" + foreach intr_port $interrupt_port { + set interrupt_signal_name [get_property NAME $intr_port] + set intc_port [get_pins -of_objects $target_periph -filter {TYPE==INTERRUPT&&DIRECTION==O}] + + # Make sure the interrupt signal was connected in this design. We assume + # at least one is. (could be a bug if user just wants polled mode) + if { $intc_port != "" } { + set found_intc "" + foreach intr_sink $intc_port { + set pname_type [::hsi::utils::get_connected_intr_cntrl $target_periph $intr_sink] + if {$pname_type != "chipscope_ila"} { + set special [get_property IP_TYPE $pname_type] + if {[string compare -nocase $special "INTERRUPT_CNTLR"] == 0} { + set found_intc $intr_sink + } + } + } + + if {$found_intc == ""} { + puts "Info: DMA interrupt not connected to intc\n" + puts "Info: There are no AXIDMA Interrupt ports" + puts $file_handle [format "#define XPAR_%s_CONNECTED_DMARX_INTR 0xFF" $canonical_tag] + add_field_to_periph_config_struct $deviceid 0xFF + puts $file_handle [format "#define XPAR_%s_CONNECTED_DMATX_INTR 0xFF" $canonical_tag] + add_field_to_periph_config_struct $deviceid 0xFF + return + } + set intc_periph [get_cells -of_objects $found_intc] + set intc_periph_type [get_property IP_NAME $pname_type] + set intc_name [string toupper [get_property NAME $pname_type]] + } else { + puts "Info: $target_periph_name interrupt signal $interrupt_signal_name not connected" + continue + } + } + + # A bit of ugliness here. The only way to figure the ordinal is to + # iterate over the interrupt lines again and see if a particular signal + # matches the original interrupt signal we were tracking. + # If it does, put out the XPAR + if { $intc_periph_type != [format "ps7_scugic"] } { + set rx_int_id [::hsi::utils::get_port_intr_id $target_periph $dmarx_signal] + set canonical_name [format "XPAR_%s_CONNECTED_DMARX_INTR" $canonical_tag] + puts $file_handle [format "#define $canonical_name %d" $rx_int_id] + add_field_to_periph_config_struct $deviceid $canonical_name + set tx_int_id [::hsi::utils::get_port_intr_id $target_periph $dmatx_signal] + set canonical_name [format "XPAR_%s_CONNECTED_DMATX_INTR" $canonical_tag] + puts $file_handle [format "#define $canonical_name %d" $tx_int_id] + add_field_to_periph_config_struct $deviceid $canonical_name + } else { + set addentry 2 + } + + + # Now add to the config table in the proper order (RX first, then TX + + if { $intc_periph_type == [format "ps7_scugic"] } { + set canonical_name [format "XPAR_%s_CONNECTED_DMARX_INTR" $canonical_tag] + puts $file_handle [format "#define $canonical_name XPAR_FABRIC_%s_S2MM_INTROUT_INTR" $target_periph_name] + add_field_to_periph_config_struct $deviceid $canonical_name + set canonical_name [format "XPAR_%s_CONNECTED_DMATX_INTR" $canonical_tag] + puts $file_handle [format "#define $canonical_name XPAR_FABRIC_%s_MM2S_INTROUT_INTR" $target_periph_name] + add_field_to_periph_config_struct $deviceid $canonical_name + } + + if { $addentry == 1} { + # for some reason, only one DMA interrupt was connected (probably a bug), + # but fill in a dummy entry for the other (may be the wrong direction!) + puts "WARNING: only one SDMA interrupt line connected for $target_periph_name" + } +} + +# ------------------------------------------------------------------------------------ +# This procedure re-forms the AXI Ethernet interrupt ID XPAR constant and adds it to +# the driver config table. This Tcl needs to be careful of the order of the +# config table entries +# ------------------------------------------------------------------------------------ +proc xdefine_temac_interrupt {file_handle periph device_id} { + + #set mhs_handle [xget_hw_parent_handle $periph] + set periph_name [string toupper [get_property NAME $periph]] + + # set up the canonical constant name + set canonical_name [format "XPAR_AXIETHERNET_%d_INTR" $device_id] + + # + # In order to reform the XPAR for the interrupt ID, we need to hunt + # for the interrupt ID based on the interrupt signal name of the TEMAC + # + # First get the interrupt ports on this peripheral + set interrupt_port [::hsi::get_pins -of_objects $periph -filter {TYPE==INTERRUPT&&DIRECTION==O}] + if {$interrupt_port == ""} { + puts "Info: There are no AXI Ethernet Interrupt ports" + # No interrupts were connected, so add dummy entry to the config structure + puts $file_handle [format "#define $canonical_name 0xFF"] + add_field_to_periph_config_struct $device_id 0xFF + } + + set addentry 0 + # For each interrupt port, find out the ordinal of the interrupt line + # as connected to an interrupt controller + set interrupt_signal_name [get_property NAME $interrupt_port] + #set interrupt_signal [xget_hw_value $interrupt_port] + set intc_prt [::hsi::utils::get_sink_pins [get_pins -of_objects [get_cells $periph] INTERRUPT]] + + # Make sure the interrupt signal was connected in this design. We assume + # at least one is. (could be a bug if user just wants polled mode) + if { $intc_prt != "" } { + set intc_periph [::hsi::utils::get_connected_intr_cntrl $periph [get_pins -of_objects [get_cells $periph] INTERRUPT] ] + if {$intc_periph == ""} { + puts "Info: Axi Ethernet interrupt not connected to intc\n" + # No interrupts were connected, so add dummy entry to the config structure + puts $file_handle [format "#define $canonical_name 0xFF"] + add_field_to_periph_config_struct $device_id 0xFF + return + } + + set intc_periph_type [get_property IP_NAME $intc_periph] + set intc_name [string toupper [get_property NAME $intc_periph]] + } else { + puts "Info: $periph_name interrupt signal $interrupt_signal_name not connected" + # No interrupts were connected, so add dummy entry to the config structure + puts $file_handle [format "#define $canonical_name 0xFF"] + add_field_to_periph_config_struct $device_id 0xFF + return + } + + # A bit of ugliness here. The only way to figure the ordinal is to + # iterate over the interrupt lines again and see if a particular signal + # matches the original interrupt signal we were tracking. + + if { $intc_periph_type != [format "ps7_scugic"] } { + set ethernet_int_signal_name [get_pins -of_objects $periph INTERRUPT] + set int_id [::hsi::utils::get_port_intr_id $periph $ethernet_int_signal_name] + puts $file_handle "\#define $canonical_name $int_id" + add_field_to_periph_config_struct $device_id $canonical_name + set addentry 1 + } else { + puts $file_handle [format "#define $canonical_name XPAR_FABRIC_%s_INTERRUPT_INTR" $periph_name] + add_field_to_periph_config_struct $device_id $canonical_name + set addentry 1 + } + + if { $addentry == 0 } { + # No interrupts were connected, so add dummy entry to the config structure + puts $file_handle [format "#define $canonical_name 0xFF"] + add_field_to_periph_config_struct $device_id 0xFF + } +} + +proc generate_sgmii_params {drv_handle file_name} { + set file_handle [::hsi::utils::open_include_file $file_name] + set ips [get_cells "*"] + + foreach ip $ips { + set periph [get_property IP_NAME $ip] + if { [string compare -nocase $periph "gig_ethernet_pcs_pma"] == 0} { + set PhyStandard [get_property CONFIG.Standard $ip] + } + } + + foreach ip $ips { + set periph [get_property IP_NAME $ip] + if { [string compare -nocase $periph "axi_ethernet_buffer"] == 0} { + set phya [is_gige_pcs_pma_ip_present $ip] + if { $phya == 0} { + close $file_handle + return 0 + } + if { $PhyStandard == "1000BASEX" } { + puts $file_handle "/* Definitions related to PCS PMA PL IP*/" + puts $file_handle "\#define XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT 1" + puts $file_handle "\#define XPAR_PCSPMA_1000BASEX_PHYADDR $phya" + puts $file_handle "\n/******************************************************************/\n" + } else { + puts $file_handle "/* Definitions related to PCS PMA PL IP*/" + puts $file_handle "\#define XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT 1" + puts $file_handle "\#define XPAR_PCSPMA_SGMII_PHYADDR $phya" + puts $file_handle "\n/******************************************************************/\n" + + } + } + } + close $file_handle +} + +proc is_gige_pcs_pma_ip_present {slave} { + set port_value 0 + set phy_addr 0 + set ipconv 0 + + set ips [get_cells "*"] + set enetipinstance_name [get_property IP_NAME $slave] + + foreach ip $ips { + set periph [get_property IP_NAME $ip] + if { [string compare -nocase $periph "gig_ethernet_pcs_pma"] == 0} { + set sgmii_param [get_property CONFIG.c_is_sgmii $ip] + set PhyStandarrd [get_property CONFIG.Standard $ip] + if {$sgmii_param == true || $PhyStandarrd == "1000BASEX"} { + set ipconv $ip + } + break + } + } + + if { $ipconv != 0 } { + set port_value [get_pins -of_objects [get_nets -of_objects [get_pins -of_objects $ipconv gmii_txd]]] + if { $port_value != 0 } { + if { [string compare -nocase $enetipinstance_name "axi_ethernet_buffer"] == 0} { + set phyaddr [::hsi::utils::get_param_value $ipconv C_PHYADDR] + set phy_addr [::hsi::utils::convert_binary_to_decimal $phyaddr] + if {[llength $phy_addr] == 0} { + set phy_addr 0 + } + } + } + } + return $phy_addr +} diff --git a/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet_fifo_intr_header.h b/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet_fifo_intr_header.h new file mode 100644 index 00000000..7e37c1c8 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet_fifo_intr_header.h @@ -0,0 +1,47 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ + +#include "xstatus.h" +#include "xil_types.h" +#include "xparameters.h" + +#ifdef XPAR_INTC_0_DEVICE_ID +#define INTC XIntc +#else +#define INTC XScuGic +#endif + +int AxiEthernetFifoIntrExample(INTC * IntcInstancePtr, + XAxiEthernet * AxiEthernetInstancePtr, + XLlFifo * FifoInstancePtr, + u16 AxiEthernetDeviceId, u16 FifoDeviceId, + u16 AxiEthernetIntrId, u16 FifoIntrId); diff --git a/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet_header.h b/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet_header.h new file mode 100644 index 00000000..17e8b6cf --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet_header.h @@ -0,0 +1,36 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ + +#include "xstatus.h" +#include "xil_types.h" + +int AxiEthernetPolledExample(u16 AxiEthernetDeviceId, u16 FifoDeviceId); diff --git a/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet_intr_header.h b/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet_intr_header.h new file mode 100644 index 00000000..44d3e645 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet_intr_header.h @@ -0,0 +1,49 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ + +#include "xstatus.h" +#include "xil_types.h" + +#include "xparameters.h" + +#ifdef XPAR_INTC_0_DEVICE_ID +#define INTC XIntc +#else +#define INTC XScuGic +#endif + +int AxiEthernetSgDmaIntrExample(INTC * IntcInstancePtr, + XAxiEthernet * AxiEthernetInstancePtr, + XAxiDma * DmaInstancePtr, + u16 AxiEthernetDeviceId, + u16 AxiDmaDeviceId, u16 AxiEthernetIntrId, + u16 DmaRxIntrId, u16 DmaTxIntrId); diff --git a/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet_tapp.tcl b/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet_tapp.tcl new file mode 100755 index 00000000..f292cd7e --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet_tapp.tcl @@ -0,0 +1,416 @@ +############################################################################### +# +# Copyright (C) 2010 - 2014 Xilinx, Inc. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# Use of the Software is limited solely to applications: +# (a) running on a Xilinx device, or +# (b) that interact with a Xilinx device through a bus or interconnect. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +# OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# Except as contained in this notice, the name of the Xilinx shall not be used +# in advertising or otherwise to promote the sale, use or other dealings in +# this Software without prior written authorization from Xilinx. +# +# MODIFICATION HISTORY: +# +# Ver Who Date Changes +# -------- ------ -------- ---------------------------------------------------- +# 1.00.a asa 05/12/10 First Release +# 4.0 adk 10/12/13 Updated as per the New Tcl API's +# 4.1 adk 21/4/14 Fixed the CR:780537 Modified the get_dma_info proc +# logic as appropriate(In case of multiple dma's in the +# system some connected to ethernet some not). +# +############################################################################### + +# ----------------------------------------------------------------- +# Software Project Types (swproj): +# 0 : MemoryTest - Calls basic memorytest routines from common driver dir +# 1 : PeripheralTest - Calls any existing polled_example and/or selftest +# ----------------------------------------------------------------- + +# ----------------------------------------------------------------- +# TCL Procedures: +# ----------------------------------------------------------------- + +proc gen_include_files {swproj mhsinst} { + if {$swproj == 0} { + return "" + } + if {$swproj == 1} { + set ifintr [::hsi::utils::is_ip_interrupting_current_proc $mhsinst] + set dmaType [get_dma_type $mhsinst] + + if {$ifintr == 1} { + set inc_file_lines {xaxiethernet.h xaxiethernet_example.h} + + if {$dmaType == 1} { + append inc_file_lines " xllfifo.h" + append inc_file_lines " axiethernet_header.h" + append inc_file_lines " axiethernet_fifo_intr_header.h" + } + if {$dmaType == 3} { + append inc_file_lines " xaxidma.h" + append inc_file_lines " axiethernet_intr_header.h" + } + } else { + if {$dmaType == 1} { + set inc_file_lines {xaxiethernet.h xaxiethernet_example.h axiethernet_header.h} + } else { + return "" + } + } + + return $inc_file_lines + } +} + +proc gen_src_files {swproj mhsinst} { + if {$swproj == 0} { + return "" + } + if {$swproj == 1} { + set ifintr [::hsi::utils::is_ip_interrupting_current_proc $mhsinst] + set dmaType [get_dma_type $mhsinst] + + if {$ifintr == 1} { + if {$dmaType == 1} { + set inc_file_lines {examples/xaxiethernet_example.h examples/xaxiethernet_example_polled.c examples/xaxiethernet_example_util.c examples/xaxiethernet_example_intr_fifo.c data/axiethernet_header.h data/axiethernet_fifo_intr_header.h} + } elseif {$dmaType == 3} { + set inc_file_lines {examples/xaxiethernet_example.h examples/xaxiethernet_example_util.c examples/xaxiethernet_example_intr_sgdma.c data/axiethernet_intr_header.h} + } + } else { + if {$dmaType == 1} { + set inc_file_lines {examples/xaxiethernet_example.h examples/xaxiethernet_example_polled.c examples/xaxiethernet_example_util.c data/axiethernet_header.h} + } else { + return "" + } + } + return $inc_file_lines + } +} + +proc gen_testfunc_def {swproj mhsinst} { + return "" +} + +proc gen_init_code {swproj mhsinst} { + if {$swproj == 0} { + return "" + } + if {$swproj == 1} { + + set ipname [get_property NAME $mhsinst] + set ifintr [::hsi::utils::is_ip_interrupting_current_proc $mhsinst] + + if {$ifintr == 1} { + set dmaType [get_dma_type $mhsinst] + set decl " static XAxiEthernet ${ipname}_AxiEthernet;" + + # FIFO + if {$dmaType == 1} { + set fifo_ipname [get_fifo_info $mhsinst "name"] + + append decl " + static XLlFifo ${fifo_ipname}_AxiFifo; + +" + } + + # DMA + if {$dmaType == 3} { + append decl " + static XAxiDma ${ipname}_AxiDma; + +" + } + + set inc_file_lines $decl + return $inc_file_lines + } + } + + return "" +} + + +proc gen_testfunc_call {swproj mhsinst} { + + if {$swproj == 0} { + return "" + } + + set ipname [get_property NAME $mhsinst] + set deviceid [::hsi::utils::get_ip_param_name $mhsinst "DEVICE_ID"] + set stdout [get_property CONFIG.STDOUT [get_os]] + if { $stdout == "" || $stdout == "none" } { + set hasStdout 0 + } else { + set hasStdout 1 + } + set dma [get_dma_type $mhsinst] + set ifintr [::hsi::utils::is_ip_interrupting_current_proc $mhsinst] + + set fifo_deviceid [get_fifo_info $mhsinst "id"] + set fifo_ipname [get_fifo_info $mhsinst "name"] + + set dma_deviceid [get_dma_info $mhsinst "id"] + set dma_ipname [get_dma_info $mhsinst "name"] + + if {$ifintr == 1} { + set intr_pin_name [get_pins -of_objects [get_cells $ipname] INTERRUPT] + set intcname [::hsi::utils::get_connected_intr_cntrl $ipname $intr_pin_name] + set intcvar intc + set proc [get_property IP_NAME [get_cells [get_sw_processor]]] + } + + + if { $dma == 1 } { + set type "Fifo" + } + if { $dma == 3 } { + set type "SgDma" + } + + set testfunc_call "" + + # BEGIN: FIFO + if { $dma == 1 } { + append testfunc_call " + + { + int Status; +" + + if {${hasStdout} == 1} { + append testfunc_call " + print(\"\\r\\n Running AxiEthernetPolledExample() for ${ipname}...\\r\\n\"); +" + } + + append testfunc_call " + Status = AxiEthernetPolledExample( ${deviceid}, + ${fifo_deviceid} ); +" + + if {${hasStdout} == 1} { + append testfunc_call " + if (Status == 0) { + print(\"AxiEthernetPolledExample PASSED\\r\\n\"); + } + else { + print(\"AxiEthernetPolledExample FAILED\\r\\n\"); + } +" + } + + append testfunc_call " + } +" + } + # END: FIFO + + # BEGIN: DMA + if { $dma == 3 } { + append testfunc_call " + /* AxiEthernetPolledExample does not support AXI DMA */ +" + } + # END: DMA + + # BEGIN: INTERRUPT + if { ${ifintr} == 1 } { + + # AXIETHERNET + if { + $proc == "microblaze" + } then { + set intr_id "XPAR_${intcname}_${ipname}_${intr_pin_name}_INTR" + } else { + set intr_id "XPAR_FABRIC_${ipname}_${intr_pin_name}_INTR" + } + set intr_id [string toupper $intr_id] + + + # BEGIN: FIFO & INTERRUPT + if {$dma == 1} { + # AXIFIFO + if { + $proc == "microblaze" + } then { + set fifo_intr_id "XPAR_${intcname}_${fifo_ipname}_${intr_pin_name}_INTR" + } else { + set fifo_intr_id "XPAR_FABRIC_${fifo_ipname}_${intr_pin_name}_INTR" + } + + set fifo_intr_id [string toupper $fifo_intr_id] + + append testfunc_call " + { + int Status; +" + + if {${hasStdout} == 1} { + append testfunc_call " + print(\"\\r\\nRunning AxiEthernet${type}IntrExample() for ${ipname}...\\r\\n\"); +" + } + + append testfunc_call " + Status = AxiEthernet${type}IntrExample(&${intcvar}, &${ipname}_AxiEthernet, + &${fifo_ipname}_AxiFifo, + ${deviceid}, + ${fifo_deviceid}, + ${intr_id}, + ${fifo_intr_id}); +" + + if {${hasStdout} == 1} { + append testfunc_call " + if(Status == 0) { + print(\"AxiEthernet Interrupt Test PASSED.\\r\\n\"); + } + else { + print(\"AxiEthernet Interrupt Test FAILED.\\r\\n\"); + } +" + } + + append testfunc_call " + } +" + } + # END: FIFO & INTERRUPT + + # BEGIN: DMA & INTERRUPT + if {$dma == 3} { + # DMA + set dmaDriverInst "${ipname}_AxiDma" + set dmaRxIntrId "XPAR_AXIETHERNET_0_CONNECTED_DMARX_INTR" + set dmaTxIntrId "XPAR_AXIETHERNET_0_CONNECTED_DMATX_INTR" + + append testfunc_call " + { + int Status; +" + + if {${hasStdout} == 1} { + append testfunc_call " + print(\"\\r\\nRunning AxiEthernet${type}IntrExample() for ${ipname}...\\r\\n\"); +" + } + + append testfunc_call " + Status = AxiEthernet${type}IntrExample(&${intcvar}, &${ipname}_AxiEthernet, + &${dmaDriverInst}, + ${deviceid}, + ${dma_deviceid}, + ${intr_id}, + ${dmaRxIntrId}, + ${dmaTxIntrId}); +" + + if {${hasStdout} == 1} { + append testfunc_call " + if (Status == 0) { + print(\"AxiEthernet Interrupt Test PASSED.\\r\\n\"); + } + else { + print(\"AxiEthernet Interrupt Test FAILED.\\r\\n\"); + } +" + } + + append testfunc_call " + }" + } + # END: DMA & INTERRUPT + } + # END: INTERRUPT + + return $testfunc_call +} + +proc get_fifo_info {mhsHandle type} { + + set ipinst_list [get_cells $mhsHandle "*"] + + foreach ipinst $ipinst_list { + set coreName [get_property IP_NAME $ipinst] + set instName [get_property NAME $ipinst] + + if {[string compare -nocase $coreName "axi_fifo_mm_s"] == 0} { + + if {[string compare -nocase $type "id"] == 0} { + set deviceid [::hsi::utils::get_ip_param_name $ipinst "DEVICE_ID"] + return $deviceid + } + if {[string compare -nocase $type "name"] == 0} { + return $instName + } + } + } +} + +proc get_dma_info {mhsinst type} { + set ipinst_list [get_cells $mhsinst "*"] + + set p2p_busifs_i [get_intf_pins -of_objects $mhsinst -filter "TYPE==INITIATOR"] + # Add p2p periphs + foreach p2p_busif $p2p_busifs_i { + set busif_name [string toupper [get_property NAME $p2p_busif]] + set conn_busif_handle [::hsi::utils::get_connected_intf $mhsinst $busif_name] + if { [string compare -nocase $conn_busif_handle ""] == 0} { + continue + } else { + # if there is a single match, we know if it is FIFO or DMA + # no need for further iterations + set conn_busif_name [get_property NAME $conn_busif_handle] + set target_periph [get_cells -of_objects $conn_busif_handle] + set target_periph_type [get_property IP_NAME $target_periph] + if { [string compare -nocase $target_periph_type "tri_mode_ethernet_mac"] == 0 } { + continue + } + set target_periph_name [string toupper [get_property NAME $target_periph]] + set instName [get_property NAME $target_periph] + if {[string compare -nocase $target_periph_type "axi_dma"] == 0} { + if {[string compare -nocase $type "id"] == 0} { + set deviceid [::hsi::utils::get_ip_param_name $target_periph "DEVICE_ID"] + return $deviceid + } + if {[string compare -nocase $type "name"] == 0} { + return $instName + } + } + } + } +} + +proc get_dma_type {mhsinst} { + + set dma_deviceid [get_dma_info $mhsinst "id"] + + if { $dma_deviceid != "" } { + set dma 3 + } else { + set dma 1 + } + return $dma +} diff --git a/XilinxProcessorIPLib/drivers/axiethernet/data/dependencies.props b/XilinxProcessorIPLib/drivers/axiethernet/data/dependencies.props new file mode 100644 index 00000000..edba046f --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/data/dependencies.props @@ -0,0 +1,5 @@ +xaxiethernet_example_polled.c=xemacps_example_util.c,xaxiethernet_example_util.c,xaxiethernet_example.h +xaxiethernet_example_intr_sgdma.c=xemacps_example_util.c,xaxiethernet_example_util.c,xaxiethernet_example.h +xaxiethernet_example_intr_fifo.c=xemacps_example_util.c,xaxiethernet_example_util.c,xaxiethernet_example.h +xaxiethernet_example_extmulticast.c=xemacps_example_util.c,xaxiethernet_example_util.c,xaxiethernet_example.h +xaxiethernet_example_extvlan.c=xemacps_example_util.c,xaxiethernet_example_util.c,xaxiethernet_example.h \ No newline at end of file diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb.c b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb.c new file mode 100644 index 00000000..f436ff17 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb.c @@ -0,0 +1,742 @@ +/****************************************************************************** +* +* Copyright (C) 2008 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xavb.c +* +* The top level c file for the AVB driver. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -----------------------------------------------
+* 1.00a mbr  09/19/08 First release
+* 1.01a mbr  06/24/09 PTP frame format updates for IEEE802.1 AS draft 5-0
+* 2_02a mbr  09/16/09 Updates for programmable PTP timers
+* 2_04a kag  07/23/10 PTP frame format updates for IEEE802.1 AS draft 6-7
+* 3_01a kag  08/29/11 Added new APIs to update the RX Filter Control Reg.
+*		      Fix for CR:572539. Updated bit map for Rx Filter
+*		      control reg.
+*
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xil_types.h" +#include "xil_io.h" +#include "xil_assert.h" +#include "xenv.h" +#include "xavb_hw.h" +#include "xavb.h" +#include "xparameters.h" +#include "stdio.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Variable Definitions *****************************/ + +extern XAvb_Config XAvb_ConfigTable[]; +extern volatile u8 EchoPTPFramesReceived; + +/************************** Function Prototypes ******************************/ +static void XAvb_StubHandler(void *CallBackRef, u32 TimestampsUncertain); + +/*****************************************************************************/ + +/* + * Mandatory Device Driver Functions + */ + +/****************************************************************************/ +/** +* +* A function to initialise variables in the data structure records +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* @param ConfigPtr is the Configuration Pointer +* @param EffectiveAddress is the base address of the Configuration Pointer +* +* @return +* - XST_SUCCESS if initialization was successful +* - XST_DEVICE_NOT_FOUND if device configuration information was not found +* for a device with the supplied device ID.* +* @note None. +* +*****************************************************************************/ +XStatus XAvb_CfgInitialize(XAvb *InstancePtr, + XAvb_Config *ConfigPtr, + u32 EffectiveAddress) { + + Xil_AssertNonvoid(InstancePtr != NULL); + + /** The component is not yet ready to use */ + InstancePtr->IsReady = 0; + + /** Clear instance memory */ + memset(InstancePtr, 0, sizeof(XAvb)); + memcpy(&InstancePtr->Config, ConfigPtr, sizeof(XAvb_Config)); + + /** + * Lookup the device configuration in the temporary CROM table. Use this + * configuration info down below when initializing this component. + */ + if (ConfigPtr == NULL) { + return XST_DEVICE_NOT_FOUND; + } + + /** + * Populate Base Address field using the base address value in the + * configuration structure. + */ + InstancePtr->Config.BaseAddress = EffectiveAddress; + + /** + * Indicate the component is now ready to use. + */ + InstancePtr->IsReady = XIL_COMPONENT_IS_READY; + + /** + * Set the callback handler to a stub + */ + InstancePtr->GMDiscHandler = XAvb_StubHandler; + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function resets all of the AVB device driver functions to the start-up +* (reset) defaults. +* +* @param InstancePtr is a pointer to the Xavb instance to be worked on. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XAvb_Reset(XAvb * InstancePtr) +{ + /** Assert bad arguments and conditions */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /** + * Perform a Software Reset of the AVB Core. + * This will reset both the transmitter and receiver paths. + * The RTC counter is not reset here. + */ + XAvb_WriteReg(InstancePtr->Config.BaseAddress, + XAVB_SW_RESET_OFFSET, + XAVB_SW_RESET_TX_AND_RX_PATHS); + + /** + * Set IEEE specification default values in the device's data structure + */ + xil_printf("\r\n*** XAvb_Reset() : Call XAvb_BecomeRtcMaster() *** \r\n"); + XAvb_BecomeRtcMaster(InstancePtr,0); + XAvb_ChangePeerASCapability(InstancePtr, 0); + + InstancePtr->PtpIsRunning = 0; + InstancePtr->PtpRecords.LinkDelay = 0; + InstancePtr->SignallingFrameData.SyncIntervalDuration = + XAvb_ConvertLogMeanToDuration(XAVB_DEFAULT_LOG_MEAN_SYNC_INTERVAL); + InstancePtr->SignallingFrameData.LinkDelayIntervalDuration = + XAvb_ConvertLogMeanToDuration(XAVB_DEFAULT_LOG_MEAN_PDELAY_REQ_INTERVAL); + InstancePtr->SignallingFrameData.AnnounceIntervalDuration = + XAvb_ConvertLogMeanToDuration(XAVB_DEFAULT_LOG_MEAN_ANNOUNCE_INTERVAL); + + InstancePtr->latestMDSyncReceive.SyncIntervalDuration = + XAvb_ConvertLogMeanToDuration(XAVB_DEFAULT_LOG_MEAN_SYNC_INTERVAL); + + /** Update logMeanMessageInterval in the pre-loaded TX SYNC message buffer */ + XAvb_UpdateLogMeanMessageInterval(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_SYNC_OFFSET, + InstancePtr->SignallingFrameData.SyncIntervalDuration); + /** Update logMeanMessageInterval in the pre-loaded TX FOLLOW_UP message buffer */ + XAvb_UpdateLogMeanMessageInterval(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_FOLLOW_UP_OFFSET, + InstancePtr->SignallingFrameData.SyncIntervalDuration); + + /** Update logMeanMessageInterval in the pre-loaded TX PDELAYREQ message buffer */ + XAvb_UpdateLogMeanMessageInterval(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYREQ_OFFSET, + InstancePtr->SignallingFrameData.LinkDelayIntervalDuration); + + /** Update logMeanMessageInterval in the pre-loaded TX ANNOUNCE message buffer */ + XAvb_UpdateLogMeanMessageInterval(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_ANNOUNCE_OFFSET, + InstancePtr->SignallingFrameData.AnnounceIntervalDuration); + + /** + * Initialise other driver variables in the device's data structure + */ + InstancePtr->PtpCounters.RxPtpHardPointer = 0; + InstancePtr->PtpCounters.RxPtpSoftPointer = 0xFF; + InstancePtr->PtpCounters.CounterSyncInterval = 0; + InstancePtr->PtpCounters.CounterLinkDelayInterval = 0; + InstancePtr->PtpCounters.CounterAnnounceInterval = 0; + InstancePtr->PtpCounters.CounterSyncEvents = 0; + InstancePtr->StateMachineData.lostResponses = 0; + InstancePtr->StateMachineData.rcvdPDelayResp = 0; + InstancePtr->StateMachineData.rcvdPDelayRespFollowUp = 0; +#ifdef DEBUG_XAVB_LEVEL1 + xil_printf("\r\n** XAvb_Reset(): PTP Driver Reset **"); +#endif +} + + +/* + * Device Specific Driver Functions + */ + + +/*****************************************************************************/ +/** +* +* This function will start the PTP drivers running. +* +* @param InstancePtr is a pointer to the Xavb instance to be worked on. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XAvb_Start(XAvb * InstancePtr) +{ + /** Assert bad arguments and conditions */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /** Re-run the BMCA algorithm with the current PTP buffer Announce Packet */ + XAvb_DecodeTxAnnounceFrame(InstancePtr); + + /** Set to PTP running in the PTP data structure */ + InstancePtr->PtpIsRunning = 1; + + /** Assume that the Peer is not AS capable until it replies to a pDelay_Req + * frame */ + XAvb_ChangePeerASCapability(InstancePtr, 0); + +#ifdef DEBUG_XAVB_LEVEL1 + xil_printf("\r\n** XAvb_Start(): Starting PTP **"); +#endif +} + + +/*****************************************************************************/ +/** +* +* This function will stop the PTP drivers from running. +* +* @param InstancePtr is a pointer to the Xavb instance to be worked on. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XAvb_Stop(XAvb * InstancePtr) +{ + /** Assert bad arguments and conditions */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + +#ifdef DEBUG_XAVB_LEVEL1 + xil_printf("\r\n** XAvb_Stop(): PTP STOPPED **"); +#endif + XAvb_Reset(InstancePtr); +} + + +/****************************************************************************/ +/** +* +* The Interrupt subroutine for the "interruptPtpTimer" signal. This interrupt +* fires reguarly on a 1/128 second period (based on the RTC). +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_PtpTimerInterruptHandler(XAvb * InstancePtr) { + + /** Clear Interrupt */ + XAvb_WriteReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_CLEAR_INT_OFFSET, + XAVB_RTC_CLEAR_INT_MASK); + + /** If PTP functions are marked as not running, then take no further action */ + if (InstancePtr->PtpIsRunning == 1) { + + /** If the Link Partner is not AS capable, then take no further action */ + if (InstancePtr->PeerASCapable == 1) { + + + /** If a Master, then initiate Sync Frames and Announce frames at the + * correct intervals + */ + if (InstancePtr->CurrentBmc.IAmTheRtcMaster == 1) { + + /** Master will initiate a Sync Frame when the SyncIntervalDuration + * expires (SyncIntervalDuration is used to count/time the duration) + * - unless a Signalling frame has told us not to send Sync Frames + */ + if ((InstancePtr->SignallingFrameData.SyncIntervalDuration != XAVB_PKT_TYPE_DISABLED) && + (InstancePtr->PtpCounters.CounterSyncInterval >= + (InstancePtr->SignallingFrameData.SyncIntervalDuration-1))) { + + XAvb_MasterSendSync(InstancePtr); + InstancePtr->PtpCounters.CounterSyncInterval = 0; + + /** Following a Sync Frame, a Follow Up frame should always be sent + */ + XAvb_MasterSendFollowUp(InstancePtr); + + + } else { + InstancePtr->PtpCounters.CounterSyncInterval + = InstancePtr->PtpCounters.CounterSyncInterval + 1; + } + + /** Master will initiate an Announce Frame when the + * AnnounceIntervalDuration expires (CounterAnnounceInterval is used + * to count/time the duration) + * - unless a Signalling frame has told us not to send Announce Frames + */ + if ((InstancePtr->SignallingFrameData.AnnounceIntervalDuration != XAVB_PKT_TYPE_DISABLED) && + (InstancePtr->PtpCounters.CounterAnnounceInterval >= + (InstancePtr->SignallingFrameData.AnnounceIntervalDuration-1))) { + + XAvb_MasterSendAnnounce(InstancePtr); + InstancePtr->PtpCounters.CounterAnnounceInterval = 0; + + } else { + InstancePtr->PtpCounters.CounterAnnounceInterval + = InstancePtr->PtpCounters.CounterAnnounceInterval + 1; + } + + /** If a Slave, monitor Announce/Sync Packet reception from the Master */ + } else { + + /** Timeout for Announce Packet reception: XAVB_ANNOUNCE_RECEIPT_TIMEOUT + * The AnnounceIntervalDuration is stored with the GrandMaster BMCA data + * as it is captured from the last Announce frame that was received. + */ + if (InstancePtr->PtpCounters.CounterAnnounceInterval >= + ((InstancePtr->CurrentBmc.AnnounceIntervalDuration-1) * + XAVB_ANNOUNCE_RECEIPT_TIMEOUT) ) { + +#ifdef XAVB_DEBUG_LEVEL1 + xil_printf("XAVB_ANNOUNCE_RECEIPT_TIMEOUT: Becoming GM! CounterAnnounceInterval = %d\r\n", InstancePtr->PtpCounters.CounterAnnounceInterval); +#endif + + InstancePtr->PtpCounters.CounterAnnounceInterval = 0; + + /** No Announce received from GM for timeout interval: we become the master */ + xil_printf("\r\n*** Announce timeout : Call XAvb_BecomeRtcMaster() *** \r\n"); + XAvb_BecomeRtcMaster(InstancePtr,0); + + } else { + InstancePtr->PtpCounters.CounterAnnounceInterval + = InstancePtr->PtpCounters.CounterAnnounceInterval + 1; + } + + /** Timeout for Sync Packet reception: XAVB_SYNC_RECEIPT_TIMEOUT * + * The SyncIntervalDuration is stored with the Received Sync data + * as it is captured from the last Sync frame that was received. + */ + if( InstancePtr->PtpCounters.CounterSyncInterval >= + ((InstancePtr->latestMDSyncReceive.SyncIntervalDuration-1) * + XAVB_SYNC_RECEIPT_TIMEOUT) ) { + +#ifdef XAVB_DEBUG_LEVEL1 + xil_printf("\r\nXAVB_SYNC_RECEIPT_TIMEOUT: Becoming GM! CounterSyncInterval = %d\r\n", InstancePtr->PtpCounters.CounterSyncInterval); + xil_printf("\r\nXAVB_SYNC_RECEIPT_TIMEOUT: SyncIntervalDuration = %d\r\n", InstancePtr->SignallingFrameData.SyncIntervalDuration); +#endif + + InstancePtr->PtpCounters.CounterSyncInterval = 0; + + + /** No Syncs received from GM for timeout interval: we become + * the master */ + xil_printf("\r\n*** Sync Timeout : Call XAvb_BecomeRtcMaster() *** \r\n"); + XAvb_BecomeRtcMaster(InstancePtr,0); + + } else { + InstancePtr->PtpCounters.CounterSyncInterval + = InstancePtr->PtpCounters.CounterSyncInterval + 1; + } + } + } + + /** Both Master and Slave will initiate a link delay measurement when the + * LinkDelayIntervalDuration expires (LinkDelayIntervalDuration is used to + * count/time the duration) + * - unless a Signalling frame has told us not to send PdelayReq Frames + */ + if ((InstancePtr->SignallingFrameData.LinkDelayIntervalDuration != XAVB_PKT_TYPE_DISABLED) && + (InstancePtr->PtpCounters.CounterLinkDelayInterval >= + (InstancePtr->SignallingFrameData.LinkDelayIntervalDuration-1))) { + + /** Check to see if we've received PDelayResp and + * PDelayRespFollowUp messages since the last PDelayReq was + * sent */ + if( InstancePtr->StateMachineData.rcvdPDelayResp && + InstancePtr->StateMachineData.rcvdPDelayRespFollowUp ) { + + InstancePtr->StateMachineData.lostResponses = 0; + } else { + InstancePtr->StateMachineData.lostResponses++; + } + + if( InstancePtr->StateMachineData.lostResponses >= XAVB_ALLOWED_LOST_RESPONSES ) { + /** the peer is no longer ASCapable */ + XAvb_ChangePeerASCapability(InstancePtr, 0); + + xil_printf("\r\n** XAvb_PtpTimerInterruptHandler(): The peer is no longer ASCapable **"); + xil_printf("\r\n** XAvb_PtpTimerInterruptHandler(): StateMachineData.lostResponses >= %d **", + XAVB_ALLOWED_LOST_RESPONSES); + + /** avoid potential overflow */ + InstancePtr->StateMachineData.lostResponses = XAVB_ALLOWED_LOST_RESPONSES; + } + + XAvb_SendPDelayReq(InstancePtr); + + InstancePtr->StateMachineData.rcvdPDelayResp = 0; + InstancePtr->StateMachineData.rcvdPDelayRespFollowUp = 0; + InstancePtr->PtpCounters.CounterLinkDelayInterval = 0; + + } else { + InstancePtr->PtpCounters.CounterLinkDelayInterval + = InstancePtr->PtpCounters.CounterLinkDelayInterval + 1; + } + + } /** end of 'if (InstancePtr->PtpIsRunning == 1)' */ + +} + + +/****************************************************************************/ +/** +* +* The Interrupt subroutine for the "interrupt_ptp_rx" signal. This interrupt +* fires whenever a PTP frame has been received. The main function is to +* identify, decode, and act on the type of PTP frame received. +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_PtpRxInterruptHandler(XAvb * InstancePtr) { +#ifdef DEBUG_XAVB_LEVEL1 + u32 x = 0; +#endif + u32 MessageType = 0; + u32 PtpFrameBaseAddr = 0; + + /** RxPtpHardPointer indicates the bin location of the last frame to be + * received and written into the Rx PTP buffer in hardware. This read will + * also clear the interrupt.*/ + InstancePtr->PtpCounters.RxPtpHardPointer + = (XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_PTP_RX_CONTROL_OFFSET) + & XAVB_PTP_RX_PACKET_FIELD_MASK) >> 8; + + /** If PTP functions are marked as not running, then take no further action */ + if (InstancePtr->PtpIsRunning == 1) { + + + /** RxPtpSoftPointer indicates the bin location of the last frame to be + * processed in software. */ + while ( (InstancePtr->PtpCounters.RxPtpSoftPointer & 0xF) + != (InstancePtr->PtpCounters.RxPtpHardPointer & 0xF) ) { + + /** decode the rx'd frames until RxPtpHardPointer = RxPtpSoftPointer */ + InstancePtr->PtpCounters.RxPtpSoftPointer + = InstancePtr->PtpCounters.RxPtpSoftPointer + 1; + + /** Set the base address of the current PTP frame in the Buffer */ + PtpFrameBaseAddr = XAVB_PTP_RX_BASE_OFFSET + + ((InstancePtr->PtpCounters.RxPtpSoftPointer & 0xF) + << 8); + + + /** Perform very basic sanity checking of the frame : is it a PTP? */ + if (XAvb_IsRxFramePTP(InstancePtr, PtpFrameBaseAddr) == 1) { + + + /** Determine which PTP frame was received. */ + MessageType = (XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_TYPE_OFFSET) + & 0x000F0000 ) >> 16; + + + /** Now act on the received frame */ + switch (MessageType) { + + /** Sync Frame + * ---------- */ + case XAVB_PTP_TYPE_SYNC: + XAvb_DecodeRxSync(InstancePtr, PtpFrameBaseAddr); + break; + + /** Follow Up Frame + * --------------- */ + case XAVB_PTP_TYPE_FOLLOW_UP: + XAvb_DecodeRxFollowUp(InstancePtr, PtpFrameBaseAddr); + break; + + /** PDelayReq Frame + * --------------- */ + case XAVB_PTP_TYPE_PDELAYREQ: + /** Send a send PDelayResp frame after receiving a PDelayReq Frame */ + XAvb_SendPDelayResp(InstancePtr, PtpFrameBaseAddr); + + /** Send a send PDelayRespFollowUp frame after a PDelayResp Frame */ + XAvb_SendPDelayRespFollowUp(InstancePtr); + + break; + + /** PDelayResp Frame + * ---------------- */ + case XAVB_PTP_TYPE_PDELAYRESP: + XAvb_DecodeRxPDelayResp(InstancePtr, PtpFrameBaseAddr); + break; + + /** PDelayRespFollowUp Frame + * ------------------------ */ + case XAVB_PTP_TYPE_PDELAYRESP_FOLLOW_UP: + EchoPTPFramesReceived = 1; + XAvb_DecodeRxPDelayRespFollowUp(InstancePtr, PtpFrameBaseAddr); + break; + + /** Announce Frame + * -------------- */ + case XAVB_PTP_TYPE_ANNOUNCE: + XAvb_DecodeRxAnnounceFrame(InstancePtr, + PtpFrameBaseAddr); + break; + + /** Signaling Frame + * -------------- */ + case XAVB_PTP_TYPE_SIGNALING: + XAvb_DecodeRxSignaling(InstancePtr, PtpFrameBaseAddr); + break; + + /** Unknown Frame + * -------------- */ + default: +#ifdef DEBUG_XAVB_LEVEL1 + xil_printf("\r\nXAvb_PtpRxInterruptHandler()"); + xil_printf("\r\n** Unknown PTP Frame Rx'd **"); + xil_printf("\r\nMessage Type is %x", MessageType); + xil_printf("\r\n-------Unknown Frame -------"); + for (x = 0; x < 0x100; x = x + 4) { + xil_printf("\r\n %x %x", x, + (XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + x))); + } +#endif + break; + } + } + } + + } else { /* InstancePtr->PtpIsRunning != 1 */ + + /** PTP is not running so just consume the packets so they are not left in the + * queue and cause problems when we actually start */ + + /** RxPtpSoftPointer indicates the bin location of the last frame to be + * processed in software. */ + while ( (InstancePtr->PtpCounters.RxPtpSoftPointer & 0xF) + != (InstancePtr->PtpCounters.RxPtpHardPointer & 0xF) ) { + + /** decode the rx'd frames until RxPtpHardPointer = RxPtpSoftPointer */ + InstancePtr->PtpCounters.RxPtpSoftPointer + = InstancePtr->PtpCounters.RxPtpSoftPointer + 1; + } + } + +} + +/**************************************************************************** +* +* This function provides a stub handler such that if the application does not +* define a handler this function will be called. +* +* @param CallBackRef has no purpose but is necessary to match the +* interface for a handler. +* @param TimestampsUncertain has no purpose but is necessary to match the +* interface for a handler. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +static void XAvb_StubHandler(void *CallBackRef, u32 TimestampsUncertain) +{ + /* + * Assert occurs always since this is a stub and should never be called + */ + Xil_AssertVoidAlways(); +} + +/****************************************************************************/ +/** +* +* A function to set the VLAN PCP field for either SR A or B traffic in the +* RX Filtering Control Register - such that AV traffic is correctly filtered +* by the RX Splitter. +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @param VlanPriority contains the 3-bit value to be written to the register +* in the correct bit positions as defined in the address map +* +* @param SrClass is '0' if VLAN Priority (PCP) A is to be updated and is +* '1' if VLAN Priority (PCP) B is to be updated +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_SetupRxFilterControlPcp(XAvb * InstancePtr, + u32 VlanPriority, + u8 SrClass) { + u32 LocalData = 0; + + LocalData = XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RX_FILTER_CONTROL); + + if (SrClass == 0x0) { + LocalData = LocalData | (VlanPriority & XAVB_RX_AV_VLAN_PRIORITY_A_MASK); + } else { + LocalData = LocalData | (VlanPriority & XAVB_RX_AV_VLAN_PRIORITY_B_MASK); + } + + XAvb_WriteReg(InstancePtr->Config.BaseAddress, + XAVB_RX_FILTER_CONTROL, + LocalData); +} + +/****************************************************************************/ +/** +* +* A function to set the VLAN VID field for either SR A or B traffic in the +* RX Filtering Control Register - such that AV traffic is correctly filtered +* by the RX Splitter. +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @param VlanVid contains the 12-bit value to be written to the register +* in the correct bit positions as defined in the address map +* +* @param SrClass is '0' if VLAN VID A is to be updated and is +* '1' if VLAN VID B is to be updated +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_SetupRxFilterControlVid(XAvb * InstancePtr, + u32 VlanVid, + u8 SrClass) { + u32 LocalData = 0; + + LocalData = XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RX_FILTER_CONTROL); + + if (SrClass == 0x0) { + LocalData = LocalData | (VlanVid & XAVB_RX_AV_VLAN_VID_A_MASK); + } else { + LocalData = LocalData | (VlanVid & XAVB_RX_AV_VLAN_VID_B_MASK); + } + + XAvb_WriteReg(InstancePtr->Config.BaseAddress, + XAVB_RX_FILTER_CONTROL, + LocalData); +} + + +/****************************************************************************/ +/** +* +* A function to set the VLAN Match Mode field for the RX Filtering Control +* Register - such that AV traffic is correctly filtered by the RX Splitter. +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @param VlanMatchMode contains the 1-bit value to be written to the register +* in the correct bit position as defined in the address map +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_SetupRxFilterControlMatchMode(XAvb * InstancePtr, + u32 VlanMatchMode) { + u32 LocalData = 0; + + LocalData = XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RX_FILTER_CONTROL); + + LocalData = LocalData | (VlanMatchMode & XAVB_RX_AV_VLAN_MATCH_MODE_MASK); + + XAvb_WriteReg(InstancePtr->Config.BaseAddress, + XAVB_RX_FILTER_CONTROL, + LocalData); +} diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb.h b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb.h new file mode 100644 index 00000000..249c5453 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb.h @@ -0,0 +1,668 @@ +/****************************************************************************** +* +* Copyright (C) 2008 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xavb.h +* +* This header file contains the identifiers and basic driver functions (or +* macros) that can be used to access the device. Other driver functions +* are defined in xavb.h. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -----------------------------------------------
+* 1.00a mbr  09/19/08 First release
+* 1.01a mbr  06/24/09 PTP frame format updates for IEEE802.1 AS draft 5-0
+* 2_02a mbr  09/16/09 Updates for programmable PTP timers
+* 2_04a kag  07/23/10 PTP frame format updates for IEEE802.1 AS draft 6-7
+* 3_01a kag  08/29/11 Added new APIs to update the RX Filter Control Reg.
+*		      Fix for CR:572539. Updated bit map for Rx Filter
+*		      control reg.
+* 4_0	asa  03/06/14 Fix for CR 740863. The value of XAVB_CLOCK_LOCK_THRESHOLD
+*					  is increased to 1000ns (1 us) to make it more
+*					  meningful and reasonable.
+*
+* 
+* +******************************************************************************/ + +#ifndef XAVB_H /* prevent circular inclusions */ +#define XAVB_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/***************************** Include Files *********************************/ + +#include "xavb_hw.h" +#include "xstatus.h" +#include "stdio.h" + +/************************** Constant Definitions *****************************/ + +/** @name Define the Debug Level Verbosity for print messages for this driver + * @{ + */ +#undef DEBUG_XAVB_LEVEL1 /* Basic messages and PTP frame reception messages */ +#undef DEBUG_XAVB_LEVEL2 /* PTP Calculation messages */ +#undef DEBUG_XAVB_LEVEL3 /* PTP frame transmission messages */ + +/** @name MAC Latency Definitions + * @{ + */ +#define XAVB_TX_MAC_LATENCY_IN_NS 80 +#define XAVB_RX_MAC_LATENCY_IN_NS 80 +/* @} */ + + +/** @name PTP Buffer Storage Definitions + * @{ + */ +#define XAVB_PTP_TX_SYNC 0x0 +#define XAVB_PTP_TX_FOLLOW_UP 0x1 +#define XAVB_PTP_TX_PDELAYREQ 0x2 +#define XAVB_PTP_TX_PDELAYRESP 0x3 +#define XAVB_PTP_TX_PDELAYRESP_FOLLOW_UP 0x4 +#define XAVB_PTP_TX_ANNOUNCE 0x5 +#define XAVB_PTP_TX_SIGNALING 0x6 +/* @} */ + + +/** @name PTP Packet Message Type Definitions + * @{ + */ +#define XAVB_PTP_TYPE_SYNC 0x0 +#define XAVB_PTP_TYPE_FOLLOW_UP 0x8 +#define XAVB_PTP_TYPE_PDELAYREQ 0x2 +#define XAVB_PTP_TYPE_PDELAYRESP 0x3 +#define XAVB_PTP_TYPE_PDELAYRESP_FOLLOW_UP 0xA +#define XAVB_PTP_TYPE_ANNOUNCE 0xB +#define XAVB_PTP_TYPE_SIGNALING 0xC +/* @} */ + + +/** @name Common PTP Frame Structure Definitions. + * @{ + */ +#define XAVB_PTP_PKT_CAPTURED_TIMESTAMP_OFFSET 0x000000FC +/* @} */ + + +/** @name General Tx PTP Frame Structure Definitions. + * @{ + */ +#define XAVB_PTP_TX_PKT_SA_UPPER_OFFSET 0x0000000C +#define XAVB_PTP_TX_PKT_SA_LOWER_OFFSET 0x00000010 +#define XAVB_PTP_TX_PKT_TYPE_OFFSET 0x00000014 +#define XAVB_PTP_TX_PKT_CORRECTION_FIELD_OFFSET 0x00000020 +#define XAVB_PTP_TX_PKT_PORTID_UPPER_OFFSET 0x00000028 +#define XAVB_PTP_TX_PKT_PORTID_MID_OFFSET 0x0000002C +#define XAVB_PTP_TX_PKT_PORTID_LOWER_OFFSET 0x00000030 +#define XAVB_PTP_TX_PKT_SEQUENCEID_OFFSET 0x00000034 +#define XAVB_PTP_TX_PKT_TIMESTAMP_UPPER_OFFSET 0x00000038 +#define XAVB_PTP_TX_PKT_TIMESTAMP_MID_OFFSET 0x0000003C +#define XAVB_PTP_TX_PKT_TIMESTAMP_LOWER_OFFSET 0x00000040 /* upper 2 bytes */ +#define XAVB_PTP_TX_PKT_REQ_PORTID_UPPER_OFFSET 0x00000040 /* lower 2 bytes */ +#define XAVB_PTP_TX_PKT_REQ_PORTID_MID_OFFSET 0x00000044 +#define XAVB_PTP_TX_PKT_REQ_PORTID_LOWER_OFFSET 0x00000048 +/* @} */ + +/** @name Tx Announce PTP Frame Structure Definitions. + * @{ + */ +#define XAVB_PTP_TX_PKT_ANNOUNCE_CURR_UTCOFF_OFFSET 0x00000040 +#define XAVB_PTP_TX_PKT_ANNOUNCE_QUAL_LOW_PRI2_GMID_HI_OFFSET 0x00000048 +#define XAVB_PTP_TX_PKT_ANNOUNCE_GMID_MID_OFFSET 0x0000004C +#define XAVB_PTP_TX_PKT_ANNOUNCE_GMID_LOW_STEPSREMOVED_HI_OFFSET 0x00000050 +#define XAVB_PTP_TX_PKT_ANNOUNCE_STEPSREMOVED_LOW_TIMESRC_OFFSET 0x00000054 +#define XAVB_PTP_TX_PKT_ANNOUNCE_TLVLEN_PATHSEQ_START_OFFSET 0x00000058 +/* @} */ + +/** @name PTP frame constant definitions + * @{ + * + * Constant value for the control field and LogMeanMessageInterval field for + * pDelayResp and pDelayRespFollowUp PTP frames (defined in IEEE802.1 AS) + */ +#define XAVB_PDELAY_LOG_MEAN_MESSAGE_INT 0x7F050000 +/* @} */ + + +/** @name Default LogMeanInterval values +* @{ +*/ +#define XAVB_DEFAULT_LOG_MEAN_SYNC_INTERVAL (-3) /** 2^(-3) = 125ms */ +#define XAVB_DEFAULT_LOG_MEAN_PDELAY_REQ_INTERVAL 0 /** 128/128 = 2^(0) = 1 s */ +#define XAVB_DEFAULT_LOG_MEAN_ANNOUNCE_INTERVAL 0 /** 128/128 = 2^(0) = 1 s */ +#define XAVB_PKT_TYPE_DISABLED 0xffff + +#define XAVB_MAX_SUPPORTED_LOG_MEAN_INTERVAL 8 /** 32768/128 = 256 s */ +#define XAVB_MIN_SUPPORTED_LOG_MEAN_INTERVAL (-7) /** 1/128 s */ +/* @} */ + +/** @name Announce / Sync Timeout values +* @{ +*/ +/** XAVB_ANNOUNCE_RECEIPT_TIMEOUT is the number of announce + * intervals without the receipt of an Announce message from + * the GM that are allowed before the GM is assumed to be no + * longer present and BMCA should be run again + */ +#define XAVB_ANNOUNCE_RECEIPT_TIMEOUT 2 + +/** XAVB_SYNC_RECEIPT_TIMEOUT is the number of sync intervals + * without the receipt of an Sync message from the GM that are + * allowed before the GM is assumed to be no longer present and + * BMCA should be run again + */ +#define XAVB_SYNC_RECEIPT_TIMEOUT 3 +/* @} */ + + +/** @name AS Network Requirements +* @{ +*/ +/** XAVB_NEIGHBOR_PROP_DELAY_THRESH is the maximum allowed delay (in nanosecs) + * across a full duplex link for which the AVB protocol is allowed to function. + * Although this parameter is defined in the IEEE spec, no default is defined. + */ +#define XAVB_NEIGHBOR_PROP_DELAY_THRESH 5000 + +/** XAVB_ALLOWED_LOST_RESPONSES is the number of Pdelay_Req + * messages for which a valid response is not received, above + * which the Peer should no longer be considered ASCapable + */ +#define XAVB_ALLOWED_LOST_RESPONSES 3 + +/* @} */ + + +/** @name General Rx PTP Frame Structure Definitions. + * @{ + */ +#define XAVB_PTP_RX_PKT_SA_UPPER_OFFSET 0x00000004 +#define XAVB_PTP_RX_PKT_SA_LOWER_OFFSET 0x00000008 +#define XAVB_PTP_RX_PKT_TYPE_OFFSET 0x0000000C +#define XAVB_PTP_RX_PKT_CORRECTION_FIELD_OFFSET 0x00000018 +#define XAVB_PTP_RX_PKT_PORTID_UPPER_OFFSET 0x00000020 +#define XAVB_PTP_RX_PKT_PORTID_MID_OFFSET 0x00000024 +#define XAVB_PTP_RX_PKT_PORTID_LOWER_OFFSET 0x00000028 +#define XAVB_PTP_RX_PKT_SEQUENCEID_OFFSET 0x0000002C +#define XAVB_PTP_RX_PKT_TIMESTAMP_UPPER_OFFSET 0x00000030 +#define XAVB_PTP_RX_PKT_TIMESTAMP_MID_OFFSET 0x00000034 +#define XAVB_PTP_RX_PKT_TIMESTAMP_LOWER_OFFSET 0x00000038 /* upper 2 bytes */ +#define XAVB_PTP_RX_PKT_REQ_PORTID_UPPER_OFFSET 0x00000038 /* lower 2 bytes */ +#define XAVB_PTP_RX_PKT_REQ_PORTID_MID_OFFSET 0x0000003C +#define XAVB_PTP_RX_PKT_REQ_PORTID_LOWER_OFFSET 0x00000040 +/* @} */ + + +/** @name Rx Announce PTP Frame Structure Definitions. + * @{ + */ +#define XAVB_PTP_RX_PKT_ANNOUNCE_PRI1_QUAL_HI_OFFSET 0x0000003C +#define XAVB_PTP_RX_PKT_ANNOUNCE_QUAL_LOW_PRI2_GMID_HI_OFFSET 0x00000040 +#define XAVB_PTP_RX_PKT_ANNOUNCE_GMID_MID_OFFSET 0x00000044 +#define XAVB_PTP_RX_PKT_ANNOUNCE_GMID_LOW_STEPSREMOVED_HI_OFFSET 0x00000048 +#define XAVB_PTP_RX_PKT_ANNOUNCE_STEPSREMOVED_LOW_TIMESRC_OFFSET 0x0000004C +/* @} */ + + +/** @name Rx Signalling PTP Frame Structure Definitions. + * @{ + */ +#define XAVB_PTP_RX_PKT_SIGNALING_DELAY_INTERVAL_OFFSET 0x00000044 +/* @} */ + +/** @name Standard PTP Frame Field Definitions (from IEEE802.1AS specification). + * @{ + */ +#define XAVB_PTP_ETHERTYPE 0x88F7 +#define XAVB_PTP_VERSION_PTP 2 +/* @} */ + + +/** @name Real Time Clock Definitions. + * @{ + */ +#define XAVB_ONE_SECOND 1000000000 /**< Value in ns */ +#define XAVB_PERIOD_8KHZ 125000 /**< Value in ns */ +/* @} */ + +/** @name Real Time Clock Locked Definitions. + * @{ + * If the Slave error is > this threshold then define PTP to be + * unlocked and link not asCapable. + * @note: This threshold is not specified in IEEE 802.1as. + */ +#define XAVB_CLOCK_LOCK_THRESHOLD 1000 /**< Value in ns */ +/* @} */ + +/** @name RTC Increment Value Update Definitions + * @{ + * Define how often to re-calculate the RTC Increment This value + * indicates how many good Sync/FollowUp message pairs + * are received before the re-calculation is performed. + */ +#define XAVB_NUM_SYNC_FU_PAIR_CALC_RTC_INCREMENT 2 +/* @} */ + +/**************************** Type Definitions *******************************/ + +/** + * Callback function. The first argument is a callback reference passed in by + * the upper layer when setting the callback functions, and passed back to the + * upper layer when the callback is invoked. + * The second argument is a '1' if a Grandmaster Discontinuity event has occurred + * otherwise it is '0'. + */ +typedef void (*XAvb_Handler)(void *CallBackRef, u32 TimestampsUncertain); + +/** + * This typedef contains configuration information for a device. + */ +typedef struct { + u16 DeviceId; /**< Unique ID of device */ + u32 BaseAddress; /**< Register base address */ +} XAvb_Config; + + +/** + * This typedef defines the format for a data structure which stores the Port + * Identity information from received Announce packets + */ +typedef struct +{ + u32 ClockIdentityUpper; /**< Upper 4 bytes of ClockIdentity */ + u32 ClockIdentityLower; /**< Lower 4 bytes of ClockIdentity*/ + u16 PortNumber; /**< PortNumber associated with ClockIdentity*/ +} XAvb_PortIdentity; + +/** + * This typedef defines the format for a data structure which stores the Clock + * Identity information from received Announce packets + */ +typedef struct +{ + u32 ClockIdentityUpper; /**< Upper 4 bytes of ClockIdentity */ + u32 ClockIdentityLower; /**< Lower 4 bytes of ClockIdentity*/ +} XAvb_ClockIdentity; + +/** + * This typedef defines the quality of a clock + */ +typedef struct +{ + u8 clockClass; /**< Announce message: clockClass */ + u8 clockAccuracy; /**< Announce message: clockAccuracy */ + u16 offsetScaledLogVariance; /**< Announce message: offsetScaledLogVariance*/ +} XAvb_ClockQuality; + +/** + * This typedef defines the format for a data structure which stores the relevant + * fields which are captured from Announce Packets. + */ +typedef struct +{ + XAvb_PortIdentity SourcePortIdentity; /**< Announce message: sourcePortIdentity */ + XAvb_ClockIdentity GrandmasterIdentity; /**< Announce message: grandmasterIdentity */ + u16 stepsRemoved; /**< Announce message: stepsRemoved */ + XAvb_ClockQuality ClockQuality; /**< Announce message: grandmasterClockQuality */ + u8 GrandmasterPriority1; /**< Announce message: grandmasterPriority1*/ + u8 GrandmasterPriority2; /**< Announce message: grandmasterPriority2*/ + u8 IAmTheRtcMaster; /**< Boolean: 1 = grandmaster, 0 = slave*/ + u16 tlvLengthField; /**< Announce message: lengthField (for TLV)*/ + char logMessageInterval; /**< Announce message: logMessageInterval. + * NOTE: 8-bit signed integer */ + u16 AnnounceIntervalDuration; /**< Announce Interval in units of 1/128 secs */ +} XAvb_BmcData; + + +/** + * This typedef defines the format for a data structure which stores information + * relating to the 1588 based PTP timing calculations + */ +typedef struct +{ + u32 Nanosec; /**< ns value for sync frame tx request */ + u32 SlaveSyncTimestamp; /**< The timestamp taken of a rx'd sync */ + u32 MasterCorrectionField; /**< Correction Field from rx'd follow-up */ + u32 PDelayTimestampT1; /**< T1 :PDelayReq Frame transmission */ + u32 PDelayTimestampT2; /**< T2 :PDelayReq rx'd at link partner */ + u32 PDelayTimestampT3; /**< T3 :PDelayResp Frame reception */ + u32 PDelayTimestampT4; /**< T4 :PDelayResp tx'd by link partner */ + u32 LinkDelay; /**< Last calculated value of Link Delay */ + u32 NewSlaveTime; /**< RTC ns at slave for last rx'd sync */ + u32 NewMasterTime; /**< RTC ns at master for last tx'd sync */ + u32 OldSlaveTime; /**< Stored RTC slave ns for past sync rx */ + u32 OldMasterTime; /**< Stored RTC master ns for past sync tx*/ + u32 NsOffsetForPDelayResp; /**< RTC ns offset at PDelayResp tx time */ +} XAvb_PtpStruct; + + +/** + * This typedef defines the format for a data structure which stores the last + * used sequence ID for all of the PTP timing frames. + */ +typedef struct +{ + u16 SyncSequenceId; /**< SequenceId of the latest RX'd Sync message */ + u16 FollowUpSequenceId; /**< SequenceId of the latest RX'd FollowUp message */ + u16 PDelayReqSequenceId; /**< SequenceId of the latest TX'd PDelayReq message */ + u16 PDelayRespSequenceId; /**< SequenceId of the latest RX'd PDelayResp message */ + u16 PDelayFollowUpSequenceId; /**< SequenceId of the latest RX'd PDelayRespFollowUp message */ + u16 OldSyncSequenceId; /**< SequenceId of the previous RX'd Sync message used + * for XAvb_UpdateRtcIncrement() calculations */ + u16 NewSyncSequenceId; /**< SequenceId of the current RX'd Sync message used + * for XAvb_UpdateRtcIncrement() calculations */ +} XAvb_SequenceIdStruct; + + +/** + * The Signalling frame defines the delays to be used between Sync Frames, Link + * Delay measurements and Announce Frame events + */ +typedef struct +{ + u16 SyncIntervalDuration; /**< Sync Interval in units of 1/128 seconds */ + u16 LinkDelayIntervalDuration; /**< Link Delay Interval in units of 1/128 seconds */ + u16 AnnounceIntervalDuration; /**< Announce Interval in units of 1/128 seconds */ +} XAvb_SignallingFrameData; + + +/** + * This typedef defines the various counters which have to maintained for the + * PTP operation. + */ +typedef struct +{ + u8 RxPtpHardPointer; /**< The Rx PTP Buffer last written to */ + u8 RxPtpSoftPointer; /**< The current software pointer to Rx Buffer */ + u16 CounterSyncInterval; /**< To count units of 1/128 seconds */ + u16 CounterLinkDelayInterval; /**< To count units of 1/128 seconds */ + u16 CounterAnnounceInterval; /**< To count units of 1/128 seconds */ + u8 CounterSyncEvents; /**< To count the number of Sync Events */ +} XAvb_Counters; + +/** Keep track of state machine data to make sure we're fully + * compliant with the spec + */ +typedef struct +{ + u8 lostResponses; /**< Keep track of the state machine errors */ + u8 rcvdPDelayResp; /**< Received a valid PDelayResp packet since PDelayReq was sent */ + u8 rcvdPDelayRespFollowUp; /**< Received a valid PDelayFollowUp packet since PDelayResp was received */ + XAvb_PortIdentity respPortIdentity; /**< sourcePortIdentity of the last PDelayResp packet received */ + XAvb_PortIdentity respReqPortIdentity; /**< requestingPortIdentity of the last PDelayResp packet received */ +} XAvb_StateMachineData; + + +/** This struct captures information from RX'd Sync/FollowUp message pairs in a format similiar + * to the MDSyncReceive structure described in the IEEE P802.1AS specification. + */ +typedef struct +{ + /** The logMessageInterval is the value of the logMessageInterval of the time-synchronization + * event message received by this port. It is the logSyncInterval of the upstream MasterPort + * that sent the event message.*/ + u8 logMessageInterval; + + /** Convert logMessageInterval into a value we can relate to our 1/128 ns clk pulse */ + u16 SyncIntervalDuration; + +} XAvb_MDSyncReceive; + + +/** + * The XAvb driver instance data. The user is required to allocate a + * variable of this type for every AVB device in the system. A pointer + * to a variable of this type is then passed to the driver API functions. + */ +typedef struct { + /** hardware configuration */ + XAvb_Config Config; + + /** Device is initialized and ready */ + u32 IsReady; + + /** Is AVB enabled */ + u32 AVBIsEnabled; + + /** The PTP algorithm can be started and stopped as requested */ + u32 PtpIsRunning; + + /** The peer must be AS capable before we start full blown PTP */ + u32 PeerASCapable; + + /** Current PTP Slave Error is less than XAVB_CLOCK_LOCK_THRESHOLD nsec */ + u32 PTPLocked; + + /** Store the info from the latest RX'd Sync/Follow message pair */ + XAvb_MDSyncReceive latestMDSyncReceive; + + /** Contains the local port Identity information */ + XAvb_PortIdentity portIdLocal; + + /** Create a data structure for the Best Master Clock Algorithm (BMCA) */ + XAvb_BmcData CurrentBmc; + + /** Create a data structure for the Precise Timing Protocol (PTP) */ + XAvb_PtpStruct PtpRecords; + + /** Create a data structure to record the PTP frames Sequence ID values */ + XAvb_SequenceIdStruct SequenceIdRecords; + + /** Create a data structure to store the Signalling frame information */ + XAvb_SignallingFrameData SignallingFrameData; + + /** Create a data structure to store various PTP counters/timers */ + XAvb_Counters PtpCounters; + + /** Create a data structure to store state machine flags */ + XAvb_StateMachineData StateMachineData; + + /** Callback Handler for a GrandMaster discontinuity event */ + XAvb_Handler GMDiscHandler; + /** Callback ref for a GrandMaster discontinuity event */ + void *GMDiscCallBackRef; + +} XAvb; + + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +/* + * Functions in xavb.c + */ +XStatus XAvb_CfgInitialize(XAvb *InstancePtr, \ + XAvb_Config *ConfigPtr, \ + u32 EffectiveAddress); + +XAvb_Config *XAvb_LookupConfig(u16 DeviceId); + +void XAvb_Reset(XAvb * InstancePtr); + +void XAvb_Start(XAvb * InstancePtr); + +void XAvb_Stop(XAvb * InstancePtr); + +void XAvb_PtpTimerInterruptHandler(XAvb * InstancePtr); + +void XAvb_PtpRxInterruptHandler(XAvb * InstancePtr); + +void XAvb_SetupRxFilterControlPcp(XAvb * InstancePtr, \ + u32 VlanPriority, \ + u8 SrClass); + +void XAvb_SetupRxFilterControlVid(XAvb * InstancePtr, \ + u32 VlanVid, \ + u8 SrClass); + +void XAvb_SetupRxFilterControlMatchMode(XAvb * InstancePtr, \ + u32 VlanMatchMode); + +/* + * Functions in xavb_ptp_packets.c + */ +u32 XAvb_ReorderWord(u32 Data); +u32 XAvb_CompareClockIdentity(u32 BaseAddress, \ + XAvb_ClockIdentity Identity1, \ + XAvb_ClockIdentity Identity2); + +u32 XAvb_ComparePortIdentity(u32 BaseAddress, \ + XAvb_PortIdentity Identity1, \ + XAvb_PortIdentity Identity2); + +void XAvb_WriteToMultipleTxPtpFrames(u32 BaseAddress, \ + u32 Address, \ + u32 Data, \ + u32 DataBitEnable, \ + u8 BufferEnable); + +u32 XAvb_IncSequenceId(u32 BaseAddress, \ + u32 PTPFrameBaseAddress); + +void XAvb_GetPortIdentity(u32 BaseAddress, \ + u32 PtpFrameBaseAddr, \ + u32 PortIdOffset, \ + XAvb_PortIdentity *portID); + +void XAvb_WaitOnTxPtpQueue(XAvb * InstancePtr); + +void XAvb_MasterSendAnnounce(XAvb * InstancePtr); + +void XAvb_MasterSendSync(XAvb * InstancePtr); + +void XAvb_MasterSendFollowUp(XAvb * InstancePtr); + +void XAvb_SendPDelayReq(XAvb * InstancePtr); + +void XAvb_SendPDelayResp(XAvb * InstancePtr, \ + u32 PtpFrameBaseAddr); + +void XAvb_SendPDelayRespFollowUp(XAvb * InstancePtr); + +u32 XAvb_IsRxFramePTP(XAvb * InstancePtr, \ + u32 PtpFrameBaseAddr); + +void XAvb_DecodeRxSync(XAvb * InstancePtr, \ + u32 PtpFrameBaseAddr); + +void XAvb_DecodeRxFollowUp(XAvb * InstancePtr, \ + u32 PtpFrameBaseAddr); + +void XAvb_DecodeRxPDelayResp(XAvb * InstancePtr, \ + u32 PtpFrameBaseAddr); + +void XAvb_DecodeRxPDelayRespFollowUp(XAvb * InstancePtr, \ + u32 PtpFrameBaseAddr); + +void XAvb_DecodeRxSignaling(XAvb * InstancePtr, \ + u32 PtpFrameBaseAddr); + +u16 XAvb_UpdateIntervalDuration(u16 currentIntervalDuration, \ + char logMeanVal); + +u16 XAvb_ConvertLogMeanToDuration(char logMeanVal); + +char XAvb_ConvertDurationToLogMean(u16 fractionalVal); + +void XAvb_UpdateLogMeanMessageInterval(u32 BaseAddress, \ + u32 PtpFrameBaseAddr, \ + u16 intervalDuration); + +void XAvb_SetupSourcePortIdentity(XAvb * InstancePtr, \ + XAvb_PortIdentity systemIdentity); + +/* + * Functions in xavb_ptp_bmca.c + */ +void XAvb_DecodeTxAnnounceFrame(XAvb * InstancePtr); + +void XAvb_DecodeRxAnnounceFrame(XAvb * InstancePtr, \ + u32 PtpFrameBaseAddr); + +void XAvb_ReadAnnounceFrame(u32 BaseAddress, \ + u32 PtpFrameBaseAddr, \ + XAvb_BmcData* AnnounceFrame); + +void XAvb_ReadAnnounceReceiptTimeout(u32 BaseAddress, \ + u32 PtpFrameBaseAddr, \ + XAvb_BmcData * AnnounceFrame); + +void XAvb_UpdateBmcRecords(XAvb_BmcData* NewMaster, \ + XAvb_BmcData* CurrentBmc); + +u32 XAvb_BestMasterClockAlgorithm(XAvb_BmcData* AnnounceFrame, \ + XAvb_BmcData* CurrentBmc); + +void XAvb_BecomeRtcMaster(XAvb * InstancePtr, u8 txAnnounceHasWon); + +void XAvb_BecomeRtcSlave(XAvb * InstancePtr); + +void XAvb_ChangePTPLockStatus(XAvb * InstancePtr, u8 locked); + +void XAvb_ChangePeerASCapability(XAvb *InstancePtr, u8 capable); + +void XAvb_SetGMDiscontinuityHandler(XAvb *InstancePtr, \ + XAvb_Handler FuncPtr, \ + void *CallBackRef); + +/* + * Functions in xavb_rtc_sync.c + */ +u32 XAvb_CaptureNanoSec(u32 BaseAddress, \ + u32 PtpFrameBaseAddr); + +void XAvb_CalcDelay(XAvb * InstancePtr); + +void XAvb_CalcRtcOffset(XAvb * InstancePtr, \ + u32 PtpFrameBaseAddr); + +void XAvb_UpdateRtcIncrement(XAvb * InstancePtr); + +void XAvb_Adjust8kClock(u32 BaseAddress, \ + u32 NewOffset); + + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_example.c b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_example.c new file mode 100644 index 00000000..ded52272 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_example.c @@ -0,0 +1,654 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/** +* +* @file xavb_example.c +* +* This file implements a simple example to show the usage of Audio Video +* Bridging (AVB) functionality of Axi Ethernet IP in loopback mode. +* The example uses the PTP Timer and the PTP Rx interrupts. A PDelay_Req packet +* is sent and is received back (as we are in loopback mode). . +* After this loop backed PDelay_Req packet is received, a PDelay_Resp and +* PDelay_RespFollowUp packets are sent. These packets are also received. +* Since the source port identity of the received packets matches with our +* systems's own source port identity there is no further processing done. +* +* @note +* +* This code assumes the processor type is Microblaze, Xilinx interrupt +* controller (XIntc) is used in the system , and that no operating +* system is used. +* +* It also assumes that all the relevant AVB interrupts are properly +* connected to the Intc module. +* +* The Ethernet AVB Endpoint functionality should be enabled in the Xilinx +* Axi Ethernet core for this example to work. +* +* The Axi Ethernet is used with a GMII interface. The example initializes +* the GMII interface with 1000 Mbps speed. +* +* IMPORTANT NOTE: +* The user must define the macro XAVB_CLOCK_LOCK_THRESHOLD in xavb.h to +* an appropriate value as relevant for the corresponding use case. Presently +* it is defined to 1000 ns which is typical for telecom industry. +* This macro is used to compare against the slave error as calculated everytime +* after receiving 2 successive sync/followup frames. Slave error is the +* difference between master time duration and slave time duration as calculated +* for the time gap (the time it takes to receive two successive sync/follow up +* frames). If slave error is greater than the value defined in +* XAVB_CLOCK_LOCK_THRESHOLD, then master and slave clocks are unlocked. This +* means the node running this SW assumes that the peer is no more capable of +* processing 802.1as frames. The node running the SW then waits till it successful +* calculates the path delay (which essentially means the peer is again capable +* of processing 802.1as frames. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who      Date     Changes
+* ----- -------  -------- -----------------------------------------------------
+* 1.00a kag/asa  08/25/10 First release
+* 3.00a asa	 04/10/12 Disabled enabling of promiscuous mode. This is
+*		          required for AxiEthernet cores with version v3_01_a
+*		          onwards because of a change in the AVB implementation.
+* 4.0   asa  03/06/14 Fix for CR 740863. Added a #warning message for
+*				  users of this example to take note of the fact that
+*				  we have just used a typical value for XAVB_CLOCK_LOCK_THRESHOLD
+*                 and users may want to change it as per their requirements.
+*
+* 
+*******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" +#include "xil_types.h" +#include "xintc.h" +#include "xil_exception.h" +#include "xavb_hw.h" +#include "xavb.h" +#include "xil_cache.h" +#include "xaxiethernet.h" /* defines Axi Ethernet APIs */ + +/************************** Constant Definitions *****************************/ +/** + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#define AXIETHERNET_DEVICE_ID XPAR_AXIETHERNET_0_DEVICE_ID + +#define AVB_PTP_RX_INTERRUPT_ID \ +XPAR_INTC_0_AXIETHERNET_0_AV_INTERRUPT_PTP_RX_VEC_ID /* + * AVB PTP Received + * Frame Interrupt ID + */ +#define AVB_PTP_INTERRUPT_ID \ +XPAR_INTC_0_AXIETHERNET_0_AV_INTERRUPT_10MS_VEC_ID /* AVB PTP Timer + * Interrupt ID + */ + +/* + * Other constants used in this file. + */ + +#define PHY_DETECT_REG 1 +#define PHY_DETECT_MASK 0x1808 + + +#define PHY_R0_RESET 0x8000 +#define PHY_R0_LOOPBACK 0x4000 +#define PHY_R0_DFT_SPD_1000 0x0040 + +/* + * The source MAC address used in this example. This will also form + * a part of source port identity field in the PTP messages + */ +#define ETH_SYSTEM_ADDRESS_EUI48_HIGH 0x000A35 +#define ETH_SYSTEM_ADDRESS_EUI48_LOW 0x010203 + +/******************************************************************************/ +#warning The threshold or tolerance limit for slave error is currently set to \ + 1000 ns. This can be configured through the macro \ + XAVB_CLOCK_LOCK_THRESHOLD in xavb.h. Slave error is the difference \ + between measured master time duration and slave time duration over \ + two sync-frame intervals. If slave error exceeds the configured \ + threshold, the master and slave clocks are unlocked. For usage of the \ + macro XAVB_CLOCK_LOCK_THRESHOLD refer to the function \ + XAvb_UpdateRtcIncrement in file xavb_rtc_sync.c +/******************************************************************************/ + +/************************** Function Prototypes ******************************/ + +static int AvbSetupInterruptSystem(XAvb *InstancePtr); +static int AvbConfigHW(XAxiEthernet *AxiEthernetInstancePtr,XAvb *InstancePtr); +void AvbGMDiscontinuityHandler(void *CallBackRef, u32 TimestampsUncertain); +static int AvbConfigureGmii(XAxiEthernet *InstancePtr, XAvb *AvbInstancePtr); +static int AvbEnterPhyLoopBack(XAxiEthernet *InstancePtr); +static void AvbUtilPhyDelay(unsigned int Seconds); +static void AvbEnablePTPInterrupts(void); +static void AvbUtilPrintMessage(char *Message); + + +static XAxiEthernet AxiEthernetInstance; /* Instance of Axi Ethernet driver */ +static XAvb Avb; /* Instance of AVB driver */ +static XIntc InterruptController; /* Instance of INTC driver */ + +static XAvb_Config AvbConfigStruct; +volatile u8 EchoPTPFramesReceived = 0; + +/*****************************************************************************/ +/** +* +* This is the main function for the AVB example. +* +* @param None. +* +* @return - XST_SUCCESS to indicate success. +* - XST_FAILURE to indicate failure +* +* @note This example will be in a infinte loop if the HW is not working +* properly and if the interrupts are not received. +* +****************************************************************************/ +int main() +{ + + int Status; + XAxiEthernet_Config *AxiEtherCfgPtr; + XAvb_PortIdentity SystemIdentity; + u32 WriteData; + +#if XPAR_MICROBLAZE_USE_ICACHE + Xil_ICacheInvalidate(); + Xil_ICacheEnable(); +#endif + +#if XPAR_MICROBLAZE_USE_DCACHE + Xil_DCacheInvalidate(); + Xil_DCacheEnable(); +#endif + + AvbUtilPrintMessage("\r\n--- Entering main() ---"); + + /* + * Initialize Axi Ethernet Driver. + */ + AxiEtherCfgPtr = XAxiEthernet_LookupConfig(AXIETHERNET_DEVICE_ID); + Status = XAxiEthernet_CfgInitialize(&AxiEthernetInstance, + AxiEtherCfgPtr, + AxiEtherCfgPtr->BaseAddress); + if (Status != XST_SUCCESS) { + AvbUtilPrintMessage("Failed initializing config for Axi Ethernet\r\n"); + AvbUtilPrintMessage("--- Exiting main() ---\r\n"); + return XST_FAILURE; + } + + /* + * Initialize the AVB Config structure. + */ + AvbConfigStruct.DeviceId = AxiEtherCfgPtr->DeviceId; + AvbConfigStruct.BaseAddress = AxiEtherCfgPtr->BaseAddress; + Status = XAvb_CfgInitialize(&Avb, &AvbConfigStruct, AvbConfigStruct.BaseAddress); + if (Status != XST_SUCCESS) { + AvbUtilPrintMessage("Failed initializing config for AVB\r\n"); + AvbUtilPrintMessage("--- Exiting main() ---\r\n"); + return XST_FAILURE; + } + + /* + * Setup the handler for the AVB that will be called if the PTP drivers + * identify a possible discontinuity in GrandMaster time. + */ + XAvb_SetGMDiscontinuityHandler(&Avb, AvbGMDiscontinuityHandler, &Avb); + + /* + * Reset and initialize the AVB driver. + */ + XAvb_Reset(&Avb); + + /* + * Perform configuration on the Axi Ethernet and Ethernet AVB Endpoint + * cores + */ + Status = AvbConfigHW(&AxiEthernetInstance, &Avb); + if (Status != XST_SUCCESS) { + AvbUtilPrintMessage("Failed initializing Axi Ethernet and AVB\r\n"); + AvbUtilPrintMessage("--- Exiting main() ---\r\n"); + return XST_FAILURE; + } + + + /* + * Initialize Interrupt Controller + */ + Status = AvbSetupInterruptSystem(&Avb); + if (Status != XST_SUCCESS) { + AvbUtilPrintMessage("Failed initializing INTC system\r\n"); + AvbUtilPrintMessage("--- Exiting main() ---\r\n"); + return XST_FAILURE; + } + + /* + * Setup the Source Address and Source Port Identity fields in all + * TX PTP Buffers + */ + SystemIdentity.ClockIdentityUpper = (ETH_SYSTEM_ADDRESS_EUI48_HIGH + << 8) | 0xFF; + SystemIdentity.ClockIdentityLower = (0xFE << 24) | + (ETH_SYSTEM_ADDRESS_EUI48_LOW); + SystemIdentity.PortNumber = 1; + + /* + * Write the SA to all default TX PTP buffers + */ + WriteData = (XAvb_ReorderWord(SystemIdentity.ClockIdentityUpper)) << 16; + XAvb_WriteToMultipleTxPtpFrames(Avb.Config.BaseAddress, + XAVB_PTP_TX_PKT_SA_UPPER_OFFSET, + (WriteData & 0xFFFF0000) , + 0xFFFF0000, + 0x7F); + + WriteData = (SystemIdentity.ClockIdentityUpper << 16); + WriteData = (WriteData & 0xFF000000); + WriteData = (WriteData | (SystemIdentity.ClockIdentityLower & 0x00FFFFFF)); + WriteData = XAvb_ReorderWord(WriteData); + XAvb_WriteToMultipleTxPtpFrames(Avb.Config.BaseAddress, + XAVB_PTP_TX_PKT_SA_LOWER_OFFSET, + WriteData, + 0xFFFFFFFF, + 0x7F); + + /* + * Write sourceportidentity to all default TX PTP buffers + */ + XAvb_SetupSourcePortIdentity(&Avb,SystemIdentity); + + + /* + * Start AVB and enable the PTP interrupts. + */ + XAvb_Start(&Avb); + AvbEnablePTPInterrupts(); + + + while(1) { + if(EchoPTPFramesReceived) { + AvbUtilPrintMessage("\r\nExample passed\r\n"); + AvbUtilPrintMessage("--- Exiting main() ---\r\n"); + break; + } + } + return XST_SUCCESS; +} + + +/*****************************************************************************/ +/** +* +* This function configures Axi Ethernet core and AVB module. +* +* @param AxiEthernetInstancePtr is a pointer to the Axi Ethernet driver +* instance +* @param AvbInstancePtr is a pointer to the AVB instance. +* +* @return -XST_SUCCESS to indicate success +* -XST_FAILURE to indicate failure. +* +* @note None. +* +******************************************************************************/ +static int AvbConfigHW(XAxiEthernet *AxiEthernetInstancePtr, XAvb *AvbInstancePtr) +{ + u32 ReadData; + int Status; + + /* + * Configure MDIO Master in Axi Ethernet - MUST be done before + * any MDIO accesses + */ + XAxiEthernet_WriteReg(AxiEthernetInstancePtr->Config.BaseAddress, + XAE_MDIO_MC_OFFSET,0x0000005D); + + /* + * Disable Axi Ethernet Flow Control + */ + XAxiEthernet_WriteReg(AxiEthernetInstancePtr->Config.BaseAddress, + XAE_FCC_OFFSET,0x0); + + /* + * Initialise Axi Ethernet by enabling Tx and Rx with VLAN capability + */ + XAxiEthernet_WriteReg(AxiEthernetInstancePtr->Config.BaseAddress, + XAE_TC_OFFSET,XAE_TC_TX_MASK | XAE_TC_VLAN_MASK); + XAxiEthernet_WriteReg(AxiEthernetInstancePtr->Config.BaseAddress, + XAE_RCW1_OFFSET, XAE_RCW1_RX_MASK | XAE_RCW1_VLAN_MASK); + + /* + * Initialise RTC reference clock for nominal frequency 125MHz - + * (see xavb_hw.h for value) + */ + XAvb_WriteReg(AvbInstancePtr->Config.BaseAddress, + XAVB_RTC_INCREMENT_OFFSET, + XAVB_RTC_INCREMENT_NOMINAL_RATE); + + Status = AvbConfigureGmii(AxiEthernetInstancePtr,AvbInstancePtr); + return Status; +} + +/*****************************************************************************/ +/** +* +* This function configures the GMII interface and Axi Ethernet registers for +* 1000 Mbps speed configuration. +* +* @param InstancePtr is a pointer to the Axi Ethernet driver instance +* @param AvbInstancePtr is a pointer to the AVB instance. +* +* @return - XST_SUCCESS if successful. +* - XST_FAILURE, in case of failure... +* +* @note None. +* +******************************************************************************/ +static int AvbConfigureGmii(XAxiEthernet *InstancePtr, XAvb *AvbInstancePtr) +{ + u32 EmmcReg; + int Status; + + /* + * Set PHY to loopback. + */ + Status = AvbEnterPhyLoopBack(InstancePtr); + if(Status != XST_SUCCESS) { + XAvb_Stop(AvbInstancePtr); + return XST_FAILURE; + } + + /* + * Get the current contents of the EMAC config register and + * zero out speed bits + */ + EmmcReg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_EMMC_OFFSET); + EmmcReg = EmmcReg & (~XAE_EMMC_LINKSPEED_MASK); + EmmcReg |= XAE_EMMC_LINKSPD_1000; + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_EMMC_OFFSET,EmmcReg); + + /* + * Setting the operating speed of the MAC needs a delay. There + * doesn't seem to be register to poll, so please consider this + * during your application design. + */ + AvbUtilPhyDelay(1); + return XST_SUCCESS; + +} + +/******************************************************************************/ +/** +* +* This function sets the PHY to loopback mode. This works with the marvell PHY +* common on Xilinx evaluation boards. This sets the PHY speed to 1000 Mbps. +* +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* AxiEthernet component. +* +* @return - XST_SUCCESS if successful. +* - XST_FAILURE, in case of failure.. +* +* @note None. +* +******************************************************************************/ +static int AvbEnterPhyLoopBack(XAxiEthernet *InstancePtr) +{ + u16 PhyReg0; + signed int PhyAddr; + u16 PhyReg; + + for (PhyAddr = 31; PhyAddr >= 0; PhyAddr--) { + XAxiEthernet_PhyRead(&AxiEthernetInstance, PhyAddr, + PHY_DETECT_REG, &PhyReg); + if ((PhyReg != 0xFFFF) && ((PhyReg & PHY_DETECT_MASK) + == PHY_DETECT_MASK)) { + /* Found a valid PHY address */ + break; + } + } + + if(PhyAddr == 0) + return XST_FAILURE; + /* + * Clear the PHY of any existing bits by zeroing this out + */ + PhyReg0 = 0; + PhyReg0 |= PHY_R0_DFT_SPD_1000; + + /* + * Set the speed and put the PHY in reset, then put the PHY in loopback + */ + XAxiEthernet_PhyWrite(&AxiEthernetInstance, PhyAddr, 0, + PhyReg0 | PHY_R0_RESET); + AvbUtilPhyDelay(1); + XAxiEthernet_PhyRead(&AxiEthernetInstance, PhyAddr, 0,&PhyReg0); + XAxiEthernet_PhyWrite(&AxiEthernetInstance, PhyAddr, 0, + PhyReg0 | PHY_R0_LOOPBACK); + AvbUtilPhyDelay(1); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function sets up the interrupt system so interrupts can occur for the +* AVB design. +* +* @param InstancePtr contains a pointer to the instance of the AVB +* component which is going to be connected to the interrupt +* controller. +* +* @return - XST_SUCCESS if successful. +* - XST_FAILURE, in case of failure.. +* +* @note None. +* +****************************************************************************/ +static int AvbSetupInterruptSystem(XAvb *InstancePtr) +{ + int Status; + + /* + * Initialize the interrupt controller driver so that it can be used. + * XPAR_INTC_0_DEVICE_ID specifies the XINTC device ID that is + * generated in xparameters.h + */ + Status = XIntc_Initialize(&InterruptController, XPAR_INTC_0_DEVICE_ID); + + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + + /* + * Connect the Ethernet AVB Endpoint's 10 ms interrupt + */ + Status = XIntc_Connect(&InterruptController, + AVB_PTP_INTERRUPT_ID, + (XInterruptHandler)XAvb_PtpTimerInterruptHandler, + InstancePtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Connect the Ethernet AVB Endpoint's PTP Rx interrupt + */ + Status = XIntc_Connect(&InterruptController, + AVB_PTP_RX_INTERRUPT_ID, + (XInterruptHandler)XAvb_PtpRxInterruptHandler, + InstancePtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Start the interrupt controller so interrupts are enabled for all + * devices that cause interrupts. + */ + Status = XIntc_Start(&InterruptController, XIN_REAL_MODE); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Enable interrupt on Microblaze + */ + Xil_ExceptionInit(); + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, + (Xil_ExceptionHandler)XIntc_InterruptHandler, + (void *)&InterruptController); + Xil_ExceptionEnable(); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function enables the PTP Timer interrupt and PTP Rx interrupt in the +* INTC module. +* +* @param None +* +* @return None +* +* @note None. +* +******************************************************************************/ +static void AvbEnablePTPInterrupts(void) +{ + XIntc_Enable(&InterruptController, AVB_PTP_RX_INTERRUPT_ID); + XIntc_Enable(&InterruptController, AVB_PTP_INTERRUPT_ID); + return; +} + +/****************************************************************************/ +/** +* +* This function is the handler which will be called if the PTP drivers +* identify a possible discontinuity in GrandMaster time. +* +* This handler provides an example of how to handle this situation - +* but this function is application specific. +* +* +* @param CallBackRef contains a callback reference from the driver, in +* this case it is the instance pointer for the AVB driver. +* @param TimestampsUncertain - a value of 1 indicates that there is a +* possible discontinuity in GrandMaster time. A value of 0 +* indicates that Timestamps are no longer uncertain. +* +* @return None. +* +* @note This Handler ned to be defined otherwise the XAvb_StubHandler +* will generate an error +* +****************************************************************************/ +void AvbGMDiscontinuityHandler(void *CallBackRef, u32 TimestampsUncertain) +{ + + xil_printf("\r\nGMDiscontinuityHandler: Timestamps are now %s\r\n", + TimestampsUncertain ? "uncertain" : "certain"); + +} + + +/******************************************************************************/ +/** +* +* For Microblaze we use an assembly loop that is roughly the same regardless of +* optimization level, although caches and memory access time can make the delay +* vary. Just keep in mind that after resetting or updating the PHY modes, +* the PHY typically needs time to recover. +* +* @return None +* +* @note None +* +******************************************************************************/ +static void AvbUtilPhyDelay(unsigned int Seconds) +{ + static int WarningFlag = 0; + + /* If MB caches are disabled or do not exist, this delay loop could + * take minutes instead of seconds (e.g., 30x longer). Print a warning + * message for the user (once). If only MB had a built-in timer! + */ + if (((mfmsr() & 0x20) == 0) && (!WarningFlag)) { + WarningFlag = 1; + } + +#define ITERS_PER_SEC (XPAR_CPU_CORE_CLOCK_FREQ_HZ / 6) + asm volatile ("\n" + "1: \n\t" + "addik r7, r0, %0 \n\t" + "2: \n\t" + "addik r7, r7, -1 \n\t" + "bneid r7, 2b \n\t" + "or r0, r0, r0 \n\t" + "bneid %1, 1b \n\t" + "addik %1, %1, -1 \n\t" + :: "i"(ITERS_PER_SEC), "d" (Seconds)); + +} + +/******************************************************************************/ +/** +* +* This function is called by example code to display a console message +* +* @param Message is the text explaining the error +* +* @return None +* +* @note None +* +******************************************************************************/ +static void AvbUtilPrintMessage(char *Message) +{ +#ifdef STDOUT_BASEADDRESS + xil_printf("%s\r\n", Message); +#endif +} diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_hw.c b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_hw.c new file mode 100644 index 00000000..387a7e1b --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_hw.c @@ -0,0 +1,164 @@ +/****************************************************************************** +* +* Copyright (C) 2008 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ + +/*****************************************************************************/ +/** +* +* @file xavb_hw.c +* +* The xavb_hw driver. Functions in this file are the minimum required functions +* for this driver. See xavb_hw.h for a detailed description of the driver. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -----------------------------------------------
+* 1.00a mbr  09/19/08 First release
+* 1.01a mbr  06/24/09 PTP frame format updates for IEEE802.1 AS draft 5-0
+* 2_02a mbr  09/16/09 Updates for programmable PTP timers
+* 2_04a kag  07/23/10 PTP frame format updates for IEEE802.1 AS draft 6-7
+* 3_01a kag  08/29/11 Added new APIs to update the RX Filter Control Reg.
+*		      Fix for CR:572539. Updated bit map for Rx Filter
+*		      control reg.
+*
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xil_types.h" +#include "xil_io.h" +#include "xavb_hw.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Variable Definitions *****************************/ + +/************************** Function Prototypes ******************************/ + +/*****************************************************************************/ + +/****************************************************************************/ +/** +* +* This function reads the given Ethernet Statistic Register +* +* @param BaseAddress is the base address of the device +* @param CounterID is the Statistic Counter to be read +* @param Value a pointer to the read value of the 64-bit value of the counter +* and it is updated by this function +* +* @return None. +* +* @note The CounterID's defined here are the same as the Statistic Counter +* Addresses as used with the TEMAC core. Since each counter is 8-bytes +* wide, we must multiply these Counter ID's by 8 (or a left shift of 3) +* when mapping this into the PLB memory map. The 64-bit counter value +* is read as two separate 32-bit accesses. +* +*****************************************************************************/ +void XAvbMac_ReadStats(u32 BaseAddress, + u32 CounterId, + XAvb_Uint64* Value) +{ + Value->Upper = Xil_In32(BaseAddress + ((CounterId & 0x00ff) << 3) + 0x4); + Value->Lower = Xil_In32(BaseAddress + ((CounterId & 0x00ff) << 3)); +} + + +/****************************************************************************/ +/** +* +* This function reads the current Real Time Counter (RTC) value +* +* @param BaseAddress is the base address of the device +* @param RtcValue is a pointer to a struct in which to store the value read +* from the RTC (The RTC 48-bit seconds field and the 32-bit ns field +* of this struct are updated). +* +* @return None +* +* @note This is provided as a basic function since the ns field MUST be read +* before the seconds/epoch registers (reading the ns samples the entire +* RTC in hardware). +* +*****************************************************************************/ +void XAvb_ReadRtc(u32 BaseAddress, + XAvb_RtcFormat* RtcValue) +{ + RtcValue->NanoSeconds = + Xil_In32(BaseAddress + XAVB_RTC_NANOSEC_VALUE_OFFSET) + & XAVB_RTC_NS_MASK; + + RtcValue->SecondsLower = + Xil_In32(BaseAddress + XAVB_RTC_SEC_LOWER_VALUE_OFFSET) + & XAVB_RTC_SEC_LOWER_MASK; + + RtcValue->SecondsUpper = + Xil_In32(BaseAddress + XAVB_RTC_SEC_UPPER_VALUE_OFFSET) + & XAVB_RTC_SEC_UPPER_MASK; +} + + +/****************************************************************************/ +/** +* +* This function writes to the Real Time Counter (RTC) Offset Registers +* +* @param BaseAddress is the base address of the device +* @param RtcValue is the nanoseconds and seconds offset values that should +* be written to the RTC. +* +* @return None +* +* @note This is provided as a basic function since the ns field MUST be +* written after the seconds/epoch offset registers (writing to the ns +* offset registers samples the entire RTC offset in hardware). +* +*****************************************************************************/ +void XAvb_WriteRtcOffset(u32 BaseAddress, XAvb_RtcFormat* RtcValue) +{ + Xil_Out32((BaseAddress + XAVB_RTC_SEC_UPPER_OFFSET), + (RtcValue->SecondsUpper & XAVB_RTC_SEC_UPPER_MASK)); + + Xil_Out32((BaseAddress + XAVB_RTC_SEC_LOWER_OFFSET), + (RtcValue->SecondsLower & XAVB_RTC_SEC_LOWER_MASK)); + + Xil_Out32((BaseAddress + XAVB_RTC_NANOSEC_OFFSET), + (RtcValue->NanoSeconds & XAVB_RTC_NS_MASK)); +} diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_hw.h b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_hw.h new file mode 100644 index 00000000..1494a75b --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_hw.h @@ -0,0 +1,504 @@ +/****************************************************************************** +* +* Copyright (C) 2008 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xavb_hw.h +* +* This header file contains the identifiers and basic driver functions (or +* macros) that can be used to access the device. Other driver functions +* are defined in xavb.h. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -----------------------------------------------
+* 1.00a mbr  09/19/08 First release
+* 1.01a mbr  06/24/09 PTP frame format updates for IEEE802.1 AS draft 5-0
+* 2_02a mbr  09/16/09 Updates for programmable PTP timers
+* 2_04a kag  07/23/10 PTP frame format updates for IEEE802.1 AS draft 6-7
+* 3_01a kag  08/29/11 Added new APIs to update the RX Filter Control Reg.
+*		      Fix for CR:572539. Updated bit map for Rx Filter
+*		      control reg.
+* 3_01a asa  04/10/12 The AVB core is now brought inside the AxiEthernet
+*		      core. Because of this there are changes in the
+*		      register map.
+*
+* 
+* +******************************************************************************/ + +#ifndef XAVB_HW_H /* prevent circular inclusions */ +#define XAVB_HW_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/***************************** Include Files *********************************/ + +#include "xil_types.h" +#include "xil_io.h" + +/************************** Constant Definitions *****************************/ + +/** @name Register offsets for the Tri-Mode Ethernet MAC. Each register is 32 + * bits. The MAC is addressable through the Ethernet AVB Endpoint core. + * @{ + */ +#define XAVB_MAC_RX_REG0_OFFSET 0x00000400 /**< MAC Rx Config Register 0 */ +#define XAVB_MAC_RX_REG1_OFFSET 0x00000404 /**< MAC Rx Config Register 1 */ +#define XAVB_MAC_TX_REG_OFFSET 0x00000408 /**< MAC Tx Config Register */ +#define XAVB_MAC_FC_REG_OFFSET 0x0000040c /**< MAC Flow Control Register */ +#define XAVB_MAC_SPD_REG_OFFSET 0x00000410 /**< MAC Speed Control Register */ +//#define XAVB_MAC_MGMT_REG_OFFSET 0x0000050C /**< MAC MDIO Management Register*/ +/* @} */ + +/** @name Register offsets for the Ethernet Audio Video Endpoint. Each register + * is 32 bits. + * @{ + */ +#define XAVB_PTP_TX_CONTROL_OFFSET 0x00012000 /**< Tx PTP Control Reg */ +#define XAVB_PTP_RX_CONTROL_OFFSET 0x00012004 /**< Rx PTP Control Reg */ +#define XAVB_RX_FILTER_CONTROL 0x00012008 /**< Rx Filter Control Reg */ +#define XAVB_TX_SENDSLOPE 0x0001200C /**< Tx rate sendSlope Reg */ +#define XAVB_TX_IDLESLOPE 0x00012010 /**< Tx rate idleSlope Reg */ +#define XAVB_TX_HILIMIT 0x00012014 /**< Tx rate hiLimit Reg */ +#define XAVB_TX_LOLIMIT 0x00012018 /**< Tx rate loLimit Reg */ +#define XAVB_RTC_NANOSEC_OFFSET 0x00012800 /**< RTC ns offset Reg */ +#define XAVB_RTC_SEC_LOWER_OFFSET 0x00012808 /**< RTC sec[31:0] offset */ +#define XAVB_RTC_SEC_UPPER_OFFSET 0x0001280C /**< RTC sec[47:32] offset */ +#define XAVB_RTC_INCREMENT_OFFSET 0x00012810 /**< RTC Increment Reg */ +#define XAVB_RTC_NANOSEC_VALUE_OFFSET 0x00012814 /**< RTC ns value Reg */ +#define XAVB_RTC_SEC_LOWER_VALUE_OFFSET 0x00012818 /**< RTC sec[31:0] value */ +#define XAVB_RTC_SEC_UPPER_VALUE_OFFSET 0x0001281C /**< RTC sec[47:32] value */ +#define XAVB_RTC_CLEAR_INT_OFFSET 0x00012820 /**< RTC Interrupt Clear */ +#define XAVB_RTC_8K_OFFSET_OFFSET 0x00012824 /**< RTC 8k phase offset */ +#define XAVB_SW_RESET_OFFSET 0x00012828 /**< S/W Reset Reg */ +/* @} */ + +/** @name Packet base address offsets for the Ethernet Audio Video Endpoint Tx + * Precise Timing Protocol (PTP) frame buffer. Each PTP frames is + * stored in 256-byte chunks of BRAM. This BRAM can store 8 PTP frames + * of which only 6 are currently in use. + * @{ + */ +#define XAVB_PTP_TX_SYNC_OFFSET 0x00011000 +#define XAVB_PTP_TX_FOLLOW_UP_OFFSET 0x00011100 +#define XAVB_PTP_TX_PDELAYREQ_OFFSET 0x00011200 +#define XAVB_PTP_TX_PDELAYRESP_OFFSET 0x00011300 +#define XAVB_PTP_TX_PDELAYRESP_FOLLOW_UP_OFFSET 0x00011400 +#define XAVB_PTP_TX_ANNOUNCE_OFFSET 0x00011500 +/* @} */ + +/** @name Base address offset for the Ethernet Audio Video Endpoint Rx + * Precise Timing Protocol (PTP) frame buffer. These PTP frames are + * stored in 256-byte chunks of BRAM. This BRAM can store 16 PTP frames. + * @{ + */ +#define XAVB_PTP_RX_BASE_OFFSET 0x00010000 +/* @} */ + +/** @name AVB Tx PTP Control Register + * @{ + */ +#define XAVB_PTP_TX_SEND_SYNC_FRAME_MASK 0x00000001 +#define XAVB_PTP_TX_SEND_FOLLOWUP_FRAME_MASK 0x00000002 +#define XAVB_PTP_TX_SEND_PDELAYREQ_FRAME_MASK 0x00000004 +#define XAVB_PTP_TX_SEND_PDELAYRESP_FRAME_MASK 0x00000008 +#define XAVB_PTP_TX_SEND_PDELAYRESPFOLLOWUP_FRAME_MASK 0x00000010 +#define XAVB_PTP_TX_SEND_ANNOUNCE_FRAME_MASK 0x00000020 +#define XAVB_PTP_TX_SEND_FRAME6_BIT_MASK 0x00000040 +#define XAVB_PTP_TX_SEND_FRAME7_BIT_MASK 0x00000080 +#define XAVB_PTP_TX_WAIT_SYNC_FRAME_MASK 0x00000100 +#define XAVB_PTP_TX_WAIT_FOLLOWUP_FRAME_MASK 0x00000200 +#define XAVB_PTP_TX_WAIT_PDELAYREQ_FRAME_MASK 0x00000400 +#define XAVB_PTP_TX_WAIT_PDELAYRESP_FRAME_MASK 0x00000800 +#define XAVB_PTP_TX_WAIT_PDELAYRESPFOLLOWUP_FRAME_MASK 0x00001000 +#define XAVB_PTP_TX_WAIT_ANNOUNCE_FRAME_MASK 0x00002000 +#define XAVB_PTP_TX_WAIT_FRAME6_BIT_MASK 0x00004000 +#define XAVB_PTP_TX_WAIT_FRAME7_BIT_MASK 0x00008000 +#define XAVB_PTP_TX_WAIT_ALL_FRAMES_MASK 0x0000FF00 +#define XAVB_PTP_TX_PACKET_FIELD_MASK 0x00070000 + +/* @} */ + +/** @name AVB Rx PTP Control Register + * @{ + */ +#define XAVB_PTP_RX_CLEAR_BIT_MASK 0x00000001 +#define XAVB_PTP_RX_PACKET_FIELD_MASK 0x00000F00 +/* @} */ + +/** @name AVB Rx Filter Control Register + * @{ + */ +#define XAVB_RX_AV_VLAN_PRIORITY_A_MASK 0x00000007 +#define XAVB_RX_AV_VLAN_VID_A_MASK 0x00007FF8 +#define XAVB_RX_AV_VLAN_MATCH_MODE_MASK 0x00008000 +#define XAVB_RX_AV_VLAN_PRIORITY_B_MASK 0x00070000 +#define XAVB_RX_AV_VLAN_VID_B_MASK 0x7FF80000 +#define XAVB_RX_LEGACY_PROMISCUOUS_MODE_MASK 0x80000000 +/* @} */ + +/** @name AVB Tx rate control sendSlope + * @{ + */ +#define XAVB_TX_SENDSLOPE_MASK 0X000FFFFF +/* @} */ + +/** @name AVB Tx rate control idleSlope + * @{ + */ +#define XAVB_TX_IDLESLOPE_MASK 0X000FFFFF +/* @} */ + +/** @name AVB Tx rate control hiLimit + * @{ + */ +#define XAVB_TX_HILIMIT_MASK 0X01FFFFFF +/* @} */ + +/** @name AVB Tx rate control loLimit + * @{ + */ +#define XAVB_TX_LOLIMIT_MASK 0X01FFFFFF +/* @} */ + +/** @name RTC field Registers + * @{ + */ +#define XAVB_RTC_NS_MASK 0x3FFFFFFF +#define XAVB_RTC_SEC_LOWER_MASK 0xFFFFFFFF +#define XAVB_RTC_SEC_UPPER_MASK 0x0000FFFF +/* @} */ + +/** @name RTC Increment Register + * @{ + */ +#define XAVB_RTC_INCREMENT_VALUE_MASK 0x03FFFFFF +/** This value assumes a 125MHz rtc_clock */ +#define XAVB_RTC_INCREMENT_NOMINAL_RATE 0x00800000 +/** Add some rails so that recovery is possible after a + * string of bad pDelay values. The RTC should be able to lock + * to within 100ppm of the slowest allowable clock (25 MHz). + * This equates to +/-4ps. Let's arbitrarily set the rails to + * 400ppm (+/-16ps) just in case someone decides to use a + * particularly bad oscillator. The lowest 20 bits of + * NewIncrement are fractions of a nanosecond, which equates + * to +/- 0x04189 */ +#define XAVB_RTC_400PPM_OFFSET 0x00004189 +/* @} */ + +/** @name RTC Interrupt Clear Register + * @{ + */ +#define XAVB_RTC_INCREMENT_VALUE_MASK 0x03FFFFFF +/* @} */ + + +/** @name RTC Interrupt Clear Register + * @{ + */ +#define XAVB_RTC_CLEAR_INT_MASK 0x00000000 +/* @} */ + + +/** @name RTC 8k phase offset Register + * @{ + */ +#define XAVB_RTC_8K_PHASE_OFFSET_MASK 0x3FFFFFFF +/* @} */ + +/** @name S/W Reset Register + * @{ + */ +#define XAVB_SW_RESET_TX_AND_RX_PATHS 0x00000003 +/* @} */ + + +/** @name AVB MAC MDIO register address space. + * @{ + */ +#define XAVB_MAC_MDIO_BASE_OFFSET 0x00006000 +/* @} */ + + +/** @name MDIO valid data mask (MDIO registers are all 16-bits). + * @{ + */ +#define XAVB_MAC_MDIO_DATA_MASK 0x0000FFFF +/* @} */ + + +/** @name MAC Statistic Counter names and CounterID. + * @{ + */ +#define XAVB_STATS_BYTES_TRANSMITTED 0x00000000 +#define XAVB_STATS_BYTES_RECEIVED 0x00000001 +#define XAVB_STATS_UNDERSIZED_FRAMES_RECEIVED 0x00000002 +#define XAVB_STATS_FRAGMENT_FRAMES_RECEIVED 0x00000003 +#define XAVB_STATS_64_BYTE_FRAMES_RECEIVED_OK 0x00000004 +#define XAVB_STATS_65_TO_127_BYTE_FRAMES_RECEIVED_OK 0x00000005 +#define XAVB_STATS_128_TO_255_BYTE_FRAMES_RECEIVED_OK 0x00000006 +#define XAVB_STATS_256_TO_511_BYTE_FRAMES_RECEIVED_OK 0x00000007 +#define XAVB_STATS_512_TO_1023_BYTE_FRAMES_RECEIVED_OK 0x00000008 +#define XAVB_STATS_1024_TO_1518_BYTE_FRAMES_RECEIVED_OK 0x00000009 +#define XAVB_STATS_OVERSIZED_FRAMES_RECEIVED_OK 0x0000000A +#define XAVB_STATS_64_BYTE_FRAMES_TRANSMITTED_OK 0x0000000B +#define XAVB_STATS_65_TO_127_BYTE_FRAMES_TRANSMITTED_OK 0x0000000C +#define XAVB_STATS_128_TO_255_BYTE_FRAMES_TRANSMITTED_OK 0x0000000D +#define XAVB_STATS_256_TO_511_BYTE_FRAMES_TRANSMITTED_OK 0x0000000E +#define XAVB_STATS_512_TO_1023_BYTE_FRAMES_TRANSMITTED_OK 0x0000000F +#define XAVB_STATS_1024_TO_1518_BYTE_FRAMES_TRANSMITTED_OK 0x00000010 +#define XAVB_STATS_OVERSIZE_FRAMES_TRANSMITTED_OK 0x00000011 +#define XAVB_STATS_FRAMES_RECEIVED_OK 0x00000012 +#define XAVB_STATS_FCS_ERRORS 0x00000013 +#define XAVB_STATS_BROADCAST_FRAMES_RECEIVED_OK 0x00000014 +#define XAVB_STATS_MULTICAST_FRAMES_RECEIVED_OK 0x00000015 +#define XAVB_STATS_CONTROL_FRAMES_RECEIVED_OK 0x00000016 +#define XAVB_STATS_LENGTH_TYPE_OUT_OF_RANGE 0x00000017 +#define XAVB_STATS_VLAN_TAGGED_FRAMES_RECEIVED_OK 0x00000018 +#define XAVB_STATS_PAUSE_FRAMES_RECEIVED_OK 0x00000019 +#define XAVB_STATS_CONTROL_FRAMES_WITH_UNSUPPORTED_OPCODE 0x0000001A +#define XAVB_STATS_FRAMES_TRANSMITTED 0x0000001B +#define XAVB_STATS_BROADCAST_FRAMES_TRANSMITTED 0x0000001C +#define XAVB_STATS_MULTICAST_FRAMES_TRANSMITTED 0x0000001D +#define XAVB_STATS_UNDERRUN_ERRORS 0x0000001E +#define XAVB_STATS_CONTROL_FRAMES_TRANSMITTED_OK 0x0000001F +#define XAVB_STATS_VLAN_TAGGED_FRAMES_TRANSMITTED_OK 0x00000020 +#define XAVB_STATS_PAUSE_FRAMES_TRANSMITTED_OK 0x00000021 +#define XAVB_STATS_SINGLE_COLLISION_FRAMES 0x00000022 +#define XAVB_STATS_MULTI_COLLISION_FRAMES 0x00000023 +#define XAVB_STATS_DEFERRAL_FRAMES 0x00000024 +#define XAVB_STATS_LATE_COLLISION_FRAMES 0x00000025 +#define XAVB_STATS_EXCESS_COLLISION_FRAMES 0x00000026 +#define XAVB_STATS_EXCESS_DEFERRAL_FRAMES 0x00000027 +#define XAVB_STATS_CARRIER_SENSE_ERRORS 0x00000028 +#define XAVB_STATS_ALIGNMENT_ERRORS 0x00000029 +/* @} */ + + +/**************************** Type Definitions *******************************/ + +/** + * This typedef defines the format for the Real Time Clock (RTC). The RTC + * contains a 48-bit seconds field (split into upper and lower sections) and + * a 32-bit nano-seconds field. + */ +typedef struct +{ + u16 SecondsUpper; /**< Upper 16-bits of seconds field */ + u32 SecondsLower; /**< Lower 32-bits of seconds field */ + u32 NanoSeconds; /**< 32-bit nanoseconds field */ +} XAvb_RtcFormat; + +/** + * This typedef descibes a 64-bit un-signed integer in terms of 2 u32s + */ +typedef struct +{ + u32 Upper; /**< Upper 32 bits */ + u32 Lower; /**< Lower 32 bits */ +} XAvb_Uint64; + +/***************** Macros (Inline Functions) Definitions *********************/ + +/****************************************************************************/ +/** +* +* This macro reads from the given AVB core register. +* +* @param BaseAddress is the base address of the device +* @param RegOffset is the register offset to be read +* +* @return The 32-bit value of the register +* +* @note None. +* +*****************************************************************************/ +#define XAvb_ReadReg(BaseAddress, RegOffset) \ + Xil_In32((BaseAddress) + (RegOffset)) + + +/****************************************************************************/ +/** +* +* This macro writes to the given AVB core register. +* +* @param BaseAddress is the base address of the device +* @param RegOffset is the register offset to be written +* @param Data is the 32-bit value to write to the register +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +#define XAvb_WriteReg(BaseAddress, RegOffset, Data) \ + Xil_Out32((BaseAddress) + (RegOffset), (Data)) + + +/****************************************************************************/ +/** +* +* This macro reads from the given PTP frame buffer. +* +* @param BaseAddress is the base address of the device +* @param PtpPacketBaseAddress is the base address of the frame in the PTP +* BRAM packet buffer + @param PtpPacketOffset is the offset address within the PTP frame +* +* @return The 32-bit value of the register +* +* @note None. +* +*****************************************************************************/ +#define XAvb_ReadPtpBuffer(BaseAddress, PtpPacketBaseAddress, PtpPacketOffset)\ + Xil_In32(BaseAddress + PtpPacketBaseAddress + PtpPacketOffset) + + +/****************************************************************************/ +/** +* +* This macro writes to the given PTP frame buffer. +* +* @param BaseAddress is the base address of the device +* @param PtpPacketBaseAddress is the base address of the frame in the PTP +* packet buffer + @param PtpPacketOffset is the offset address within the PTP frame +* @param Data is the 32-bit value to write to the register +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +#define XAvb_WritePtpBuffer(BaseAddress, PtpPacketBaseAddress, \ + PtpPacketOffset, Data) \ + Xil_Out32(BaseAddress + PtpPacketBaseAddress + PtpPacketOffset, (Data)) + + +/****************************************************************************/ +/** +* +* This macro reads from the given TEMAC Configuration Register. +* +* @param BaseAddress is the base address of the device +* @param RegOffset is the register offset to be read +* +* @return The 32-bit value of the register +* +* @note None. +* +*****************************************************************************/ +#define XAvbMac_ReadConfig(BaseAddress, RegOffset) \ + Xil_In32((BaseAddress) + (RegOffset)) + + +/****************************************************************************/ +/** +* +* This macro writes to the given TEMAC Configuration Register. +* +* @param BaseAddress is the base address of the device +* @param RegOffset is the register offset to be written +* @param Data is the 32-bit value to write to the register +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +#define XAvbMac_WriteConfig(BaseAddress, RegOffset, Data) \ + Xil_Out32((BaseAddress) + (RegOffset), (Data)) + + +/****************************************************************************/ +/** +* +* This macro reads from the given MDIO Register using the TEMAC +* +* @param BaseAddress is the base address of the device +* @param Phyad is the Physical Address of the PHY +* @param Regad is the Address of the MDIO register within the addressed PHY +* +* @return The 32-bit value of the register (upper 16-bits will be all 0's) +* +* @note None. +* +*****************************************************************************/ +#define XAvbMac_ReadMdio(BaseAddress, Phyad, Regad) \ + Xil_In32((BaseAddress) + XAVB_MAC_MDIO_BASE_OFFSET \ + + (((Phyad) & 0x1F) << 8) \ + + (((Regad) & 0x1F) << 3)) + + +/****************************************************************************/ +/** +* +* This macro writes to the given MDIO Register using the TEMAC +* +* @param BaseAddress is the base address of the device +* @param Phyad is the Physical Address of the PHY +* @param Regad is the Address of the MDIO register within the addressed PHY +* @param Data is the 32-bit value to write +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +#define XAvbMac_WriteMdio(BaseAddress, Phyad, Regad, Data) \ + Xil_Out32(BaseAddress + XAVB_MAC_MDIO_BASE_OFFSET \ + + (((Phyad) & 0x1F) << 8) \ + + (((Regad) & 0x1F) << 3), \ + (Data & XAVB_MAC_MDIO_DATA_MASK)) + + +/************************** Function Prototypes ******************************/ + +/* + * Functions in xavb_hw.c + */ +void XAvbMac_ReadStats(u32 BaseAddress, u32 CounterId, XAvb_Uint64* Value); +void XAvb_ReadRtc(u32 BaseAddress, XAvb_RtcFormat* RtcValue); +void XAvb_WriteRtcOffset(u32 BaseAddress, XAvb_RtcFormat* RtcValue); + + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_ptp_bmca.c b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_ptp_bmca.c new file mode 100644 index 00000000..3d487dea --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_ptp_bmca.c @@ -0,0 +1,819 @@ +/****************************************************************************** +* +* Copyright (C) 2008 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xavb_ptp_bmca.c +* +* The XAvb driver. Functions in this file all relate to the Best Master Clock +* Algorithm (BMCA) which is performed on the AVB network to select a network +* Grand Master Clock. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -----------------------------------------------
+* 1.00a mbr  09/19/08 First release
+* 1.01a mbr  06/24/09 PTP frame format updates for IEEE802.1 AS draft 5-0
+* 2_02a mbr  09/16/09 Updates for programmable PTP timers
+* 2_04a kag  07/23/10 PTP frame format updates for IEEE802.1 AS draft 6-7
+* 3_01a kag  08/29/11 Added new APIs to update the RX Filter Control Reg.
+*		      Fix for CR:572539. Updated bit map for Rx Filter
+*		      control reg.
+*
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xil_types.h" +#include "xil_assert.h" +#include "xavb_hw.h" +#include "xavb.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Variable Definitions *****************************/ + +/************************** Function Prototypes ******************************/ + +/*****************************************************************************/ + +/****************************************************************************/ +/** +* +* A New Announce Packet has been written to this device to transmit. We need to +* decode it and rerun the Best Master Clock Algorithm (BMCA) +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @return None. But an updated True/False decision as to whether this device +* should operate as a clock master or a slave is written into the +* CurrentBmc data structure. +* +* @note None. +* +*****************************************************************************/ +void XAvb_DecodeTxAnnounceFrame(XAvb * InstancePtr) { + + u32 NewMaster = 0; + XAvb_BmcData TxAnnounceFrame; + + + /** Read the attributes for the new Announce frame in the Tx PTP buffer */ + XAvb_ReadAnnounceFrame(InstancePtr->Config.BaseAddress, + (XAVB_PTP_TX_ANNOUNCE_OFFSET + 8), + &TxAnnounceFrame); + + /** Compare the clock attributes between then new Announce frame and the + * current master */ + NewMaster = XAvb_BestMasterClockAlgorithm(&TxAnnounceFrame, + &InstancePtr->CurrentBmc); + + + if ((NewMaster == 1) | (InstancePtr->CurrentBmc.IAmTheRtcMaster == 1)) { + /** Update records with the NEW best master */ + XAvb_UpdateBmcRecords(&TxAnnounceFrame, + &InstancePtr->CurrentBmc); + +#ifdef DEBUG_XAVB_LEVEL1 + xil_printf("\r\nXAvb_DecodeTxAnnounceFrame()"); + xil_printf("\r\n* BMC : I am the MASTER"); + xil_printf("\r\n-----------------------"); + xil_printf("\r\nLocal Announce Frame"); + xil_printf("\r\n-----------------------"); + xil_printf("\r\nGM ID upper %x", + InstancePtr->CurrentBmc.GrandmasterIdentity.ClockIdentityUpper); + + xil_printf("\r\nGM ID lower %x", + InstancePtr->CurrentBmc.GrandmasterIdentity.ClockIdentityLower); + + xil_printf("\r\nPriority1 %x", + InstancePtr->CurrentBmc.GrandmasterPriority1); + + xil_printf("\r\nclockClass %x", + InstancePtr->CurrentBmc.ClockQuality.clockClass); + + xil_printf("\r\nPriority2 %x", + InstancePtr->CurrentBmc.GrandmasterPriority2); +#endif + + /** Our new Tx Announce Packet has won - so this device must be the + * master */ + xil_printf("\r\n*** XAvb_DecodeTxAnnounceFrame() : Call XAvb_BecomeRtcMaster() *** \r\n"); + XAvb_BecomeRtcMaster(InstancePtr,1); + + } + +} + + +/****************************************************************************/ +/** +* +* A New Announce Packet has been received. We need to decode it and rerun the +* Best Master Clock Algorithm (BMCA) +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* @param PtpFrameBaseAddr is the base address of the received Announce Packet +* in the Rx PTP Packet Buffer +* +* @return None. But an updated True/False decision as to whether this device +* should operate as a clock master or a slave is written into the +* CurrentBmc data structure. +* +* @note None. +* +*****************************************************************************/ +void XAvb_DecodeRxAnnounceFrame(XAvb * InstancePtr, + u32 PtpFrameBaseAddr) { + + u32 NewMaster = 0; + XAvb_BmcData RxAnnounceFrame; + + /** Read the attributes for the new Announce frame received */ + XAvb_ReadAnnounceFrame(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + &RxAnnounceFrame); + + /** If the received packet's clockIdentity matches our + * clockIdentity, ignore the packet */ + if( XAvb_ComparePortIdentity(InstancePtr->Config.BaseAddress, + InstancePtr->portIdLocal, + RxAnnounceFrame.SourcePortIdentity) ) { + xil_printf("Got an announce from myself.. ignoring\r\n"); + return; + } + + /** If the received packet's stepsRemoved field is >= 255, + * ignore the packet */ + if( RxAnnounceFrame.stepsRemoved >= 255 ) { + xil_printf("Got an announce with stepsRemoved > 255.. ignoring\r\n"); + return; + } + + /** If the Announce packet's GMID matches that of our current GM + * record, then update its records based on the current packet, + * just in case something (such as priority) has changed. */ + if( XAvb_CompareClockIdentity(InstancePtr->Config.BaseAddress, + RxAnnounceFrame.GrandmasterIdentity, + InstancePtr->CurrentBmc.GrandmasterIdentity) ) { + + /** update timeout information */ + InstancePtr->PtpCounters.CounterAnnounceInterval = 0; + + XAvb_UpdateBmcRecords(&RxAnnounceFrame, + &InstancePtr->CurrentBmc); + /** Compare against this device's information to see if we should be GM */ + XAvb_DecodeTxAnnounceFrame(InstancePtr); + + } else if( InstancePtr->CurrentBmc.IAmTheRtcMaster ) { + + /** run BMCA on this announce to see if it is better than me */ + NewMaster = XAvb_BestMasterClockAlgorithm(&RxAnnounceFrame, + &InstancePtr->CurrentBmc); + + if (NewMaster == 1) { + /** Update records with the NEW best master */ + XAvb_UpdateBmcRecords(&RxAnnounceFrame, + &InstancePtr->CurrentBmc); + + /** Capture the Announce Receipt Timeout Interval. + * Reset the announce receipt timeout interval to use the new value. + */ + XAvb_ReadAnnounceReceiptTimeout(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + &RxAnnounceFrame); + + InstancePtr->CurrentBmc.AnnounceIntervalDuration = + XAvb_ConvertLogMeanToDuration(RxAnnounceFrame.logMessageInterval); + + +#ifdef DEBUG_XAVB_LEVEL1 + xil_printf("\r\r\nXAvb_DecodeRxAnnounceFrame()"); + xil_printf("\r\n-----------------------"); + xil_printf("\r\nWinning Announce Frame"); + xil_printf("\r\n-----------------------"); + + xil_printf("\r\nGM ID upper %x", + InstancePtr->CurrentBmc.GrandmasterIdentity.ClockIdentityUpper); + + xil_printf("\r\nGM ID lower %x", + InstancePtr->CurrentBmc.GrandmasterIdentity.ClockIdentityLower); + + xil_printf("\r\nPriority1 %x", + InstancePtr->CurrentBmc.GrandmasterPriority1); + + xil_printf("\r\nclockClass %x", + InstancePtr->CurrentBmc.ClockQuality.clockClass); + + xil_printf("\r\nPriority2 %x", + InstancePtr->CurrentBmc.GrandmasterPriority2); +#endif + + /** New Rx Announce Packet has won - so this device cannot be a master */ + xil_printf("\r\n* XAvb_DecodeRxAnnounceFrame()::BMC : I am a SLAVE"); + XAvb_BecomeRtcSlave(InstancePtr); + } + } +} + + +/****************************************************************************/ +/** +* +* A New Announce Packet is to be analyzed. This function will read in the +* packet, decode it, and extract the relevent information fields to the +* "AnnounceFrame" data pointer. +* +* @param BaseAddress is the base address of the device +* @param PtpFrameBaseAddr is the base address of the received Announce Packet +* in the Rx PTP Packet Buffer +* @param AnnounceFrame is a pointer to a suitable data structure, designed to +* record the useful fields from the received Announce Packet +* +* @return The AnnounceFrame data structure is updated. +* +* @note None. +* +*****************************************************************************/ +void XAvb_ReadAnnounceFrame(u32 BaseAddress, + u32 PtpFrameBaseAddr, + XAvb_BmcData * AnnounceFrame) { + + u32 ReadWord; + + AnnounceFrame->SourcePortIdentity.ClockIdentityLower = 0; + AnnounceFrame->SourcePortIdentity.ClockIdentityUpper = 0; + + /** Get the Source Port Identity of the port sending the Announce Packet */ + XAvb_GetPortIdentity(BaseAddress, PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_PORTID_UPPER_OFFSET, &AnnounceFrame->SourcePortIdentity); + + + /** Read priority1 and top half of ClockQuality */ + ReadWord = XAvb_ReorderWord(XAvb_ReadPtpBuffer(BaseAddress, PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_ANNOUNCE_PRI1_QUAL_HI_OFFSET)); + AnnounceFrame->GrandmasterPriority1 = (ReadWord >> 16); + AnnounceFrame->ClockQuality.clockClass = (ReadWord >> 8); + AnnounceFrame->ClockQuality.clockAccuracy = ReadWord; + + + /** Read bottom half of ClockQuality, priority2, and top byte of GMID */ + ReadWord = XAvb_ReorderWord(XAvb_ReadPtpBuffer(BaseAddress, PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_ANNOUNCE_QUAL_LOW_PRI2_GMID_HI_OFFSET)); + AnnounceFrame->ClockQuality.offsetScaledLogVariance = (ReadWord >> 16); + AnnounceFrame->GrandmasterPriority2 = (ReadWord >> 8); + AnnounceFrame->GrandmasterIdentity.ClockIdentityUpper = (ReadWord << 24); + + /** Read bytes 4-7 of GMID */ + ReadWord = XAvb_ReorderWord(XAvb_ReadPtpBuffer(BaseAddress, PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_ANNOUNCE_GMID_MID_OFFSET)); + AnnounceFrame->GrandmasterIdentity.ClockIdentityUpper |= (ReadWord >> 8); + AnnounceFrame->GrandmasterIdentity.ClockIdentityLower = (ReadWord << 24); + + /** Read bytes 1-3 of GMID and high byte of stepsRemoved */ + ReadWord = XAvb_ReorderWord(XAvb_ReadPtpBuffer(BaseAddress, PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_ANNOUNCE_GMID_LOW_STEPSREMOVED_HI_OFFSET)); + AnnounceFrame->GrandmasterIdentity.ClockIdentityLower |= (ReadWord >> 8); + AnnounceFrame->stepsRemoved = (ReadWord << 8); + + /** Read low byte of stepsRemoved */ + ReadWord = XAvb_ReorderWord(XAvb_ReadPtpBuffer(BaseAddress, PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_ANNOUNCE_STEPSREMOVED_LOW_TIMESRC_OFFSET)); + AnnounceFrame->stepsRemoved |= (ReadWord >> 24); + +} + +/****************************************************************************/ +/** +* +* This function reads the logMessageinteval from an RX PTP Buffer and updates +* the AnnounceFrame struct with the value read. +* +* @param BaseAddress is the base address of the device +* @param PtpFrameBaseAddr is the base address of the received Announce Packet +* in the Rx PTP Packet Buffer +* @param AnnounceFrame is a pointer to a suitable data structure, designed to +* record the useful fields from the received Announce Packet +* +* @return The AnnounceFrame data structure is updated. +* +* @note None. +* +*****************************************************************************/ +void XAvb_ReadAnnounceReceiptTimeout(u32 BaseAddress, + u32 PtpFrameBaseAddr, + XAvb_BmcData * AnnounceFrame) { + + u32 ReadWord; + u8 logMessageInterval; + + ReadWord = XAvb_ReorderWord((XAvb_ReadPtpBuffer(BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_SEQUENCEID_OFFSET)) & + 0xFF000000); + + logMessageInterval = ReadWord; + + /* Implicit convert from unsigned (u8) to signed (char) */ + AnnounceFrame->logMessageInterval = logMessageInterval; + +} + +/****************************************************************************/ +/** +* +* This function will accept the data pointer to the current BMCA records, accept +* a pointer to an equivalent data structure for the new Announce Packet. The +* Best Master Clock Algorithm (BMCA) is then performed on these two data +* structures by comparing the data fields +* +* @param CurrentBmc is a pointer to a suitable data structure, designed to +* record the current fields from the current Grand Master's Announce +* Packet. +* @param AnnounceFrame is a pointer to a suitable data structure, designed to +* record the useful fields from the received Announce Packet +* +* @return An updated True/False decision as to whether there is to be a change +* of Grand Master in the network. +* +* @note None. +* +*****************************************************************************/ +u32 XAvb_BestMasterClockAlgorithm(XAvb_BmcData * AnnounceFrame, + XAvb_BmcData * CurrentBmc) { + + u32 NewMaster = 0; + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("*** Performing BMCA ***\r\n"); +#endif + + /** Priority1 takes precedence over all over priorites */ + if (AnnounceFrame->GrandmasterPriority1 < CurrentBmc->GrandmasterPriority1) { + /** we have found a better master! */ + NewMaster = 1; + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: Found new GM on priority1: AnnPri1 (%d) < BmcPri1 (%d)\r\n", + AnnounceFrame->GrandmasterPriority1, + CurrentBmc->GrandmasterPriority1); +#endif + + } else if (AnnounceFrame->GrandmasterPriority1 == + CurrentBmc->GrandmasterPriority1) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: priority1 equal moving on: (%d)\r\n", + AnnounceFrame->GrandmasterPriority1); +#endif + + /** convert structs to u32 values for easy comparison */ + u32 AnnClockQualityInteger; + u32 BmcClockQualityInteger; + AnnClockQualityInteger = (AnnounceFrame->ClockQuality.clockClass << 24) | + (AnnounceFrame->ClockQuality.clockAccuracy << 16) | + (AnnounceFrame->ClockQuality.offsetScaledLogVariance); + BmcClockQualityInteger = (CurrentBmc->ClockQuality.clockClass << 24) | + (CurrentBmc->ClockQuality.clockAccuracy << 16) | + (CurrentBmc->ClockQuality.offsetScaledLogVariance); + + /** ClockQuality has the next priority */ + if (AnnClockQualityInteger < BmcClockQualityInteger ) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: Found new GM on clockQuality: Ann (0x%08x) < Bmc (0x%08x)\r\n", + AnnClockQualityInteger, + BmcClockQualityInteger); +#endif + + /** we have found a better master! */ + NewMaster = 1; + + } else if ( AnnClockQualityInteger == BmcClockQualityInteger ) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: clockQuality equal moving on: (0x%08x)\r\n", + AnnClockQualityInteger); +#endif + + /** Priority2 provides fine grained ordering amongst otherwise equal + * clocks */ + if (AnnounceFrame->GrandmasterPriority2 < + CurrentBmc->GrandmasterPriority2) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: Found new GM on priority2: AnnPri1 (%d) < BmcPri1 (%d)\r\n", + AnnounceFrame->GrandmasterPriority2, + CurrentBmc->GrandmasterPriority2); +#endif + + /** we have found a better master! */ + NewMaster = 1; + + /** Next compare the Clock Identities */ + } else if (AnnounceFrame->GrandmasterPriority2 + == CurrentBmc->GrandmasterPriority2) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: priority2 equal moving on: (%d)\r\n", + AnnounceFrame->GrandmasterPriority2); +#endif + + if (AnnounceFrame->GrandmasterIdentity.ClockIdentityUpper < + CurrentBmc->GrandmasterIdentity.ClockIdentityUpper) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: Found new GM on GMIDClockIDUp: Ann (0x%08x) < Bmc (0x%08x)\r\n", + AnnounceFrame->GrandmasterIdentity.ClockIdentityUpper, + CurrentBmc->GrandmasterIdentity.ClockIdentityUpper); +#endif + + /** we have found a better master! */ + NewMaster = 1; + + } else if (AnnounceFrame->GrandmasterIdentity.ClockIdentityUpper + == CurrentBmc->GrandmasterIdentity.ClockIdentityUpper) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: GMIDclockIDUp equal moving on: (0x%08x)\r\n", + AnnounceFrame->GrandmasterIdentity.ClockIdentityUpper); +#endif + + if (AnnounceFrame->GrandmasterIdentity.ClockIdentityLower < + CurrentBmc->GrandmasterIdentity.ClockIdentityLower) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: Found new GM on GMIDClockIDLow: Ann (0x%08x) < Bmc (0x%08x)\r\n", + AnnounceFrame->GrandmasterIdentity.ClockIdentityLower, + CurrentBmc->GrandmasterIdentity.ClockIdentityLower); +#endif + + /** we have found a better master! */ + NewMaster = 1; + + /** Next compare stepsRemoved */ + } else if( AnnounceFrame->GrandmasterIdentity.ClockIdentityLower + == CurrentBmc->GrandmasterIdentity.ClockIdentityLower ) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: GMIDclockIDLo equal moving on: (0x%08x)\r\n", + AnnounceFrame->GrandmasterIdentity.ClockIdentityLower); +#endif + + if( AnnounceFrame->stepsRemoved < CurrentBmc->stepsRemoved ) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: Found new GM on stepsRemoved: Ann (%d) < Bmc (%d)\r\n", + AnnounceFrame->stepsRemoved, + CurrentBmc->stepsRemoved); +#endif + + /** we have found a better master! */ + NewMaster = 1; + + /** Next compare SourcePortIdentity */ + } else if( AnnounceFrame->stepsRemoved == CurrentBmc->stepsRemoved ) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: stepsRemoved equal moving on: (%d)\r\n", + AnnounceFrame->stepsRemoved); +#endif + + if( AnnounceFrame->SourcePortIdentity.ClockIdentityUpper < + CurrentBmc->SourcePortIdentity.ClockIdentityUpper) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: Found new GM on sourceIDClockIDupper: Ann (0x%08x) < Bmc (0x%08x)\r\n", + AnnounceFrame->SourcePortIdentity.ClockIdentityUpper, + CurrentBmc->SourcePortIdentity.ClockIdentityUpper); +#endif + + /** we have found a better master! */ + NewMaster = 1; + + } else if( AnnounceFrame->SourcePortIdentity.ClockIdentityUpper + == CurrentBmc->SourcePortIdentity.ClockIdentityUpper ) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: sourceIDportUp equal moving on: (0x%08x)\r\n", + CurrentBmc->SourcePortIdentity.ClockIdentityUpper); +#endif + + if( AnnounceFrame->SourcePortIdentity.ClockIdentityLower < + CurrentBmc->SourcePortIdentity.ClockIdentityLower ) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: Found new GM on sourceIDClockIDlow: Ann (0x%08x) < Bmc (0x%08x)\r\n", + AnnounceFrame->SourcePortIdentity.ClockIdentityLower, + CurrentBmc->SourcePortIdentity.ClockIdentityLower); +#endif + + /** we have found a better master! */ + NewMaster = 1; + + /** If all else fails, the SourcePortIdentity Port Number must + * act as the tie-breaker */ + } else if( AnnounceFrame->SourcePortIdentity.PortNumber < + CurrentBmc->SourcePortIdentity.PortNumber ) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: Found new GM on sourceIDportNum: AnnPort (0x%08x) < BmcPort (0x%08x)\r\n", + AnnounceFrame->SourcePortIdentity.PortNumber, + CurrentBmc->SourcePortIdentity.PortNumber); +#endif + + /** A new master has won on the tie-break! */ + NewMaster = 1; + } + } + } + } + } + } + } + } + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("*** END BMCA ***\r\n"); +#endif + + return NewMaster; + +} + + +/****************************************************************************/ +/** +* +* This function will accept the data pointer to the current BMCA records, accept +* an equivalent pointer to a new (winning) Grand Masters Announce Packet +* information. The CurrentBmc data structure is then updated with the +* information from the NewMaster. +* +* @param NewMaster is a pointer to a suitable data structure which has recorded +* the relevent Announce Packet fields of the new (winning) Grand Master. +* @param CurrentBmc is a pointer to a suitable data structure which has +* recorded the current fields of the current Grand Master's Announce +* Packet. +* +* @return The CurrentBmc data structure is updated. +* +* @note None. +* +*****************************************************************************/ +void XAvb_UpdateBmcRecords(XAvb_BmcData* NewMaster, + XAvb_BmcData* CurrentBmc) { + + CurrentBmc->SourcePortIdentity.ClockIdentityUpper = + NewMaster->SourcePortIdentity.ClockIdentityUpper; + + CurrentBmc->SourcePortIdentity.ClockIdentityLower = + NewMaster->SourcePortIdentity.ClockIdentityLower; + + CurrentBmc->SourcePortIdentity.PortNumber = + NewMaster->SourcePortIdentity.PortNumber; + + CurrentBmc->GrandmasterIdentity.ClockIdentityUpper = + NewMaster->GrandmasterIdentity.ClockIdentityUpper; + + CurrentBmc->GrandmasterIdentity.ClockIdentityLower = + NewMaster->GrandmasterIdentity.ClockIdentityLower; + + + CurrentBmc->stepsRemoved = NewMaster->stepsRemoved; + CurrentBmc->ClockQuality = NewMaster->ClockQuality; + CurrentBmc->GrandmasterPriority1 = NewMaster->GrandmasterPriority1; + CurrentBmc->GrandmasterPriority2 = NewMaster->GrandmasterPriority2; + +} + + +/****************************************************************************/ +/** +* +* This function will make any adjustments needed when the node becomes the Grand +* Master, including resetting the RTC to its nominal value +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @param txAnnounceHasWon indicates that this function has been called from +* the function XAvb_DecodeTxAnnounceFrame(). Is this is set then this +* function has no need to repeat actions that have been already performed. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_BecomeRtcMaster(XAvb *InstancePtr, + u8 txAnnounceHasWon) { + + XAvb_BmcData deviceData; + + if (txAnnounceHasWon == 0) { + /** + * Update the BMCA records to this device's information + */ + + /** Read the attributes in the Tx PTP buffer */ + XAvb_ReadAnnounceFrame(InstancePtr->Config.BaseAddress, + (XAVB_PTP_TX_ANNOUNCE_OFFSET + 8), + &deviceData); + + /** Update records */ + XAvb_UpdateBmcRecords(&deviceData, + &InstancePtr->CurrentBmc); + } + + /** reset the RTC to a nominal value */ + XAvb_WriteReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_INCREMENT_OFFSET, + XAVB_RTC_INCREMENT_NOMINAL_RATE); + + /** set timestamp uncertainty if new status */ + if( !InstancePtr->CurrentBmc.IAmTheRtcMaster ) { + xil_printf("\r\n*** I am now the Grand Master ***"); + xil_printf("\r\nNOTICE: timestamps are now certain\r\n"); + InstancePtr->GMDiscHandler(InstancePtr->GMDiscCallBackRef, + 0); + } + + /** inform the rest of the system */ + InstancePtr->CurrentBmc.IAmTheRtcMaster = 1; + +} + +/****************************************************************************/ +/** +* +* This function will make any adjustments needed when the node becomes a PTP slave +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_BecomeRtcSlave(XAvb *InstancePtr) { + + /** set timestamp uncertainty if new status */ + if( InstancePtr->CurrentBmc.IAmTheRtcMaster ) { + xil_printf("\r\n*** I am now a PTP slave ***"); + xil_printf("\r\nNOTICE: timestamps are now uncertain\r\n"); + InstancePtr->GMDiscHandler(InstancePtr->GMDiscCallBackRef, + 1); + } + + /* Reset the syncReceiptTimeoutTimeInterval counter as this has now changed purpose + */ + InstancePtr->PtpCounters.CounterSyncInterval = 0; + + /* inform the rest of the system */ + InstancePtr->CurrentBmc.IAmTheRtcMaster = 0; + + +} + +/****************************************************************************/ +/** +* +* Operations needed when PTP locks or unlocks +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* @param locked is 1 if changing to locked status, zero if unlocked +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_ChangePTPLockStatus(XAvb *InstancePtr, u8 locked) { + u32 lockedOld; + u32 tu = 0; + + lockedOld = InstancePtr->PTPLocked; + + /** set status variable */ + InstancePtr->PTPLocked = locked; + + /** set timestamp uncertainty if necessary */ + if( InstancePtr->PTPLocked != lockedOld ) { + XAvb_ChangePeerASCapability(InstancePtr, locked); + +#ifdef XAVB_DEBUG_LEVEL2 + if (locked == 0) { + xil_printf("\r\nXAvb_ChangePTPLockStatus():The peer is no longer ASCapable "); + xil_printf("\r\nXAvb_ChangePTPLockStatus():locked = %d\r\n",locked); + } +#endif + + tu = InstancePtr->PTPLocked ? 0 : 1; + xil_printf("\r\nXAvb_ChangePTPLockStatus()::"); + xil_printf("\r\nNOTICE: timestamps are now %s\r\n", tu ? "uncertain" : "certain"); + InstancePtr->GMDiscHandler(InstancePtr->GMDiscCallBackRef, + tu); + } + +} + +/****************************************************************************/ +/** +* +* Operations needed when the peer's AS capability changes +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* @param capable is 1 if the peer is ASCapable, 0 otherwise +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_ChangePeerASCapability(XAvb *InstancePtr, u8 capable) { + u32 capableOld; + + capableOld = InstancePtr->PeerASCapable; + + /* set status variable */ + InstancePtr->PeerASCapable = capable; + + if( capable != capableOld ) { + if( capable ) { + xil_printf("\r\nThe Peer is now AS Capable\r\n"); + } else { + xil_printf("\r\nThe Peer is no longer AS Capable\r\n"); + } + } + +} + +/****************************************************************************/ +/** +* +* This function sets the handler that will be called when a GM discontinuity +* event is identified by the driver. The purpose of the handler is to allow +* application specific processing to be performed. +* +* @param InstancePtr is a pointer to the XAvb instance. +* @param FuncPtr is the pointer to the callback function. +* @param CallBackRef is the upper layer callback reference passed back +* when the callback function is invoked. +* +* @return None. +* +* @note There is no assert on the CallBackRef since the driver doesn't +* know what it is (nor should it) +* +*****************************************************************************/ +void XAvb_SetGMDiscontinuityHandler(XAvb *InstancePtr, + XAvb_Handler FuncPtr, void *CallBackRef) +{ + /* + * Assert validates the input arguments + * CallBackRef not checked, no way to know what is valid + */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(FuncPtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + InstancePtr->GMDiscHandler = FuncPtr; + InstancePtr->GMDiscCallBackRef = CallBackRef; +} diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_ptp_packets.c b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_ptp_packets.c new file mode 100644 index 00000000..110a3c7d --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_ptp_packets.c @@ -0,0 +1,1742 @@ +/****************************************************************************** +* +* Copyright (C) 2008 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xavb_ptp_packets.c +* +* The XAvb driver. Functions in this file all contain functions which decode the +* received Precise Timing Protocol (PTP) frames, or to format and transmit PTP +* frames. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -----------------------------------------------
+* 1.00a mbr  09/19/08 First release
+* 1.01a mbr  06/24/09 PTP frame format updates for IEEE802.1 AS draft 5-0
+* 2_02a mbr  09/16/09 Updates for programmable PTP timers
+* 2_04a kag  07/23/10 PTP frame format updates for IEEE802.1 AS draft 6-7
+* 3_01a kag  08/29/11 Added new APIs to update the RX Filter Control Reg.
+*		      Fix for CR:572539. Updated bit map for Rx Filter
+*		      control reg.
+*
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xil_types.h" +#include "xavb_hw.h" +#include "xavb.h" +#include "stdlib.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Variable Definitions *****************************/ + +/************************** Function Prototypes ******************************/ + +/*****************************************************************************/ + +/****************************************************************************/ +/** +* +* A function to compare two ClockIdentity values. +* +* @param BaseAddress is the base address of the device +* @param Identity1 is the first ClockIdentity to be compared +* @param Identity2 is the second ClockIdentity to be compared +* +* @return 1 if the two values are equal, 0 if not equal +* +* @note +* +*****************************************************************************/ +u32 XAvb_CompareClockIdentity(u32 BaseAddress, + XAvb_ClockIdentity Identity1, + XAvb_ClockIdentity Identity2) { + + if( Identity1.ClockIdentityUpper != Identity2.ClockIdentityUpper ) { + /*xil_printf("ID1Upper (0x%08x) != ID2Upper (0x%08x)\r\n", + Identity1.ClockIdentityUpper, + Identity2.ClockIdentityUpper);*/ + return 0; + } + if( Identity1.ClockIdentityLower != Identity2.ClockIdentityLower ) { + /*xil_printf("ID1Lower (0x%08x) != ID2Lower (0x%08x)\r\n", + Identity1.ClockIdentityLower, + Identity2.ClockIdentityLower);*/ + return 0; + } + + /** values are equal */ + return 1; +} + +/****************************************************************************/ +/** +* +* A function to compare two PortIdentity values. +* +* @param BaseAddress is the base address of the device +* @param Identity1 is the first sourcePortIdentity to be compared +* @param Identity2 is the second sourcePortIdentity to be compared +* +* @return 1 if the two values are equal, 0 if not equal +* +* @note None. +* +*****************************************************************************/ +u32 XAvb_ComparePortIdentity(u32 BaseAddress, + XAvb_PortIdentity Identity1, + XAvb_PortIdentity Identity2) { + + if( Identity1.ClockIdentityUpper != Identity2.ClockIdentityUpper ) { + /*xil_printf("ID1Upper (0x%08x) != ID2Upper (0x%08x)\r\n", + Identity1.ClockIdentityUpper, + Identity2.ClockIdentityUpper);*/ + return 0; + } + if( Identity1.ClockIdentityLower != Identity2.ClockIdentityLower ) { + /*xil_printf("ID1Lower (0x%08x) != ID2Lower (0x%08x)\r\n", + Identity1.ClockIdentityLower, + Identity2.ClockIdentityLower);*/ + return 0; + } + if( Identity1.PortNumber != Identity2.PortNumber ) { + /*xil_printf("ID1Port (0x%08x) != ID2Port (0x%08x)\r\n", + Identity1.PortNumber, + Identity2.PortNumber);*/ + return 0; + } + + /** values are equal */ + return 1; +} + +/****************************************************************************/ +/** +* +* A function to extract portIdentity information from a received PTP frame. +* This can be any portIdentity field (header portIdentity, requestingPortIdentity, +* etc.) +* +* @param BaseAddress is the base address of the device +* @param PtpFrameBaseAddr is the base address of the received Announce Packet +* in the Rx PTP Packet Buffer +* @param PortIdOffset is the packet offset of the first byte of the portIdentity +* field to be parsed +* @param portID is the XAvb_PortIdentity struct that the data will be written to. +* +* @return None, but portID will be updated with the portIdentity information +* +* @note None. +* +*****************************************************************************/ +void XAvb_GetPortIdentity(u32 BaseAddress, u32 PtpFrameBaseAddr, + u32 PortIdOffset, XAvb_PortIdentity *portID) { + + u32 ReadWord; + + ReadWord = XAvb_ReorderWord(XAvb_ReadPtpBuffer(BaseAddress, PtpFrameBaseAddr, PortIdOffset)); + + portID->ClockIdentityUpper = (ReadWord << 16); + + ReadWord = XAvb_ReorderWord(XAvb_ReadPtpBuffer(BaseAddress, PtpFrameBaseAddr, PortIdOffset + 4)); + + portID->ClockIdentityUpper |= (ReadWord >> 16); + portID->ClockIdentityLower = (ReadWord << 16); + + ReadWord = XAvb_ReorderWord(XAvb_ReadPtpBuffer(BaseAddress, PtpFrameBaseAddr, PortIdOffset + 8)); + + portID->ClockIdentityLower |= (ReadWord >> 16); + portID->PortNumber = ReadWord; + +} + +/****************************************************************************/ +/** +* +* A function to write common data (eg the Source Address) to all PTP frames +* stored in the Tx PTP Packet buffer +* +* @param BaseAddress is the base address of the device +* @param PtpFieldAddress is the offset address of the relevant field in PTP +* frames. +* @param Data is the common data to be written to all Tx PTP frame templates +* @param DataBitEnable allows only selected bits of the 32-bit Data word to +* be modified. +* @param BufferEnable allows the selected buffer to be seleced: there are 8 +* PTP buffers - these are encoded as one-hot. For example, 0x3F will +* write the selected data to the first 6 buffers only. +* +* @return None. But the Tx PTP Packet Buffer is written to as requested +* +* @note None. +* +*****************************************************************************/ +void XAvb_WriteToMultipleTxPtpFrames(u32 BaseAddress, + u32 PtpFieldAddress, + u32 Data, + u32 DataBitEnable, + u8 BufferEnable) { + u32 PtpBufferPointer = 0; + u32 LocalData = 0; + u32 LocalAddr = 0; + + /** Write to all 8 PTP frame templates */ + for (PtpBufferPointer= 0; PtpBufferPointer < 8; PtpBufferPointer++) { + + /** Only write to selected buffers */ + if ( ((BufferEnable >> PtpBufferPointer) & 0x1) == 0x1) { + + LocalAddr = (PtpBufferPointer<<8) + XAVB_PTP_TX_SYNC_OFFSET; + + /** Read the current value */ + LocalData = XAvb_ReadPtpBuffer(BaseAddress, + LocalAddr, + PtpFieldAddress); + + /** Only change the selected data bits */ + LocalData = LocalData | (Data & DataBitEnable); + + /** Write the updated value */ + XAvb_WritePtpBuffer(BaseAddress, + LocalAddr, + PtpFieldAddress, + LocalData); +#ifdef DEBUG_XAVB_LEVEL3 + xil_printf("\r\nWriteToMultipleTxPtpFrames read/mod(PtpBufferPointer = %x) ", PtpBufferPointer); + xil_printf("\r\n PTPAddress = %x ", LocalAddr); + xil_printf("\r\n PtpFieldAddress = %x ", PtpFieldAddress); + xil_printf("\r\n LocalData = %x ", LocalData); +#endif + } + } +} + + +/****************************************************************************/ +/** +* +* This function switches the bytes in a 4-byte word, swapping the MSB for the +* LSB, and vice-versa. +* +* @param Data is the 4-byte input data word +* +* @return The input data word with the bytes swapped (most significant down to +* least significant +* +* @note None. +* + +*****************************************************************************/ +u32 XAvb_ReorderWord(u32 Data) { + u32 ReOrder = 0; + + ReOrder = (Data & 0x000000FF) << 24; + ReOrder = ReOrder | ((Data & 0x0000FF00) << 8); + ReOrder = ReOrder | ((Data & 0x00FF0000) >> 8); + ReOrder = ReOrder | ((Data & 0xFF000000) >> 24); + return ReOrder; +} + + +/****************************************************************************/ +/** +* +* A function to increment the sequenceId in a PTP frame template +* +* @param BaseAddress is the base address of the device +* @param PtpFrameBaseAddress is the base address of the TX PTP Buffer whose +* SequenceID is to be incremented +* +* @return None. But the relevant TX PTP Packet Buffer is written to with the +* updated SequenceID +* +* @note None. +* +*****************************************************************************/ +u32 XAvb_IncSequenceId(u32 BaseAddress, u32 PtpFrameBaseAddress) { + u32 BufferWord = 0; + u32 SequenceId = 0; + + /** Read the 32-bit BufferWord containing the SequenceId from the PTP buffer */ + BufferWord = XAvb_ReadPtpBuffer(BaseAddress, + PtpFrameBaseAddress, + XAVB_PTP_TX_PKT_SEQUENCEID_OFFSET); + + /** Swap byte order into correct binary and increment the SequenceId */ + SequenceId = XAvb_ReorderWord(BufferWord) + 0x10000; + + /** Swap back the byte order into frame storage order */ + SequenceId = XAvb_ReorderWord(SequenceId); + + /** Write the 32-bit BufferWord variable containing the updated SequenceId */ + XAvb_WritePtpBuffer(BaseAddress, + PtpFrameBaseAddress, + XAVB_PTP_TX_PKT_SEQUENCEID_OFFSET, + SequenceId); + + return SequenceId; + +} + + +/****************************************************************************/ +/** +* +* The software drivers are kept simple by only requesting a single PTP frame to +* be transmitted at a time. This function checks (and if necessary waits) +* until the previously request PTP frame has been transmitted. +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @return None. +** +* @note None. +* +*****************************************************************************/ +void XAvb_WaitOnTxPtpQueue(XAvb * InstancePtr) { + u32 TxPtpType = 0; + + do { + + /** Wait until any queued PTP frame has been transmitted. This is a + * software safety feature, not a hardware restriction */ + TxPtpType = (XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_CONTROL_OFFSET) + & XAVB_PTP_TX_WAIT_ALL_FRAMES_MASK); + + } while(TxPtpType != 0); + +} + + +/****************************************************************************/ +/** +* +* A function to format then request the transmission of a PTP Announce Packet +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @return None. But the relevant Tx PTP Packet Buffer is written to with the +* updated PTP fields, and then the Tx PTP Packet Buffer Control +* Register is written to request the frame transmission. +* +* @note None. +* +*****************************************************************************/ +void XAvb_MasterSendAnnounce(XAvb * InstancePtr) { + u32 Unused = 0; + + + /** Wait until there are no PTP frames to be transmitted */ + XAvb_WaitOnTxPtpQueue(InstancePtr); + + /** Increment the sequenceId */ + Unused = XAvb_IncSequenceId(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_ANNOUNCE_OFFSET); + +#ifdef DEBUG_XAVB_LEVEL3 + xil_printf("\r\n--------------------------------"); + xil_printf("\r\n---XAvb_MasterSendAnnounce()----"); + xil_printf("\r\n--------------------------------"); + xil_printf("\r\nsequenceId is %x", Unused); + Unused = XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_NANOSEC_VALUE_OFFSET); + Unused = XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_SEC_LOWER_VALUE_OFFSET); + xil_printf("\r\nSeconds %d", Unused); +#endif + + /** Send the Announce Frame! */ + XAvb_WriteReg(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_CONTROL_OFFSET, + XAVB_PTP_TX_SEND_ANNOUNCE_FRAME_MASK); +} + + +/****************************************************************************/ +/** +* +* A function to format then request the transmission of a PTP Sync Packet +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @return None. But the relevant Tx PTP Packet Buffer is written to with the +* updated PTP fields, and then the Tx PTP Packet Buffer Control +* Register is written to request the frame transmission. +* +* @note None. +* +*****************************************************************************/ +void XAvb_MasterSendSync(XAvb * InstancePtr) { + u32 Epoch = 0; + u32 Sec = 0; + u32 SequenceId = 0; + u32 BufferWord = 0; + + /** Wait until there are no PTP frames to be transmitted */ + XAvb_WaitOnTxPtpQueue(InstancePtr); + + /** Increment the sequenceId in the Sync frame */ + SequenceId = XAvb_IncSequenceId(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_SYNC_OFFSET); + + /** Read the current RTC Offset values */ + InstancePtr->PtpRecords.Nanosec + = XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_NANOSEC_VALUE_OFFSET); + + Sec = XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_SEC_LOWER_VALUE_OFFSET); + + Epoch = XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_SEC_UPPER_VALUE_OFFSET); + + /** Send the Sync Frame! */ + XAvb_WriteReg(InstancePtr->Config.BaseAddress, XAVB_PTP_TX_CONTROL_OFFSET, + XAVB_PTP_TX_SEND_SYNC_FRAME_MASK); + + + /** Now some pre-work on the Follow-Up Frame + *----------------------------------------- + * + * Write the same sequenceId to the Follow-up frame */ + BufferWord = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_SEQUENCEID_OFFSET); + + BufferWord = (BufferWord & 0xFFFF0000) | (SequenceId & 0x0000FFFF); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_SEQUENCEID_OFFSET, + BufferWord); + + + /** Format the Timestamp (RTC) into correct byte positioning. + * Note: this is how the Timestamp is stored in + * the PTP frame itself (transmitted MSB of Epoch first): + * + * |----------------|----------------|----------------|----------------| + * | seconds[23:16] | seconds[31:24] | epoch[7:0] | epoch[15:8] | + * |----------------|----------------|----------------|----------------| + * | nanosec[23:16] | nanosec[31:24] | seconds[7:0] | seconds[15:8] | + * |----------------|----------------|----------------|----------------| + * | 0's | 0's | nanosec[7:0] | nanosec[15:8] | + * |----------------|----------------|----------------|----------------| + */ + + BufferWord = XAvb_ReorderWord((Epoch<<16) | (Sec>>16)); + + /** Write the Timestamp (RTC) to the Follow-up frame */ + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_TIMESTAMP_UPPER_OFFSET, + BufferWord); + + BufferWord = XAvb_ReorderWord((Sec<<16) | + (InstancePtr->PtpRecords.Nanosec>>16)); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_TIMESTAMP_MID_OFFSET, + BufferWord); + + BufferWord = XAvb_ReorderWord(InstancePtr->PtpRecords.Nanosec<<16); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_TIMESTAMP_LOWER_OFFSET, + BufferWord); + +#ifdef DEBUG_XAVB_LEVEL3 + xil_printf("\r\n--------------------------------"); + xil_printf("\r\n-----XAvb_MasterSendSync()------"); + xil_printf("\r\n--------------------------------"); + xil_printf("\r\n--------------RTC---------------"); + xil_printf("\r\nRTC nanosec field is %x", InstancePtr->PtpRecords.Nanosec); + xil_printf("\r\nRTC seconds field is %x", Sec); + xil_printf("\r\nRTC epoch field is %x", Epoch); + xil_printf("\r\n--------------------------------"); + xil_printf("\r\nsequenceId is %x", SequenceId); +#endif + +} + + + +/****************************************************************************/ +/** +* +* A function to format then request the transmission of a PTP Follow-Up Packet +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @return None. But the relevant Tx PTP Packet Buffer is written to with the +* updated PTP fields, and then the Tx PTP Packet Buffer Control +* Register is written to request the frame transmission. +* +* @note None. +* +*****************************************************************************/ +void XAvb_MasterSendFollowUp(XAvb * InstancePtr) { + u32 Timestamp = 0; + u32 NsOffset = 0; + u32 CorrectionField = 0; + u32 BufferWord = 0; + + /** Wait until there are no PTP frames to be transmitted */ + XAvb_WaitOnTxPtpQueue(InstancePtr); + + /** Read the current RTC offset */ + NsOffset = XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_NANOSEC_OFFSET); + + /** Read the Timestamp and adjust it for the MAC transmit latency */ + Timestamp = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_SYNC_OFFSET, + XAVB_PTP_PKT_CAPTURED_TIMESTAMP_OFFSET) + + XAVB_TX_MAC_LATENCY_IN_NS; + + /** Adjust the Timestamp with current RTC ns offset */ + Timestamp = Timestamp + NsOffset; + if (Timestamp >= XAVB_ONE_SECOND) { + Timestamp = Timestamp - XAVB_ONE_SECOND; + } + + /** Calculate the Correction Field */ + CorrectionField = Timestamp - InstancePtr->PtpRecords.Nanosec; + if (CorrectionField >= XAVB_ONE_SECOND) { + CorrectionField = CorrectionField + XAVB_ONE_SECOND; + } + + /** Format the Correction Field into correct byte positioning for PTP frame + * storage in the buffer + */ + BufferWord = XAvb_ReorderWord(CorrectionField); + + /** Write the Correction Field to the Follow Up frame */ + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_CORRECTION_FIELD_OFFSET, + BufferWord); + + /** Send the Follow Up Frame! */ + XAvb_WriteReg(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_CONTROL_OFFSET, + XAVB_PTP_TX_SEND_FOLLOWUP_FRAME_MASK); + +#ifdef DEBUG_XAVB_LEVEL3 + xil_printf("\r\n--------------------------------"); + xil_printf("\r\n---XAvb_MasterSendFollowUp()----"); + xil_printf("\r\n--------------------------------"); + xil_printf("\r\nTimestamp is %x", Timestamp); + xil_printf("\r\nRTC nano seconds field is %x", + InstancePtr->PtpRecords.Nanosec); + xil_printf("\r\nCorrection Field %x", CorrectionField); +#endif + +} + + + +/****************************************************************************/ +/** +* +* A function to format then request the transmission of a PTP PDelay Request +* Packet +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @return None. But the relevant Tx PTP Packet Buffer is written to with the +* updated PTP fields, and then the Tx PTP Packet Buffer Control +* Register is written to request the frame transmission. +* +* @note None. +* +*****************************************************************************/ +void XAvb_SendPDelayReq(XAvb * InstancePtr) { + u32 SequenceId; + + /** Wait until there are no PTP frames to be transmitted */ + XAvb_WaitOnTxPtpQueue(InstancePtr); + + /** Increment the SequenceId */ + SequenceId = XAvb_IncSequenceId(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYREQ_OFFSET) + & 0x0000FFFF; + +#ifdef DEBUG_XAVB_LEVEL3 + xil_printf("\r\n--------------------------------"); + xil_printf("\r\n------XAvb_SendPDelayReq()------"); + xil_printf("\r\n--------------------------------"); + xil_printf("\r\nsequenceId is %x", SequenceId); +#endif + + /** Send the PDelayReq Frame! */ + XAvb_WriteReg(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_CONTROL_OFFSET, + XAVB_PTP_TX_SEND_PDELAYREQ_FRAME_MASK); + + /** Wait for the frame to be transmitted */ + XAvb_WaitOnTxPtpQueue(InstancePtr); + + /** Capture the Timestamp for Tx of PDelayReq (t1) and adjust it for MAC + * transmit latency */ + InstancePtr->PtpRecords.PDelayTimestampT1 + = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYREQ_OFFSET, + XAVB_PTP_PKT_CAPTURED_TIMESTAMP_OFFSET) + + XAVB_TX_MAC_LATENCY_IN_NS; + + /** Capture the SequenceID of the the PDelayReq */ + InstancePtr->SequenceIdRecords.PDelayReqSequenceId = + XAvb_ReorderWord(XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYREQ_OFFSET, + XAVB_PTP_TX_PKT_SEQUENCEID_OFFSET)) >> 16; +} + + +/****************************************************************************/ +/** +* +* A function to format then request the transmission of a PTP PDelay Response +* Packet +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* @param PtpFrameBaseAddr is the base address of the received Announce Packet +* in the Rx PTP Packet Buffer +* +* @return None. But the relevant Tx PTP Packet Buffer is written to with the +* updated PTP fields, and then the Tx PTP Packet Buffer Control +* Register is written to request the frame transmission. +* +* @note None. +* +*****************************************************************************/ +void XAvb_SendPDelayResp(XAvb * InstancePtr, + u32 PtpFrameBaseAddr) { + u32 SequenceId = 0; + u32 TimestampT2 = 0; + u32 BufferWord = 0; + u32 NanoSec = 0; + u32 Seconds = 0; + u32 Epoch = 0; + u32 CopyPortId = 0; + u32 CopyPortId1 = 0; + + /** Wait until there are no PTP frames to be transmitted */ + XAvb_WaitOnTxPtpQueue(InstancePtr); + + /** Format the Timestamp + *--------------------- + * + * Capture the current Synchronised time */ + NanoSec = XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_NANOSEC_VALUE_OFFSET); + + Seconds = XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_SEC_LOWER_VALUE_OFFSET); + Epoch = XAvb_ReadReg(InstancePtr->Config.BaseAddress, + + XAVB_RTC_SEC_UPPER_VALUE_OFFSET); + + /** Read the current RTC offset */ + InstancePtr->PtpRecords.NsOffsetForPDelayResp = + XAvb_ReadReg(InstancePtr->Config.BaseAddress, XAVB_RTC_NANOSEC_OFFSET); + + /** Read the TimestampT2 for PDelayReq reception and adjust it for MAC + * receive latency */ + TimestampT2 = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_PKT_CAPTURED_TIMESTAMP_OFFSET) + - XAVB_RX_MAC_LATENCY_IN_NS; + + /** The TimestampT2 was captured using syntonised ns time. We need to + * convert this into synchronised time by adding on the current offset */ + TimestampT2 = TimestampT2 + InstancePtr->PtpRecords.NsOffsetForPDelayResp; + + /** Check for ns wrap-around condition */ + if (TimestampT2 >= XAVB_ONE_SECOND) { + TimestampT2 = TimestampT2 - XAVB_ONE_SECOND; + } + + /** Even though we read the RTC value at the beginning of this + * function, there would have been processing delay between the + * actual reception (and timestamping) of the PDelayReq frame and the + * start of this function. During this time, the RTC Seconds + * field could have wrapped around. We need to detect this and if it + * has done, the slave Seconds field would also have incremented (so + * it needs to be set back). + */ + if (NanoSec < TimestampT2) { + /** NanoSec has wrapped since timestamp was taken so decrement the + * Seconds field */ + if (Seconds == 0x00000000) { + Epoch = Epoch - 0x1; + } + Seconds = Seconds - 0x1; + } + + /** Format the Timestamp (t2) into correct byte positioning for PTP frame + * storage, then write the Timestamp (t2) to the PDelayResp frame + */ + BufferWord = XAvb_ReorderWord((Epoch<<16) | (Seconds>>16)); + + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_OFFSET, + XAVB_PTP_TX_PKT_TIMESTAMP_UPPER_OFFSET, + BufferWord); + + BufferWord = XAvb_ReorderWord((Seconds<<16) | (TimestampT2>>16)); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_OFFSET, + XAVB_PTP_TX_PKT_TIMESTAMP_MID_OFFSET, + BufferWord); + + BufferWord = XAvb_ReorderWord(TimestampT2<<16); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_OFFSET, + XAVB_PTP_TX_PKT_TIMESTAMP_LOWER_OFFSET, + BufferWord); + + + /** Format the SequenceId + *---------------------- + * + * Set the SequenceId in the PDelayResp and PDelayRespFollowUp frame to be + * that of the received PDelayReq frame */ + SequenceId = (XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_SEQUENCEID_OFFSET)) + & 0x0000FFFF; + + BufferWord = XAVB_PDELAY_LOG_MEAN_MESSAGE_INT | SequenceId; + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_OFFSET, + XAVB_PTP_TX_PKT_SEQUENCEID_OFFSET, + BufferWord); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_SEQUENCEID_OFFSET, + BufferWord); + + + /** Format the sourcePortIdentity + *------------------------------ + * + * Copy the sourcePortIdentity field from the PDelayReq into the PDelayResp + * and PDelayRespFollowUp frame + */ + CopyPortId = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_PORTID_UPPER_OFFSET); + + CopyPortId &= 0xffff0000; + CopyPortId1 = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_OFFSET, + XAVB_PTP_TX_PKT_REQ_PORTID_UPPER_OFFSET); + + CopyPortId |= (CopyPortId1 & 0x0000ffff); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_OFFSET, + XAVB_PTP_TX_PKT_REQ_PORTID_UPPER_OFFSET, + CopyPortId); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_REQ_PORTID_UPPER_OFFSET, + CopyPortId); + + CopyPortId = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_PORTID_MID_OFFSET); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_OFFSET, + XAVB_PTP_TX_PKT_REQ_PORTID_MID_OFFSET, + CopyPortId); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_REQ_PORTID_MID_OFFSET, + CopyPortId); + + CopyPortId = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_PORTID_LOWER_OFFSET); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_OFFSET, + XAVB_PTP_TX_PKT_REQ_PORTID_LOWER_OFFSET, + CopyPortId); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_REQ_PORTID_LOWER_OFFSET, + CopyPortId); + + + /** Send the PDelayResp Frame! + *---------------------------*/ + + XAvb_WriteReg(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_CONTROL_OFFSET, + XAVB_PTP_TX_SEND_PDELAYRESP_FRAME_MASK); + +#ifdef DEBUG_XAVB_LEVEL3 + xil_printf("\r\n--------------------------------"); + xil_printf("\r\n------XAvb_SendPDelayResp()-----"); + xil_printf("\r\n--------------------------------"); + xil_printf("\r\nTimestampT2 is %x", TimestampT2); +#endif + +} + + +/****************************************************************************/ +/** +* +* A function to format then request the transmission of a PTP PDelay Response +* Follow-Up Packet +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @return None. But the relevant Tx PTP Packet Buffer is written to with the +* updated PTP fields, and then the Tx PTP Packet Buffer Control +* Register is written to request the frame transmission. +* +* @note None. +* +*****************************************************************************/ +void XAvb_SendPDelayRespFollowUp(XAvb * InstancePtr) { + u32 TimestampT3 = 0; + u32 BufferWordA = 0; + u32 BufferWordB = 0; + XAvb_RtcFormat Rtc[1]; + + /** Wait until there are no PTP frames to be transmitted */ + XAvb_WaitOnTxPtpQueue(InstancePtr); + + /** Format the Timestamp + *---------------------*/ + + /** Capture the current Synchronised time */ + XAvb_ReadRtc(InstancePtr->Config.BaseAddress, Rtc); + + + /** Read the TimestampT3 for PDelayResp transmission and adjust it for MAC + * transmit latency */ + TimestampT3 = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_OFFSET, + XAVB_PTP_PKT_CAPTURED_TIMESTAMP_OFFSET) + + XAVB_TX_MAC_LATENCY_IN_NS; + + /** The TimestampT3 was captured using syntonised ns time. We need to + * convert this into synchronised time by adding on the ns offset. We + * use the same offset here as for the PDelayResp frame since if a + * ns offset change had been made between PDelayResp and , + * PDelayRespFollowUp, this would result in an error in the link delay + * measurement. */ + TimestampT3 = TimestampT3 + InstancePtr->PtpRecords.NsOffsetForPDelayResp; + + /** Check for ns wrap-around condition */ + if (TimestampT3 >= XAVB_ONE_SECOND) { + TimestampT3 = TimestampT3 - XAVB_ONE_SECOND; + } + + /** Even though we read the RTC value at the beginning of this + * function, there would have been processing delay between the + * actual reception (and timestamping) of the PDelayReq frame and the + * start of this function. During this time, the RTC seconds + * field could have wrapped around. We need to detect this and if it + * has done, the slave seconds field would also have incremented (so + * it needs to be set back). + */ + if (Rtc->NanoSeconds < TimestampT3) { + /** nanosec has wrapped since timestamp was taken so decrement the + * seconds field */ + if (Rtc->SecondsLower == 0x00000000) { + Rtc->SecondsUpper = Rtc->SecondsUpper - 0x1; + } + Rtc->SecondsLower = Rtc->SecondsLower - 0x1; + } + + /** Format the Timestamp (t3) into correct byte positioning for PTP frame + * storage, the write the Timestamp (t3) to the PDelayRespFollowUp frame + */ + BufferWordA = XAvb_ReorderWord((Rtc->SecondsUpper<<16) | + (Rtc->SecondsLower>>16)); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_TIMESTAMP_UPPER_OFFSET, + BufferWordA); + + BufferWordA = XAvb_ReorderWord((Rtc->SecondsLower<<16) | (TimestampT3>>16)); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_TIMESTAMP_MID_OFFSET, + BufferWordA); + + BufferWordA = XAvb_ReorderWord(TimestampT3<<16); + BufferWordB = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_TIMESTAMP_LOWER_OFFSET); + BufferWordA &= 0x0000ffff; + BufferWordA |= (BufferWordB & 0xffff0000); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_TIMESTAMP_LOWER_OFFSET, + BufferWordA); + + + /** Send the PDelayRespFollowUp Frame! + *----------------------------------- */ + + XAvb_WriteReg(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_CONTROL_OFFSET, + XAVB_PTP_TX_SEND_PDELAYRESPFOLLOWUP_FRAME_MASK); + +#ifdef DEBUG_XAVB_LEVEL3 + xil_printf("\r\n--------------------------------"); + xil_printf("\r\n--XAvb_SendPDelayRespFollowUp()-"); + xil_printf("\r\n--------------------------------"); + xil_printf("\r\nReading TimestampT3 from address %x", + (InstancePtr->Config.BaseAddress + XAVB_PTP_TX_PDELAYRESP_OFFSET + + XAVB_PTP_PKT_CAPTURED_TIMESTAMP_OFFSET)); + xil_printf("\r\nTimestampT3 is %x", TimestampT3); +#endif + +} + + +/****************************************************************************/ +/** +* +* A function to check that various fields in the received frame contain the +* expected values which define it as a valid AVB PTP frame. If this check does +* not pass then the frame should not be decoded and used. +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* @param PtpFrameBaseAddr is the base address of the received Announce Packet +* in the Rx PTP Packet Buffer +* +* @return An updated True/False decision as to whether this received frame +* really is a valid PTP type. +* +* @note None. +* +*****************************************************************************/ +u32 XAvb_IsRxFramePTP(XAvb * InstancePtr, + u32 PtpFrameBaseAddr) { + u32 FrameIsPTP; + u32 FrameField; + + /** Start by assuming that it is a valid PTP frame */ + FrameIsPTP = 1; + + /** Perform a 32-bit read from the relevant position in the frame */ + FrameField = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_TYPE_OFFSET); + + FrameField = XAvb_ReorderWord(FrameField); + + /** Check the Length/Type field for a valid Ethertype */ + if ((FrameField >>16) != XAVB_PTP_ETHERTYPE) { + FrameIsPTP = 0; +#ifdef DEBUG_XAVB_LEVEL1 + xil_printf("\r\nXAvb_IsRxFramePTP(): Bad Ethertype: %x", (FrameField >>16)); +#endif + } + + /** Check the versionPTP */ + if ((FrameField & 0xF) != XAVB_PTP_VERSION_PTP) { + FrameIsPTP = 0; +#ifdef DEBUG_XAVB_LEVEL1 + xil_printf("\r\nXAvb_IsRxFramePTP():Bad versionPTP:%x", (FrameField & 0xF)); +#endif + } + + return FrameIsPTP; + +} + + +/****************************************************************************/ +/** +* +* A function to decode a received PTP Sync Packet +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* @param PtpFrameBaseAddr is the base address of the received Announce Packet +* in the Rx PTP Packet Buffer +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_DecodeRxSync(XAvb * InstancePtr, + u32 PtpFrameBaseAddr) { + + u32 ReadWord = 0; + XAvb_PortIdentity syncPortID; + + /** Read sourcePortIdentity from packet */ + XAvb_GetPortIdentity(InstancePtr->Config.BaseAddress, PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_PORTID_UPPER_OFFSET, &syncPortID); + + /** Only decode if configured for a slave and if SourcePortID is that of the + * RTC Clock Master */ + if ( (InstancePtr->CurrentBmc.IAmTheRtcMaster == 0) && + XAvb_ComparePortIdentity(InstancePtr->Config.BaseAddress, + InstancePtr->CurrentBmc.SourcePortIdentity, + syncPortID) ) { + + /** Reset Sync Interval Counter as we have received a valid Sync */ + InstancePtr->PtpCounters.CounterSyncInterval = 0; + + /** Capture the local Timestamp for receipt of this frame and adjust it for + * MAC receive latency */ + InstancePtr->PtpRecords.SlaveSyncTimestamp + = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_PKT_CAPTURED_TIMESTAMP_OFFSET) + - XAVB_RX_MAC_LATENCY_IN_NS; + + /** Capture the Sync SequenceID */ + ReadWord = XAvb_ReorderWord(XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_SEQUENCEID_OFFSET)); + InstancePtr->SequenceIdRecords.SyncSequenceId = (ReadWord >> 16); + + /** Capture the logMeanMessageInterval and convert into a useful duration + * (NOTE: there is an implicit conversion from u32 to char here) + */ + InstancePtr->latestMDSyncReceive.logMessageInterval = ReadWord & 0x000000ff; + InstancePtr->latestMDSyncReceive.SyncIntervalDuration = + XAvb_ConvertLogMeanToDuration(InstancePtr->latestMDSyncReceive.logMessageInterval); + + /** We don't need to capture the correction field - unless we want to check that it is 0.*/ + + } else { + xil_printf("\r\nXAvb_DecodeRxSync()"); + xil_printf("\r\nSync ignored due to unmatched SourcePortID"); +#ifdef DEBUG_XAVB_LEVEL1 + xil_printf("\r\nInstancePtr->CurrentBmc.SourcePortIdentity.ClockIdentityUpper = %x",InstancePtr->CurrentBmc.SourcePortIdentity.ClockIdentityUpper); + xil_printf("\r\nInstancePtr->CurrentBmc.SourcePortIdentity.ClockIdentityLower = %x",InstancePtr->CurrentBmc.SourcePortIdentity.ClockIdentityLower); + xil_printf("\r\nInstancePtr->CurrentBmc.SourcePortIdentity.PortNumber = %x\r\n",InstancePtr->CurrentBmc.SourcePortIdentity.PortNumber); + xil_printf("\r\nsyncPortID.ClockIdentityUpper = %x",syncPortID.ClockIdentityUpper); + xil_printf("\r\nsyncPortID.ClockIdentityLower = %x",syncPortID.ClockIdentityLower); + xil_printf("\r\nsyncPortID.PortNumber = %x\r\n",syncPortID.PortNumber); +#endif + } +} + + +/****************************************************************************/ +/** +* +* A function to decode a received PTP Follow-up Packet +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* @param PtpFrameBaseAddr is the base address of the received Announce Packet +* in the Rx PTP Packet Buffer +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_DecodeRxFollowUp(XAvb * InstancePtr, + u32 PtpFrameBaseAddr) { + + XAvb_PortIdentity followUpPortID; + + /** Read sourcePortIdentity from packet */ + XAvb_GetPortIdentity(InstancePtr->Config.BaseAddress, PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_PORTID_UPPER_OFFSET, &followUpPortID); + + /** Only decode if configured for a slave and if SA is that of the RTC + * Clock Master */ + if ( (InstancePtr->CurrentBmc.IAmTheRtcMaster == 0) && + XAvb_ComparePortIdentity(InstancePtr->Config.BaseAddress, + InstancePtr->CurrentBmc.SourcePortIdentity, + followUpPortID) ) { + + /** Capture the Follow Up SequenceID */ + InstancePtr->SequenceIdRecords.FollowUpSequenceId + = XAvb_ReorderWord(XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_SEQUENCEID_OFFSET)) + >> 16; + + /** SequenceID in Follow Up Frame should always match that of the + * Sync Frame */ + if (InstancePtr->SequenceIdRecords.FollowUpSequenceId + == InstancePtr->SequenceIdRecords.SyncSequenceId) { + + /** Capture the correction field from follow up frame */ + InstancePtr->PtpRecords.MasterCorrectionField + = XAvb_ReorderWord(XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_CORRECTION_FIELD_OFFSET)); + + /** Perform the Course RTC Offset correction for every Sync / + * FollowUp pair */ + XAvb_CalcRtcOffset(InstancePtr, + PtpFrameBaseAddr); + + /** Every n Sync / FollowUp pairs, we are going to calculate a + * corrected increment rate of RTC */ + if ((InstancePtr->PtpCounters.CounterSyncEvents & 0xF) + == (XAVB_NUM_SYNC_FU_PAIR_CALC_RTC_INCREMENT - 1)) { + + /** Reset the CounterSyncEvents Counter */ + InstancePtr->PtpCounters.CounterSyncEvents = 0x0; + + /** Capture the Sequence ID of the Follow Up frame */ + InstancePtr->SequenceIdRecords.NewSyncSequenceId + = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_SEQUENCEID_OFFSET); + + InstancePtr->SequenceIdRecords.NewSyncSequenceId + = (XAvb_ReorderWord + (InstancePtr->SequenceIdRecords.NewSyncSequenceId) + ) >> 16; + + /** Perform the RTC increment rate adjustment calculation */ + XAvb_UpdateRtcIncrement(InstancePtr); + + /** Sample Sync Frame Time sent (as estimated by the slave) for + * comparison in ten more repetition's time */ + InstancePtr->PtpRecords.OldSlaveTime + = InstancePtr->PtpRecords.NewSlaveTime; + + /** Sample Sync Frame Time sent (as calculated by the master) + * for comparison in ten more repetition's time */ + InstancePtr->PtpRecords.OldMasterTime + = InstancePtr->PtpRecords.NewMasterTime; + + /** Sample the current Follow Up Sequence ID for comparison in + * ten more repetition's time */ + InstancePtr->SequenceIdRecords.OldSyncSequenceId + = InstancePtr->SequenceIdRecords.NewSyncSequenceId; + + } else { + InstancePtr->PtpCounters.CounterSyncEvents + = InstancePtr->PtpCounters.CounterSyncEvents + 1; + } + } else { + xil_printf("SequenceIDs on RxFollowup don't match.\r\n"); + } + } else { + xil_printf("\r\nXAvb_DecodeRxFollowUp()"); + xil_printf("\r\nFollowUp ignored due to unmatched SourcePortID\r\n"); + } +} + + +/****************************************************************************/ +/** +* +* A function to decode a received PDelayResp Packet +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* @param PtpFrameBaseAddr is the base address of the received Announce Packet +* in the Rx PTP Packet Buffer +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_DecodeRxPDelayResp(XAvb * InstancePtr, + u32 PtpFrameBaseAddr) { + + /** Have we already seen a PDelayResp since the last + * PDelayReq was sent? If so, ignore the packet */ + if( InstancePtr->StateMachineData.rcvdPDelayResp ) { + xil_printf("Error: already saw a PDelayResp since the last PDelayReq was sent\r\n"); + return; + } + + /** Find the ClockIdentity of the Sender */ + XAvb_GetPortIdentity(InstancePtr->Config.BaseAddress, PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_PORTID_UPPER_OFFSET, + &InstancePtr->StateMachineData.respPortIdentity); + + /** Is the PDelayResp message from ourself? If so, the Peer + * is most likely a dumb hub and should be considered not + * ASCapable */ + if( XAvb_ComparePortIdentity(InstancePtr->Config.BaseAddress, + InstancePtr->portIdLocal, + InstancePtr->StateMachineData.respPortIdentity) ) { + + XAvb_ChangePeerASCapability(InstancePtr, 0); + + xil_printf("\r\nXAvb_DecodeRxPDelayResp():The peer is no longer ASCapable "); + xil_printf("\r\nXAvb_DecodeRxPDelayResp():Saw a PDelayResp from myself\r\n"); + return; + + } + + /** Capture the requestingPortIdentity */ + XAvb_GetPortIdentity(InstancePtr->Config.BaseAddress, PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_REQ_PORTID_UPPER_OFFSET, + &InstancePtr->StateMachineData.respReqPortIdentity); + + /** Capture the PDelayResp SequenceID */ + InstancePtr->SequenceIdRecords.PDelayRespSequenceId = + XAvb_ReorderWord(XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_SEQUENCEID_OFFSET)) >> 16; + + /** Verify that the requestingPortIdentity matches our + * portIdentity */ + if( !XAvb_ComparePortIdentity(InstancePtr->Config.BaseAddress, + InstancePtr->portIdLocal, + InstancePtr->StateMachineData.respReqPortIdentity) ) { + xil_printf("Error: PDelayResp reqPortID doesn't match our portID\r\n"); + return; + } + + /** Only process if the received frame's sequenceId matches + * the sequenceId sent in the last pDelay_Req packet */ + if( (InstancePtr->SequenceIdRecords.PDelayReqSequenceId == + InstancePtr->SequenceIdRecords.PDelayRespSequenceId) ) { + + /** Mark this as a valid PDelayResp packet */ + InstancePtr->StateMachineData.rcvdPDelayResp = 1; + + /** Capture timestamp for receipt time of PDelayReq at Master (t2) */ + InstancePtr->PtpRecords.PDelayTimestampT2 = + XAvb_CaptureNanoSec(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr); + + /** Capture timestamp for receipt time of PDelayResp at Slave (t4) and adjust + * it for MAC receive latency */ + InstancePtr->PtpRecords.PDelayTimestampT4 = + XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_PKT_CAPTURED_TIMESTAMP_OFFSET) + - XAVB_RX_MAC_LATENCY_IN_NS; + } else { + xil_printf("Error: PDelayResp seqID's don't match\r\n"); + } +} + + +/****************************************************************************/ +/** +* +* A function to decode a received PDelayRespFollowUp Packet +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* @param PtpFrameBaseAddr is the base address of the received Announce Packet +* in the Rx PTP Packet Buffer +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_DecodeRxPDelayRespFollowUp(XAvb * InstancePtr, + u32 PtpFrameBaseAddr) { + + XAvb_PortIdentity portId; + + /** Has a valid PDelayResp packet been received since the + * last PDelayReq packet was sent? */ + if( !InstancePtr->StateMachineData.rcvdPDelayResp ) { + /*xil_printf("Error: Received a PDelayRespFollowUp before receiving a PDelayResp\r\n");*/ + return; + } + + /** Capture the PDelayRespFollowUp SequenceID */ + InstancePtr->SequenceIdRecords.PDelayFollowUpSequenceId = + XAvb_ReorderWord(XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_SEQUENCEID_OFFSET)) >> 16; + + /** Get the sourcePortIdentity of the sender */ + XAvb_GetPortIdentity(InstancePtr->Config.BaseAddress, PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_PORTID_UPPER_OFFSET, + &portId); + + /** The sourcePortIdentity of the PDelayRespFollowUp should + * match that of the last PDelayResp packet received */ + if( !XAvb_ComparePortIdentity(InstancePtr->Config.BaseAddress, + portId, + InstancePtr->StateMachineData.respPortIdentity) ) { + xil_printf("Error: sourcePortIdentity of PDelayRespFollowUp doesn't match PDelayResp\r\n"); + return; + } + + /** Get the requestingPortIdentity of the sender */ + XAvb_GetPortIdentity(InstancePtr->Config.BaseAddress, PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_REQ_PORTID_UPPER_OFFSET, + &portId); + + /** The requestingPortIdentity of the PDelayRespFollowUp should + * match that of the last PDelayResp packet received */ + if( !XAvb_ComparePortIdentity(InstancePtr->Config.BaseAddress, + portId, + InstancePtr->StateMachineData.respReqPortIdentity) ) { + xil_printf("Error: reqPortID of PDelayRespFollowUp doesn't match PDelayResp\r\n"); + return; + } + + /** SequenceID of PDelayRespFollowUp Frame should always match that of + * the PDelayResp Frame and the original PDelayReq Frame. */ + if (InstancePtr->SequenceIdRecords.PDelayFollowUpSequenceId == + InstancePtr->SequenceIdRecords.PDelayRespSequenceId) { + + /** Mark this as a valid PDelayRespFollowUp packet */ + InstancePtr->StateMachineData.rcvdPDelayRespFollowUp = 1; + + /** Capture the timestamp for transmit time of PDelayResp at Master + * (t3) */ + InstancePtr->PtpRecords.PDelayTimestampT3 = + XAvb_CaptureNanoSec(InstancePtr->Config.BaseAddress, PtpFrameBaseAddr); + + /** Now we know t1, t2, t3 and t4, calculate the link delay */ + XAvb_CalcDelay(InstancePtr); + + } else { + xil_printf("Error: seqID of PDelayRespFollowUp doesn't match PDelayResp\r\n"); + } +} + +/****************************************************************************/ +/** +* +* A function to decode a received Signalling Packet and modify the TX PTP +* Buffers based on the requested values. +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* @param PtpFrameBaseAddr is the base address of the received Signaling Packet +* in the Rx PTP Packet Buffer +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_DecodeRxSignaling(XAvb * InstancePtr, u32 PtpFrameBaseAddr) { + + u32 ReadData; + char currentInterval; + + /** Read the requested logMeanMessage durations from the Signalling frame */ + ReadData = XAvb_ReorderWord(XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_SIGNALING_DELAY_INTERVAL_OFFSET)); + + /** update linkDelayInterval */ + currentInterval = (ReadData >> 24); + switch( currentInterval ) { + case (-128): + /** don't change the interval */ + break; + /** currently only support the default value */ + case XAVB_DEFAULT_LOG_MEAN_PDELAY_REQ_INTERVAL: + case 126: + /** set the interval to initial value */ + InstancePtr->SignallingFrameData.LinkDelayIntervalDuration = + XAvb_UpdateIntervalDuration(InstancePtr->SignallingFrameData.LinkDelayIntervalDuration, + XAVB_DEFAULT_LOG_MEAN_PDELAY_REQ_INTERVAL); + + /** Update logMeanMessageInterval in the pre-loaded TX PDELAYREQ message buffer */ + XAvb_UpdateLogMeanMessageInterval(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYREQ_OFFSET, + InstancePtr->SignallingFrameData.LinkDelayIntervalDuration); + break; + case 127: + /** stop sending pDelay messages */ + InstancePtr->SignallingFrameData.LinkDelayIntervalDuration = XAVB_PKT_TYPE_DISABLED; + break; + default: + xil_printf( "Got a signalling message with an interval (%d) I don't support!\r\n", currentInterval); + } + + /** update timeSyncInterval */ + currentInterval = (ReadData >> 16); + switch( currentInterval ) { + case (-128): + /** don't change the interval */ + break; + case XAVB_DEFAULT_LOG_MEAN_SYNC_INTERVAL: + case 126: + /** set the interval to initial value */ + InstancePtr->SignallingFrameData.SyncIntervalDuration = + XAvb_UpdateIntervalDuration(InstancePtr->SignallingFrameData.SyncIntervalDuration, + XAVB_DEFAULT_LOG_MEAN_SYNC_INTERVAL); + + /** Update logMeanMessageInterval in the pre-loaded TX SYNC message buffer */ + XAvb_UpdateLogMeanMessageInterval(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_SYNC_OFFSET, + InstancePtr->SignallingFrameData.SyncIntervalDuration); + /** Update logMeanMessageInterval in the pre-loaded TX FOLLOW_UP message buffer */ + XAvb_UpdateLogMeanMessageInterval(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_FOLLOW_UP_OFFSET, + InstancePtr->SignallingFrameData.SyncIntervalDuration); + break; + case 127: + /** stop sending sync messages */ + InstancePtr->SignallingFrameData.SyncIntervalDuration = XAVB_PKT_TYPE_DISABLED; + break; + default: + xil_printf( "Got a signalling message with an interval (%d) I don't support!\r\n", currentInterval); + } + + /** update announceInterval */ + currentInterval = (ReadData >> 8); + switch( currentInterval ) { + case (-128): + /** don't change the interval */ + break; + case XAVB_DEFAULT_LOG_MEAN_ANNOUNCE_INTERVAL: + case 126: + /** set the interval to initial value */ + InstancePtr->SignallingFrameData.AnnounceIntervalDuration = + XAvb_UpdateIntervalDuration(InstancePtr->SignallingFrameData.AnnounceIntervalDuration, + XAVB_DEFAULT_LOG_MEAN_ANNOUNCE_INTERVAL); + + /** Update logMeanMessageInterval in the pre-loaded TX ANNOUNCE message buffer */ + XAvb_UpdateLogMeanMessageInterval(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_ANNOUNCE_OFFSET, + InstancePtr->SignallingFrameData.AnnounceIntervalDuration); + break; + case 127: + /** stop sending Announce messages */ + InstancePtr->SignallingFrameData.AnnounceIntervalDuration = XAVB_PKT_TYPE_DISABLED; + break; + default: + xil_printf( "Got a signalling message with an interval (%d) I don't support!\r\n", currentInterval); + } +} + + +/****************************************************************************/ +/** +* +* A function to update a PTP message Interval Duration (defined as a +* fraction of 128 seconds). If the endpoint cannot support a requested +* logMeanVal then do not perform the conversion - return the current value. +* +* @param currentIntervalDuration is the Interval Duration to be updated +* @param logMeanVal is the base2 value that is to be converted +* +* @return logMeanVal represented as a fraction of 128 +* +* @note This endpoint only supports logMeanValues >=-7 and <=8. +* +*****************************************************************************/ +u16 XAvb_UpdateIntervalDuration(u16 currentIntervalDuration, + char logMeanVal) { + + if((logMeanVal >= XAVB_MIN_SUPPORTED_LOG_MEAN_INTERVAL) && + (logMeanVal <= XAVB_MAX_SUPPORTED_LOG_MEAN_INTERVAL)) { + + return XAvb_ConvertLogMeanToDuration(logMeanVal); + + } else { + + return currentIntervalDuration; + + } +} + + +/****************************************************************************/ +/** +* +* A function to convert a logMean (power of 2) value into a fraction of 128 +* that is compatible with Signalling data. +* +* @param logMeanVal is the base2 value that is to be converted + +* @return logMeanVal represented as a fraction of 128 +* +* @note None. +* +*****************************************************************************/ +u16 XAvb_ConvertLogMeanToDuration(char logMeanVal) { + + u8 logMeanAbs; + + logMeanAbs = (u8)(abs(logMeanVal)); + + return (logMeanVal < 0) ? + (128 >> logMeanAbs) : + (logMeanVal > 0) ? + (128 << logMeanAbs) : + 128; +} + +/****************************************************************************/ +/** +* +* A function to convert a fraction of 128 value that is compatible with +* Signalling data into a logMean (power of 2) value; +* +* @param fractionalVal is the Signalling data value that is to be converted + +* @return fractionalVal represented as logMean (power of 2) value +* +* @note None. +* +*****************************************************************************/ +char XAvb_ConvertDurationToLogMean(u16 fractionalVal) { + + char logMeanVal = 0; + u8 numShifts = 0; + + /** just in case fractionalVal is not a power of 2, we'll + * only look at the most significant bit + * Count how many shifts it takes for most significant set bit + * to be in the highest (16th) bit location + */ + while( !(fractionalVal & 0x8000) ) { + fractionalVal <<= 1; + numShifts++; + } + + /** logMeanVal = 0 = 2^0 = 128/128 would give us a numShifts + * result of 8, so 8 will be our base + */ + logMeanVal = 8 - numShifts; + + return logMeanVal; +} + +/****************************************************************************/ +/** +* +* A function to update the logMeanMessageInterval field in a PTP packet +* +* @param BaseAddress is the base address of the device +* @param PtpFrameBaseAddr is the base address of the TX PTP Buffer to be updated +* @param intervalDuration is the "fraction of 128" value of the data to be written +* +* @return None. But the relevant Tx PTP Packet Buffer is written to with the +* updated logMeanMessageInterval +* +* @note None. +* +*****************************************************************************/ +void XAvb_UpdateLogMeanMessageInterval(u32 BaseAddress, + u32 PtpFrameBaseAddr, + u16 intervalDuration) { + + u32 ReadVal; + u8 logMean; + + /** Convert intervalDuration to a logMean value */ + logMean = (u8)XAvb_ConvertDurationToLogMean(intervalDuration); + + /** Read the current fields */ + ReadVal = XAvb_ReadPtpBuffer(BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_TX_PKT_SEQUENCEID_OFFSET); + + /** Update just the logMeanMessageInterval field */ + ReadVal = (ReadVal & 0x00ffffff) | (logMean << 24); + + /** Write back */ + XAvb_WritePtpBuffer(BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_TX_PKT_SEQUENCEID_OFFSET, + ReadVal); +} + +/****************************************************************************/ +/** +* +* This function updates the portIdLocal local copy of the sourcePortIdentity +* and writes this value into the TX PTP frame buffer templates. The fields +* that are written are: +* o sourcePortIdentity for all default PTP frames +* o Announce:: grandmasterIdentity +* o Announce:: TLV clockIdentity +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* @param systemIdentity is the clockIdentity and portNumber for this endpoint +* +* @return None. +* +* @note Announce::TLV. By default the tlvType and length field are set +* up in the BRAM, assuming that N = 1. +* +****************************************************************************/ +void XAvb_SetupSourcePortIdentity(XAvb * InstancePtr, + XAvb_PortIdentity systemIdentity) +{ + u32 BufferWord; + u8 BufferEnable; + u32 DataBitEnable; + u32 ReadWord; + + /* Set up our local copy of the sourcePortIdentity */ + InstancePtr->portIdLocal = systemIdentity; + + /** Write the sourcePortIdentity into the header for all TX PTP buffers + * except the empty default buffer AND write the GMID for TX announce AND + * Write the ClockIdentity into the TX Announce TLV */ + BufferEnable = 0x7F; + + /** (a) Write the upper 2 bytes of the ClockIdentityUpper + * - REM: Swap back the byte order into frame storage order */ + DataBitEnable = 0xFFFF0000; + BufferWord = (systemIdentity.ClockIdentityUpper >> 16); + BufferWord = XAvb_ReorderWord(BufferWord); + + XAvb_WriteToMultipleTxPtpFrames(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PKT_PORTID_UPPER_OFFSET, + BufferWord, + DataBitEnable, + BufferEnable); + + ReadWord = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_ANNOUNCE_OFFSET, + XAVB_PTP_TX_PKT_ANNOUNCE_TLVLEN_PATHSEQ_START_OFFSET); + + BufferWord = (ReadWord & 0x0000FFFF) | (BufferWord & 0xFFFF0000); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_ANNOUNCE_OFFSET, + XAVB_PTP_TX_PKT_ANNOUNCE_TLVLEN_PATHSEQ_START_OFFSET, + BufferWord); + + /** (b) Write the lower 2 bytes of the ClockIdentityUpper and upper + * 2 bytes of the ClockIdentityLower. + * - REM: Swap back the byte order into frame storage order*/ + BufferWord = ((systemIdentity.ClockIdentityUpper << 16) & 0xFFFF0000) | ((systemIdentity.ClockIdentityLower >> 16) & 0x0000FFFF); + BufferWord = XAvb_ReorderWord(BufferWord); + DataBitEnable = 0xFFFFFFFF; + + XAvb_WriteToMultipleTxPtpFrames(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PKT_PORTID_MID_OFFSET, + BufferWord, + DataBitEnable, + BufferEnable); + + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_ANNOUNCE_OFFSET, + (XAVB_PTP_TX_PKT_ANNOUNCE_TLVLEN_PATHSEQ_START_OFFSET + 4), + BufferWord); + + /** (c) Write the lower 2 bytes of the ClockIdentityLower and the portNumber + * - REM: Swap back the byte order into frame storage order*/ + BufferWord = ((systemIdentity.ClockIdentityLower << 16) & 0xFFFF0000) | (systemIdentity.PortNumber & 0x0000FFFF); + BufferWord = XAvb_ReorderWord(BufferWord); + + XAvb_WriteToMultipleTxPtpFrames(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PKT_PORTID_LOWER_OFFSET, + BufferWord, + DataBitEnable, + BufferEnable); + + BufferWord = (systemIdentity.ClockIdentityLower << 16) & 0xFFFF0000; + BufferWord = XAvb_ReorderWord(BufferWord); + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_ANNOUNCE_OFFSET, + (XAVB_PTP_TX_PKT_ANNOUNCE_TLVLEN_PATHSEQ_START_OFFSET + 8), + BufferWord); + + + + /** Write the grandmasterIdentity into the header for the TX Announce PTP buffer */ + /** (a) Write 1 byte of GMID (Upper)*/ + BufferWord = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_ANNOUNCE_OFFSET, + XAVB_PTP_TX_PKT_ANNOUNCE_QUAL_LOW_PRI2_GMID_HI_OFFSET); + + BufferWord = (BufferWord & 0x00FFFFFF) | (systemIdentity.ClockIdentityUpper & 0xFF000000); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_ANNOUNCE_OFFSET, + XAVB_PTP_TX_PKT_ANNOUNCE_QUAL_LOW_PRI2_GMID_HI_OFFSET, + BufferWord); + + /** (b) Write 3 bytes of GMID (Upper) and 1 byte of GMID (Lower)**/ + BufferWord = (systemIdentity.ClockIdentityUpper << 8) | ((systemIdentity.ClockIdentityLower >> 24) & 0x000000FF); + BufferWord = XAvb_ReorderWord(BufferWord); + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_ANNOUNCE_OFFSET, + XAVB_PTP_TX_PKT_ANNOUNCE_GMID_MID_OFFSET, + BufferWord); + + /** (c) Write 3 bytes of GMID (Lower) */ + BufferWord = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_ANNOUNCE_OFFSET, + XAVB_PTP_TX_PKT_ANNOUNCE_GMID_LOW_STEPSREMOVED_HI_OFFSET); + + BufferWord = ((BufferWord >> 24) & 0x000000FF) | ((systemIdentity.ClockIdentityLower << 8) & 0xFFFFFF00); + BufferWord = XAvb_ReorderWord(BufferWord); + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_ANNOUNCE_OFFSET, + XAVB_PTP_TX_PKT_ANNOUNCE_GMID_LOW_STEPSREMOVED_HI_OFFSET, + BufferWord); + + +#ifdef DEBUG_XAVB_LEVEL2 + xil_printf("\r\n setupSourcePortIdentity: Writing systemIdentity to buffers %08x", BufferEnable); + xil_printf("\r\n setupSourcePortIdentity: ClockIdentityUpper --> 0x%08x, ClockIdentityLower --> 0x%08x, PortNumber --> 0x%08x", + InstancePtr->portIdLocal.ClockIdentityUpper, + InstancePtr->portIdLocal.ClockIdentityLower, + InstancePtr->portIdLocal.PortNumber); +#endif +} diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_rtc_sync.c b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_rtc_sync.c new file mode 100644 index 00000000..3f2dcb10 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_rtc_sync.c @@ -0,0 +1,640 @@ +/****************************************************************************** +* +* Copyright (C) 2008 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/******************************************************************************/ +/*** +* +* @file xavb_rtc_sync.c +* +* The XAvb driver. Functions in this file all contain calculations which are +* essential for the AVB (1588 based) Real Time Clock (RTC) Sychronisation. In +* here are functions to measure the Link Delay (Master and Slave); to measure +* and correct the current RTC error (Slave); to measure and correct the current +* RTC increment rate error. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -----------------------------------------------
+* 1.00a mbr  09/19/08 First release
+* 1.01a mbr  06/24/09 PTP frame format updates for IEEE802.1 AS draft 5-0
+* 2_02a mbr  09/16/09 Updates for programmable PTP timers
+* 2_04a kag  07/23/10 PTP frame format updates for IEEE802.1 AS draft 6-7
+* 3_01a kag  08/29/11 Added new APIs to update the RX Filter Control Reg.
+*		      Fix for CR:572539. Updated bit map for Rx Filter
+*		      control reg.
+*
+* 
+* +******************************************************************************/ + +/****************************** Include Files *********************************/ + +#include "xil_types.h" +#include "xavb_hw.h" +#include "xavb.h" + +/*************************** Constant Definitions *****************************/ + +/***************************** Type Definitions *******************************/ + +/****************** Macros (Inline Functions) Definitions *********************/ + +/*************************** Variable Definitions *****************************/ + +/*************************** Function Prototypes ******************************/ + +/******************************************************************************/ + +/*****************************************************************************/ +/*** +* +* A function to capture the nanosecond timestamp field from a received PTP frame +* +* @param BaseAddress is the base address of the device +* @param PtpFrameBaseAddr is the base address of the received Announce Packet +* in the Rx PTP Packet Buffer +* +* @return The Nanoseconds Timestamp field, captured from an Rx PTP frame +* +* @note None. +* +*****************************************************************************/ +u32 XAvb_CaptureNanoSec(u32 BaseAddress, u32 PtpFrameBaseAddr) { + u32 Timestamp = 0; + u32 BufferWordA = 0; + u32 BufferWordB = 0; + + /** The timestamp is located over several 32-bit Words of the PTP frame buffer + * Read the relevant Words containing the ns timestamp: */ + BufferWordA = XAvb_ReadPtpBuffer(BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_TIMESTAMP_MID_OFFSET); + + BufferWordB = XAvb_ReadPtpBuffer(BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_TIMESTAMP_LOWER_OFFSET); + + /** Now re-arrange the data from the Words to obtain the required ns Timestamp + * in binrary format */ + Timestamp = (XAvb_ReorderWord(BufferWordA)<<16) | + (XAvb_ReorderWord(BufferWordB)>>16); + + return Timestamp; + +} + + +/*****************************************************************************/ +/*** +* +* A function to Measure the Link Delay of the local full-duplex Ethernet link +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_CalcDelay(XAvb * InstancePtr) { + u32 T4MinusT1 = 0; + u32 T3MinusT2 = 0; + u32 Delay = 0; + + /** Since we are only using the nanoseconds field here we need to account for + * wrap. So we add one second to the T4 and T3 terms to ensure that the + * T4MinusT1 and T3MinusT2 results cannot be negative. These two additional + * seconds then cancel each other out in the T4MinusT1 - T3MinusT2 equation. + */ +#ifdef DEBUG_XAVB_LEVEL2 + xil_printf("\r\nXAvb_CalcDelay()"); + xil_printf("\r\nt1 %x ", InstancePtr->PtpRecords.PDelayTimestampT1); + xil_printf("\r\nt2 %x ", InstancePtr->PtpRecords.PDelayTimestampT2); + xil_printf("\r\nt3 %x ", InstancePtr->PtpRecords.PDelayTimestampT3); + xil_printf("\r\nt4 %x ", InstancePtr->PtpRecords.PDelayTimestampT4); +#endif + + /** If the nanoseconds count has wrapped, add on 1 second to ensure we get the right answer*/ + if (InstancePtr->PtpRecords.PDelayTimestampT4 < InstancePtr->PtpRecords.PDelayTimestampT1) { + T4MinusT1 = (InstancePtr->PtpRecords.PDelayTimestampT4 + XAVB_ONE_SECOND) + - InstancePtr->PtpRecords.PDelayTimestampT1; + } else { + T4MinusT1 = InstancePtr->PtpRecords.PDelayTimestampT4 + - InstancePtr->PtpRecords.PDelayTimestampT1; + } + /** If the nanoseconds count has wrapped, add on 1 second to ensure we get the right answer*/ + if (InstancePtr->PtpRecords.PDelayTimestampT3 < InstancePtr->PtpRecords.PDelayTimestampT2) { + T3MinusT2 = (InstancePtr->PtpRecords.PDelayTimestampT3 + XAVB_ONE_SECOND) + - InstancePtr->PtpRecords.PDelayTimestampT2; + } else { + T3MinusT2 = InstancePtr->PtpRecords.PDelayTimestampT3 + - InstancePtr->PtpRecords.PDelayTimestampT2; + } + + Delay = (T4MinusT1 - T3MinusT2) >> 1; + + /** For now we are simply going to throw out any absurdly large link delays.*/ + if (Delay < XAVB_NEIGHBOR_PROP_DELAY_THRESH ) { + + InstancePtr->PtpRecords.LinkDelay = Delay; + + /** The peer has responded to the pDelay_Req and the measured delay is + * within tolerance: the peer is deemed to be AS capable */ + XAvb_ChangePeerASCapability(InstancePtr, 1); + + } else { + xil_printf("\r\n Bad Link Delay %d ", Delay); +#ifdef DEBUG_XAVB_LEVEL2 + xil_printf("\r\nXAvb_CalcDelay()"); + xil_printf("\r\nt1 %x ", InstancePtr->PtpRecords.PDelayTimestampT1); + xil_printf("\r\nt2 %x ", InstancePtr->PtpRecords.PDelayTimestampT2); + xil_printf("\r\nt3 %x ", InstancePtr->PtpRecords.PDelayTimestampT3); + xil_printf("\r\nt4 %x ", InstancePtr->PtpRecords.PDelayTimestampT4); + xil_printf("\r\nLinkDelay %x ", InstancePtr->PtpRecords.LinkDelay); +#endif + } +} + + +/*****************************************************************************/ +/*** +* +* A function to calculate the Slave Offset from the GrandMaster time +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* @param PtpFrameBaseAddr is the base address of the received Announce Packet +* in the Rx PTP Packet Buffer +* +* @return The PtpRecords data structure is updated with the calculated RTC +* Offset value. +* +* @note None. +* +*****************************************************************************/ +void XAvb_CalcRtcOffset (XAvb * InstancePtr, + u32 PtpFrameBaseAddr) { + + u32 MasterNanosec = 0; + u32 MasterSeconds = 0; + u32 MasterEpoch = 0; + + u32 SyncRouteDelay = 0; + u32 MasterNsCorrected = 0; + u32 MasterNsHasWrapped = 0; + + u32 SlaveNsTimestamp = 0; + XAvb_RtcFormat RtcError; + + u32 BufferWordA = 0; + u32 BufferWordB = 0; + + XAvb_RtcFormat SlaveRtc; + + + /** Capture the Slave Time + * ---------------------------- + * We do this immediately to get the slave time ASAP (since processing + * time is uncertain and the RTC does not stand still). */ + XAvb_ReadRtc(InstancePtr->Config.BaseAddress, &SlaveRtc); + + + /** Capture the Master Origin Timestamp (from received FollowUp Frame) + * ---------------------------- */ + MasterNanosec = XAvb_CaptureNanoSec(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr); + + /** read the Words from the PTP frame buffer containing the RTC seconds field + */ + BufferWordA = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_TIMESTAMP_UPPER_OFFSET); + + BufferWordB = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_TIMESTAMP_MID_OFFSET); + + /** Now re-arrange the required data from the Words to obtain the required + * seconds field timestamp in binary format */ + MasterSeconds = (XAvb_ReorderWord(BufferWordA) << 16) | + (XAvb_ReorderWord(BufferWordB) >> 16); + + MasterEpoch = XAvb_ReorderWord(BufferWordA) >> 16; + + + + /** Correct the Nanoseconds + * ---------------------------- + * NOTE: we are trying to compare the value of the slave RTC nano- + * seconds field timestamp with the nano-seconds value of the Masters + * RTC nanosecond field at exactly that time. + * + * + * Sync Frame routing delay is equal to the value of the correction + * field (sum of correction fields in Sync and FollowUp frames) plus + * the link delay measurement made by this slave. + */ + SyncRouteDelay = InstancePtr->PtpRecords.MasterCorrectionField + + InstancePtr->PtpRecords.LinkDelay; + + /** MasterNsCorrected time here is the calculated time that the + * master will be at the point in time when the sync frame is received + * (and timestamped) at the slave. This is calculated from the + * originTimeStamp (from the FollowUpframe), plus the Sync Frame + * routing delay. A direct comparison can then be made between master + * and slave. + */ + MasterNsCorrected = MasterNanosec + SyncRouteDelay; + + /** Check for ns wrap-around condition */ + if (MasterNsCorrected >= XAVB_ONE_SECOND) { + MasterNsCorrected = MasterNsCorrected - XAVB_ONE_SECOND; + MasterNsHasWrapped = 1; + } + + + /** Make the Master and Slave comparison and discover the difference! */ + RtcError.NanoSeconds = MasterNsCorrected + - InstancePtr->PtpRecords.SlaveSyncTimestamp; + + /** Check for ns wrap-around condition */ + if (RtcError.NanoSeconds >= XAVB_ONE_SECOND) { + RtcError.NanoSeconds = RtcError.NanoSeconds + XAVB_ONE_SECOND; + } + + + /** Return these comparison figures in the form of a pointer (RTC + * increment rate adjust function also needs to know this information) */ + InstancePtr->PtpRecords.NewSlaveTime + = InstancePtr->PtpRecords.SlaveSyncTimestamp; + + InstancePtr->PtpRecords.NewMasterTime = MasterNsCorrected; + + + /** Adjust the 8k clock logic (if necessary) */ + XAvb_Adjust8kClock(InstancePtr->Config.BaseAddress, RtcError.NanoSeconds); + + + + /** Correct the Seconds and Epoch + * ----------------------------- + * NOTE: we are trying to compare the value of the slave RTC seconds + * field at the exact time when the timestamp was taken with the + * RTC seconds value of the Master at that time. + * + * + * We need to know the value of the slaves synchronised nano-seconds + * field at the time when the timestamp was taken (since timestamps + * use the syntonised time). So we add the current nanosecond field + * offset value: + */ + SlaveNsTimestamp = InstancePtr->PtpRecords.SlaveSyncTimestamp + + XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_NANOSEC_OFFSET); + + /** Check for ns wrap-around condition */ + if (SlaveNsTimestamp >= XAVB_ONE_SECOND) { + SlaveNsTimestamp = SlaveNsTimestamp - XAVB_ONE_SECOND; + } + + /** Even though we read the slave RTC value at the beginning of this + * function, there would have been processing delay between the + * actual reception (and timestamping) of the FollowUp frame and the + * start of this function. During this time, the slave RTC seconds + * field could have wrapped around. We need to detect this and if it + * has done, the slave seconds field would also have incremented (so + * it needs to be set back). + */ + if (SlaveRtc.NanoSeconds < SlaveNsTimestamp) { + /** slave_nanosec has wrapped since timestamp so decrement the + * seconds field */ + if (SlaveRtc.SecondsLower == 0x00000000) { + SlaveRtc.SecondsUpper = SlaveRtc.SecondsUpper - 0x1; + } + SlaveRtc.SecondsLower = SlaveRtc.SecondsLower - 0x1; + } + + + /** If the Master nano seconds field wrapped during the Sync frame + * routing delay, then we need to increment the seconds field. + */ + if (MasterNsHasWrapped == 1) { + if (MasterSeconds == 0xFFFFFFFF) { + MasterEpoch = MasterEpoch + 0x1; + } + MasterSeconds = MasterSeconds + 0x1; + } + + + /** Calculate the slave RTC error: the master time minus the timestamp + * taken by this slave for Sync Frame reception. */ + RtcError.SecondsLower = MasterSeconds - SlaveRtc.SecondsLower; + RtcError.SecondsUpper = MasterEpoch - SlaveRtc.SecondsUpper; + + +#ifdef DEBUG_XAVB_LEVEL2 + if (RtcError.SecondsLower != 0) { + xil_printf("\r\nXAvb_CalcRtcOffset()"); + xil_printf("\r\n-- Seconds Field Correction"); + xil_printf("\r\nSlaveNsTimestamp : %x" , SlaveNsTimestamp); + xil_printf("\r\nslave_ns : %x", SlaveRtc.NanoSeconds); + xil_printf("\r\n--"); + xil_printf("\r\nread slave seconds : %x", + XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_SEC_LOWER_VALUE_OFFSET)); + + xil_printf("\r\ncalc slave secs : %x", SlaveRtc.SecondsLower); + xil_printf("\r\n--"); + xil_printf("\r\nmaster sec wrap : %x" , MasterNsHasWrapped); + xil_printf("\r\ncalc master_secs : %x" , MasterSeconds); + xil_printf("\r\nrtc_sec_error : %x" , RtcError.SecondsLower); + xil_printf("\r\n--"); + } +#endif + + + /** Write the results to the RTC Offset registers + * --------------------------------------------- */ + XAvb_WriteRtcOffset(InstancePtr->Config.BaseAddress, &RtcError); + +} + + +/*****************************************************************************/ +/*** +* +* A function to Adjust the phase offset of the 8k clock +* +* @param InstancePtr->BaseAddress is the base address of the device +* @param NewOffset is the newly calculated RTC Offset value +* +* @return None. But the devices RTC Phase Adjustment Register is updated +* +* @note None. +* +*****************************************************************************/ +void XAvb_Adjust8kClock (u32 BaseAddress, u32 NewOffset) { + + u32 PreviousOffset = 0; + u32 OffsetChange = 0; + u32 ChangeIn8kPeriods = 0; +#ifdef DEBUG_XAVB_LEVEL2 + u32 Clock8kOffset = 0; +#endif + + /** Read the previous offset */ + PreviousOffset = XAvb_ReadReg(BaseAddress, XAVB_RTC_NANOSEC_OFFSET); + + /** Calculate the change in the previous and current RTC ns offset */ + if (PreviousOffset > NewOffset) { + OffsetChange = PreviousOffset - NewOffset; + } else { + OffsetChange = NewOffset - PreviousOffset; + } + + + /** Is the adjustment "large"? "large" is chosen here to be one 8k + * clock period which is a somewhat arbitrary figure */ + if (OffsetChange > XAVB_PERIOD_8KHZ) { + +#ifdef DEBUG_XAVB_LEVEL2 + Clock8kOffset = XAvb_ReadReg(BaseAddress, XAVB_RTC_8K_OFFSET_OFFSET); + xil_printf("\r\nXAvb_Adjust8kClock()"); + xil_printf("\r\nold ns offset: %x" , PreviousOffset); + xil_printf("\r\nold Clk8kOffset: %x", Clock8kOffset); +#endif + + + /** The value XAVB_PERIOD_8KHZ is one 8k clock period in ns. We divide the + * RTC ns offset change by this to get the offset change in a + * multiple of 8k clock periods, the add 1 so that we always round + * up. Then multiply this by XAVB_PERIOD_8KHZ again so that we are always + * phased aligned to the RTC master (only evey adjust in a multiple + * of 8k periods. + */ + ChangeIn8kPeriods = NewOffset / XAVB_PERIOD_8KHZ; + OffsetChange = (ChangeIn8kPeriods + 1) * XAVB_PERIOD_8KHZ; + + /** Write the results to the 8K clock logic Offset register */ + XAvb_WriteReg(BaseAddress, XAVB_RTC_8K_OFFSET_OFFSET, OffsetChange); + +#ifdef DEBUG_XAVB_LEVEL2 + xil_printf("\r\nXAvb_Adjust8kClock()"); + xil_printf("\r\nnew ns offset: %x" , NewOffset); + xil_printf("\r\nnew Clk8kOffset: %x", OffsetChange); +#endif + + } +} + + +/*****************************************************************************/ +/*** +* +* A function to calculate the RTC increment value based on the Slave Error +* +* @return None. But the devices RTC Increment Value Control Register is updated +* +* @note None. +* +*****************************************************************************/ +void XAvb_UpdateRtcIncrement(XAvb * InstancePtr) { + + u32 LoopCount = 31; + u8 SlaveIsFast = 0; + u32 SlaveTimeDuration = 0; + u32 MasterTimeDuration = 0; + u32 SlaveError = 0; + u32 ScaledError = 0; + u32 NormalisedError = 0; + u32 IncrementAdjust = 0; + u32 OldIncrement = 0; + u32 NewIncrement = 0; + + + /** Sanity Check that Sync Frames were n apart. This safeguards the + * calculation against the ethernet cable being pulled out and then + * replaced, etc. */ + if ( ((InstancePtr->SequenceIdRecords.OldSyncSequenceId + + XAVB_NUM_SYNC_FU_PAIR_CALC_RTC_INCREMENT) & 0xFFFF) == + InstancePtr->SequenceIdRecords.NewSyncSequenceId ) { + +#ifdef DEBUG_XAVB_LEVEL2 + xil_printf("\r\nXAvb_UpdateRtcIncrement(): Debug...(a)"); + xil_printf("\r\nNewMasterTime : %x, %d" , InstancePtr->PtpRecords.NewMasterTime, InstancePtr->PtpRecords.NewMasterTime); + xil_printf("\r\nOldMasterTime : %x, %d" , InstancePtr->PtpRecords.OldMasterTime, InstancePtr->PtpRecords.OldMasterTime); + xil_printf("\r\nNewSlaveTime : %x, %d" , InstancePtr->PtpRecords.NewSlaveTime, InstancePtr->PtpRecords.NewSlaveTime); + xil_printf("\r\nOldSlaveTime : %x, %d\r\n" , InstancePtr->PtpRecords.OldSlaveTime, InstancePtr->PtpRecords.OldSlaveTime); +#endif + + /** Measure the time duration, as measured by the RTC master of the + * M sync delay measurment period. */ + MasterTimeDuration = (InstancePtr->PtpRecords.NewMasterTime + - InstancePtr->PtpRecords.OldMasterTime); + + if (MasterTimeDuration >= XAVB_ONE_SECOND) { + MasterTimeDuration = MasterTimeDuration + XAVB_ONE_SECOND; + } + + /** Measure the time duration, as measured by the RTC slave of the + * M sync delay measurment period. */ + SlaveTimeDuration = (InstancePtr->PtpRecords.NewSlaveTime + - InstancePtr->PtpRecords.OldSlaveTime); + + if (SlaveTimeDuration >= XAVB_ONE_SECOND) { + SlaveTimeDuration = SlaveTimeDuration + XAVB_ONE_SECOND; + } + + /** Therefore calculate the slave error (in ns) */ + SlaveError = MasterTimeDuration - SlaveTimeDuration; + + /** If the slave error is zero, skip the remainder of function. + * (Note : a zero error would otherwise get stuck in the while loop + * further down this function). */ + if (SlaveError != 0) { + + + /** Analyse msb of error signal to see which clock is running fastest */ + if (SlaveError & 0x80000000) { + SlaveIsFast = 1; + SlaveError = SlaveTimeDuration - MasterTimeDuration; + } else { + SlaveIsFast = 0; + } + + /** This check is in addition to the checks described in IEEE802.1as. + * If the SlaveError is unexpectedly large, then set asCapable to 0. + */ + if (SlaveError < XAVB_CLOCK_LOCK_THRESHOLD) { + XAvb_ChangePTPLockStatus(InstancePtr, 1); + } else { + XAvb_ChangePTPLockStatus(InstancePtr, 0); + } + + /** SlaveError signal is 32-bits (ns). This can indicate > 4 sec of + * error: this is too large for 100 ms measurement period. So we + * expect upper bits to be zero. + * + * This function will shift the 1st none zero bit of SlaveError up + * to bit 31, so that forthcoming calculation uses maximum accuracy. + * + * This shift is equivalent to a multiply (of the error signal). A + * shift the opposite way (equivalent to a divide) will follow at + * end of full calculation. */ + + while ( !(SlaveError & (0x1 << LoopCount)) ) { + LoopCount = LoopCount - 1; + } + LoopCount = 31 - LoopCount; + ScaledError = (SlaveError << LoopCount); + + + /** Calculate the relative error: can be thought of as a scaled ratio + * of error per time unit */ + NormalisedError = ScaledError / MasterTimeDuration; + + + /** Obtain the current increment value */ + OldIncrement = (XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_INCREMENT_OFFSET) + & XAVB_RTC_INCREMENT_VALUE_MASK); + + + /** Calculate the increment adjustment: multiply NormalisedError by + * the increment time unit. Then shift back the other way to + * correct the calculation (restore to ns). */ + IncrementAdjust = (NormalisedError * OldIncrement) >> LoopCount; + + + /** Now calculate the new increment value */ + if (SlaveIsFast) { + NewIncrement = OldIncrement - IncrementAdjust; + } else { + NewIncrement = OldIncrement + IncrementAdjust; + } + + /** Add some rails so that recovery is possible after a + * string of bad pDelay values. The RTC should be able to lock + * to within 100ppm of the slowest allowable clock (25 MHz). + * This equates to +/-4ps. Let's arbitrarily set the rails to + * 400ppm (+/-16ps) just in case someone decides to use a + * particularly bad oscillator. The lowest 20 bits of + * NewIncrement are fractions of a nanosecond, which equates + * to +/- 0x04189 + */ + if( NewIncrement > (XAVB_RTC_INCREMENT_NOMINAL_RATE + XAVB_RTC_400PPM_OFFSET) ) { + xil_printf("\r\nRTC Exceeded 400ppm offset: Railing to 400ppm\r\n"); + NewIncrement = XAVB_RTC_INCREMENT_NOMINAL_RATE + XAVB_RTC_400PPM_OFFSET; + } + if( NewIncrement < (XAVB_RTC_INCREMENT_NOMINAL_RATE - XAVB_RTC_400PPM_OFFSET) ) { + xil_printf("\r\nRTC Exceeded 400ppm offset: Railing to 400ppm\r\n"); + NewIncrement = XAVB_RTC_INCREMENT_NOMINAL_RATE - XAVB_RTC_400PPM_OFFSET; + } + + /** And write the new increment value! */ + XAvb_WriteReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_INCREMENT_OFFSET, + NewIncrement); + +#ifdef DEBUG_XAVB_LEVEL2 + xil_printf("\r\nXAvb_UpdateRtcIncrement(): Debug..."); + xil_printf("\r\nM Time : %x" , MasterTimeDuration); + xil_printf("\r\nS Time : %x" , SlaveTimeDuration); + xil_printf("\r\nErr : %x %x" , SlaveIsFast, SlaveError); + xil_printf("\r\nScaled : %x" , ScaledError); + xil_printf("\r\nNorm : %x" , NormalisedError); + xil_printf("\r\nAdjust : %x" , IncrementAdjust); + xil_printf("\r\nNew Inc: %x" , NewIncrement); +#endif + + } + } else { + + xil_printf("\r\nXAvb_UpdateRtcIncrement()"); + xil_printf("\r\nERROR: Syncs not %d apart - %d\r\n", + XAVB_NUM_SYNC_FU_PAIR_CALC_RTC_INCREMENT, + InstancePtr->SequenceIdRecords.NewSyncSequenceId - + InstancePtr->SequenceIdRecords.OldSyncSequenceId); + } + + if (SlaveError > 0x2700) { + xil_printf("\r\nXAvb_UpdateRtcIncrement(): Large Error over 100ms"); + xil_printf("\r\nM Time : %x" , MasterTimeDuration); + xil_printf("\r\nS Time : %x" , SlaveTimeDuration); + xil_printf("\r\nErr : %x %x" , SlaveIsFast, SlaveError); + xil_printf("\r\nScaled : %x" , ScaledError); + xil_printf("\r\nNorm : %x" , NormalisedError); + xil_printf("\r\nAdjust : %x" , IncrementAdjust); + xil_printf("\r\nNew Inc: %x" , NewIncrement); +} + +} diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/index.html b/XilinxProcessorIPLib/drivers/axiethernet/examples/index.html new file mode 100755 index 00000000..1f784aa6 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/index.html @@ -0,0 +1,22 @@ + + + + + +Driver example applications + + + +

Example Applications for the driver axiethernet_v4_2

+
+ +

Copyright � 1995-2014 Xilinx, Inc. All rights reserved.

+ + diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example.h b/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example.h new file mode 100644 index 00000000..9b077ab2 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example.h @@ -0,0 +1,124 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/** +* +* @file xaxiethernet_example.h +* +* Defines common data types, prototypes, and includes the proper headers +* for use with the Axi Ethernet example code residing in this directory. +* +* This file along with xaxiethernet_example_util.c are utilized with the +* specific example code in the other source code files provided. +* +* These examples are designed to be compiled and utilized within the EDK +* standalone BSP development environment. The readme file contains more +* information on build requirements needed by these examples. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a asa  4/30/10 First release based on the ll temac driver
+* 3.02a srt  4/26/13 Added function prototype for *_ConfigureInternalPhy().
+*
+* 
+* +******************************************************************************/ +#ifndef XAXIETHERNET_EXAMPLE_H +#define XAXIETHERNET_EXAMPLE_H + + +/***************************** Include Files *********************************/ + +#include "xparameters.h" /* defines XPAR values */ +#include "xaxiethernet.h" /* defines Axi Ethernet APIs */ +#include "stdio.h" /* stdio */ + +/************************** Constant Definitions ****************************/ +#define AXIETHERNET_LOOPBACK_SPEED 100 /* 100Mb/s for Mii */ +#define AXIETHERNET_LOOPBACK_SPEED_1G 1000 /* 1000Mb/s for GMii */ +#define AXIETHERNET_PHY_DELAY_SEC 4 /* + * Amount of time to delay waiting on + * PHY to reset. + */ + +#define MAX_MULTICAST_ADDR (1<<23) /* + * Maximum number of multicast ethernet + * mac addresses. + */ + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/**************************** Type Definitions ******************************/ + +/* + * Define an aligned data type for an ethernet frame. This declaration is + * specific to the GNU compiler + */ +typedef unsigned char EthernetFrame[XAE_MAX_JUMBO_FRAME_SIZE] __attribute__ ((aligned(64))); + + +/************************** Function Prototypes *****************************/ + +/* + * Utility functions implemented in xaxiethernet_example_util.c + */ +void AxiEthernetUtilSetupUart(void); +void AxiEthernetUtilFrameHdrFormatMAC(EthernetFrame * FramePtr, + char *DestAddr); +void AxiEthernetUtilFrameHdrFormatType(EthernetFrame * FramePtr, + u16 FrameType); +void AxiEthernetUtilFrameSetPayloadData(EthernetFrame * FramePtr, + int PayloadSize); +void AxiEthernetUtilFrameHdrVlanFormatVid(EthernetFrame * FramePtr, + u32 VlanNumber,u32 Vid); +void AxiEthernetUtilFrameHdrVlanFormatType(EthernetFrame * FramePtr, + u16 FrameType,u32 VlanNumber); +void AxiEthernetUtilFrameSetVlanPayloadData(EthernetFrame * FramePtr, + int PayloadSize,u32 VlanNumber); +int AxiEthernetUtilFrameVerify(EthernetFrame * CheckFrame, + EthernetFrame * ActualFrame); +void AxiEthernetUtilFrameMemClear(EthernetFrame * FramePtr); +int AxiEthernetUtilEnterLoopback(XAxiEthernet * AxiEthernetInstancePtr, + int Speed); +void AxiEthernetUtilErrorTrap(char *Message); +void AxiEthernetUtilPhyDelay(unsigned int Seconds); +int AxiEthernetUtilConfigureInternalPhy(XAxiEthernet *AxiEthernetInstancePtr, + int Speed); + +/************************** Variable Definitions ****************************/ + +extern char AxiEthernetMAC[]; /* Local MAC address */ + +#endif /* XAXIETHERNET_EXAMPLE_H */ diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example_extmulticast.c b/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example_extmulticast.c new file mode 100644 index 00000000..5bce008a --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example_extmulticast.c @@ -0,0 +1,1582 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/** +* +* @file xaxiethernet_example_extmulticast.c +* +* Implements examples that utilize the AXI Ethernet's interrupt driven DMA +* packet transfer mode to send and receive multicast frames when +* XAE_EXT_MULTICAST_OPTION is enabled. +* +* This example demonstrates: +* +* - How to perform option enable +* - Which interrupt BD word are verified and confirm it is a valid multicast +* frame. +* +* Functional guide to example: +* +* - AxiEthernetSgDmaIntrExtMulticast Example demonstrates the extended +* multicast. The HW must be setup for extended multicast for this +* example to execute. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a asa  4/30/10  First release based on the ll temac driver
+* 1.01a asa  12/10/10 Changes made to enable the AXIDMA Tx/Rx ring interrupts
+*		      		  before allocation of Tx/Rx BDs.
+* 3.00a asa  6/25/12  Modifed XAxiDma_BdSetLength API call to support new
+*		      		  AXI DMA driver version 7.00a.
+* 3.00a bss  10/22/12 Added support for Fast Interrupt Handlers.
+* 3.01a srt  02/14/13 Added support for Zynq (CR 681136)
+*
+* 
+* +******************************************************************************/ + +#warning "This test requires at least 1MB space in RAM." +#warning "Please make sure required resources are available." + +/***************************** Include Files *********************************/ + +#include "xaxiethernet_example.h" +#include "xaxidma.h" +#include "xil_cache.h" +#include "xil_exception.h" + +#ifdef XPAR_INTC_0_DEVICE_ID +#include "xintc.h" +#else +#include "xscugic.h" +#endif + +#ifdef XPAR_XUARTNS550_NUM_INSTANCES +#include "xuartns550_l.h" +#endif + +/*************************** Constant Definitions ****************************/ + +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#ifndef TESTAPP_GEN +#define AXIETHERNET_DEVICE_ID XPAR_AXIETHERNET_0_DEVICE_ID +#define AXIDMA_DEVICE_ID XPAR_AXIDMA_0_DEVICE_ID +#ifdef XPAR_INTC_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID +#define AXIETHERNET_IRPT_INTR XPAR_INTC_0_AXIETHERNET_0_VEC_ID +#define DMA_RX_IRPT_INTR XPAR_AXIETHERNET_0_CONNECTED_DMARX_INTR +#define DMA_TX_IRPT_INTR XPAR_AXIETHERNET_0_CONNECTED_DMATX_INTR +#else +#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID +#define AXIETHERNET_IRPT_INTR XPAR_FABRIC_AXIETHERNET_0_VEC_ID +#define DMA_RX_IRPT_INTR XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_VEC_ID +#define DMA_TX_IRPT_INTR XPAR_FABRIC_AXIDMA_0_MM2S_INTROUT_VEC_ID +#endif +#endif + +#define RXBD_CNT 128 /* Number of RxBDs to use */ +#define TXBD_CNT 128 /* Number of TxBDs to use */ +#define BD_ALIGNMENT XAXIDMA_BD_MINIMUM_ALIGNMENT/* Byte alignment of + * BDs + */ +#define PAYLOAD_SIZE 1000 /* Payload size used in examples */ +#define BD_RX_STATUS_OFFSET 2 + +/* + * Number of bytes to reserve for BD space for the number of BDs desired + */ +#define RXBD_SPACE_BYTES XAxiDma_BdRingMemCalc(BD_ALIGNMENT, RXBD_CNT) +#define TXBD_SPACE_BYTES XAxiDma_BdRingMemCalc(BD_ALIGNMENT, TXBD_CNT) + + +/*************************** Variable Definitions ****************************/ + +static EthernetFrame TxFrame; /* Transmit buffer */ +static EthernetFrame RxFrame; /* Receive buffer */ + +XAxiEthernet AxiEthernetInstance; +XAxiDma DmaInstance; + +#if XPAR_INTC_0_HAS_FAST == 1 + +/* Variables for Fast Interrupt Handlers */ +XAxiEthernet *AxiEthernetInstancePtr_Fast; +XAxiDma_BdRing *TxRingPtr_Fast; +XAxiDma_BdRing *RxRingPtr_Fast; + +/****** Fast Interrupt Handlers prototypes ******/ + +static void AxiEthernetErrorFastHandler(void) __attribute__ ((fast_interrupt)); + +static void RxIntrFastHandler(void) __attribute__ ((fast_interrupt)); + +static void TxIntrFastHandler(void) __attribute__ ((fast_interrupt)); + +#else + +static void AxiEthernetErrorHandler(XAxiEthernet *AxiEthernet); +static void RxIntrHandler(XAxiDma_BdRing *RxRingPtr); +static void TxIntrHandler(XAxiDma_BdRing *TxRingPtr); + +#endif + +/* + * Aligned memory segments to be used for buffer descriptors + */ +char RxBdSpace[RXBD_SPACE_BYTES] __attribute__ ((aligned(BD_ALIGNMENT))); +char TxBdSpace[TXBD_SPACE_BYTES] __attribute__ ((aligned(BD_ALIGNMENT))); + +/* + * Counters to be incremented by callbacks + */ +static volatile int FramesRx; /* Num of frames that have been received */ +static volatile int FramesTx; /* Num of frames that have been sent */ +static volatile int DeviceErrors; /* Num of errors detected in the device */ + +#ifdef XPAR_INTC_0_DEVICE_ID +#define INTC XIntc +#define INTC_HANDLER XIntc_InterruptHandler +#else +#define INTC XScuGic +#define INTC_HANDLER XScuGic_InterruptHandler +#endif + +#ifndef TESTAPP_GEN +static INTC IntcInstance; +#endif + +/* + * Multicast MAC address + */ +char MulticastMAC[6] = { 0x01, 0x00, 0x5E, 0x04, 0x05, 0x06 }; + +/* + * Determine how much space for ALL multicast MAC addresses, there are 2**23 + * per RFC1112. Each bit represents an address. The total number of bytes are + * (2**23)/8=2**20=1MB + */ +u32 McastAddressTable[(MAX_MULTICAST_ADDR>>3)/sizeof(u32)]; + +/*************************** Function Prototypes *****************************/ + +/* + * Examples + */ +int AxiEthernetMcastExample(INTC *IntcInstancePtr, + XAxiEthernet *AxiEthernetInstancePtr, + XAxiDma *DmaInstancePtr, + u16 AxiEthernetDeviceId, + u16 AxiDmaDeviceId, + u16 AxiEthernetIntrId, + u16 DmaRxIntrId, + u16 DmaTxIntrId); + +int AxiEthernetSgDmaIntrExtMulticastExample(XAxiEthernet + *AxiEthernetInstancePtr, XAxiDma *DmaInstancePtr); + +/* + * Interrupt setup and Callbacks for examples + */ + +static int AxiEthernetSetupIntrSystem(INTC *IntcInstancePtr, + XAxiEthernet *AxiEthernetInstancePtr, + XAxiDma *DmaInstancePtr, + u16 AxiEthernetIntrId, + u16 DmaRxIntrId, u16 DmaTxIntrId); + +static void AxiEthernetDisableIntrSystem(INTC *IntcInstancePtr, + u16 AxiEthernetIntrId, + u16 DmaRxIntrId, u16 DmaTxIntrId); + +/* + * Manage functions for Multicast table in RAM + */ +static int AxiEthernet_AddExtMulticast(void *AddressPtr); +static int AxiEthernet_ClearExtMulticast(void *AddressPtr); +static int AxiEthernet_GetExtMulticast(void *AddressPtr); + +/*****************************************************************************/ +/** +* +* This is the main function for the Axi Ethernet example. This function is not +* included if the example is generated from the TestAppGen test tool. +* +* @param None. +* +* @return - XST_SUCCESS to indicate success. +* - XST_FAILURE to indicate failure +* +* @note None. +* +****************************************************************************/ +#ifndef TESTAPP_GEN +int main(void) +{ + int Status; + +#ifdef XPAR_XUARTNS550_NUM_INSTANCES + XUartNs550_SetBaud(STDIN_BASEADDRESS, XPAR_XUARTNS550_CLOCK_HZ, 9600); + XUartNs550_SetLineControlReg(STDIN_BASEADDRESS, XUN_LCR_8_DATA_BITS); +#endif + +#if XPAR_MICROBLAZE_USE_ICACHE + Xil_ICacheInvalidate(); + Xil_ICacheEnable(); +#endif + +#if XPAR_MICROBLAZE_USE_DCACHE + Xil_DCacheInvalidate(); + Xil_DCacheEnable(); +#endif + + AxiEthernetUtilErrorTrap("\r\n--- Enter main() ---"); + AxiEthernetUtilErrorTrap("This test may take several minutes to finish"); + + /* + * Call the Axi Ethernet multicast example. + */ + Status = AxiEthernetMcastExample(&IntcInstance, + &AxiEthernetInstance, + &DmaInstance, + AXIETHERNET_DEVICE_ID, + AXIDMA_DEVICE_ID, + AXIETHERNET_IRPT_INTR, + DMA_RX_IRPT_INTR, + DMA_TX_IRPT_INTR); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Failed test intr sgdma"); + AxiEthernetUtilErrorTrap("--- Exiting main() ---"); + return XST_FAILURE; + } + + AxiEthernetUtilErrorTrap("Test passed"); + AxiEthernetUtilErrorTrap("--- Exiting main() ---"); + + return XST_SUCCESS; + +} +#endif + +/*****************************************************************************/ +/** +* +* This function demonstrates the usage usage of the Axi Ethernet extended +* multicast feature. It uses AXI DMA core in interrupt mode to transfer Ethernet +* frames. +* +* +* @param IntcInstancePtr is a pointer to the instance of the Intc +* component. +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* AxiEthernet component. +* @param DmaInstancePtr is a pointer to the instance of the AXIDMA +* component. +* @param AxiEthernetDeviceId is Device ID of the Axi Ethernet Device , +* typically XPAR__DEVICE_ID value from +* xparameters.h. +* @param AxiDmaDeviceId is Device ID of the Axi DMAA Device , +* typically XPAR__DEVICE_ID value from +* xparameters.h. +* @param AxiEthernetIntrId is the Interrupt ID and is typically +* XPAR___VEC_ID +* value from xparameters.h. +* @param DmaRxIntrId is the interrupt id for DMA Rx and is typically +* taken from XPAR__CONNECTED_DMARX_INTR +* @param DmaTxIntrId is the interrupt id for DMA Tx and is typically +* taken from XPAR__CONNECTED_DMATX_INTR +* +* @return +* - XST_SUCCESS to indicate success. +* - XST_FAILURE.to indicate failure. +* +* @note AxiDma hardware must be initialized before initializing +* AxiEthernet. Since AxiDma reset line is connected to the +* AxiEthernet reset line, a reset of AxiDma hardware during its +* initialization would reset AxiEthernet. +* +******************************************************************************/ +int AxiEthernetMcastExample(INTC *IntcInstancePtr, + XAxiEthernet *AxiEthernetInstancePtr, + XAxiDma *DmaInstancePtr, + u16 AxiEthernetDeviceId, + u16 AxiDmaDeviceId, + u16 AxiEthernetIntrId, + u16 DmaRxIntrId, + u16 DmaTxIntrId) +{ + int Status; + int LoopbackSpeed; + XAxiEthernet_Config *MacCfgPtr; + XAxiDma_Config *DmaConfig; + XAxiDma_BdRing *RxRingPtr = XAxiDma_GetRxRing(DmaInstancePtr); + XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(DmaInstancePtr); + XAxiDma_Bd BdTemplate; + + /*************************************/ + /* Setup device for first-time usage */ + /*************************************/ + + /* + * Get the configuration of AxiEthernet hardware. + */ + MacCfgPtr = XAxiEthernet_LookupConfig(AxiEthernetDeviceId); + + /* + * Check if DMA is present or not. + */ + if(MacCfgPtr->AxiDevType != XPAR_AXI_DMA) { + AxiEthernetUtilErrorTrap + ("Device HW not configured for DMA mode\r\n"); + return XST_FAILURE; + } + + DmaConfig = XAxiDma_LookupConfig(AxiDmaDeviceId); + /* + * Initialize AXIDMA engine. AXIDMA engine must be initialized before + * AxiEthernet. During AXIDMA engine initialization, AXIDMA hardware is + * reset, and since AXIDMA reset line is connected to AxiEthernet, this + * would ensure a reset of AxiEthernet. + */ + Status = XAxiDma_CfgInitialize(DmaInstancePtr, DmaConfig); + if(Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error initializing DMA\r\n"); + return XST_FAILURE; + } + + /* + * Initialize AxiEthernet hardware. + */ + Status = XAxiEthernet_CfgInitialize(AxiEthernetInstancePtr, MacCfgPtr, + MacCfgPtr->BaseAddress); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error in initialize"); + return XST_FAILURE; + } + + /* + * Set the MAC address + */ + Status = XAxiEthernet_SetMacAddress(AxiEthernetInstancePtr, + AxiEthernetMAC); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting MAC address"); + return XST_FAILURE; + } + + /* + * Setup RxBD space. + * + * We have already defined a properly aligned area of memory to store + * RxBDs at the beginning of this source code file so just pass its + * address into the function. No MMU is being used so the physical and + * virtual addresses are the same. + * + * Setup a BD template for the Rx channel. This template will be copied + * to every RxBD. We will not have to explicitly set these again. + */ + + /* Disable all RX interrupts before RxBD space setup */ + XAxiDma_BdRingIntDisable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK); + + /* + * Create the RxBD ring + */ + Status = XAxiDma_BdRingCreate(RxRingPtr, (u32) &RxBdSpace, + (u32) &RxBdSpace, BD_ALIGNMENT, RXBD_CNT); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting up RxBD space"); + return XST_FAILURE; + } + XAxiDma_BdClear(&BdTemplate); + Status = XAxiDma_BdRingClone(RxRingPtr, &BdTemplate); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error initializing RxBD space"); + return XST_FAILURE; + } + + /* + * Setup TxBD space. + * + * Like RxBD space, we have already defined a properly aligned area of + * memory to use. + */ + /* Disable all RX interrupts before RxBD space setup */ + XAxiDma_BdRingIntDisable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK); + + /* + * Create the TxBD ring + */ + Status = XAxiDma_BdRingCreate(TxRingPtr, (u32) &TxBdSpace, + (u32) &TxBdSpace, BD_ALIGNMENT, TXBD_CNT); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting up TxBD space"); + return XST_FAILURE; + } + + /* + * We reuse the bd template, as the same one will work for both rx and + * tx. + */ + Status = XAxiDma_BdRingClone(TxRingPtr, &BdTemplate); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error initializing TxBD space"); + return XST_FAILURE; + } + + /* + * Set PHY to loopback, speed depends on phy type. + * MII is 100 and all others are 1000. + */ + if (XAxiEthernet_GetPhysicalInterface(AxiEthernetInstancePtr) + == XAE_PHY_TYPE_MII) { + LoopbackSpeed = AXIETHERNET_LOOPBACK_SPEED; + } else { + LoopbackSpeed = AXIETHERNET_LOOPBACK_SPEED_1G; + } + + AxiEthernetUtilEnterLoopback(AxiEthernetInstancePtr, LoopbackSpeed); + + /* + * Set PHY<-->MAC data clock + */ + Status = XAxiEthernet_SetOperatingSpeed(AxiEthernetInstancePtr, + (u16)LoopbackSpeed); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Setting the operating speed of the MAC needs a delay. There + * doesn't seem to be register to poll, so please consider this + * during your application design. + */ + AxiEthernetUtilPhyDelay(2); + + /* + * Connect to the interrupt controller and enable interrupts + */ + Status = AxiEthernetSetupIntrSystem(IntcInstancePtr, + AxiEthernetInstancePtr, DmaInstancePtr, + AxiEthernetIntrId, DmaRxIntrId, DmaTxIntrId); + + + /****************************/ + /* Run the example */ + /****************************/ + + /* Run the new multicast feature. Make sure HW has the capability */ + if (XAxiEthernet_IsExtMcast(AxiEthernetInstancePtr)) { + Status = AxiEthernetSgDmaIntrExtMulticastExample + (AxiEthernetInstancePtr,DmaInstancePtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + } + + /* + * Disable the interrupts for the Axi Ethernet device + */ + AxiEthernetDisableIntrSystem(IntcInstancePtr, AxiEthernetIntrId, + DmaRxIntrId, DmaTxIntrId); + + /* + * Stop the device + */ + XAxiEthernet_Stop(AxiEthernetInstancePtr); + + return XST_SUCCESS; +} + + +/*****************************************************************************/ +/** +* +* This example sends and receives a single packet in loopback mode with +* extended multicast address support. +* +* The transmit frame will be addressed one of programed multicast addresses. +* +* On receive, HW should pass the frame to receive interrupt handler for further +* address checking. +* +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* AxiEthernet component. +* @param DmaInstancePtr is a pointer to the instance of the AXI DMA +* component. +* +* @return - XST_SUCCESS to indicate success. +* - XST_FAILURE to indicate failure. +* +* @note None. +* +******************************************************************************/ +int AxiEthernetSgDmaIntrExtMulticastExample(XAxiEthernet *AxiEthernetInstancePtr + , XAxiDma *DmaInstancePtr) +{ + int Status; + u32 TxFrameLength; + u32 Reg; + u32 RxFrameLength; + u32 RxStatusControlWord; + int PayloadSize = PAYLOAD_SIZE; + char MulticastAdd[6]; + XAxiDma_BdRing *RxRingPtr = XAxiDma_GetRxRing(DmaInstancePtr); + XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(DmaInstancePtr); + XAxiDma_Bd *BdPtr; + XAxiDma_Bd *BdCurPtr; + u32 BdSts; + + /* + * Cannot run this example if extended features support is not enabled + */ + if (!XAxiEthernet_IsExtMcast(AxiEthernetInstancePtr)) { + AxiEthernetUtilErrorTrap("Extended multicast not available"); + return XST_FAILURE; + } + + /* + * Clear variables shared with callbacks + */ + FramesRx = 0; + FramesTx = 0; + DeviceErrors = 0; + + /* + * Calculate frame length (not including FCS) + */ + TxFrameLength = XAE_HDR_SIZE + PayloadSize; + + /* + * Setup the packet to be transmitted, with destination address set + * to provisioned multicast address. + */ + AxiEthernetUtilFrameMemClear(&TxFrame); + AxiEthernetUtilFrameHdrFormatMAC(&TxFrame, MulticastMAC); + AxiEthernetUtilFrameHdrFormatType(&TxFrame, PayloadSize); + AxiEthernetUtilFrameSetPayloadData(&TxFrame, PayloadSize); + + /* + * Flush the TX frame before giving it to DMA TX channel to transmit. + */ + Xil_DCacheFlushRange((u32)&TxFrame, TxFrameLength); + + /* + * Clear out receive packet memory area + */ + AxiEthernetUtilFrameMemClear(&RxFrame); + + /* + * Invalidate the RX frame before giving it to DMA RX channel to + * receive data. + */ + Xil_DCacheInvalidateRange((u32)&RxFrame, TxFrameLength); + + /* + * Interrupt coalescing parameters are set to their default settings + * which is to interrupt the processor after every frame has been + * processed by the DMA engine. + */ + Status = XAxiDma_BdRingSetCoalesce(TxRingPtr, 1, 1); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting coalescing for transmit"); + return XST_FAILURE; + } + + Status = XAxiDma_BdRingSetCoalesce(RxRingPtr, 1, 1); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting coalescing for recv"); + return XST_FAILURE; + } + + AxiEthernetInstancePtr->Options = XAE_DEFAULT_OPTIONS + | XAE_EXT_MULTICAST_OPTION; + Status = XAxiEthernet_SetOptions(AxiEthernetInstancePtr, + AxiEthernetInstancePtr->Options); + + Status |= XAxiEthernet_ClearOptions(AxiEthernetInstancePtr, + ~(AxiEthernetInstancePtr->Options)); + + /* + * When extended multicasting is enabled, unicast MAC address needs + * to be updated in registers UAWL and UAWU. Hence call driver + * routine to take care of this. + */ + Status |= XAxiEthernet_SetMacAddress(AxiEthernetInstancePtr, + AxiEthernetMAC); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error Options setup"); + return XST_FAILURE; + } + + /* + * Setup multicast address into the Multicast table for HW to perform + * first layer of checking. + */ + Status = XAxiEthernet_AddExtMulticastGroup(AxiEthernetInstancePtr, + MulticastMAC); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error Multicast address setup"); + return XST_FAILURE; + } + + /* + * Read back the setup to make sure Multicast Table is configured with + * MAC address. + */ + if (!XAxiEthernet_GetExtMulticastGroup(AxiEthernetInstancePtr, + MulticastMAC)) { + AxiEthernetUtilErrorTrap("Read back Multicast address fail"); + return XST_FAILURE; + } + + /* + * Setup multicast address for SW to perform final checking. + */ + AxiEthernet_AddExtMulticast(MulticastMAC); + + /* + * Make sure Tx, Rx and extended multicast are enabled. + */ + Status = XAxiEthernet_SetOptions(AxiEthernetInstancePtr, + XAE_RECEIVER_ENABLE_OPTION | + XAE_TRANSMITTER_ENABLE_OPTION); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting options"); + return XST_FAILURE; + } + + /* + * Start the Axi Ethernet and enable its ERROR interrupts + */ + XAxiEthernet_Start(AxiEthernetInstancePtr); + XAxiEthernet_IntEnable(AxiEthernetInstancePtr, XAE_INT_RECV_ERROR_MASK); + + /* + * Enable DMA receive related interrupts + */ + XAxiDma_BdRingIntEnable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK); + + /* + * Allocate 1 RxBD. + */ + Status = XAxiDma_BdRingAlloc(RxRingPtr, 1, &BdPtr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error allocating RxBD"); + return XST_FAILURE; + } + + /* + * Setup the Rx BD. + */ + XAxiDma_BdSetBufAddr(BdPtr, (u32)&RxFrame); +#ifndef XPAR_AXIDMA_0_ENABLE_MULTI_CHANNEL + XAxiDma_BdSetLength(BdPtr, sizeof(RxFrame)); +#else + XAxiDma_BdSetLength(BdPtr, sizeof(RxFrame), + RxRingPtr->MaxTransferLen); +#endif + XAxiDma_BdSetCtrl(BdPtr, 0); + + /* + * Enqueue to HW + */ + Status = XAxiDma_BdRingToHw(RxRingPtr, 1, BdPtr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error committing RxBD to HW"); + return XST_FAILURE; + } + + /* + * Start DMA RX channel. Now it's ready to receive data. + */ + Status = XAxiDma_BdRingStart(RxRingPtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Enable DMA transmit related interrupts + */ + XAxiDma_BdRingIntEnable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK); + + /* + * Allocate 1 TxBD + */ + Status = XAxiDma_BdRingAlloc(TxRingPtr, 1, &BdPtr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error allocating TxBD"); + return XST_FAILURE; + } + + /* + * Setup the TxBD + */ + XAxiDma_BdSetBufAddr(BdPtr, (u32)&TxFrame); + +#ifndef XPAR_AXIDMA_0_ENABLE_MULTI_CHANNEL + XAxiDma_BdSetLength(BdPtr, TxFrameLength); +#else + XAxiDma_BdSetLength(BdPtr, TxFrameLength, + TxRingPtr->MaxTransferLen); +#endif + XAxiDma_BdSetCtrl(BdPtr, XAXIDMA_BD_CTRL_TXSOF_MASK | + XAXIDMA_BD_CTRL_TXEOF_MASK); + + /* + * Enqueue to HW + */ + Status = XAxiDma_BdRingToHw(TxRingPtr, 1, BdPtr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error committing TxBD to HW"); + return XST_FAILURE; + } + + /* + * Start DMA TX channel. Transmission starts at once. + */ + Status = XAxiDma_BdRingStart(TxRingPtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait for transmission to complete + */ + while (!FramesTx); + + /* + * Now that the frame has been sent, post process our TxBDs. + * Since we have only submitted 2 to HW, then there should be only 2 + * ready for post processing. + */ + if (XAxiDma_BdRingFromHw(TxRingPtr, 1, &BdPtr) == 0) { + AxiEthernetUtilErrorTrap("TxBDs were not ready for post processing"); + return XST_FAILURE; + } + + /* + * Examine the TxBDs. + * + * There isn't much to do. The only thing to check would be DMA + * exception bits. But this would also be caught in the error handler. + * So we just return these BDs to the free list + */ + Status = XAxiDma_BdRingFree(TxRingPtr, 1, BdPtr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error freeing up TxBDs"); + return XST_FAILURE; + } + + /* + * Wait for Rx indication + */ + while (!FramesRx); + + /* + * Now that the frame has been received, post process our RxBD. + * Since we have only submitted 1 to HW, then there should be only 1 + * ready for post processing. + */ + if (XAxiDma_BdRingFromHw(RxRingPtr, 1, &BdPtr) == 0) { + AxiEthernetUtilErrorTrap("RxBD was not ready for post processing"); + return XST_FAILURE; + } + + BdCurPtr = BdPtr; + BdSts = XAxiDma_BdGetSts(BdCurPtr); + if ((BdSts & XAXIDMA_BD_STS_ALL_ERR_MASK) || + (!(BdSts & XAXIDMA_BD_STS_COMPLETE_MASK))) { + AxiEthernetUtilErrorTrap("Rx Error"); + return XST_FAILURE; + } + else { + + RxFrameLength = + (XAxiDma_BdRead(BdCurPtr,XAXIDMA_BD_USR4_OFFSET)) & 0x0000FFFF; + } + + /* + * This word has indication about what type of frame is received. + * Current hardware flags Broadcast, IP multicast, and MAC multicast. + * IP multicast mode, MAC address is 01:00:5E:AB:CD:EF, + * MAC multicast mode, MAC address is 01:QR:ST:UV:WX:YZ, e.g. + * the least significant bit of most significant byte is 1. + * Check to see if further ethernet MAC verification is required... + */ + RxStatusControlWord =XAxiDma_BdRead(BdCurPtr,XAXIDMA_BD_USR2_OFFSET); + if(RxStatusControlWord & XAE_BD_RX_USR2_IP_MCAST_MASK) { + /* + * The multicast MAC address is stored in status words + * 0 and 1 in the AXI4-Stream. + */ + + Reg = XAxiDma_BdRead(BdPtr, XAXIDMA_BD_USR0_OFFSET); + MulticastAdd[5] = ((Reg >> 8) & 0xFF); + MulticastAdd[4] = (Reg & 0xFF); + + Reg = XAxiDma_BdRead(BdPtr, XAXIDMA_BD_USR1_OFFSET); + MulticastAdd[3] = ((Reg >> 24) & 0xFF); + MulticastAdd[2] = ((Reg >> 16) & 0xFF); + MulticastAdd[1] = ((Reg >> 8) & 0xFF); + MulticastAdd[0] = (Reg & 0xFF); + + if (!AxiEthernet_GetExtMulticast(MulticastAdd)) { + AxiEthernetUtilErrorTrap("Multicast address mismatch\n"); + return XST_FAILURE; + } + } + else { + AxiEthernetUtilErrorTrap("Not a multicast frame\n"); + return XST_FAILURE; + } + + /* + * Destination address(multicast MAC address in this example) is part + * of received frame, comparing the Tx and Rx frame would include the + * multicast address verification again. + */ + if (AxiEthernetUtilFrameVerify(&TxFrame, &RxFrame) != 0) { + AxiEthernetUtilErrorTrap("Data mismatch"); + return XST_FAILURE; + } + + /* + * Return the RxBD back to the channel for later allocation. Free the + * exact number we just post processed. + */ + Status = XAxiDma_BdRingFree(RxRingPtr, 1, BdPtr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error freeing up TxBDs"); + return XST_FAILURE; + } + + return XST_SUCCESS; +} + + +/*****************************************************************************/ +/** +* AxiEthernet_AddExtMulticast adds the multicast Ethernet address table in +* DDR. This table is mainly for software driver to perform the final address +* filtering. +* +* Once an Ethernet address is programmed, the Axi Ethernet channel will begin +* receiving data sent from that address. The way to prevent the +* Axi Ethernet channel from receiving messages from an Ethernet address in the +* DDR table is to clear it with AxiEthernet_ClearExtMulticast(). +* +* @param AddressPtr is a pointer to the 6-byte Ethernet address to set. +* +* @return - XST_SUCCESS,on successful completion +* - XST_INVALID_PARAM, if input MAC address is not between +* 01:00:5E:00:00:00 and 01:00:5E:7F:FF:FF, as per RFC1112. +* @note +* +* This table is independent to BRAM table that is used for HW address +* filtering. It is user's responsiblility to maintain these tables. +* +* In the multicast table, hardware requires it to be 'indexed' with bit 22-8, +* 15 bits in total of mac address. This address filtering is done in hardware +* and provisioned with XAxiEthernet_[Add|Clear]ExtMulticastSet() APIs. +* +* This routine consider all 2**23 possible multicast ethernet addresses to be +* 8Mx1 bit or 1M bytes memory area. All defined multicast addresses are from +* 01.00.5E.00.00.00 to 01.00.5E.7F.FF.FF +* The first 25 bit out of 48 bit are static, so they will not be part of +* calculation. +* +* In memory, software used every bit represents every defined MAC address, +* then we have this formula for table lookup. +* offset + (address >> 3) => memory location. +* address % 32 => bit location for multicast address +* Let's take 01:00:5E:00:01:FF(hex), +* memory location : 0x3F +* bit location : 0x1F + *****************************************************************************/ +static int AxiEthernet_AddExtMulticast(void *AddressPtr) +{ + u32 MaOffset; + u32 Loc; + u32 Bval; + u32 BvalNew; + u8 *Aptr = (u8 *) AddressPtr; + + /* + * Verify if address is a good/valid multicast address, between + * 01:00:5E:00:00:00 to 01:00:5E:7F:FF:FF per RFC1112. + * This address is referenced to be index to BRAM table. + */ + if ((0x01 != Aptr[0]) || (0x00 != Aptr[1]) || (0x5e != Aptr[2]) || + (0x0 != (Aptr[3] & 0x80))) { + return (XST_INVALID_PARAM); + } + + /* Program software Multicast table in RAM */ + /* Calculate memory locations in software table */ + MaOffset = Aptr[5]; + MaOffset |= Aptr[4] << 8; + MaOffset |= Aptr[3] << 16; + + Loc = ((MaOffset >> 5) << 2); /* it is not same as ">> 3" */ + + /* Bit value */ + BvalNew = 1 << (MaOffset % 32); + + /* Program software Multicast table in RAM */ + Bval = XAxiEthernet_ReadReg((u32)&McastAddressTable, Loc); + XAxiEthernet_WriteReg((u32)&McastAddressTable, Loc, Bval | BvalNew); + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** +* AxiEthernet_ClearExtMulticast clears the Ethernet address in multicast +* address table in DDR. +* +* @param AddressPtr is a pointer to the 6-byte Ethernet address to set. +* +* @return - XST_SUCCESS,on successful completion +* - XST_INVALID_PARAM, if input MAC address is not between +* 01:00:5E:00:00:00 and 01:00:5E:7F:FF:FF, as per RFC1112. +* +* @note +* +* Please reference AxiEthernet_AddExtMulticast for multicast ethernet address +* index and bit value calculation. +* +*****************************************************************************/ +static int AxiEthernet_ClearExtMulticast(void *AddressPtr) +{ + u32 MaOffset; + u32 Loc; + u32 Bval; + u32 BvalNew; + u8 *Aptr = (u8 *) AddressPtr; + + /* + * Verify if address is a good/valid multicast address, between + * 01:00:5E:00:00:00 to 01:00:5E:7F:FF:FF per RFC1112. + * This address is referenced to be index to BRAM table. + */ + + if ((0x01 != Aptr[0]) || (0x00 != Aptr[1]) || (0x5e != Aptr[2]) || + (0x0 != (Aptr[3] & 0x80))) { + return (XST_INVALID_PARAM); + } + + /* Program software Multicast table in RAM */ + /* Calculate memory locations in software table */ + MaOffset = Aptr[5]; + MaOffset |= Aptr[4] << 8; + MaOffset |= Aptr[3] << 16; + + Loc = ((MaOffset >> 5) << 2); + + /* Bit value */ + BvalNew = 1 << (MaOffset % 32); + + /* Program software Multicast table in RAM */ + Bval = XAxiEthernet_ReadReg((u32)&McastAddressTable, Loc); + XAxiEthernet_WriteReg((u32)&McastAddressTable, Loc, Bval & ~BvalNew); + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** +* AxiEthernet_GetExtMulticast verifies the Ethernet address in multicast +* address table in DDR. +* +* @param AddressPtr is a pointer to the 6-byte Ethernet address to set. +* +* @return -TRUE, if AddressPtr is provisioned. +* -FALSE, if AddressPtr is not provisioned. +* @note +* +* Please reference AxiEthernet_AddExtMulticast for multicast ethernet address +* index and bit value calculation. +* +*****************************************************************************/ +static int AxiEthernet_GetExtMulticast(void *AddressPtr) +{ + u32 MaOffset; + u32 Loc; + u32 Bval; + u8 *Aptr = (u8 *) AddressPtr; + + + /* + * Verify if address is a good/valid multicast address, between + * 01:00:5E:00:00:00 to 01:00:5E:7F:FF:FF per RFC1112. + * This address is referenced to be index to BRAM table. + */ + if ((0x01 != Aptr[0]) || (0x00 != Aptr[1]) || (0x5e != Aptr[2]) || + (0x0 != (Aptr[3] & 0x80))) { + return (FALSE); + } + + /* Program software Multicast table in RAM */ + /* Calculate memory locations in software table */ + MaOffset = Aptr[5]; + MaOffset |= Aptr[4] << 8; + MaOffset |= Aptr[3] << 16; + + Loc = ((MaOffset >> 5) << 2); + + /* Program software Multicast table in RAM */ + Bval = XAxiEthernet_ReadReg((u32)&McastAddressTable, Loc); + + if (Bval & (1 << (MaOffset % 32))) { + return (TRUE); + } else { + return (FALSE); + } +} + + +/*****************************************************************************/ +/** +* +* This is the DMA TX callback function to be called by TX interrupt handler. +* This function handles BDs finished by hardware. +* +* @param TxRingPtr is a pointer to TX channel of the DMA engine. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void TxCallBack(XAxiDma_BdRing *TxRingPtr) +{ + /* + * Disable the transmit related interrupts + */ + XAxiDma_BdRingIntDisable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK); + /* + * Increment the counter so that main thread knows something happened + */ + FramesTx++; +} + +/*****************************************************************************/ +/** +* +* This is the DMA TX Interrupt handler function. +* +* @param TxRingPtr is a pointer to TX channel of the DMA engine. +* +* @return None. +* +* @note This Interrupt handler MUST clear pending interrupts before +* handling them by calling the call back. Otherwise the following +* corner case could raise some issue: +* +* A packet got transmitted and a TX interrupt got asserted. If +* the interrupt handler calls the callback before clearing the +* interrupt, a new packet may get transmitted in the callback. +* This new packet then can assert one more TX interrupt before +* the control comes out of the callback function. Now when +* eventually control comes out of the callback function, it will +* never know about the second new interrupt and hence while +* clearing the interrupts, would clear the new interrupt as well +* and will never process it. +* To avoid such cases, interrupts must be cleared before calling +* the callback. +* +******************************************************************************/ +static void TxIntrHandler(XAxiDma_BdRing *TxRingPtr) +{ + u32 IrqStatus; + + /* Read pending interrupts */ + IrqStatus = XAxiDma_BdRingGetIrq(TxRingPtr); + + /* Acknowledge pending interrupts */ + XAxiDma_BdRingAckIrq(TxRingPtr, IrqStatus); + + /* + * If no interrupt is asserted, raise error flag, reset the + * hardware to recover from the error, and return with no further + * processing. + */ + if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) { + DeviceErrors++; + AxiEthernetUtilErrorTrap + ("AXIDma: No interrupts asserted in TX status register"); + XAxiDma_Reset(&DmaInstance); + if(!XAxiDma_ResetIsDone(&DmaInstance)) { + AxiEthernetUtilErrorTrap ("AxiDMA: Error: Could not reset\n"); + } + return; + } + + /* If error interrupt is asserted, raise error flag, reset the + * hardware to recover from the error, and return with no further + * processing. + */ + if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) { + + AxiEthernetUtilErrorTrap("AXIDMA: TX Error interrupts\n"); + /* + * Reset should never fail for transmit channel + */ + XAxiDma_Reset(&DmaInstance); + + if(!XAxiDma_ResetIsDone(&DmaInstance)) { + + AxiEthernetUtilErrorTrap ("AxiDMA: Error: Could not reset\n"); + } + return; + } + + /* + * If Transmit done interrupt is asserted, call TX call back function + * to handle the processed BDs and raise the according flag + */ + if ((IrqStatus & (XAXIDMA_IRQ_DELAY_MASK | XAXIDMA_IRQ_IOC_MASK))) { + TxCallBack(TxRingPtr); + } +} + + +/*****************************************************************************/ +/** +* +* This is the DMA RX callback function to be called by RX interrupt handler. +* This function handles finished BDs by hardware, attaches new buffers to those +* BDs, and give them back to hardware to receive more incoming packets +* +* @param RxRingPtr is a pointer to RX channel of the DMA engine. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void RxCallBack(XAxiDma_BdRing *RxRingPtr) +{ + /* + * Disable the receive related interrupts + */ + XAxiDma_BdRingIntDisable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK); + /* + * Increment the counter so that main thread knows something + * happened + */ + FramesRx++; +} + + +/*****************************************************************************/ +/** +* +* This is the Receive handler function for examples 1 and 2. +* It will increment a shared counter, receive and validate the frame. +* +* @param RxRingPtr is a pointer to the DMA ring instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void RxIntrHandler(XAxiDma_BdRing *RxRingPtr) +{ + u32 IrqStatus; + + /* Read pending interrupts */ + IrqStatus = XAxiDma_BdRingGetIrq(RxRingPtr); + + /* Acknowledge pending interrupts */ + XAxiDma_BdRingAckIrq(RxRingPtr, IrqStatus); + + /* + * If no interrupt is asserted, raise error flag, reset the + * hardware to recover from the error, and return with no further + * processing. + */ + if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) { + DeviceErrors++; + AxiEthernetUtilErrorTrap + ("AXIDma: No interrupts asserted in RX status register"); + XAxiDma_Reset(&DmaInstance); + if(!XAxiDma_ResetIsDone(&DmaInstance)) { + AxiEthernetUtilErrorTrap ("Could not reset\n"); + } + return; + } + + /* If error interrupt is asserted, raise error flag, reset the + * hardware to recover from the error, and return with no further + * processing. + */ + if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) { + + AxiEthernetUtilErrorTrap("AXIDMA: RX Error interrupts\n"); + + /* Reset could fail and hang + * NEED a way to handle this or do not call it?? + */ + XAxiDma_Reset(&DmaInstance); + + if(!XAxiDma_ResetIsDone(&DmaInstance)) { + AxiEthernetUtilErrorTrap ("Could not reset\n"); + } + + return; + } + + /* + * If Reception done interrupt is asserted, call RX call back function + * to handle the processed BDs and then raise the according flag. + */ + if ((IrqStatus & (XAXIDMA_IRQ_DELAY_MASK | XAXIDMA_IRQ_IOC_MASK))) { + RxCallBack(RxRingPtr); + } +} + +/*****************************************************************************/ +/** +* +* This is the Error handler callback function and this function increments the +* the error counter so that the main thread knows the number of errors. +* +* @param AxiEthernet is a reference to the Axi Ethernet device instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void AxiEthernetErrorHandler(XAxiEthernet *AxiEthernet) +{ + u32 Pending = XAxiEthernet_IntPending(AxiEthernet); + + if (Pending & XAE_INT_RXRJECT_MASK) { + AxiEthernetUtilErrorTrap("AxiEthernet: Rx packet rejected"); + } + + if (Pending & XAE_INT_RXFIFOOVR_MASK) { + AxiEthernetUtilErrorTrap("AxiEthernet: Rx fifo over run"); + } + + XAxiEthernet_IntClear(AxiEthernet, Pending); + + /* + * Bump counter + */ + DeviceErrors++; +} + + + +/*****************************************************************************/ +/** +* +* This function setups the interrupt system so interrupts can occur for the +* Axi Ethernet. This function is application-specific since the actual system +* may or may not have an interrupt controller. The Axi Ethernet could be +* directly connected to a processor without an interrupt controller. The user +* should modify this function to fit the application. +* +* @param IntcInstancePtr is a pointer to the instance of the Intc +* component. +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* AxiEthernet component. +* @param DmaInstancePtr is a pointer to the instance of the AXI DMA +* component. +* @param AxiEthernetDeviceId is Device ID of the Axi Ethernet Device , +* typically XPAR__DEVICE_ID value from +* xparameters.h. +* @param AxiEthernetIntrId is the Interrupt ID and is typically +* XPAR___VEC_ID +* value from xparameters.h. +* @param DmaRxIntrId is the interrupt id for DMA Rx and is typically +* taken from XPAR__CONNECTED_DMARX_INTR +* @param DmaTxIntrId is the interrupt id for DMA Tx and is typically +* taken from XPAR__CONNECTED_DMATX_INTR +* +* @return - XST_SUCCESS, if successful. +* - XST_FAILURE, if failure condition. +* +* @note None. +* +******************************************************************************/ +static int AxiEthernetSetupIntrSystem(INTC *IntcInstancePtr, + XAxiEthernet *AxiEthernetInstancePtr, + XAxiDma *DmaInstancePtr, + u16 AxiEthernetIntrId, + u16 DmaRxIntrId, + u16 DmaTxIntrId) +{ + XAxiDma_BdRing * TxRingPtr = XAxiDma_GetTxRing(DmaInstancePtr); + XAxiDma_BdRing * RxRingPtr = XAxiDma_GetRxRing(DmaInstancePtr); + int Status; +#ifdef XPAR_INTC_0_DEVICE_ID +#ifndef TESTAPP_GEN + /* + * Initialize the interrupt controller and connect the ISR + */ + Status = XIntc_Initialize(IntcInstancePtr, INTC_DEVICE_ID); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Unable to intialize the interrupt controller"); + return XST_FAILURE; + } +#endif + +#if XPAR_INTC_0_HAS_FAST == 1 + + TxRingPtr_Fast = TxRingPtr; + RxRingPtr_Fast = RxRingPtr; + AxiEthernetInstancePtr_Fast = AxiEthernetInstancePtr; + Status = XIntc_ConnectFastHandler(IntcInstancePtr, AxiEthernetIntrId, + (XFastInterruptHandler) AxiEthernetErrorFastHandler); + Status |= XIntc_ConnectFastHandler(IntcInstancePtr, DmaTxIntrId, + (XFastInterruptHandler) TxIntrFastHandler); + Status |= XIntc_ConnectFastHandler(IntcInstancePtr, DmaRxIntrId, + (XFastInterruptHandler) RxIntrFastHandler); +#else + Status = XIntc_Connect(IntcInstancePtr, AxiEthernetIntrId, + (XInterruptHandler) + AxiEthernetErrorHandler, + AxiEthernetInstancePtr); + Status |= XIntc_Connect(IntcInstancePtr, DmaTxIntrId, + (XInterruptHandler) TxIntrHandler, + TxRingPtr); + Status |= XIntc_Connect(IntcInstancePtr, DmaRxIntrId, + (XInterruptHandler) RxIntrHandler, + RxRingPtr); +#endif + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Unable to connect ISR to interrupt controller"); + return XST_FAILURE; + } + +#ifndef TESTAPP_GEN + /* + * Start the interrupt controller + */ + Status = XIntc_Start(IntcInstancePtr, XIN_REAL_MODE); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error starting intc"); + return XST_FAILURE; + } +#endif + + /* + * Enable interrupts from the hardware + */ + XIntc_Enable(IntcInstancePtr, AxiEthernetIntrId); + XIntc_Enable(IntcInstancePtr, DmaTxIntrId); + XIntc_Enable(IntcInstancePtr, DmaRxIntrId); +#else + XScuGic_Config *IntcConfig; + + + /* + * Initialize the interrupt controller driver so that it is ready to + * use. + */ + IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID); + if (NULL == IntcConfig) { + return XST_FAILURE; + } + + Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig, + IntcConfig->CpuBaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + + XScuGic_SetPriorityTriggerType(IntcInstancePtr, DmaTxIntrId, 0xA0, 0x3); + + XScuGic_SetPriorityTriggerType(IntcInstancePtr, DmaRxIntrId, 0xA0, 0x3); + + XScuGic_SetPriorityTriggerType(IntcInstancePtr, AxiEthernetIntrId, 0xA0, 0x3); + /* + * Connect the device driver handler that will be called when an + * interrupt for the device occurs, the handler defined above performs + * the specific interrupt processing for the device. + */ + Status = XScuGic_Connect(IntcInstancePtr, DmaTxIntrId, + (Xil_InterruptHandler)TxIntrHandler, + TxRingPtr); + if (Status != XST_SUCCESS) { + return Status; + } + + Status = XScuGic_Connect(IntcInstancePtr, DmaRxIntrId, + (Xil_InterruptHandler)RxIntrHandler, + RxRingPtr); + if (Status != XST_SUCCESS) { + return Status; + } + + Status = XScuGic_Connect(IntcInstancePtr, AxiEthernetIntrId, + (Xil_InterruptHandler)AxiEthernetErrorHandler, + AxiEthernetInstancePtr); + if (Status != XST_SUCCESS) { + return Status; + } + + XScuGic_Enable(IntcInstancePtr, AxiEthernetIntrId); + XScuGic_Enable(IntcInstancePtr, DmaTxIntrId); + XScuGic_Enable(IntcInstancePtr, DmaRxIntrId); +#endif +#ifndef TESTAPP_GEN + Xil_ExceptionInit(); + + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, + (Xil_ExceptionHandler)INTC_HANDLER, + (void *)(IntcInstancePtr)); + + Xil_ExceptionEnable(); +#endif + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function disables the interrupts that occur for Axi Ethernet. +* +* @param IntcInstancePtr is a pointer to the instance of the Intc +* component. +* @param AxiEthernetIntrId is the Interrupt ID and is typically +* XPAR___VEC_ID +* value from xparameters.h. +* @param DmaRxIntrId is the interrupt id for DMA Rx and is typically +* taken from XPAR__CONNECTED_DMARX_INTR +* @param DmaTxIntrId is the interrupt id for DMA Tx and is typically +* taken from XPAR__CONNECTED_DMATX_INTR +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void AxiEthernetDisableIntrSystem(INTC *IntcInstancePtr, + u16 AxiEthernetIntrId, + u16 DmaRxIntrId, + u16 DmaTxIntrId) +{ +#ifdef XPAR_INTC_0_DEVICE_ID + /* + * Disconnect the interrupts for the DMA TX and RX channels + */ + XIntc_Disconnect(IntcInstancePtr, DmaTxIntrId); + XIntc_Disconnect(IntcInstancePtr, DmaRxIntrId); + + /* + * Disconnect and disable the interrupt for the Axi Ethernet device + */ + XIntc_Disconnect(IntcInstancePtr, AxiEthernetIntrId); + +#else + /* + * Disconnect the interrupts for the DMA TX and RX channels + */ + XScuGic_Disconnect(IntcInstancePtr, DmaTxIntrId); + XScuGic_Disconnect(IntcInstancePtr, DmaRxIntrId); + + /* + * Disconnect and disable the interrupt for the AxiEthernet device + */ + XScuGic_Disconnect(IntcInstancePtr, AxiEthernetIntrId); +#endif +} + +#if XPAR_INTC_0_HAS_FAST == 1 +/*****************************************************************************/ +/** +* +* Fast Error Handler which calls AxiEthernetErrorHandler. +* +* @param None +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void AxiEthernetErrorFastHandler(void) +{ + AxiEthernetErrorHandler((XAxiEthernet *)AxiEthernetInstancePtr_Fast); +} + +/*****************************************************************************/ +/** +* +* Fast Tramsmit Handler which calls TxIntrHandler. +* +* @param None +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void TxIntrFastHandler(void) +{ + TxIntrHandler((XAxiDma_BdRing *)TxRingPtr_Fast); +} + +/*****************************************************************************/ +/** +* +* Fast Receive Handler which calls RxIntrHandler. +* +* @param None +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void RxIntrFastHandler(void) +{ + RxIntrHandler((XAxiDma_BdRing *)RxRingPtr_Fast); +} + +#endif diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example_extvlan.c b/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example_extvlan.c new file mode 100644 index 00000000..4d4dbfa7 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example_extvlan.c @@ -0,0 +1,1451 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/** +* +* @file xaxiethernet_example_extvlan.c +* +* Implements examples that utilize the Axi Ethernet's interrupt driven SGDMA +* packet transfer mode to send and receive frames. +* +* This example demonstrates: +* +* - How to setup VLAN strip/translate/tag in TX and RX direction +* - How the VLAN tags are handled +* - What is the expected VLAN tag(s) after VLAN functions are invoked +* +* Functional guide to example: +* +* - AxiEthernetSgDmaIntrExtVlanExample demonstrates the extended VLAN +* capability. The HW must be setup for extended VLAN for this example +* to execute. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a asa  4/30/10  First release based on the ll temac driver
+* 1.01a asa  12/10/10 Changes made to enable the AXIDMA Tx/Rx ring interrupts
+*		      		  before allocation of Tx/Rx BDs.
+* 3.00a asa  6/25/12  Modifed XAxiDma_BdSetLength API call to support new
+*		      		  AXI DMA driver version 7.00a.
+* 3.00a bss  10/22/12 Added support for Fast Interrupt Handlers.
+* 3.01a srt  02/14/13 Added support for Zynq (CR 681136)
+*
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xaxiethernet_example.h" +#include "xaxidma.h" +#include "xil_cache.h" +#include "xil_exception.h" + +#ifdef XPAR_INTC_0_DEVICE_ID +#include "xintc.h" +#else +#include "xscugic.h" +#endif + +#ifdef XPAR_XUARTNS550_NUM_INSTANCES +#include "xuartns550_l.h" +#endif +/*************************** Constant Definitions ****************************/ +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#ifndef TESTAPP_GEN +#define AXIETHERNET_DEVICE_ID XPAR_AXIETHERNET_0_DEVICE_ID +#define AXIDMA_DEVICE_ID XPAR_AXIDMA_0_DEVICE_ID +#ifdef XPAR_INTC_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID +#define AXIETHERNET_IRPT_INTR XPAR_INTC_0_AXIETHERNET_0_VEC_ID +#define DMA_RX_IRPT_INTR XPAR_AXIETHERNET_0_CONNECTED_DMARX_INTR +#define DMA_TX_IRPT_INTR XPAR_AXIETHERNET_0_CONNECTED_DMATX_INTR +#else +#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID +#define AXIETHERNET_IRPT_INTR XPAR_FABRIC_AXIETHERNET_0_VEC_ID +#define DMA_RX_IRPT_INTR XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_VEC_ID +#define DMA_TX_IRPT_INTR XPAR_FABRIC_AXIDMA_0_MM2S_INTROUT_VEC_ID +#endif +#endif + +#define RXBD_CNT 128 /* Number of RxBDs to use */ +#define TXBD_CNT 128 /* Number of TxBDs to use */ +#define BD_ALIGNMENT XAXIDMA_BD_MINIMUM_ALIGNMENT/* + * Byte alignment + * of BDs + */ +#define PAYLOAD_SIZE 1000 /* Payload size used in examples */ +#define BD_VLAN_TPID_OFFSET 3 /* AXI4-Stream status Word offset from + * the start of app user words in BD. + * TPID is at status word 3, bits + * 31-16 + */ +#define BD_VLAN_VID_OFFSET 4 /* AXI4-Stream status word offset from + * the start of app user words in BD. + * VID is at status word 4, bits + * 31-16 + */ +#define TPID_MASK 0xFFFF0000 /* Mask to extract TPID from + * the AXI4 STream status + * word + */ + +/* + * Number of bytes to reserve for BD space for the number of BDs desired + */ +#define RXBD_SPACE_BYTES XAxiDma_BdRingMemCalc(BD_ALIGNMENT, RXBD_CNT) +#define TXBD_SPACE_BYTES XAxiDma_BdRingMemCalc(BD_ALIGNMENT, TXBD_CNT) + + +/*************************** Variable Definitions ****************************/ + +static EthernetFrame TxFrame; /* Transmit buffer */ +static EthernetFrame RxFrame; /* Receive buffer */ + +XAxiEthernet AxiEthernetInstance; +XAxiDma DmaInstance; + +#if XPAR_INTC_0_HAS_FAST == 1 + +/* Variables for Fast Interrupt Handlers */ +XAxiEthernet *AxiEthernetInstancePtr_Fast; +XAxiDma_BdRing *TxRingPtr_Fast; +XAxiDma_BdRing *RxRingPtr_Fast; + +/****** Fast Interrupt Handlers prototypes ******/ + +static void AxiEthernetErrorFastHandler(void) __attribute__ ((fast_interrupt)); + +static void RxIntrFastHandler(void) __attribute__ ((fast_interrupt)); + +static void TxIntrFastHandler(void) __attribute__ ((fast_interrupt)); + +#else + +static void AxiEthernetErrorHandler(XAxiEthernet *AxiEthernet); +static void RxIntrHandler(XAxiDma_BdRing *RxRingPtr); +static void TxIntrHandler(XAxiDma_BdRing *TxRingPtr); + +#endif + +/* + * Aligned memory segments to be used for buffer descriptors + */ +char RxBdSpace[RXBD_SPACE_BYTES] __attribute__ ((aligned(BD_ALIGNMENT))); +char TxBdSpace[TXBD_SPACE_BYTES] __attribute__ ((aligned(BD_ALIGNMENT))); + +/* + * Counters to be incremented by callbacks + */ +static volatile int FramesRx; /* Num of frames that have been received */ +static volatile int FramesTx; /* Num of frames that have been sent */ +static volatile int DeviceErrors; /* Num of errors detected in the device */ + +#ifdef XPAR_INTC_0_DEVICE_ID +#define INTC XIntc +#define INTC_HANDLER XIntc_InterruptHandler +#else +#define INTC XScuGic +#define INTC_HANDLER XScuGic_InterruptHandler +#endif + +#ifndef TESTAPP_GEN +static INTC IntcInstance; +#endif + +/*************************** Function Prototypes *****************************/ + +/* + * Examples + */ +int AxiEthernetExtVlanExample(INTC *IntcInstancePtr, + XAxiEthernet *AxiEthernetInstancePtr, + XAxiDma *DmaInstancePtr, + u16 AxiEthernetDeviceId, + u16 AxiDmaDeviceId, + u16 AxiEthernetIntrId, + u16 DmaRxIntrId, + u16 DmaTxIntrId); +int AxiEthernetSgDmaIntrExtVlanExample(XAxiEthernet *AxiEthernetInstancePtr, + XAxiDma *DmaInstancePtr); + +/* + * Interrupt setup and Callbacks for examples + */ + +static int AxiEthernetSetupIntrSystem(INTC *IntcInstancePtr, + XAxiEthernet *AxiEthernetInstancePtr, + XAxiDma *DmaInstancePtr, + u16 AxiEthernetIntrId, + u16 DmaRxIntrId, u16 DmaTxIntrId); + +static void AxiEthernetDisableIntrSystem(INTC *IntcInstancePtr, + u16 AxiEthernetIntrId, + u16 DmaRxIntrId, u16 DmaTxIntrId); + + +/*****************************************************************************/ +/** +* +* This is the main function for the Axi Ethernet example. This function is not +* included if the example is generated from the TestAppGen test tool. +* +* @param None. +* +* @return - XST_SUCCESS to indicate success. +* - XST_FAILURE to indicate failure +* +* @note None. +* +****************************************************************************/ +#ifndef TESTAPP_GEN +int main(void) +{ + int Status; + +#ifdef XPAR_XUARTNS550_NUM_INSTANCES + XUartNs550_SetBaud(STDIN_BASEADDRESS, XPAR_XUARTNS550_CLOCK_HZ, 9600); + XUartNs550_SetLineControlReg(STDIN_BASEADDRESS, XUN_LCR_8_DATA_BITS); +#endif + +#if XPAR_MICROBLAZE_USE_ICACHE + Xil_ICacheInvalidate(); + Xil_ICacheEnable(); +#endif + +#if XPAR_MICROBLAZE_USE_DCACHE + Xil_DCacheInvalidate(); + Xil_DCacheEnable(); +#endif + + AxiEthernetUtilErrorTrap("\r\n--- Enter main() ---"); + AxiEthernetUtilErrorTrap("This test may take several minutes to finish"); + + /* + * Call the Axi Ethernet vlan example main function + */ + Status = AxiEthernetExtVlanExample(&IntcInstance, + &AxiEthernetInstance, + &DmaInstance, + AXIETHERNET_DEVICE_ID, + AXIDMA_DEVICE_ID, + AXIETHERNET_IRPT_INTR, + DMA_RX_IRPT_INTR, + DMA_TX_IRPT_INTR); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Failed test intr sgdma"); + AxiEthernetUtilErrorTrap("--- Exiting main() ---"); + return XST_FAILURE; + } + + AxiEthernetUtilErrorTrap("Test passed"); + AxiEthernetUtilErrorTrap("--- Exiting main() ---"); + + return XST_SUCCESS; + +} +#endif + +/*****************************************************************************/ +/** +* +* This function demonstrates the usage usage of the Axi Ethernet by sending +* and receiving frames in interrupt driven SGDMA mode. +* +* +* @param IntcInstancePtr is a pointer to the instance of the Intc +* component. +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* AxiEthernet component. +* @param DmaInstancePtr is a pointer to the instance of the AXIDMA +* component. +* @param AxiEthernetDeviceId is Device ID of the Axi Ethernet Device , +* typically XPAR__DEVICE_ID value from +* xparameters.h. +* @param AxiDmaDeviceId is Device ID of the Axi DMAA Device , +* typically XPAR__DEVICE_ID value from +* xparameters.h. +* @param AxiEthernetIntrId is the Interrupt ID and is typically +* XPAR___VEC_ID +* value from xparameters.h. +* @param DmaRxIntrId is the interrupt id for DMA Rx and is typically +* taken from XPAR__CONNECTED_DMARX_INTR +* @param DmaTxIntrId is the interrupt id for DMA Tx and is typically +* taken from XPAR__CONNECTED_DMATX_INTR +* +* @return -XST_SUCCESS to indicate success. +* -XST_FAILURE to indicate failure. +* +* @note AxiDma hardware must be initialized before initializing +* AxiEthernet. Since AxiDma reset line is connected to the +* AxiEthernet reset line, a reset of AxiDma hardware during its +* initialization would reset AxiEthernet. +* +******************************************************************************/ +int AxiEthernetExtVlanExample(INTC *IntcInstancePtr, + XAxiEthernet *AxiEthernetInstancePtr, + XAxiDma *DmaInstancePtr, + u16 AxiEthernetDeviceId, + u16 AxiDmaDeviceId, + u16 AxiEthernetIntrId, + u16 DmaRxIntrId, + u16 DmaTxIntrId) +{ + int Status; + int LoopbackSpeed; + XAxiEthernet_Config *MacCfgPtr; + XAxiDma_BdRing *RxRingPtr = XAxiDma_GetRxRing(DmaInstancePtr); + XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(DmaInstancePtr); + XAxiDma_Bd BdTemplate; + XAxiDma_Config* DmaConfig; + + /*************************************/ + /* Setup device for first-time usage */ + /*************************************/ + + /* + * Get the configuration of AxiEthernet hardware. + */ + MacCfgPtr = XAxiEthernet_LookupConfig(AxiEthernetDeviceId); + + /* + * Check if DMA is present or not. + */ + if(MacCfgPtr->AxiDevType != XPAR_AXI_DMA) { + AxiEthernetUtilErrorTrap + ("Device HW not configured for SGDMA mode\r\n"); + return XST_FAILURE; + } + + DmaConfig = XAxiDma_LookupConfig(AxiDmaDeviceId); + + /* + * Initialize AXIDMA engine. AXIDMA engine must be initialized before + * AxiEthernet. During AXIDMA engine initialization, AXIDMA hardware is + * reset, and since AXIDMA reset line is connected to AxiEthernet, this + * would ensure a reset of AxiEthernet. + */ + Status = XAxiDma_CfgInitialize(DmaInstancePtr, DmaConfig); + if(Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error initializing DMA\r\n"); + return XST_FAILURE; + } + + /* + * Initialize AxiEthernet hardware. + */ + Status = XAxiEthernet_CfgInitialize(AxiEthernetInstancePtr, MacCfgPtr, + MacCfgPtr->BaseAddress); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error in initialize"); + return XST_FAILURE; + } + + /* + * Set the MAC address + */ + Status = XAxiEthernet_SetMacAddress(AxiEthernetInstancePtr, + AxiEthernetMAC); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting MAC address"); + return XST_FAILURE; + } + + /* + * Setup RxBD space. + * + * We have already defined a properly aligned area of memory to store + * RxBDs at the beginning of this source code file so just pass its + * address into the function. No MMU is being used so the physical and + * virtual addresses are the same. + * + * Setup a BD template for the Rx channel. This template will be copied + * to every RxBD. We will not have to explicitly set these again. + */ + + /* + * Create the RxBD ring + */ + Status = XAxiDma_BdRingCreate(RxRingPtr, (u32) &RxBdSpace, + (u32) &RxBdSpace, BD_ALIGNMENT, RXBD_CNT); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting up RxBD space"); + return XST_FAILURE; + } + XAxiDma_BdClear(&BdTemplate); + Status = XAxiDma_BdRingClone(RxRingPtr, &BdTemplate); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error initializing RxBD space"); + return XST_FAILURE; + } + + /* + * Setup TxBD space. + * + * Like RxBD space, we have already defined a properly aligned area of + * memory to use. + */ + + /* + * Create the TxBD ring + */ + Status = XAxiDma_BdRingCreate(TxRingPtr, (u32) &TxBdSpace, + (u32) &TxBdSpace, BD_ALIGNMENT, TXBD_CNT); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting up TxBD space"); + return XST_FAILURE; + } + + /* + * We reuse the bd template, as the same one will work for both rx and + * tx. + */ + Status = XAxiDma_BdRingClone(TxRingPtr, &BdTemplate); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error initializing TxBD space"); + return XST_FAILURE; + } + + /* + * Set PHY to loopback, speed depends on phy type. + * MII is 100 and all others are 1000. + */ + if (XAxiEthernet_GetPhysicalInterface(AxiEthernetInstancePtr) + == XAE_PHY_TYPE_MII){ + LoopbackSpeed = AXIETHERNET_LOOPBACK_SPEED; + } else { + LoopbackSpeed = AXIETHERNET_LOOPBACK_SPEED_1G; + } + AxiEthernetUtilEnterLoopback(AxiEthernetInstancePtr, LoopbackSpeed); + + /* + * Set PHY<-->MAC data clock + */ + Status = XAxiEthernet_SetOperatingSpeed(AxiEthernetInstancePtr, + (u16)LoopbackSpeed); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Setting the operating speed of the MAC needs a delay. There + * doesn't seem to be register to poll, so please consider this + * during your application design. + */ + AxiEthernetUtilPhyDelay(2); + + /* + * Connect to the interrupt controller and enable interrupts + */ + Status = AxiEthernetSetupIntrSystem(IntcInstancePtr, + AxiEthernetInstancePtr, + DmaInstancePtr, + AxiEthernetIntrId, DmaRxIntrId, + DmaTxIntrId); + + /****************************/ + /* Run the example */ + /****************************/ + + /* Run the new VLAN feature. Make sure HW has the capability */ + if (XAxiEthernet_IsTxVlanTran(AxiEthernetInstancePtr) && + XAxiEthernet_IsTxVlanStrp(AxiEthernetInstancePtr) && + XAxiEthernet_IsTxVlanTag(AxiEthernetInstancePtr) && + XAxiEthernet_IsRxVlanTran(AxiEthernetInstancePtr) && + XAxiEthernet_IsRxVlanStrp(AxiEthernetInstancePtr) && + XAxiEthernet_IsRxVlanTag(AxiEthernetInstancePtr)) { + Status = AxiEthernetSgDmaIntrExtVlanExample + (AxiEthernetInstancePtr,DmaInstancePtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + } + + /* + * Disable the interrupts for the AxiEthernet device + */ + AxiEthernetDisableIntrSystem(IntcInstancePtr, AxiEthernetIntrId, + DmaRxIntrId, DmaTxIntrId); + + /* + * Stop the device + */ + XAxiEthernet_Stop(AxiEthernetInstancePtr); + + return XST_SUCCESS; +} + + +/*****************************************************************************/ +/** +* +* This example sends and receives a single packet in loopback mode with +* extended VLAN support. +* +* The transmit frame will have VLAN field populated. +* +* On receive, HW should pass the VLAN field to receive BDs. +* +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* AxiEthernet component. +* @param DmaInstancePtr is a pointer to the instance of the Dma +* component. +* +* @return -XST_SUCCESS to indicate success. +* -XST_FAILURE to indicate failure. +* +* @note Summary of VLAN tags handling in this example +* +* Frame setup with Tpid1+Cfi1+TxPid => 0x88A83111 +* Frame translated to TxTransVid => 0x88A83222 +* Frame tagged to Tpid2+Cfi2+TxTagVid => 0x9100C333 + 0x88A83222 +* Frame sent and loopbacked. +* +* Frame stripped with RxStrpVid(0x333) => 0x88A83222 +* Frame translated (key:RxVid:0x222) RxTransVid => 0x88A83444 +* +******************************************************************************/ +int AxiEthernetSgDmaIntrExtVlanExample(XAxiEthernet *AxiEthernetInstancePtr, + XAxiDma *DmaInstancePtr) +{ + int Status; + u32 TxFrameLength; + u32 RxFrameLength; + int PayloadSize = PAYLOAD_SIZE; + u16 Tpid1 = 0x88A8; + u16 Tpid2 = 0x9100; + u8 Cfi1 = 0x03; + u8 Cfi2 = 0x0C; + u16 TxVid = 0x0111; + u16 TxTransVid = 0x0222; + u16 TxTagVid = 0x0333; + u16 RxVid = 0x0222; + u16 RxTransVid = 0x0444; + u16 RxStrpVid = 0x0333; + u32 VTagCfiVid; + u16 RxCfiVid; + u16 RxTpid; + u32 RxStatusControlWord; + int Valid; + + + XAxiDma_BdRing *RxRingPtr = XAxiDma_GetRxRing(DmaInstancePtr); + XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(DmaInstancePtr); + XAxiDma_Bd *BdPtr; + XAxiDma_Bd *BdCurPtr; + u32 BdSts; + + /* + * Cannot run this example if extended features support is not enabled + */ + if (!(XAxiEthernet_IsTxVlanTran(AxiEthernetInstancePtr) && + XAxiEthernet_IsTxVlanStrp(AxiEthernetInstancePtr) && + XAxiEthernet_IsTxVlanTag(AxiEthernetInstancePtr) && + XAxiEthernet_IsRxVlanTran(AxiEthernetInstancePtr) && + XAxiEthernet_IsRxVlanStrp(AxiEthernetInstancePtr) && + XAxiEthernet_IsRxVlanTag(AxiEthernetInstancePtr))) { + AxiEthernetUtilErrorTrap("Extended VLAN not available"); + return XST_FAILURE; + } + + /* + * Clear variables shared with callbacks + */ + FramesRx = 0; + FramesTx = 0; + DeviceErrors = 0; + memset(RxFrame,0,sizeof(RxFrame)); + memset(TxFrame,0,sizeof(TxFrame)); + + /* + * Calculate frame length (not including FCS) plus one VLAN tag + */ + TxFrameLength = XAE_HDR_VLAN_SIZE + PayloadSize; + + /* + * Setup the packet with one VALN tag = VtagCfiVid to be transmitted + * initially. + */ + VTagCfiVid = (((u32)Tpid1 << 16) | ((u32)Cfi1 << 12) | TxVid); + AxiEthernetUtilFrameMemClear(&TxFrame); + AxiEthernetUtilFrameHdrFormatMAC(&TxFrame, AxiEthernetMAC); + AxiEthernetUtilFrameHdrVlanFormatVid(&TxFrame, 0, VTagCfiVid); + AxiEthernetUtilFrameHdrVlanFormatType(&TxFrame, PayloadSize, 1); + AxiEthernetUtilFrameSetVlanPayloadData(&TxFrame, PayloadSize, 1); + + /* Intended VLAN setup: + * TX translation and tagging. RX stripping and translation. + * + * Frame setup with Tpid1+Cfi1+TxPid => 0x88A83111 + * Frame translated to TxTransVid => 0x88A83222 + * Frame tagged to Tpid2+Cfi2+TxTagVid => 0x9100C333 + 0x88A83222 + * Frame sent and loopbacked. + * + * Frame stripped with RxStrpVid(0x333) => 0x88A83222 + * Frame translated (key:RxVid:0x222) RxTransVid => 0x88A83444 + */ + + /* Extended VLAN transmit side. Stripping->Translation->Tagging */ + /* + * Configure VLAN TX tag mode, set to XAE_VTAG_SELECT. + */ + Status = XAxiEthernet_SetOptions(AxiEthernetInstancePtr, + XAE_EXT_TXVLAN_TAG_OPTION); + Status |= XAxiEthernet_SetVTagMode(AxiEthernetInstancePtr, + XAE_VTAG_SELECT, XAE_TX); + + /* + * TX VLAN translation from TxVid to TxTransVid and enable tagging. + */ + Status |= XAxiEthernet_SetOptions(AxiEthernetInstancePtr, + XAE_EXT_TXVLAN_TRAN_OPTION); + Status |= XAxiEthernet_SetVidTable(AxiEthernetInstancePtr, TxVid, + TxTransVid,0, 1, XAE_TX); + + /* + * TX VLAN tagging is keyed on TxVid to add one additional tag based + * on register XAE_TTAG_OFFSET value. + */ + VTagCfiVid = (((u32)Tpid2 << 16) | ((u32)Cfi2 << 12) | TxTagVid); + Status |= XAxiEthernet_SetVTagValue(AxiEthernetInstancePtr, + VTagCfiVid, XAE_TX); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting TX VLAN"); + return XST_FAILURE; + } + + /* Extended VLAN receive side. Stripping->Translation->Tagging */ + /* + * Configure VLAN RX strip mode, set to XAE_VSTRP_SELECT. + */ + Status = XAxiEthernet_SetOptions(AxiEthernetInstancePtr, + XAE_EXT_RXVLAN_STRP_OPTION); + Status |= XAxiEthernet_SetVStripMode(AxiEthernetInstancePtr, + XAE_VSTRP_SELECT, XAE_RX); + + /* + * RX VLAN strips based on RxStrpVid and enable stripping. + */ + Status |= XAxiEthernet_SetVidTable(AxiEthernetInstancePtr, RxStrpVid, + RxStrpVid, 1, 0, XAE_RX); + + /* + * RX VLAN translation from RxVid to RxTransVid only. + */ + Status |= XAxiEthernet_SetOptions(AxiEthernetInstancePtr, + XAE_EXT_RXVLAN_TRAN_OPTION); + Status |= XAxiEthernet_SetVidTable(AxiEthernetInstancePtr, RxVid, + RxTransVid, 0, 0, XAE_RX); + + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting RX VLAN"); + return XST_FAILURE; + } + + /* Configure VLAN TPIDs for HW to recognize. */ + Status = XAxiEthernet_SetTpid(AxiEthernetInstancePtr, Tpid1, 0); + Status |= XAxiEthernet_SetTpid(AxiEthernetInstancePtr, Tpid2, 1); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting TPIDs"); + return XST_FAILURE; + } + + /* + * Flush the TX frame before giving it to DMA TX channel to transmit. + */ + Xil_DCacheFlushRange((u32)&TxFrame, TxFrameLength); + + /* + * Clear out receive packet memory area + */ + AxiEthernetUtilFrameMemClear(&RxFrame); + + /* + * Invalidate the RX frame before giving it to DMA RX channel to + * receive data. + */ + Xil_DCacheInvalidateRange((u32)&RxFrame, TxFrameLength + 4); + + /* + * Interrupt coalescing parameters are set to their default settings + * which is to interrupt the processor after every frame has been + * processed by the DMA engine. + */ + + Status = XAxiDma_BdRingSetCoalesce(TxRingPtr, 1, 1); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting coalescing for transmit"); + return XST_FAILURE; + } + + Status = XAxiDma_BdRingSetCoalesce(RxRingPtr, 1, 1); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting coalescing for recv"); + return XST_FAILURE; + } + + /* + * Make sure Tx and Rx are enabled + */ + Status = XAxiEthernet_SetOptions(AxiEthernetInstancePtr, + XAE_RECEIVER_ENABLE_OPTION | + XAE_TRANSMITTER_ENABLE_OPTION ); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting options"); + return XST_FAILURE; + } + + Status = XAxiEthernet_SetOptions(AxiEthernetInstancePtr, + XAE_JUMBO_OPTION); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting options"); + return XST_FAILURE; + } + + /* + * Start the AxiEthernet and enable its ERROR interrupts + */ + XAxiEthernet_Start(AxiEthernetInstancePtr); + XAxiEthernet_IntEnable(&AxiEthernetInstance, + XAE_INT_RECV_ERROR_MASK); + + /* + * Enable DMA receive related interrupts + */ + XAxiDma_BdRingIntEnable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK); + + /* + * Allocate 1 RxBD. + */ + Status = XAxiDma_BdRingAlloc(RxRingPtr, 1, &BdPtr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error allocating RxBD"); + return XST_FAILURE; + } + + /* + * Setup the BD. + */ + XAxiDma_BdSetBufAddr(BdPtr, (u32)&RxFrame); +#ifndef XPAR_AXIDMA_0_ENABLE_MULTI_CHANNEL + XAxiDma_BdSetLength(BdPtr, sizeof(RxFrame)); +#else + XAxiDma_BdSetLength(BdPtr, sizeof(RxFrame), + RxRingPtr->MaxTransferLen); +#endif + XAxiDma_BdSetCtrl(BdPtr, 0); + + /* + * Enqueue to HW + */ + Status = XAxiDma_BdRingToHw(RxRingPtr, 1, BdPtr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error committing RxBD to HW"); + return XST_FAILURE; + } + + /* + * Start DMA RX channel. Now it's ready to receive data. + */ + Status = XAxiDma_BdRingStart(RxRingPtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Enable DMA transmit related interrupts + */ + XAxiDma_BdRingIntEnable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK); + + /* + * Allocate 1 TxBD + */ + Status = XAxiDma_BdRingAlloc(TxRingPtr, 1, &BdPtr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error allocating TxBD"); + return XST_FAILURE; + } + + /* + * Setup the TxBD + */ + XAxiDma_BdSetBufAddr(BdPtr, (u32)&TxFrame); +#ifndef XPAR_AXIDMA_0_ENABLE_MULTI_CHANNEL + XAxiDma_BdSetLength(BdPtr, TxFrameLength); +#else + XAxiDma_BdSetLength(BdPtr, TxFrameLength, + TxRingPtr->MaxTransferLen); +#endif + XAxiDma_BdSetCtrl(BdPtr, XAXIDMA_BD_CTRL_TXSOF_MASK | + XAXIDMA_BD_CTRL_TXEOF_MASK); + + /* + * Enqueue to HW + */ + Status = XAxiDma_BdRingToHw(TxRingPtr, 1, BdPtr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error committing TxBD to HW"); + return XST_FAILURE; + } + + /* + * Start DMA TX channel. Transmission starts at once. + */ + Status = XAxiDma_BdRingStart(TxRingPtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait for transmission to complete + */ + while (!FramesTx); + + /* + * Now that the frame has been sent, post process our TxBDs. + * Since we have only submitted 2 to HW, then there should be only 2 + * ready for post processing. + */ + if (XAxiDma_BdRingFromHw(TxRingPtr, 1, &BdPtr) == 0) { + AxiEthernetUtilErrorTrap("TxBDs were not ready for post processing"); + return XST_FAILURE; + } + + /* + * Examine the TxBDs. + * + * There isn't much to do. The only thing to check would be DMA + * exception bits. But this would also be caught in the error handler. + * So we just return these BDs to the free list + */ + Status = XAxiDma_BdRingFree(TxRingPtr, 1, BdPtr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error freeing up TxBDs"); + return XST_FAILURE; + } + + /* + * Wait for Rx indication + */ + while (!FramesRx); + /* + * Now that the frame has been received, post process our RxBD. + * Since we have only submitted 1 to HW, then there should be only 1 + * ready for post processing. + */ + if (XAxiDma_BdRingFromHw(RxRingPtr, 1, &BdPtr) == 0) { + AxiEthernetUtilErrorTrap("RxBD was not ready for post processing"); + return XST_FAILURE; + } + + BdCurPtr = BdPtr; + BdSts = XAxiDma_BdGetSts(BdCurPtr); + + if ((BdSts & XAXIDMA_BD_STS_ALL_ERR_MASK) || + (!(BdSts & XAXIDMA_BD_STS_COMPLETE_MASK))) { + AxiEthernetUtilErrorTrap("Rx Error"); + return XST_FAILURE; + } + else { + + RxFrameLength = + (XAxiDma_BdRead(BdCurPtr,XAXIDMA_BD_USR4_OFFSET)) & 0x0000FFFF; + } + + /* Expected RX TPID+CFI+VID !!! */ + VTagCfiVid = (((u32)Tpid2 << 16) | ((u32)Cfi2 << 12) | RxStrpVid); + + /* Check on the VLAN CFI and VID */ + RxStatusControlWord = XAxiDma_BdGetAppWord(BdPtr, + BD_VLAN_VID_OFFSET, &Valid); + if(Valid) { + RxCfiVid = RxStatusControlWord >> 16; + RxCfiVid = Xil_Ntohs(RxCfiVid); + if(RxCfiVid != (VTagCfiVid & 0x0000FFFF)) { + AxiEthernetUtilErrorTrap("VLAN CFI and VID mismatch\n"); + return XST_FAILURE; + } + } + else { + AxiEthernetUtilErrorTrap("Status words not available from AXI DMA\n"); + return XST_FAILURE; + } + + RxStatusControlWord = XAxiDma_BdGetAppWord(BdPtr, + BD_VLAN_TPID_OFFSET, &Valid); + if(Valid) { + RxTpid = RxStatusControlWord >> 16; + RxTpid = Xil_Ntohs(RxTpid); + VTagCfiVid = ((VTagCfiVid & TPID_MASK) >> 16); + if(RxTpid != VTagCfiVid) { + + AxiEthernetUtilErrorTrap("VLAN TPID mismatch\n"); + return XST_FAILURE; + } + } + else { + AxiEthernetUtilErrorTrap("Status words not available from AXI DMA\n"); + return XST_FAILURE; + } + + if (AxiEthernetUtilFrameVerify(&TxFrame, &RxFrame) != 0) { + AxiEthernetUtilErrorTrap("Data mismatch"); + return XST_FAILURE; + } + + /* + * Return the RxBD back to the channel for later allocation. Free the + * exact number we just post processed. + */ + Status = XAxiDma_BdRingFree(RxRingPtr, 1, BdPtr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error freeing up TxBDs"); + return XST_FAILURE; + } + + return XST_SUCCESS; + +} + + +/*****************************************************************************/ +/** +* +* This is the DMA TX callback function to be called by TX interrupt handler. +* This function handles BDs finished by hardware. +* +* @param TxRingPtr is a pointer to TX channel of the DMA engine. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void TxCallBack(XAxiDma_BdRing * TxRingPtr) +{ + /* + * Disable the transmit related interrupts + */ + XAxiDma_BdRingIntDisable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK); + /* + * Increment the counter so that main thread knows something happened + */ + FramesTx++; +} + +/*****************************************************************************/ +/** +* +* This is the DMA TX Interrupt handler function. +* +* @param TxRingPtr is a pointer to TX channel of the DMA engine. +* +* @return None. +* +* @note This Interrupt handler MUST clear pending interrupts before +* handling them by calling the call back. Otherwise the following +* corner case could raise some issue: +* +* A packet got transmitted and a TX interrupt got asserted. If +* the interrupt handler calls the callback before clearing the +* interrupt, a new packet may get transmitted in the callback. +* This new packet then can assert one more TX interrupt before +* the control comes out of the callback function. Now when +* eventually control comes out of the callback function, it will +* never know about the second new interrupt and hence while +* clearing the interrupts, would clear the new interrupt as well +* and will never process it. +* To avoid such cases, interrupts must be cleared before calling +* the callback. +* +******************************************************************************/ +static void TxIntrHandler(XAxiDma_BdRing * TxRingPtr) +{ + u32 IrqStatus; + + /* Read pending interrupts */ + IrqStatus = XAxiDma_BdRingGetIrq(TxRingPtr); + + /* Acknowledge pending interrupts */ + XAxiDma_BdRingAckIrq(TxRingPtr, IrqStatus); + /* + * If no interrupt is asserted, raise error flag, reset the + * hardware to recover from the error, and return with no further + * processing. + */ + if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) { + DeviceErrors++; + AxiEthernetUtilErrorTrap + ("AXIDma: No interrupts asserted in TX status register"); + XAxiDma_Reset(&DmaInstance); + if(!XAxiDma_ResetIsDone(&DmaInstance)) { + AxiEthernetUtilErrorTrap ("AxiDMA: Error: Could not reset\n"); + } + return; + } + + /* If error interrupt is asserted, raise error flag, reset the + * hardware to recover from the error, and return with no further + * processing. + */ + if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) { + + AxiEthernetUtilErrorTrap("AXIDMA: TX Error interrupts\n"); + + /* Reset should never fail for transmit channel + */ + XAxiDma_Reset(&DmaInstance); + if(!XAxiDma_ResetIsDone(&DmaInstance)) { + + AxiEthernetUtilErrorTrap ("AXIDMA: Error: Could not reset\n"); + } + + return; + } + + /* + * If Transmit done interrupt is asserted, call TX call back function + * to handle the processed BDs and raise the according flag + */ + if ((IrqStatus & (XAXIDMA_IRQ_DELAY_MASK | XAXIDMA_IRQ_IOC_MASK))) { + TxCallBack(TxRingPtr); + } +} + + +/*****************************************************************************/ +/** +* +* This is the DMA RX callback function to be called by RX interrupt handler. +* This function handles finished BDs by hardware, attaches new buffers to those +* BDs, and give them back to hardware to receive more incoming packets +* +* @param RxRingPtr is a pointer to RX channel of the DMA engine. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void RxCallBack(XAxiDma_BdRing * RxRingPtr) +{ + /* + * Disable the receive related interrupts + */ + XAxiDma_BdRingIntDisable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK); + /* + * Increment the counter so that main thread knows something + * happened + */ + FramesRx++; +} + + +/*****************************************************************************/ +/** +* +* This is the Receive handler function for examples 1 and 2. +* It will increment a shared counter, receive and validate the frame. +* +* @param RxRingPtr is a pointer to the DMA ring instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void RxIntrHandler(XAxiDma_BdRing * RxRingPtr) +{ + u32 IrqStatus; + + /* Read pending interrupts */ + IrqStatus = XAxiDma_BdRingGetIrq(RxRingPtr); + + /* Acknowledge pending interrupts */ + XAxiDma_BdRingAckIrq(RxRingPtr, IrqStatus); + /* + * If no interrupt is asserted, raise error flag, reset the + * hardware to recover from the error, and return with no further + * processing. + */ + if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) { + DeviceErrors++; + AxiEthernetUtilErrorTrap + ("AXIDma: No interrupts asserted in RX status register"); + XAxiDma_Reset(&DmaInstance); + if(!XAxiDma_ResetIsDone(&DmaInstance)) { + AxiEthernetUtilErrorTrap ("Could not reset\n"); + } + return; + } + + /* If error interrupt is asserted, raise error flag, reset the + * hardware to recover from the error, and return with no further + * processing. + */ + if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) { + + AxiEthernetUtilErrorTrap("AXIDMA: RX Error interrupts\n"); + + /* Reset could fail and hang + * NEED a way to handle this or do not call it?? + */ + XAxiDma_Reset(&DmaInstance); + + if(!XAxiDma_ResetIsDone(&DmaInstance)) { + AxiEthernetUtilErrorTrap ("AXIDMA: Could not reset\n"); + } + return; + } + /* + * If Reception done interrupt is asserted, call RX call back function + * to handle the processed BDs and then raise the according flag. + */ + if ((IrqStatus & (XAXIDMA_IRQ_DELAY_MASK | XAXIDMA_IRQ_IOC_MASK))) { + RxCallBack(RxRingPtr); + } +} + +/*****************************************************************************/ +/** +* +* This is the Error handler callback function and this function increments the +* the error counter so that the main thread knows the number of errors. +* +* @param AxiEthernet is a reference to the AxiEthernet device instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void AxiEthernetErrorHandler(XAxiEthernet * AxiEthernet) +{ + u32 Pending = XAxiEthernet_IntPending(AxiEthernet); + + if (Pending & XAE_INT_RXRJECT_MASK) { + AxiEthernetUtilErrorTrap("AxiEthernet: Rx packet rejected"); + } + + if (Pending & XAE_INT_RXFIFOOVR_MASK) { + AxiEthernetUtilErrorTrap("AxiEthernet: Rx fifo over run"); + } + + XAxiEthernet_IntClear(AxiEthernet, Pending); + + /* + * Bump counter + */ + DeviceErrors++; +} + + +/*****************************************************************************/ +/** +* +* This function setups the interrupt system so interrupts can occur for the +* Axi Ethernet. This function is application-specific since the actual system +* may or may not have an interrupt controller. The Axi Ethernet could be +* directly connected to a processor without an interrupt controller. The user +* should modify this function to fit the application. +* +* @param IntcInstancePtr is a pointer to the instance of the Intc +* component. +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* AxiEthernet component. +* @param DmaInstancePtr is a pointer to the instance of the AXIDMA +* component. +* @param AxiEthernetDeviceId is Device ID of the Axi Ethernet Device , +* typically XPAR__DEVICE_ID value from +* xparameters.h. +* @param AxiEthernetIntrId is the Interrupt ID and is typically +* XPAR___VEC_ID +* value from xparameters.h. +* @param DmaRxIntrId is the interrupt id for DMA Rx and is typically +* taken from XPAR__CONNECTED_DMARX_INTR +* @param DmaTxIntrId is the interrupt id for DMA Tx and is typically +* taken from XPAR__CONNECTED_DMATX_INTR +* +* @return -XST_SUCCESS to indicate success +* -XST_FAILURE to indicate failure +* +* @note None. +* +******************************************************************************/ +static int AxiEthernetSetupIntrSystem(INTC *IntcInstancePtr, + XAxiEthernet *AxiEthernetInstancePtr, + XAxiDma *DmaInstancePtr, + u16 AxiEthernetIntrId, + u16 DmaRxIntrId, + u16 DmaTxIntrId) +{ + XAxiDma_BdRing * TxRingPtr = XAxiDma_GetTxRing(DmaInstancePtr); + XAxiDma_BdRing * RxRingPtr = XAxiDma_GetRxRing(DmaInstancePtr); + int Status; +#ifdef XPAR_INTC_0_DEVICE_ID +#ifndef TESTAPP_GEN + /* + * Initialize the interrupt controller and connect the ISR + */ + Status = XIntc_Initialize(IntcInstancePtr, INTC_DEVICE_ID); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Unable to intialize the interrupt controller"); + return XST_FAILURE; + } +#endif + +#if XPAR_INTC_0_HAS_FAST == 1 + + TxRingPtr_Fast = TxRingPtr; + RxRingPtr_Fast = RxRingPtr; + AxiEthernetInstancePtr_Fast = AxiEthernetInstancePtr; + Status = XIntc_ConnectFastHandler(IntcInstancePtr, AxiEthernetIntrId, + (XFastInterruptHandler) AxiEthernetErrorFastHandler); + Status |= XIntc_ConnectFastHandler(IntcInstancePtr, DmaTxIntrId, + (XFastInterruptHandler) TxIntrFastHandler); + Status |= XIntc_ConnectFastHandler(IntcInstancePtr, DmaRxIntrId, + (XFastInterruptHandler) RxIntrFastHandler); +#else + Status = XIntc_Connect(IntcInstancePtr, AxiEthernetIntrId, + (XInterruptHandler) + AxiEthernetErrorHandler, + AxiEthernetInstancePtr); + Status |= XIntc_Connect(IntcInstancePtr, DmaTxIntrId, + (XInterruptHandler) TxIntrHandler, + TxRingPtr); + Status |= XIntc_Connect(IntcInstancePtr, DmaRxIntrId, + (XInterruptHandler) RxIntrHandler, + RxRingPtr); +#endif + + + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Unable to connect ISR to interrupt controller"); + return XST_FAILURE; + } + +#ifndef TESTAPP_GEN + /* + * Start the interrupt controller + */ + Status = XIntc_Start(IntcInstancePtr, XIN_REAL_MODE); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error starting intc"); + return XST_FAILURE; + } +#endif + + + /* + * Enable interrupts from the hardware + */ + XIntc_Enable(IntcInstancePtr, AxiEthernetIntrId); + XIntc_Enable(IntcInstancePtr, DmaTxIntrId); + XIntc_Enable(IntcInstancePtr, DmaRxIntrId); +#else + XScuGic_Config *IntcConfig; + + + /* + * Initialize the interrupt controller driver so that it is ready to + * use. + */ + IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID); + if (NULL == IntcConfig) { + return XST_FAILURE; + } + + Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig, + IntcConfig->CpuBaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + + XScuGic_SetPriorityTriggerType(IntcInstancePtr, DmaTxIntrId, 0xA0, 0x3); + + XScuGic_SetPriorityTriggerType(IntcInstancePtr, DmaRxIntrId, 0xA0, 0x3); + + XScuGic_SetPriorityTriggerType(IntcInstancePtr, AxiEthernetIntrId, 0xA0, 0x3); + /* + * Connect the device driver handler that will be called when an + * interrupt for the device occurs, the handler defined above performs + * the specific interrupt processing for the device. + */ + Status = XScuGic_Connect(IntcInstancePtr, DmaTxIntrId, + (Xil_InterruptHandler)TxIntrHandler, + TxRingPtr); + if (Status != XST_SUCCESS) { + return Status; + } + + Status = XScuGic_Connect(IntcInstancePtr, DmaRxIntrId, + (Xil_InterruptHandler)RxIntrHandler, + RxRingPtr); + if (Status != XST_SUCCESS) { + return Status; + } + + Status = XScuGic_Connect(IntcInstancePtr, AxiEthernetIntrId, + (Xil_InterruptHandler)AxiEthernetErrorHandler, + AxiEthernetInstancePtr); + if (Status != XST_SUCCESS) { + return Status; + } + + XScuGic_Enable(IntcInstancePtr, AxiEthernetIntrId); + XScuGic_Enable(IntcInstancePtr, DmaTxIntrId); + XScuGic_Enable(IntcInstancePtr, DmaRxIntrId); +#endif +#ifndef TESTAPP_GEN + Xil_ExceptionInit(); + + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, + (Xil_ExceptionHandler)INTC_HANDLER, + (void *)(IntcInstancePtr)); + + Xil_ExceptionEnable(); + +#endif + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function disables the interrupts that occur for AxiEthernet. +* +* @param IntcInstancePtr is a pointer to the instance of the Intc +* component. +* @param AxiEthernetIntrId is the Interrupt ID and is typically +* XPAR___VEC_ID +* value from xparameters.h. +* @param DmaRxIntrId is the interrupt id for DMA Rx and is typically +* taken from XPAR__CONNECTED_DMARX_INTR +* @param DmaTxIntrId is the interrupt id for DMA Tx and is typically +* taken from XPAR__CONNECTED_DMATX_INTR +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void AxiEthernetDisableIntrSystem(INTC *IntcInstancePtr, + u16 AxiEthernetIntrId, + u16 DmaRxIntrId, + u16 DmaTxIntrId) +{ +#ifdef XPAR_INTC_0_DEVICE_ID + /* + * Disconnect the interrupts for the DMA TX and RX channels + */ + XIntc_Disconnect(IntcInstancePtr, DmaTxIntrId); + XIntc_Disconnect(IntcInstancePtr, DmaRxIntrId); + /* + * Disconnect and disable the interrupt for the AxiEthernet device + */ + XIntc_Disconnect(IntcInstancePtr, AxiEthernetIntrId); + +#else + /* + * Disconnect the interrupts for the DMA TX and RX channels + */ + XScuGic_Disconnect(IntcInstancePtr, DmaTxIntrId); + XScuGic_Disconnect(IntcInstancePtr, DmaRxIntrId); + + /* + * Disconnect and disable the interrupt for the AxiEthernet device + */ + XScuGic_Disconnect(IntcInstancePtr, AxiEthernetIntrId); +#endif +} + +#if XPAR_INTC_0_HAS_FAST == 1 +/*****************************************************************************/ +/** +* +* Fast Error Handler which calls AxiEthernetErrorHandler. +* +* @param None +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void AxiEthernetErrorFastHandler(void) +{ + AxiEthernetErrorHandler((XAxiEthernet *)AxiEthernetInstancePtr_Fast); +} + +/*****************************************************************************/ +/** +* +* Fast Tramsmit Handler which calls TxIntrHandler. +* +* @param None +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void TxIntrFastHandler(void) +{ + TxIntrHandler((XAxiDma_BdRing *)TxRingPtr_Fast); +} + +/*****************************************************************************/ +/** +* +* Fast Receive Handler which calls RxIntrHandler. +* +* @param None +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void RxIntrFastHandler(void) +{ + RxIntrHandler((XAxiDma_BdRing *)RxRingPtr_Fast); +} + +#endif diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example_intr_fifo.c b/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example_intr_fifo.c new file mode 100644 index 00000000..1d6b4f8c --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example_intr_fifo.c @@ -0,0 +1,1391 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/** +* +* @file xaxiethernet_example_intr_fifo.c +* +* Implements examples that utilize the Axi Ethernet's interrupt driven FIFO +* direct packet transfer mode to send and receive frames. +* +* These examples demonstrate: +* +* - How to perform simple send and receive. +* - Advanced frame processing +* - Error handling +* - Device reset +* +* Functional guide to example: +* +* - AxiEthernetSingleFrameIntrExample() demonstrates the simplest way to send +* and receive frames in interrupt driven FIFO direct mode. +* +* - AxiEthernetSingleFrameNonContIntrExample demonstrates how to handle frames +* that are stored in more than one memory location. +* +* - AxiEthernetMultipleFramesIntrExample demonstrates how to defer frame +* reception so that CPU intensive receive functions are not performed in +* interrupt context. +* +* - AxiEthernetErrorHandler() demonstrates how to manage asynchronous errors. +* +* - AxiEthernetResetDevice() demonstrates how to reset the driver/HW while + maintaining driver/HW state. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a asa  4/30/10  First release based on the ll temac driver
+* 3.00a bss  10/22/12 Added support for Fast Interrupt Handlers.
+* 3.01a srt  02/14/13 Added support for Zynq (CR 681136)
+* 3.02a srt  08/06/13 Fixed CR 727634 -
+*			Modified FifoHandler() logic to reflect the bit
+*			changes in the Interrupt Status Register as per
+*			the latest AXI FIFO stream IP.
+*
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xaxiethernet_example.h" +#include "xllfifo.h" +#include "xil_cache.h" +#include "xil_exception.h" + +#ifdef XPAR_INTC_0_DEVICE_ID +#include "xintc.h" +#else +#include "xscugic.h" +#endif + +#ifdef XPAR_XUARTNS550_NUM_INSTANCES +#include "xuartns550_l.h" +#endif +/*************************** Constant Definitions ****************************/ + +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#ifndef TESTAPP_GEN +#define AXIETHERNET_DEVICE_ID XPAR_AXIETHERNET_0_DEVICE_ID +#define FIFO_DEVICE_ID XPAR_AXI_FIFO_0_DEVICE_ID +#ifdef XPAR_INTC_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID +#define AXIETHERNET_IRPT_INTR XPAR_INTC_0_AXIETHERNET_0_VEC_ID +#define FIFO_IRPT_INTR XPAR_INTC_0_LLFIFO_0_VEC_ID +#else +#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID +#define AXIETHERNET_IRPT_INTR XPAR_FABRIC_AXIETHERNET_0_VEC_ID +#define FIFO_IRPT_INTR XPAR_FABRIC_LLFIFO_0_VEC_ID +#endif +#endif + +#define PAYLOAD_SIZE 100 /* Payload size used in examples */ +/*************************** Variable Definitions ****************************/ + +static EthernetFrame TxFrame; /* Frame used to send with */ +static EthernetFrame RxFrame; /* Frame used to receive data */ +volatile static int DeferRx = 0; + +/* + * Counters setup to be incremented by callbacks + */ +static volatile int FramesRx; /* Number of received frames */ +static volatile int FramesRxInts; /* Number of ints for received + * frames + */ +static volatile int FramesTxInts; /* Number of ints for sent frames */ +static volatile int DeviceErrors; /* Num of errors detected in + * the device + */ +static volatile int FrameDataErrors; /* Num of times frame data check + * failed + */ +XAxiEthernet AxiEthernetInstance; +XLlFifo FifoInstance; + + +#ifdef XPAR_INTC_0_DEVICE_ID +#define INTC XIntc +#define INTC_HANDLER XIntc_InterruptHandler +#else +#define INTC XScuGic +#define INTC_HANDLER XScuGic_InterruptHandler +#endif + +#ifndef TESTAPP_GEN +static INTC IntcInstance; +#endif + +#if XPAR_INTC_0_HAS_FAST == 1 + +/* Variables for Fast Interrupt Handlers */ +XAxiEthernet *AxiEthernetInstancePtr_Fast; +XLlFifo *Fifo_Fast; + +/****** Fast Interrupt Handlers prototypes ******/ + +static void AxiEthernetErrorFastHandler(void) __attribute__ ((fast_interrupt)); + +static void FifoFastHandler(void) __attribute__ ((fast_interrupt)); + +#else + +static void AxiEthernetErrorHandler(XAxiEthernet *AxiEthernet); +static void FifoHandler(XLlFifo *Fifo); + +#endif + + +/*************************** Function Prototypes *****************************/ + +/* + * The different examples given in this file + */ +int AxiEthernetFifoIntrExample(INTC *IntcInstancePtr, + XAxiEthernet *AxiEthernetInstancePtr, + XLlFifo *FifoInstancePtr, + u16 AxiEthernetDeviceId, + u16 FifoDeviceId, u16 AxiEthernetIntrId, + u16 FifoIntrId); +int AxiEthernetSingleFrameIntrExample(XAxiEthernet *AxiEthernetInstancePtr, + XLlFifo *FifoInstancePtr); +int AxiEthernetSingleFrameNonContIntrExample(XAxiEthernet + *AxiEthernetInstancePtr, XLlFifo *FifoInstancePtr); +int AxiEthernetMultipleFramesIntrExample(XAxiEthernet *AxiEthernetInstancePtr, + XLlFifo *FifoInstancePtr); + + +/* + * The Interrupt setup and callbacks + */ +static int AxiEthernetSetupIntrSystem(INTC *IntcInstancePtr, + XAxiEthernet *AxiEthernetInstancePtr, + XLlFifo *FifoInstancePtr, + u16 AxiEthernetIntrId, u16 FifoIntrId); +static void AxiEthernetDisableIntrSystem(INTC *IntcInstancePtr, + u16 AxiEthernetIntrId, u16 FifoIntrId); + +static void FifoRecvHandler(XLlFifo *Fifo); + +/* + * Utility routines + */ +static int AxiEthernetResetDevice(XAxiEthernet *AxiEthernetInstancePtr, + XLlFifo *FifoInstancePtr); + + +/*****************************************************************************/ +/** +* +* This is the main function for the Axi Ethernet example. This function is not +* included if the example is generated from the TestAppGen test tool. +* +* @param None. +* +* - XST_SUCCESS to indicate success. +* - XST_FAILURE.to indicate failure. +* @note None. +* +****************************************************************************/ +#ifndef TESTAPP_GEN +int main(void) +{ + int Status; + +#ifdef XPAR_XUARTNS550_NUM_INSTANCES + XUartNs550_SetBaud(STDIN_BASEADDRESS, XPAR_XUARTNS550_CLOCK_HZ, 9600); + XUartNs550_SetLineControlReg(STDIN_BASEADDRESS, XUN_LCR_8_DATA_BITS); +#endif +#if XPAR_MICROBLAZE_USE_ICACHE + Xil_ICacheInvalidate(); + Xil_ICacheEnable(); +#endif + +#if XPAR_MICROBLAZE_USE_DCACHE + Xil_DCacheInvalidate(); + Xil_DCacheEnable(); +#endif + + AxiEthernetUtilErrorTrap("\r\n--- Enter main() ---"); + AxiEthernetUtilErrorTrap("This test may take several minutes to finish"); + + + /* + * Call the Axi Ethernet interrupt example , specify the parameters + * generated in xparameters.h + */ + Status = AxiEthernetFifoIntrExample(&IntcInstance, + &AxiEthernetInstance, + &FifoInstance, + AXIETHERNET_DEVICE_ID, + FIFO_DEVICE_ID, + AXIETHERNET_IRPT_INTR, FIFO_IRPT_INTR); + + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Failed test intr fifo"); + } else { + AxiEthernetUtilErrorTrap("Test passed"); + } + + AxiEthernetUtilErrorTrap("--- Exiting main() ---"); + + + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} +#endif + + + +/*****************************************************************************/ +/** +* +* This function demonstrates the usage usage of the Axi Ethernet by sending +* and receiving frames in interrupt driven fifo mode. +* +* +* @param IntcInstancePtr is a pointer to the instance of the Intc +* component. +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* Axi Ethernet component. +* @param FifoInstancePtr is a pointer to the instance of the AXIFIFO +* component. +* @param AxiEthernetDeviceId is Device ID of the Axi Ethernet Device , +* typically XPAR__DEVICE_ID value from +* xparameters.h. +* @param FifoDeviceId is the Interrupt ID and is typically +* XPAR___VEC_ID +* value from xparameters.h. +* @param AxiEthernetIntrId is the Interrupt ID and is typically +* XPAR___VEC_ID +* value from xparameters.h. +* @param FifoIntrId is the interrupt id for fifo. +* +* - XST_SUCCESS to indicate success. +* - XST_FAILURE.to indicate failure. +* +* @note AxiFifo hardware must be initialized before initializing +* AxiEthernet. Since AxiFifo reset line is connected to the +* AxiEthernet reset line, a reset of AxiFifo hardware during its +* initialization would reset AxiEthernet. +* +******************************************************************************/ +int AxiEthernetFifoIntrExample(INTC *IntcInstancePtr, + XAxiEthernet *AxiEthernetInstancePtr, + XLlFifo *FifoInstancePtr, + u16 AxiEthernetDeviceId, + u16 FifoDeviceId, u16 AxiEthernetIntrId, + u16 FifoIntrId) +{ + int Status; + XAxiEthernet_Config *MacCfgPtr; + int LoopbackSpeed; + + + /*************************************/ + /* Setup device for first-time usage */ + /*************************************/ + + /* + * Get the configuration of AxiEthernet hardware. + */ + MacCfgPtr = XAxiEthernet_LookupConfig(AxiEthernetDeviceId); + + /* + * Check whether AXIFIFO is present or not + */ + if(MacCfgPtr->AxiDevType != XPAR_AXI_FIFO) { + AxiEthernetUtilErrorTrap + ("Device HW not configured for FIFO mode\r\n"); + return XST_FAILURE; + } + + /* + * Initialize AXIFIFO hardware. AXIFIFO must be initialized before + * AxiEthernet. During AXIFIFO initialization, AXIFIFO hardware is + * reset, and since AXIFIFO reset line is connected to AxiEthernet, + * this would ensure a reset of AxiEthernet. + */ + XLlFifo_Initialize(FifoInstancePtr, MacCfgPtr->AxiDevBaseAddress); + + /* + * Initialize AxiEthernet hardware. + */ + Status = XAxiEthernet_CfgInitialize(AxiEthernetInstancePtr, MacCfgPtr, + MacCfgPtr->BaseAddress); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error in initialize"); + return XST_FAILURE; + } + + /* + * Set the MAC address + */ + Status = XAxiEthernet_SetMacAddress(AxiEthernetInstancePtr, + (u8 *) AxiEthernetMAC); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting MAC address"); + return XST_FAILURE; + } + + /* + * Set PHY to loopback, speed depends on phy type. + * MII is 100 and all others are 1000. + */ + if (XAxiEthernet_GetPhysicalInterface(AxiEthernetInstancePtr) == + XAE_PHY_TYPE_MII) { + LoopbackSpeed = AXIETHERNET_LOOPBACK_SPEED; + } else { + LoopbackSpeed = AXIETHERNET_LOOPBACK_SPEED_1G; + } + Status = AxiEthernetUtilEnterLoopback(AxiEthernetInstancePtr, + LoopbackSpeed); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting the PHY loopback"); + return XST_FAILURE; + } + + /* + * Set PHY<-->MAC data clock + */ + Status = XAxiEthernet_SetOperatingSpeed(AxiEthernetInstancePtr, + (u16)LoopbackSpeed); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Setting the operating speed of the MAC needs a delay. There + * doesn't seem to be register to poll, so please consider this + * during your application design. + */ + AxiEthernetUtilPhyDelay(2); + + /* Clear any pending FIFO interrupts from any previous + * examples (e.g., polled) + */ + XLlFifo_IntClear(FifoInstancePtr, XLLF_INT_ALL_MASK); + + /* + * Connect to the interrupt controller and enable interrupts + */ + Status = AxiEthernetSetupIntrSystem(IntcInstancePtr, + AxiEthernetInstancePtr, + FifoInstancePtr, AxiEthernetIntrId, + FifoIntrId); + + /****************************/ + /* Run through the examples */ + /****************************/ + + + /* + * Run the AxiEthernet Single Frame Interrupt example + */ + Status = AxiEthernetSingleFrameIntrExample(AxiEthernetInstancePtr, + FifoInstancePtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Run the AxiEthernet Single Frame Non Continuous Interrupt example + */ + Status = AxiEthernetSingleFrameNonContIntrExample + (AxiEthernetInstancePtr, FifoInstancePtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + DeferRx = 1; + Status = AxiEthernetMultipleFramesIntrExample(AxiEthernetInstancePtr, + FifoInstancePtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + Status = AxiEthernetResetDevice(AxiEthernetInstancePtr, + FifoInstancePtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Disable the interrupts for the AxiEthernet device + */ + AxiEthernetDisableIntrSystem(IntcInstancePtr, AxiEthernetIntrId, + FifoIntrId); + + + /* + * Stop the device + */ + XAxiEthernet_Stop(AxiEthernetInstancePtr); + + + return XST_SUCCESS; + +} + + +/*****************************************************************************/ +/** +* +* This function demonstrates the usage of the Axi Ethernet by sending and +* receiving a single frame in interrupt mode. +* +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* AxiEthernet component. +* @param FifoInstancePtr is a pointer to the instance of the Fifo +* component. +* +* - XST_SUCCESS to indicate success. +* - XST_FAILURE.to indicate failure. +* +* @note None. +* +******************************************************************************/ +int AxiEthernetSingleFrameIntrExample(XAxiEthernet *AxiEthernetInstancePtr, + XLlFifo *FifoInstancePtr) +{ + u32 FifoFreeBytes; + u32 TxFrameLength; + int PayloadSize = PAYLOAD_SIZE; + + /* + * Clear variables shared with callbacks + */ + FramesRx = 0; + FramesRxInts = 0; + FramesTxInts = 0; + DeviceErrors = 0; + FrameDataErrors = 0; + + /* + * Setup packet to be transmitted + */ + AxiEthernetUtilFrameHdrFormatMAC(&TxFrame, AxiEthernetMAC); + AxiEthernetUtilFrameHdrFormatType(&TxFrame, PayloadSize); + AxiEthernetUtilFrameSetPayloadData(&TxFrame, PayloadSize); + + /* + * Clear out receive packet memory area + */ + AxiEthernetUtilFrameMemClear(&RxFrame); + + /* + * Calculate frame length (not including FCS) + */ + TxFrameLength = XAE_HDR_SIZE + PayloadSize; + + /****************/ + /* Setup device */ + /****************/ + + /* + * Start the device + */ + XAxiEthernet_Start(AxiEthernetInstancePtr); + + /* + * Enable the interrupts + */ + XLlFifo_IntEnable(FifoInstancePtr, XLLF_INT_ALL_MASK); + XAxiEthernet_IntEnable(AxiEthernetInstancePtr, + XAE_INT_RXRJECT_MASK | XAE_INT_RXFIFOOVR_MASK); + + + /*******************/ + /* Send the packet */ + /*******************/ + + /* + * Find out how much room is in the FIFO + * Vacancy is a value in 32 bit words. Multiply by 4 to get bytes. + */ + FifoFreeBytes = XLlFifo_TxVacancy(FifoInstancePtr) * 4; + if (FifoFreeBytes < TxFrameLength) { + AxiEthernetUtilErrorTrap("Not enough room in FIFO for frame"); + return XST_FAILURE; + } + + /* + * Write frame data to FIFO + */ + XLlFifo_Write(FifoInstancePtr, TxFrame, TxFrameLength); + + /* + * Initiate the transmit + */ + XLlFifo_TxSetLen(FifoInstancePtr, TxFrameLength); + + /* + * Wait for receive indication or error + */ + while ((FramesRx == 0) && (DeviceErrors == 0)); + + /* + * Stop the device + */ + XAxiEthernet_Stop(AxiEthernetInstancePtr); + + return XST_SUCCESS; +} + + +/*****************************************************************************/ +/** +* +* This example sends a packet from non-contiguous memory locations. The header +* is stored in one area. The payload data is calculated and written to the +* packet FIFO one byte at a time. +* +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* AxiEthernet component. +* @param FifoInstancePtr is a pointer to the instance of the Fifo +* component. +* +* - XST_SUCCESS to indicate success. +* - XST_FAILURE.to indicate failure. +* +* @note None. +* +******************************************************************************/ +int AxiEthernetSingleFrameNonContIntrExample(XAxiEthernet + *AxiEthernetInstancePtr, + XLlFifo *FifoInstancePtr) +{ + u32 FifoFreeBytes; + int PayloadSize = 20; + u8 PayloadData; + u32 TxFrameLength; + + /* + * Clear variables shared with callbacks + */ + FramesRx = 0; + FramesRxInts = 0; + FramesTxInts = 0; + DeviceErrors = 0; + FrameDataErrors = 0; + + /* + * Setup the transmit packet header + */ + AxiEthernetUtilFrameHdrFormatMAC(&TxFrame, AxiEthernetMAC); + AxiEthernetUtilFrameHdrFormatType(&TxFrame, PayloadSize); + + /* + * Clear out receive packet memory area + */ + AxiEthernetUtilFrameMemClear(&RxFrame); + + /* + * Calculate frame length (not including FCS) + */ + TxFrameLength = XAE_HDR_SIZE + PayloadSize; + + /****************/ + /* Setup device */ + /****************/ + + /* + * Start the device + */ + XAxiEthernet_Start(AxiEthernetInstancePtr); + + /* + * Enable interrupts + */ + XLlFifo_IntEnable(FifoInstancePtr, XLLF_INT_ALL_MASK); + + /*******************/ + /* Send the packet */ + /*******************/ + + /* + * Make sure there is enough room for a full sized frame + * Vacancy is a value in 32 bit words. Multiply by 4 to get bytes. + */ + FifoFreeBytes = XLlFifo_TxVacancy(FifoInstancePtr) * 4; + + if (FifoFreeBytes < (XAE_MTU + XAE_HDR_SIZE)) { + AxiEthernetUtilErrorTrap("Not enough room in FIFO for frame"); + return XST_FAILURE; + } + + /* + * Write the header data + */ + XLlFifo_Write(FifoInstancePtr, TxFrame, XAE_HDR_SIZE); + + /* + * Write payload one byte at a time. Set the payload like the + * AxiEthernetUtilFrameSetPayloadData() function would. This is done + * so that the received packet will pass validation in + * AxiEthernetRecvHandler(). + * + * Keep PayloadSize less than 255 since + * AxiEthernetUtilFrameSetPayloadData() switches to a 16 bit + * counter at 256. + * + * This is not the fastest way to send a frame of data but it does + * illustrate the flexibility of the API. + */ + PayloadData = 0; + while ((PayloadData < PayloadSize) && (DeviceErrors == 0)) { + XLlFifo_Write(FifoInstancePtr, &PayloadData, 1); + PayloadData++; + } + + /* + * Did it all get written without error + */ + if (DeviceErrors != 0) { + AxiEthernetUtilErrorTrap + ("Error writing payload to FIFO, reset recommended"); + return XST_FAILURE; + } + + /* + * Now begin transmission + */ + XLlFifo_TxSetLen(FifoInstancePtr, TxFrameLength); + + /* + * Wait for receive indication or error + */ + while ((FramesRx == 0) && (DeviceErrors == 0)); + + /* + * Stop the device + */ + XAxiEthernet_Stop(AxiEthernetInstancePtr); + + return XST_SUCCESS; +} + + +/*****************************************************************************/ +/** +* +* This example sends and receives a batch of frames. Frame reception is handled +* in this function and not in the callback function. +* +* Use this method of reception when interrupt latency is important. +* +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* AxiEthernet component. +* @param FifoInstancePtr is a pointer to the instance of the Fifo +* component. +* +* - XST_SUCCESS to indicate success. +* - XST_FAILURE.to indicate failure. +* +* @note None. +* +******************************************************************************/ +int AxiEthernetMultipleFramesIntrExample(XAxiEthernet *AxiEthernetInstancePtr, + XLlFifo *FifoInstancePtr) +{ + int FramesToLoopback; + int PayloadSize; + u32 TxFrameLength; + u32 RxFrameLength; + int Index; + + /* + * Clear variables shared with callbacks + */ + FramesRx = 0; + FramesRxInts = 0; + FramesTxInts = 0; + DeviceErrors = 0; + FrameDataErrors = 0; + + /* + * Setup the number of frames to loopback and the size of the frame to + * loopback. The default settings should work for every case. Modifying + * the settings can cause problems, see discussion below: + * + * If PayloadSize is set small and FramesToLoopback high, then it is + * possible to cause the transmit status FIFO to overflow. + * + * If PayloadSize is set large and FramesToLoopback high, then it is + * possible to cause the transmit packet FIFO to overflow. + * + * Either of these scenarios may be worth trying out to observe how the + * driver reacts. The exact values to cause these types of errors + * will vary due to the sizes of the FIFOs selected at hardware build + * time. But the following settings should create problems for all + * FIFO sizes: + * + * Transmit status FIFO overflow + * PayloadSize = 1 + * FramesToLoopback = 1000 + * + * Transmit packet FIFO overflow + * PayloadSize = 1500 + * FramesToLoopback = 16 + * + * These values should always work without error + * PayloadSize = 100 + * FramesToLoopback = 5 + */ + PayloadSize = 100; + FramesToLoopback = 5; + + /* + * Setup the transmit packet + */ + AxiEthernetUtilFrameHdrFormatMAC(&TxFrame, AxiEthernetMAC); + AxiEthernetUtilFrameHdrFormatType(&TxFrame, PayloadSize); + AxiEthernetUtilFrameSetPayloadData(&TxFrame, PayloadSize); + + /* + * Calculate frame length (not including FCS) + */ + TxFrameLength = XAE_HDR_SIZE + PayloadSize; + + /****************/ + /* Setup device */ + /****************/ + + /* + * Start the device + */ + XAxiEthernet_Start(AxiEthernetInstancePtr); + + /* + * Enable the interrupts + */ + XLlFifo_IntEnable(FifoInstancePtr, XLLF_INT_ALL_MASK); + + + /****************/ + /* Send packets */ + /****************/ + + /* + * Since we may be interested to see what happens when FIFOs overflow, + * don't check for room in the transmit packet FIFO prior to writing + * to it. + */ + + /* + * With the xps_ll_fifo core we can't stuff the fifo with data from + * multiple packets and then send them. Instead, the code needs to + * write the data, and then immediately send the packet before + * writting the data for the next packet. + */ + for (Index = 0; Index < FramesToLoopback; Index++) { + /* + * Write frame data to FIFO + */ + XLlFifo_Write(FifoInstancePtr, TxFrame, TxFrameLength); + /* + * Initiate the transmission + */ + XLlFifo_TxSetLen(FifoInstancePtr, TxFrameLength); + } + + /*******************/ + /* Receive packets */ + /*******************/ + + /* + * Now wait for frames to be received. When the callback is executed, + * it will disable interrupts and set a shared variable which will + * trigger this routine to process received frames + */ + for (Index = 0; Index < FramesToLoopback; Index++) { + /* + * Wait + */ + while (FramesRxInts == 0); + + /* + * Frame has arrived, so get the length + */ + RxFrameLength = XLlFifo_RxGetLen(FifoInstancePtr); + + /* + * Decision time: We can re-enable receive interrupts here or + * after we read the frame out of the FIFO. This is a matter + * of preference and goals of an application using the driver. + */ + XLlFifo_IntEnable(FifoInstancePtr, XLLF_INT_RC_MASK); + + /* + * Frame size as expected? + */ + if ((RxFrameLength) != TxFrameLength) { + AxiEthernetUtilErrorTrap("Receive length incorrect"); + } + + /* + * Clear out receive packet memory area + */ + AxiEthernetUtilFrameMemClear(&RxFrame); + + /* + * Read frame from packet FIFO + */ + XLlFifo_Read(FifoInstancePtr, &RxFrame, RxFrameLength); + /* + * Verify the received data + */ + if (AxiEthernetUtilFrameVerify(&TxFrame, &RxFrame) != 0) { + AxiEthernetUtilErrorTrap("Data mismatch"); + return XST_FAILURE; + } + } + + /* + * Stop the device + */ + XAxiEthernet_Stop(AxiEthernetInstancePtr); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This is the Receive handler callback function for examples 1 and 2. +* It will increment a shared counter, receive and validate the frame. +* +* @param Fifo is a reference to the Fifo device instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void FifoRecvHandler(XLlFifo *Fifo) +{ + u32 FrameLength; + + /* + * We get the interrupt only once for multiple frames received. + * So get all the frames we can. + */ + /* While there is data in the fifo ... */ + while (XLlFifo_RxOccupancy(Fifo)) { + /* + * Get the packet length + */ + FrameLength = XLlFifo_RxGetLen(Fifo); + + XLlFifo_Read(Fifo, RxFrame, FrameLength); + /* + * Validate the packet data against the header of the TxFrame. + * The payload data should as placed by + * AxiEthernetUtilFrameSetPayloadData() + */ + if (AxiEthernetUtilFrameVerify(&TxFrame, &RxFrame) != 0) { + FrameDataErrors++; + AxiEthernetUtilErrorTrap("Data mismatch"); + return; + } + /* + * Bump counter + */ + FramesRx++; + } +} + +/*****************************************************************************/ +/** +* +* This is the Error handler callback function and this function increments the +* the error counter so that the main thread knows the number of errors. +* +* @param Fifo is a reference to the AxiEthernet device instance. +* +* @param Pending is a bitmask of the pending interrupts. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void FifoErrorHandler(XLlFifo *Fifo, u32 Pending) +{ + int timeout_counter; + + if (Pending & XLLF_INT_RPURE_MASK) { + AxiEthernetUtilErrorTrap("Fifo: Rx under-read error"); + } + if (Pending & XLLF_INT_RPORE_MASK) { + AxiEthernetUtilErrorTrap("Fifo: Rx over-read error"); + } + if (Pending & XLLF_INT_RPUE_MASK) { + AxiEthernetUtilErrorTrap("Fifo: Rx fifo empty"); + } + if (Pending & XLLF_INT_TPOE_MASK) { + AxiEthernetUtilErrorTrap("Fifo: Tx fifo overrun"); + } + if (Pending & XLLF_INT_TSE_MASK) { + AxiEthernetUtilErrorTrap("Fifo: Tx length mismatch"); + } + + /* + * Reset the tx or rx side of the fifo as needed + */ + if (Pending & XLLF_INT_RXERROR_MASK) { + XLlFifo_IntClear(Fifo, XLLF_INT_RRC_MASK); + XLlFifo_RxReset(Fifo); + + timeout_counter = 10000; + + while ((XLlFifo_Status(Fifo) & XLLF_INT_RRC_MASK) == 0) { + timeout_counter--; + if (timeout_counter == 0) { + XLlFifo_Reset(Fifo); + /* we've reset the whole core so just exit out */ + goto feh_exit; + } + } + } + + if (Pending & XLLF_INT_TXERROR_MASK) { + XLlFifo_IntClear(Fifo, XLLF_INT_TRC_MASK); + XLlFifo_TxReset(Fifo); + + timeout_counter = 10000; + + while ((XLlFifo_Status(Fifo) & XLLF_INT_TRC_MASK) == 0) { + timeout_counter--; + if (timeout_counter == 0) { + XLlFifo_Reset(Fifo); + + /* we've reset the whole core so just exit out */ + goto feh_exit; + } + } + } + + feh_exit: + /* + * Bump counter + */ + DeviceErrors++; +} + + +/*****************************************************************************/ +/** +* +* This is the Fifo handler function and will increment a shared +* counter that can be tested by the main thread of operation. +* +* @param Fifo is a reference to the Fifo instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void FifoHandler(XLlFifo *Fifo) +{ + u32 Pending = XLlFifo_IntPending(Fifo); + + while (Pending) { + if (Pending & XLLF_INT_RC_MASK) { + /* + * Receive the frame, unless we are deferring the + * receive. + */ + if (DeferRx) { + FramesRxInts++; /* We can count the interrupts, + * but in the handler we don't + * exactly know how many frames + * as we could get one int for + * multiple frames. + */ + /* + * use for example 3: Disable receive + * interrupts to defer frame reception + * to the example function. + */ + XLlFifo_IntDisable(Fifo, XLLF_INT_RC_MASK); + } + else { + FifoRecvHandler(Fifo); + } + XLlFifo_IntClear(Fifo, XLLF_INT_RC_MASK); + } + else if (Pending & XLLF_INT_TC_MASK) { + FramesTxInts++; /* We can count the interrupts, but in + * the handler we don't exactly know + * how many frames as we could get one + * int for multiple frames. + */ + XLlFifo_IntClear(Fifo, XLLF_INT_TC_MASK); + } + else if (Pending & XLLF_INT_ERROR_MASK){ + FifoErrorHandler(Fifo, Pending); + XLlFifo_IntClear(Fifo, XLLF_INT_ERROR_MASK); + } else { + XLlFifo_IntClear(Fifo, Pending); + } + Pending = XLlFifo_IntPending(Fifo); + } +} + + +/*****************************************************************************/ +/** +* +* This is the Error handler callback function and this function increments the +* the error counter so that the main thread knows the number of errors. +* +* @param AxiEthernet is a reference to the AxiEthernet device instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void AxiEthernetErrorHandler(XAxiEthernet *AxiEthernet) +{ + u32 Pending = XAxiEthernet_IntPending(AxiEthernet); + + if (Pending & XAE_INT_RXRJECT_MASK) { + AxiEthernetUtilErrorTrap("AxiEthernet: Rx packet rejected"); + } + if (Pending & XAE_INT_RXFIFOOVR_MASK) { + AxiEthernetUtilErrorTrap("AxiEthernet: Rx fifo over run"); + } + XAxiEthernet_IntClear(AxiEthernet, Pending); + + /* + * Bump counter + */ + DeviceErrors++; +} + +/******************************************************************************/ +/** +* This function resets the device but preserves the options set by the user. +* +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* AxiEthernet component. +* @param FifoInstancePtr is a pointer to the instance of the Fifo +* component. +* +* @return - XST_SUCCESS to indicate success. +* - XST_FAILURE.to indicate failure. +* +* @note None. +* +******************************************************************************/ +static int AxiEthernetResetDevice(XAxiEthernet *AxiEthernetInstancePtr, + XLlFifo *FifoInstancePtr) +{ + int Status; + u8 MacSave[6]; + u32 Options; + + /* + * Stop the Axi Ethernet device + */ + XAxiEthernet_Stop(AxiEthernetInstancePtr); + + + /* + * Save the device state + */ + XAxiEthernet_GetMacAddress(AxiEthernetInstancePtr, MacSave); + Options = XAxiEthernet_GetOptions(AxiEthernetInstancePtr); + + /* + * Stop and reset the Axi Ethernet device + */ + XAxiEthernet_Reset(AxiEthernetInstancePtr); + + /* + * reset the fifo + */ + XLlFifo_Reset(FifoInstancePtr); + + /* + * Restore the state + */ + Status = XAxiEthernet_SetMacAddress(AxiEthernetInstancePtr, MacSave); + Status |= XAxiEthernet_SetOptions(AxiEthernetInstancePtr, Options); + Status |= XAxiEthernet_ClearOptions(AxiEthernetInstancePtr, ~Options); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error restoring state after reset"); + return XST_FAILURE; + } + + /* + * Restart the device + */ + XAxiEthernet_Start(AxiEthernetInstancePtr); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function setups the interrupt system so interrupts can occur for the +* Axi Ethernet. This function is application-specific since the actual system +* may or may not have an interrupt controller. The Axi Ethernet could be +* directly connected to a processor without an interrupt controller. The user +* should modify this function to fit the application. +* +* @param IntcInstancePtr is a pointer to the instance of the Intc component. +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* AxiEthernet component. +* @param FifoInstancePtr is a pointer to the instance of the AXIFIFO +* component. +* @param AxiEthernetDeviceId is Device ID of the Axi Ethernet Device , +* typically XPAR__DEVICE_ID value from +* xparameters.h. +* @param AxiEthernetIntrId is the Interrupt ID and is typically +* XPAR___VEC_ID +* value from xparameters.h. +* @param FifoIntrId is the interrupt id fifo. +* +* @return - XST_SUCCESS to indicate success. +* - XST_FAILURE.to indicate failure. +* +* @note None. +* +******************************************************************************/ +static int AxiEthernetSetupIntrSystem(INTC *IntcInstancePtr, + XAxiEthernet *AxiEthernetInstancePtr, + XLlFifo *FifoInstancePtr, + u16 AxiEthernetIntrId, u16 FifoIntrId) +{ + int Status; +#ifdef XPAR_INTC_0_DEVICE_ID +#ifndef TESTAPP_GEN + /* + * Initialize the interrupt controller and connect the ISR + */ + Status = XIntc_Initialize(IntcInstancePtr, INTC_DEVICE_ID); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap + ("Unable to intialize the interrupt controller"); + return XST_FAILURE; + } +#endif + +#if XPAR_INTC_0_HAS_FAST == 1 + AxiEthernetInstancePtr_Fast = AxiEthernetInstancePtr; + Fifo_Fast = FifoInstancePtr; + Status = XIntc_ConnectFastHandler(IntcInstancePtr, AxiEthernetIntrId, + (XFastInterruptHandler) AxiEthernetErrorFastHandler); + Status |= XIntc_ConnectFastHandler(IntcInstancePtr, FifoIntrId, + (XFastInterruptHandler) FifoFastHandler); +#else + Status = XIntc_Connect(IntcInstancePtr, AxiEthernetIntrId, + (XInterruptHandler) AxiEthernetErrorHandler, + AxiEthernetInstancePtr); + Status |= XIntc_Connect(IntcInstancePtr, FifoIntrId, + (XInterruptHandler) FifoHandler, + FifoInstancePtr); +#endif + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap + ("Unable to connect ISR to interrupt controller"); + return XST_FAILURE; + } + +#ifndef TESTAPP_GEN + /* + * Start the interrupt controller + */ + Status = XIntc_Start(IntcInstancePtr, XIN_REAL_MODE); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error starting intc"); + return XST_FAILURE; + } +#endif + + /* + * Enable interrupts from the hardware + */ + XIntc_Enable(IntcInstancePtr, AxiEthernetIntrId); + XIntc_Enable(IntcInstancePtr, FifoIntrId); +#else + XScuGic_Config *IntcConfig; + + /* + * Initialize the interrupt controller driver so that it is ready to + * use. + */ + IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID); + if (NULL == IntcConfig) { + return XST_FAILURE; + } + + Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig, + IntcConfig->CpuBaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + + XScuGic_SetPriorityTriggerType(IntcInstancePtr, FifoIntrId, 0xA0, 0x3); + + XScuGic_SetPriorityTriggerType(IntcInstancePtr, AxiEthernetIntrId, 0xA0, 0x3); + /* + * Connect the device driver handler that will be called when an + * interrupt for the device occurs, the handler defined above performs + * the specific interrupt processing for the device. + */ + Status = XScuGic_Connect(IntcInstancePtr, FifoIntrId, + (Xil_InterruptHandler)FifoHandler, + FifoInstancePtr); + if (Status != XST_SUCCESS) { + return Status; + } + + Status = XScuGic_Connect(IntcInstancePtr, AxiEthernetIntrId, + (Xil_InterruptHandler)AxiEthernetErrorHandler, + AxiEthernetInstancePtr); + if (Status != XST_SUCCESS) { + return Status; + } + + XScuGic_Enable(IntcInstancePtr, AxiEthernetIntrId); + XScuGic_Enable(IntcInstancePtr, FifoIntrId); +#endif +#ifndef TESTAPP_GEN + + Xil_ExceptionInit(); + + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, + (Xil_ExceptionHandler)INTC_HANDLER, + (void *)(IntcInstancePtr)); + + Xil_ExceptionEnable(); + +#endif + + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function disables the interrupts that occur for AxiEthernet. +* +* @param IntcInstancePtr is a pointer to the instance of the Intc +* component. +* @param AxiEthernetIntrId is the Interrupt ID and is typically +* XPAR___VEC_ID +* value from xparameters.h. +* @param FifoIntrId is the interrupt id for fifo. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void AxiEthernetDisableIntrSystem(INTC *IntcInstancePtr, + u16 AxiEthernetIntrId, u16 FifoIntrId) +{ +#ifdef XPAR_INTC_0_DEVICE_ID + /* + * Disconnect and disable the interrupt for the AxiEthernet device + */ + XIntc_Disconnect(IntcInstancePtr, AxiEthernetIntrId); + /* + * Disconnect and disable the interrupt for the Fifo device + */ + XIntc_Disconnect(IntcInstancePtr, FifoIntrId); + +#else + /* + * Disconnect and disable the interrupt for the AxiEthernet device + */ + XScuGic_Disconnect(IntcInstancePtr, AxiEthernetIntrId); + /* + * Disconnect and disable the interrupt for the Fifo device + */ + XScuGic_Disconnect(IntcInstancePtr, FifoIntrId); +#endif +} + +#if XPAR_INTC_0_HAS_FAST == 1 + +/*****************************************************************************/ +/** +* +* Fast Error Handler which calls AxiEthernetErrorHandler. +* +* @param None +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void AxiEthernetErrorFastHandler(void) +{ + AxiEthernetErrorHandler((XAxiEthernet *)AxiEthernetInstancePtr_Fast); +} +/*****************************************************************************/ +/** +* +* Fast FIFO Handler which calls FifoHandler. +* +* @param None +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void FifoFastHandler(void) +{ + FifoHandler((XLlFifo *)Fifo_Fast); +} + +#endif diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example_intr_sgdma.c b/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example_intr_sgdma.c new file mode 100644 index 00000000..d629d8b9 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example_intr_sgdma.c @@ -0,0 +1,2394 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/** +* +* @file xaxiethernet_example_intr_sgdma.c +* +* Implements examples that utilize the Axi Ethernet's interrupt driven SGDMA +* packet transfer mode to send and receive frames. +* +* These examples demonstrate: +* +* - How to perform simple send and receive +* - Interrupt coalescing +* - Checksum offload +* - Error handling +* - Device reset +* +* Functional guide to example: +* +* - AxiEthernetSgDmaIntrSingleFrameExample demonstrates the simplest way to +* send and receive frames in in interrupt driven SGDMA mode. +* +* - AxiEthernetSgDmaIntrCoalescingExample demonstrates how to use interrupt +* coalescing to increase throughput. +* +* - AxiEthernetSgDmaPartialChecksumOffloadExample demonstrates the partial +* checksum offloading. The HW must be setup for partial checksum +* offloading for this example to execute. +* +* - AxiEthernetSgDmaFullChecksumOffloadExample demonstrates the full +* checksum offloading. The HW must be setup for full checksum offloading +* for this example to execute. +* +* - AxiEthernetAxiEthernetErrorHandler() demonstrates how to manage +* asynchronous errors. +* +* - AxiEthernetResetDevice() demonstrates how to reset the driver/HW without +* loosing all configuration settings. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a asa  4/30/10  First release based on the ll temac driver
+* 1.01a asa  12/10/10 Added full checksum offload example.
+* 		      		  Changes made to enable the AXIDMA Tx/Rx ring interrupts
+*		      		  before allocation of Tx/Rx BDs for all examples.
+* 3.00a asa  6/25/12  Modifed XAxiDma_BdSetLength API call to support new
+*		      		  AXI DMA driver version 7.00a. Removed the calls to
+*		      		  XAxiDma_BdRingStart for the coalesce and checksum
+*		      		  offload examples. They are not required with the new
+*		      		  AxiDMA version.
+* 3.00a bss  10/22/12 Added support for Fast Interrupt Handlers.
+* 3.01a srt  02/14/13 Added support for Zynq (CR 681136).
+*
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xaxiethernet_example.h" +#include "xaxidma.h" +#include "xil_cache.h" +#include "xil_exception.h" +#include "stdio.h" /* stdio */ + +#ifdef XPAR_INTC_0_DEVICE_ID +#include "xintc.h" +#else +#include "xscugic.h" +#endif + +#ifdef XPAR_XUARTNS550_NUM_INSTANCES +#include "xuartns550_l.h" +#endif + +/*************************** Constant Definitions ****************************/ + +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#ifndef TESTAPP_GEN +#define AXIETHERNET_DEVICE_ID XPAR_AXIETHERNET_0_DEVICE_ID +#define AXIDMA_DEVICE_ID XPAR_AXIDMA_0_DEVICE_ID +#ifdef XPAR_INTC_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID +#define AXIETHERNET_IRPT_INTR XPAR_INTC_0_AXIETHERNET_0_VEC_ID +#define DMA_RX_IRPT_INTR XPAR_AXIETHERNET_0_CONNECTED_DMARX_INTR +#define DMA_TX_IRPT_INTR XPAR_AXIETHERNET_0_CONNECTED_DMATX_INTR +#else +#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID +#define AXIETHERNET_IRPT_INTR XPAR_FABRIC_AXIETHERNET_0_VEC_ID +#define DMA_RX_IRPT_INTR XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_VEC_ID +#define DMA_TX_IRPT_INTR XPAR_FABRIC_AXIDMA_0_MM2S_INTROUT_VEC_ID +#endif +#endif + +#ifdef XPAR_INTC_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID +#else +#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID +#endif + +#define RXBD_CNT 128 /* Number of RxBDs to use */ +#define TXBD_CNT 128 /* Number of TxBDs to use */ +#define BD_ALIGNMENT XAXIDMA_BD_MINIMUM_ALIGNMENT + /* Byte alignment of BDs */ +#define PAYLOAD_SIZE 1000 /* Payload size used in examples */ +#define BD_USR0_OFFSET 0 /* AXI4-Stream Control Word offset from + * the start of app user words in BD. Offset + * 0 means, Control Word 0, used for enabling + * checksum offloading. + */ +#define BD_USR1_OFFSET 1 /* AXI4-Stream Control Word offset from + * the start of app user words in BD. Offset + * 1 means, Control Word 1, used for + * mentioning checksum begin and checksum + * insert points + */ +#define BD_USR2_OFFSET 2 /* AXI4-Stream Control Word offset from + * the start of app user words in BD. Offset + * 2 means, Control Word 2, used for + * mentioning checksum seed. + */ + +#define PARTIAL_CSUM_ENABLE 0x00000001 /* Option for partial csum enable */ +#define FULL_CSUM_ENABLE 0x00000002 /* Option for full csum enable */ +#define TX_CS_INIT_OFFSET 16 /* Offset in the control word where + * byte offset in the ethernet frame + * to start CSUM calculation need to + * be inserted + */ +#define RCV_FRM_NOT_CORRUPTED 0xFFFF /* If the received frame is not + * corrupted, for partial csum + * offloading case, the control + * word 3 would return 0xFFFF + */ + +#define IP_VERSION_4 0x800 /* For IPV4, the Ethernet frame + * type/length field will have a + * value of 0x800 + */ +#define IP_HEADER_VERSION 0x04 /* For IPv4, the version entry in + * IP header is always 4 + */ +#define IP_HEADER_LEN_IN_WORDS 0x05 /* For our case, the header length + * is always 20 bytes (5 words + */ +#define IP_HEADER_LENGTH 20 /* IP header length in bytes. Used + * as offset to kigure out the start + * of TCP header. + */ +#define IP_HEADER_PROTOCOL_TCP 0x6 /* IP header protocol entry. For TCP + * packets, it is 6. + */ +#define IP_HEADER_PROTOCOL_UDP 0x17 /* IP header protocol entry. For UDP + * packets, it is 17. + */ +#define TCP_HEADER_LEN_IN_WORDS 0x5 /* For our case, the header length + * is always 20 bytes (5 words) + */ +#define TCP_HEADER_LENGTH 20 /* IP header length in bytes. Used + * as offset to kigure out the start + * of TCP header. + */ +#define FULL_CSUM_STATUS_MASK 0x00000038 /* Mask to extract full checksum + * status field from AXI4 Stream + * Status Word 2. + */ + +#define FULL_CSUM_VALIDATED 0x00000002 /* If bits 3-5 in AXI4 Status word + * have a value of 0x010, it means + * both IP and TCP checksums have + * been found to be correct. + */ +#define IP_TCP_CSUMS_NOT_CHECKED 0x00000000 +#define IP_CSUM_OK_TCP_NOT_CHECKED 0x00000001 +#define TCP_CSUM_NOT_CHECKED_IP_NOT_OK 0x00000005 +#define IP_CSUM_OK_TCP_NOT_OK 0x00000006 + +#define DUMMY_TCP_PORT_1 0x1111 +#define DUMMY_TCP_PORT_2 0x1112 +/* + * Number of bytes to reserve for BD space for the number of BDs desired + */ +#define RXBD_SPACE_BYTES (XAxiDma_BdRingMemCalc(BD_ALIGNMENT, RXBD_CNT)) +#define TXBD_SPACE_BYTES (XAxiDma_BdRingMemCalc(BD_ALIGNMENT, TXBD_CNT)) + + +/*************************** Variable Definitions ****************************/ + +static EthernetFrame TxFrame; /* Transmit buffer */ +static EthernetFrame RxFrame; /* Receive buffer */ + +XAxiEthernet AxiEthernetInstance; +XAxiDma DmaInstance; + +#if XPAR_INTC_0_HAS_FAST == 1 + +/* Variables for Fast Interrupt Handlers */ +XAxiEthernet *AxiEthernetInstancePtr_Fast; +XAxiDma_BdRing *TxRingPtr_Fast; +XAxiDma_BdRing *RxRingPtr_Fast; + +/****** Fast Interrupt Handlers prototypes ******/ + +static void AxiEthernetErrorFastHandler(void) __attribute__ ((fast_interrupt)); + +static void RxIntrFastHandler(void) __attribute__ ((fast_interrupt)); + +static void TxIntrFastHandler(void) __attribute__ ((fast_interrupt)); + +#else + +static void AxiEthernetErrorHandler(XAxiEthernet *AxiEthernet); +static void RxIntrHandler(XAxiDma_BdRing *RxRingPtr); +static void TxIntrHandler(XAxiDma_BdRing *TxRingPtr); + +#endif + +/* + * Aligned memory segments to be used for buffer descriptors + */ +char RxBdSpace[RXBD_SPACE_BYTES] __attribute__ ((aligned(BD_ALIGNMENT))); +char TxBdSpace[TXBD_SPACE_BYTES] __attribute__ ((aligned(BD_ALIGNMENT))); + +/* + * Counters to be incremented by callbacks + */ +static volatile int FramesRx; /* Num of frames that have been received */ +static volatile int FramesTx; /* Num of frames that have been sent */ +static volatile int DeviceErrors;/* Num of errors detected in the device */ + +#ifdef XPAR_INTC_0_DEVICE_ID +#define INTC XIntc +#define INTC_HANDLER XIntc_InterruptHandler +#else +#define INTC XScuGic +#define INTC_HANDLER XScuGic_InterruptHandler +#endif + +#ifndef TESTAPP_GEN +static INTC IntcInstance; +#endif + +/*************************** Function Prototypes *****************************/ + +/* + * Examples + */ +int AxiEthernetSgDmaIntrExample(INTC *IntcInstancePtr, + XAxiEthernet *AxiEthernetInstancePtr, + XAxiDma *DmaInstancePtr, + u16 AxiEthernetDeviceId, + u16 AxiDmaDeviceId, + u16 AxiEthernetIntrId, + u16 DmaRxIntrId, + u16 DmaTxIntrId); +int AxiEthernetSgDmaIntrSingleFrameExample(XAxiEthernet + *AxiEthernetInstancePtr, XAxiDma *DmaInstancePtr); +int AxiEthernetSgDmaIntrCoalescingExample(XAxiEthernet + *AxiEthernetInstancePtr, XAxiDma *DmaInstancePtr); +int AxiEthernetSgDmaPartialChecksumOffloadExample(XAxiEthernet + *AxiEthernetInstancePtr, XAxiDma *DmaInstancePtr); + +int AxiEthernetSgDmaFullChecksumOffloadExample(XAxiEthernet + *AxiEthernetInstancePtr, XAxiDma *DmaInstancePtr); + +/* + * Interrupt setup and Callbacks for examples + */ + +static int AxiEthernetSetupIntrSystem(INTC *IntcInstancePtr, + XAxiEthernet *AxiEthernetInstancePtr, + XAxiDma *DmaInstancePtr, + u16 AxiEthernetIntrId, + u16 DmaRxIntrId, + u16 DmaTxIntrId); +static void AxiEthernetDisableIntrSystem(INTC *IntcInstancePtr, + u16 AxiEthernetIntrId, + u16 DmaRxIntrId, u16 DmaTxIntrId); + +void AxiEthernetPHYRegistersDump(XAxiEthernet * AxiEthernetInstancePtr); + +/*****************************************************************************/ +/** +* +* This is the main function for the Axi Ethernet example. This function is not +* included if the example is generated from the TestAppGen test tool. +* +* @param None. +* +* @return - XST_SUCCESS to indicate success. +* - XST_FAILURE to indicate failure +* +* @note None. +* +****************************************************************************/ +#ifndef TESTAPP_GEN +int main(void) +{ + int Status; + +#ifdef XPAR_XUARTNS550_NUM_INSTANCES + XUartNs550_SetBaud(STDIN_BASEADDRESS, XPAR_XUARTNS550_CLOCK_HZ, 9600); + XUartNs550_SetLineControlReg(STDIN_BASEADDRESS, XUN_LCR_8_DATA_BITS); +#endif + +#if XPAR_MICROBLAZE_USE_ICACHE + Xil_ICacheInvalidate(); + Xil_ICacheEnable(); +#endif + +#if XPAR_MICROBLAZE_USE_DCACHE + Xil_DCacheInvalidate(); + Xil_DCacheEnable(); +#endif + AxiEthernetUtilErrorTrap("\r\n--- Enter main() ---"); + AxiEthernetUtilErrorTrap("This test may take several minutes to finish"); + /* + * Call the Axi Ethernet SGDMA interrupt example , specify the + * parameters generated in xparameters.h. + */ + Status = AxiEthernetSgDmaIntrExample(&IntcInstance, + &AxiEthernetInstance, + &DmaInstance, + AXIETHERNET_DEVICE_ID, + AXIDMA_DEVICE_ID, + AXIETHERNET_IRPT_INTR, + DMA_RX_IRPT_INTR, + DMA_TX_IRPT_INTR); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Failed test intr sgdma"); + AxiEthernetUtilErrorTrap("--- Exiting main() ---"); + return XST_FAILURE; + } + + AxiEthernetUtilErrorTrap("Test passed"); + AxiEthernetUtilErrorTrap("--- Exiting main() ---"); + + return XST_SUCCESS; + +} +#endif + + + +/*****************************************************************************/ +/** +* +* This function demonstrates the usage usage of the Axi Ethernet by sending +* and receiving frames in interrupt driven SGDMA mode. +* +* +* @param IntcInstancePtr is a pointer to the instance of the Intc +* component. +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* AxiEthernet component. +* @param DmaInstancePtr is a pointer to the instance of the AXIDMA +* component. +* @param AxiEthernetDeviceId is Device ID of the Axi Ethernet Device , +* typically XPAR__DEVICE_ID value from +* xparameters.h. +* @param AxiDmaDeviceId is Device ID of the Axi DMAA Device , +* typically XPAR__DEVICE_ID value from +* xparameters.h. +* @param AxiEthernetIntrId is the Interrupt ID and is typically +* XPAR___VEC_ID +* value from xparameters.h. +* @param DmaRxIntrId is the interrupt id for DMA Rx and is typically +* taken from XPAR__CONNECTED_DMARX_INTR +* @param DmaTxIntrId is the interrupt id for DMA Tx and is typically +* taken from XPAR__CONNECTED_DMATX_INTR +* +* @return -XST_SUCCESS to indicate success +* -XST_FAILURE to indicate failure +* +* @note AxiDma hardware must be initialized before initializing +* AxiEthernet. Since AxiDma reset line is connected to the +* AxiEthernet reset line, a reset of AxiDma hardware during its +* initialization would reset AxiEthernet. +* +******************************************************************************/ +int AxiEthernetSgDmaIntrExample(INTC *IntcInstancePtr, + XAxiEthernet *AxiEthernetInstancePtr, + XAxiDma *DmaInstancePtr, + u16 AxiEthernetDeviceId, + u16 AxiDmaDeviceId, + u16 AxiEthernetIntrId, + u16 DmaRxIntrId, + u16 DmaTxIntrId) +{ + int Status; + int LoopbackSpeed; + XAxiEthernet_Config *MacCfgPtr; + XAxiDma_Config* DmaConfig; + XAxiDma_BdRing *RxRingPtr = XAxiDma_GetRxRing(DmaInstancePtr); + XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(DmaInstancePtr); + XAxiDma_Bd BdTemplate; + + /*************************************/ + /* Setup device for first-time usage */ + /*************************************/ + + /* + * Get the configuration of AxiEthernet hardware. + */ + MacCfgPtr = XAxiEthernet_LookupConfig(AxiEthernetDeviceId); + + /* + * Check whether DMA is present or not + */ + if(MacCfgPtr->AxiDevType != XPAR_AXI_DMA) { + AxiEthernetUtilErrorTrap + ("Device HW not configured for SGDMA mode\r\n"); + return XST_FAILURE; + } + + DmaConfig = XAxiDma_LookupConfig(AxiDmaDeviceId); + /* + * Initialize AXIDMA engine. AXIDMA engine must be initialized before + * AxiEthernet. During AXIDMA engine initialization, AXIDMA hardware is + * reset, and since AXIDMA reset line is connected to AxiEthernet, this + * would ensure a reset of AxiEthernet. + */ + Status = XAxiDma_CfgInitialize(DmaInstancePtr, DmaConfig); + if(Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error initializing DMA\r\n"); + return XST_FAILURE; + } + + /* + * Initialize AxiEthernet hardware. + */ + Status = XAxiEthernet_CfgInitialize(AxiEthernetInstancePtr, MacCfgPtr, + MacCfgPtr->BaseAddress); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error in initialize"); + return XST_FAILURE; + } + + /* + * Set the MAC address + */ + Status = XAxiEthernet_SetMacAddress(AxiEthernetInstancePtr, + AxiEthernetMAC); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting MAC address"); + return XST_FAILURE; + } + + /* + * Setup RxBD space. + * + * We have already defined a properly aligned area of memory to store + * RxBDs at the beginning of this source code file so just pass its + * address into the function. No MMU is being used so the physical and + * virtual addresses are the same. + * + * Setup a BD template for the Rx channel. This template will be + * copied to every RxBD. We will not have to explicitly set these + * again. + */ + + /* + * Disable all RX interrupts before RxBD space setup + */ + XAxiDma_BdRingIntDisable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK); + + /* + * Create the RxBD ring + */ + Status = XAxiDma_BdRingCreate(RxRingPtr, (u32) &RxBdSpace, + (u32) &RxBdSpace, BD_ALIGNMENT, RXBD_CNT); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting up RxBD space"); + return XST_FAILURE; + } + + XAxiDma_BdClear(&BdTemplate); + Status = XAxiDma_BdRingClone(RxRingPtr, &BdTemplate); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error initializing RxBD space"); + return XST_FAILURE; + } + + /* + * Setup TxBD space. + * + * Like RxBD space, we have already defined a properly aligned area of + * memory to use. + */ + + /* + * Create the TxBD ring + */ + Status = XAxiDma_BdRingCreate(TxRingPtr, (u32) &TxBdSpace, + (u32) &TxBdSpace, BD_ALIGNMENT, TXBD_CNT); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting up TxBD space"); + return XST_FAILURE; + } + /* + * We reuse the bd template, as the same one will work for both rx + * and tx. + */ + Status = XAxiDma_BdRingClone(TxRingPtr, &BdTemplate); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error initializing TxBD space"); + return XST_FAILURE; + } + + /* + * Set PHY to loopback, speed depends on phy type. + * MII is 100 and all others are 1000. + */ + if (XAxiEthernet_GetPhysicalInterface(AxiEthernetInstancePtr) == + XAE_PHY_TYPE_MII) { + LoopbackSpeed = AXIETHERNET_LOOPBACK_SPEED; + } else { + LoopbackSpeed = AXIETHERNET_LOOPBACK_SPEED_1G; + } + AxiEthernetUtilEnterLoopback(AxiEthernetInstancePtr, LoopbackSpeed); + /* + * Set PHY<-->MAC data clock + */ + Status = XAxiEthernet_SetOperatingSpeed(AxiEthernetInstancePtr, + (u16)LoopbackSpeed); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Setting the operating speed of the MAC needs a delay. There + * doesn't seem to be register to poll, so please consider this + * during your application design. + */ + AxiEthernetUtilPhyDelay(2); + + /* + * Connect to the interrupt controller and enable interrupts + */ + Status = AxiEthernetSetupIntrSystem(IntcInstancePtr, + AxiEthernetInstancePtr, + DmaInstancePtr, + AxiEthernetIntrId, + DmaRxIntrId, + DmaTxIntrId); + + + /****************************/ + /* Run through the examples */ + /****************************/ + + /* + * Run the AxiEthernet DMA Single Frame Interrupt example + */ + Status = AxiEthernetSgDmaIntrSingleFrameExample(AxiEthernetInstancePtr, + DmaInstancePtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + + /* + * Run the Axi Ethernet DMA Interrupt Coalescing example + */ + Status = AxiEthernetSgDmaIntrCoalescingExample(AxiEthernetInstancePtr, + DmaInstancePtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Tx/Rx Partial checksum offload will be disabled when any of + * Tx/Rx VLAN features are built in hardware. + */ + if (XAxiEthernet_IsRxPartialCsum(AxiEthernetInstancePtr) && + XAxiEthernet_IsTxPartialCsum(AxiEthernetInstancePtr) && + !XAxiEthernet_IsTxVlanTran(AxiEthernetInstancePtr) && + !XAxiEthernet_IsTxVlanStrp(AxiEthernetInstancePtr) && + !XAxiEthernet_IsTxVlanTag(AxiEthernetInstancePtr) && + !XAxiEthernet_IsRxVlanTran(AxiEthernetInstancePtr) && + !XAxiEthernet_IsRxVlanStrp(AxiEthernetInstancePtr) && + !XAxiEthernet_IsRxVlanTag(AxiEthernetInstancePtr)) { + Status = AxiEthernetSgDmaPartialChecksumOffloadExample + (AxiEthernetInstancePtr,DmaInstancePtr); + + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + } + + + /* + * Tx/Rx Full checksum offload will be disabled when any of + * Tx/Rx VLAN features are built in hardware. + */ + if (XAxiEthernet_IsRxFullCsum(AxiEthernetInstancePtr) && + XAxiEthernet_IsTxFullCsum(AxiEthernetInstancePtr) && + !XAxiEthernet_IsTxVlanTran(AxiEthernetInstancePtr) && + !XAxiEthernet_IsTxVlanStrp(AxiEthernetInstancePtr) && + !XAxiEthernet_IsTxVlanTag(AxiEthernetInstancePtr) && + !XAxiEthernet_IsRxVlanTran(AxiEthernetInstancePtr) && + !XAxiEthernet_IsRxVlanStrp(AxiEthernetInstancePtr) && + !XAxiEthernet_IsRxVlanTag(AxiEthernetInstancePtr)) { + Status = AxiEthernetSgDmaFullChecksumOffloadExample + (AxiEthernetInstancePtr,DmaInstancePtr); + + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + } + + /* + * Disable the interrupts for the Axi Ethernet device + */ + AxiEthernetDisableIntrSystem(IntcInstancePtr, AxiEthernetIntrId, + DmaRxIntrId, DmaTxIntrId); + + /* + * Stop the device + */ + XAxiEthernet_Stop(AxiEthernetInstancePtr); + + return XST_SUCCESS; +} + + + +/*****************************************************************************/ +/** +* +* This function demonstrates the usage of the Axi Ethernet by sending and +* receiving a single frame in SGDMA interrupt mode. +* The source packet will be described by two descriptors. It will be received +* into a buffer described by a single descriptor. +* +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* Axi Ethernet component. +* @param DmaInstancePtr is a pointer to the instance of the Dma +* component. +* +* @return -XST_SUCCESS to indicate success +* -XST_FAILURE to indicate failure +* +* @note None. +* +******************************************************************************/ +int AxiEthernetSgDmaIntrSingleFrameExample(XAxiEthernet + *AxiEthernetInstancePtr, XAxiDma *DmaInstancePtr) +{ + int Status; + u32 TxFrameLength; + u32 RxFrameLength; + int PayloadSize = PAYLOAD_SIZE; + XAxiDma_BdRing *RxRingPtr = XAxiDma_GetRxRing(DmaInstancePtr); + XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(DmaInstancePtr); + XAxiDma_Bd *Bd1Ptr; + XAxiDma_Bd *Bd2Ptr; + XAxiDma_Bd *BdCurPtr; + u32 BdSts; + + /* + * Clear variables shared with callbacks + */ + FramesRx = 0; + FramesTx = 0; + DeviceErrors = 0; + memset(RxFrame,0,sizeof(RxFrame)); + memset(TxFrame,0,sizeof(TxFrame)); + + /* + * Calculate the frame length (not including FCS) + */ + TxFrameLength = XAE_HDR_SIZE + PayloadSize; + + /* + * Setup packet to be transmitted + */ + AxiEthernetUtilFrameHdrFormatMAC(&TxFrame, AxiEthernetMAC); + AxiEthernetUtilFrameHdrFormatType(&TxFrame, PayloadSize); + AxiEthernetUtilFrameSetPayloadData(&TxFrame, PayloadSize); + + /* + * Flush the TX frame before giving it to DMA TX channel to transmit. + */ + Xil_DCacheFlushRange((u32)&TxFrame, TxFrameLength); + + /* + * Clear out receive packet memory area + */ + AxiEthernetUtilFrameMemClear(&RxFrame); + + /* + * Invalidate the RX frame before giving it to DMA RX channel to + * receive data. + */ + Xil_DCacheInvalidateRange((u32)&RxFrame, TxFrameLength); + + /* + * Make sure Tx and Rx are enabled + */ + Status = XAxiEthernet_SetOptions(AxiEthernetInstancePtr, + XAE_RECEIVER_ENABLE_OPTION | + XAE_TRANSMITTER_ENABLE_OPTION); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting options"); + return XST_FAILURE; + } + + /* + * Start the Axi Ethernet device and enable the ERROR interrupt + */ + XAxiEthernet_Start(AxiEthernetInstancePtr); + XAxiEthernet_IntEnable(AxiEthernetInstancePtr, + XAE_INT_RECV_ERROR_MASK); + + /* + * Enable DMA RX interrupt. + * + * Interrupt coalescing parameters are left at their default settings + * which is to interrupt the processor after every frame has been + * processed by the DMA engine. + */ + XAxiDma_BdRingIntEnable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK); + + /* + * Allocate 1 RxBD. + */ + Status = XAxiDma_BdRingAlloc(RxRingPtr, 1, &Bd1Ptr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error allocating RxBD"); + return XST_FAILURE; + } + + /* + * Setup the BD. + */ + XAxiDma_BdSetBufAddr(Bd1Ptr, (u32)&RxFrame); +#ifndef XPAR_AXIDMA_0_ENABLE_MULTI_CHANNEL + XAxiDma_BdSetLength(Bd1Ptr, sizeof(RxFrame)); +#else + XAxiDma_BdSetLength(Bd1Ptr, sizeof(RxFrame), + RxRingPtr->MaxTransferLen); +#endif + XAxiDma_BdSetCtrl(Bd1Ptr, 0); + + /* + * Enqueue to HW + */ + Status = XAxiDma_BdRingToHw(RxRingPtr, 1, Bd1Ptr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error committing RxBD to HW"); + return XST_FAILURE; + } + + /* + * Start DMA RX channel. Now it's ready to receive data. + */ + Status = XAxiDma_BdRingStart(RxRingPtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Enable DMA transmit interrupts + */ + XAxiDma_BdRingIntEnable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK); + + /* + * Allocate, setup, and enqueue 2 TxBDs. The first BD will describe + * the first 32 bytes of TxFrame and the second BD will describe the + * rest of the frame. + * + * The function below will allocate two adjacent BDs with Bd1Ptr being + * set as the lead BD. + */ + Status = XAxiDma_BdRingAlloc(TxRingPtr, 2, &Bd1Ptr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error allocating TxBD"); + return XST_FAILURE; + } + + /* + * Setup TxBD #1 + */ + XAxiDma_BdSetBufAddr(Bd1Ptr, (u32)&TxFrame); + +#ifndef XPAR_AXIDMA_0_ENABLE_MULTI_CHANNEL + XAxiDma_BdSetLength(Bd1Ptr, 32); +#else + XAxiDma_BdSetLength(Bd1Ptr, 32, + TxRingPtr->MaxTransferLen); +#endif + + XAxiDma_BdSetCtrl(Bd1Ptr, XAXIDMA_BD_CTRL_TXSOF_MASK); + + /* + * Setup TxBD #2 + */ + Bd2Ptr = XAxiDma_BdRingNext(TxRingPtr, Bd1Ptr); + XAxiDma_BdSetBufAddr(Bd2Ptr, (u32) (&TxFrame) + 32); +#ifndef XPAR_AXIDMA_0_ENABLE_MULTI_CHANNEL + XAxiDma_BdSetLength(Bd2Ptr, TxFrameLength - 32); +#else + XAxiDma_BdSetLength(Bd2Ptr, TxFrameLength - 32, + TxRingPtr->MaxTransferLen); +#endif + + XAxiDma_BdSetCtrl(Bd2Ptr, XAXIDMA_BD_CTRL_TXEOF_MASK); + + /* + * Enqueue to HW + */ + Status = XAxiDma_BdRingToHw(TxRingPtr, 2, Bd1Ptr); + if (Status != XST_SUCCESS) { + /* + * Undo BD allocation and exit + */ + XAxiDma_BdRingUnAlloc(TxRingPtr, 2, Bd1Ptr); + AxiEthernetUtilErrorTrap("Error committing TxBD to HW"); + return XST_FAILURE; + } + + /* + * Start DMA TX channel. Transmission starts at once. + */ + Status = XAxiDma_BdRingStart(TxRingPtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Wait for transmission to complete + */ + while (!FramesTx); + /* + * Now that the frame has been sent, post process our TxBDs. + * Since we have only submitted 2 to HW, then there should be only 2 ready + * for post processing. + */ + if (XAxiDma_BdRingFromHw(TxRingPtr, 2, &Bd1Ptr) == 0) { + AxiEthernetUtilErrorTrap("TxBDs were not ready for post processing"); + return XST_FAILURE; + } + + /* + * Examine the TxBDs. + * + * There isn't much to do. The only thing to check would be DMA exception + * bits. But this would also be caught in the error handler. So we just + * return these BDs to the free list + */ + Status = XAxiDma_BdRingFree(TxRingPtr, 2, Bd1Ptr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error freeing up TxBDs"); + return XST_FAILURE; + } + + /* + * Wait for Rx indication + */ + while (!FramesRx); + + /* + * Now that the frame has been received, post process our RxBD. + * Since we have only submitted 1 to HW, then there should be only 1 + * ready for post processing. + */ + if (XAxiDma_BdRingFromHw(RxRingPtr, 1, &Bd1Ptr) == 0) { + AxiEthernetUtilErrorTrap("RxBD was not ready for post processing"); + return XST_FAILURE; + } + BdCurPtr = Bd1Ptr; + BdSts = XAxiDma_BdGetSts(BdCurPtr); + if ((BdSts & XAXIDMA_BD_STS_ALL_ERR_MASK) || + (!(BdSts & XAXIDMA_BD_STS_COMPLETE_MASK))) { + AxiEthernetUtilErrorTrap("Rx Error"); + return XST_FAILURE; + } + else { + RxFrameLength = + (XAxiDma_BdRead(BdCurPtr,XAXIDMA_BD_USR4_OFFSET)) & 0x0000FFFF; + } + + if (RxFrameLength != TxFrameLength) { + AxiEthernetUtilErrorTrap("Length mismatch"); + return XST_FAILURE; + } + + + if (AxiEthernetUtilFrameVerify(&TxFrame, &RxFrame) != 0) { + AxiEthernetUtilErrorTrap("Data mismatch"); + return XST_FAILURE; + } + + /* + * Return the RxBD back to the channel for later allocation. Free the + * exact number we just post processed. + */ + Status = XAxiDma_BdRingFree(RxRingPtr, 1, Bd1Ptr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error freeing up TxBDs"); + return XST_FAILURE; + } + + /* + * Finished this example. If everything worked correctly, all TxBDs and + * RxBDs should be free for allocation. Stop the device. + */ + XAxiEthernet_Stop(AxiEthernetInstancePtr); + return XST_SUCCESS; +} + + +/*****************************************************************************/ +/** +* +* This example sends frames with the interrupt coalescing settings altered +* from their defaults. +* +* The default settings will interrupt the processor after every frame has been +* sent. This example will increase the threshold resulting in lower CPU +* utilization since it spends less time servicing interrupts. +* +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* Axi Ethernet component. +* @param DmaInstancePtr is a pointer to the instance of the Dma +* component. +* +* @return -XST_SUCCESS to indicate success +* -XST_FAILURE to indicate failure +* +* @note None. +* +******************************************************************************/ +int AxiEthernetSgDmaIntrCoalescingExample(XAxiEthernet *AxiEthernetInstancePtr, + XAxiDma *DmaInstancePtr) +{ + int Status; + u32 TxFrameLength; + int PayloadSize = 100; + u32 Index; + u32 NumBd; + u16 Threshold = 10; + XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(DmaInstancePtr); + XAxiDma_Bd *BdPtr; + XAxiDma_Bd *BdCurPtr; + + /* + * Clear variables shared with callbacks + */ + FramesRx = 0; + FramesTx = 0; + DeviceErrors = 0; + + /* + * Calculate the frame length (not including FCS) + */ + TxFrameLength = XAE_HDR_SIZE + PayloadSize; + + /* + * Setup packet to be transmitted. The same packet will be + * transmitted over and over + */ + AxiEthernetUtilFrameHdrFormatMAC(&TxFrame, AxiEthernetMAC); + AxiEthernetUtilFrameHdrFormatType(&TxFrame, PayloadSize); + AxiEthernetUtilFrameSetPayloadData(&TxFrame, PayloadSize); + + /* + * Flush the TX frame before giving it to DMA TX channel to transmit. + */ + Xil_DCacheFlushRange((u32)&TxFrame, TxFrameLength); + + /* + * Make sure Tx and Rx are enabled + */ + Status = XAxiEthernet_SetOptions(AxiEthernetInstancePtr, + XAE_TRANSMITTER_ENABLE_OPTION); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting options"); + return XST_FAILURE; + } + + /* + * We don't care about the receive channel for this example, + * so turn it off, in case it was turned on earlier. + */ + + Status = XAxiEthernet_ClearOptions(AxiEthernetInstancePtr, + XAE_RECEIVER_ENABLE_OPTION); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error clearing option"); + return XST_FAILURE; + } + + /* + * Set the interrupt coalescing parameters for the test. The waitbound + * timer is set to 1 (ms) to catch the last few frames. + * + * If you set variable Threshold to some value larger than TXBD_CNT, + * then there can never be enough frames sent to meet the threshold. + * In this case the waitbound timer will always cause the interrupt to + * occur. + */ + Status = XAxiDma_BdRingSetCoalesce(TxRingPtr, Threshold, 255); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting coalescing settings"); + return XST_FAILURE; + } + + /* + * Enable the send interrupts. Nothing should be transmitted yet as the + * device has not been started + */ + XAxiDma_BdRingIntEnable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK); + + /* + * Prime the engine, allocate all BDs and assign them to the same buffer + */ + Status = XAxiDma_BdRingAlloc(TxRingPtr, Threshold, &BdPtr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error allocating TxBDs prior to starting"); + return XST_FAILURE; + } + + /* + * Setup the TxBDs + */ + BdCurPtr = BdPtr; + + for (Index = 0; Index < Threshold; Index++) { + XAxiDma_BdSetBufAddr(BdCurPtr, (u32)&TxFrame); +#ifndef XPAR_AXIDMA_0_ENABLE_MULTI_CHANNEL + XAxiDma_BdSetLength(BdCurPtr, TxFrameLength); +#else + XAxiDma_BdSetLength(BdCurPtr, TxFrameLength, + TxRingPtr->MaxTransferLen); +#endif + + XAxiDma_BdSetCtrl(BdCurPtr, XAXIDMA_BD_CTRL_TXSOF_MASK | + XAXIDMA_BD_CTRL_TXEOF_MASK); + BdCurPtr = XAxiDma_BdRingNext(TxRingPtr, BdCurPtr); + } + + /* + * Enqueue all TxBDs to HW + */ + Status = XAxiDma_BdRingToHw(TxRingPtr, Threshold, BdPtr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error committing TxBDs prior to starting"); + return XST_FAILURE; + } + + /* + * Start the device. Transmission commences now! + */ + XAxiEthernet_Start(AxiEthernetInstancePtr); + + /* + * Wait for the interrupt + */ + while (!FramesTx); + + NumBd = XAxiDma_BdRingFromHw(TxRingPtr, Threshold, &BdPtr); + if (NumBd != Threshold) { + AxiEthernetUtilErrorTrap("Error in interrupt coalescing"); + } + else { + /* + * Don't bother to check the BDs status, just free them + */ + Status = XAxiDma_BdRingFree(TxRingPtr, Threshold, BdPtr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error freeing TxBDs"); + } + } + + /* + * Done sending frames. Stop the device + */ + XAxiEthernet_Stop(AxiEthernetInstancePtr); + + return XST_SUCCESS; +} + + +/*****************************************************************************/ +/** +* +* This example sends and receives a single packet in loopback mode with +* checksum offloading support. +* +* The transmit frame will be checksummed over the entire Ethernet payload +* and inserted into the last 2 bytes of the frame. +* +* On receive, HW should calculate the Ethernet payload checksum and return a +* value of 0xFFFF which means the payload data was likely not corrupted. +* +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* AxiEthernet component. +* @param DmaInstancePtr is a pointer to the instance of the Dma +* component. +* +* @return -XST_SUCCESS to indicate success +* -XST_FAILURE to indicate failure +* +* @note None. +* +******************************************************************************/ +int AxiEthernetSgDmaPartialChecksumOffloadExample(XAxiEthernet + *AxiEthernetInstancePtr, XAxiDma *DmaInstancePtr) +{ + int Status; + u32 TxFrameLength; + u32 RxFrameLength; + int PayloadSize = PAYLOAD_SIZE; + XAxiDma_BdRing *RxRingPtr = XAxiDma_GetRxRing(DmaInstancePtr); + XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(DmaInstancePtr); + XAxiDma_Bd *BdPtr; + XAxiDma_Bd *BdCurPtr; + u32 BdSts; + + /* + * Cannot run this example if partial checksum offloading support is not + * available + */ + if (!(XAxiEthernet_IsRxPartialCsum(AxiEthernetInstancePtr) && + XAxiEthernet_IsTxPartialCsum(AxiEthernetInstancePtr))) { + AxiEthernetUtilErrorTrap("Partial Checksum offloading not available"); + return XST_FAILURE; + } + + /* + * Clear variables shared with callbacks + */ + FramesRx = 0; + FramesTx = 0; + DeviceErrors = 0; + + memset(RxFrame,0,sizeof(RxFrame)); + memset(TxFrame,0,sizeof(TxFrame)); + + + /* + * Calculate frame length (not including FCS) + */ + TxFrameLength = XAE_HDR_SIZE + PayloadSize; + + /* + * Setup the packet to be transmitted, + * Last 2 bytes are reserved for checksum + */ + AxiEthernetUtilFrameMemClear(&TxFrame); + AxiEthernetUtilFrameHdrFormatMAC(&TxFrame, AxiEthernetMAC); + AxiEthernetUtilFrameHdrFormatType(&TxFrame, PayloadSize); + AxiEthernetUtilFrameSetPayloadData(&TxFrame, PayloadSize - 2); + + /* + * Flush the TX frame before giving it to DMA TX channel to transmit. + */ + Xil_DCacheFlushRange((u32)&TxFrame, TxFrameLength); + + /* + * Clear out receive packet memory area + */ + AxiEthernetUtilFrameMemClear(&RxFrame); + + /* + * Invalidate the RX frame before giving it to DMA RX channel to + * receive data. + */ + Xil_DCacheInvalidateRange((u32)&RxFrame, TxFrameLength); + + /* + * Interrupt coalescing parameters are set to their default settings + * which is to interrupt the processor after every frame has been + * processed by the DMA engine. + */ + Status = XAxiDma_BdRingSetCoalesce(TxRingPtr, 1, 1); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting coalescing for transmit"); + return XST_FAILURE; + } + + Status = XAxiDma_BdRingSetCoalesce(RxRingPtr, 1, 1); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting coalescing for recv"); + return XST_FAILURE; + } + + /* + * Make sure Tx and Rx are enabled + */ + Status = XAxiEthernet_SetOptions(AxiEthernetInstancePtr, + XAE_RECEIVER_ENABLE_OPTION | + XAE_TRANSMITTER_ENABLE_OPTION); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting options"); + return XST_FAILURE; + } + + /* + * Start the Axi Ethernet and enable its ERROR interrupts + */ + XAxiEthernet_Start(AxiEthernetInstancePtr); + XAxiEthernet_IntEnable(AxiEthernetInstancePtr, + XAE_INT_RECV_ERROR_MASK); + + /* + * Enable DMA receive related interrupts + */ + XAxiDma_BdRingIntEnable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK); + + /* + * Allocate 1 RxBD. + */ + Status = XAxiDma_BdRingAlloc(RxRingPtr, 1, &BdPtr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error allocating RxBD"); + return XST_FAILURE; + } + + /* + * Setup the BD. + */ + XAxiDma_BdSetBufAddr(BdPtr, (u32)&RxFrame); +#ifndef XPAR_AXIDMA_0_ENABLE_MULTI_CHANNEL + XAxiDma_BdSetLength(BdPtr, sizeof(RxFrame)); +#else + XAxiDma_BdSetLength(BdPtr, sizeof(RxFrame), + RxRingPtr->MaxTransferLen); +#endif + + XAxiDma_BdSetCtrl(BdPtr, 0); + + /* + * Enqueue to HW + */ + Status = XAxiDma_BdRingToHw(RxRingPtr, 1, BdPtr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error committing RxBD to HW"); + return XST_FAILURE; + } + + /* + * Enable DMA transmit related interrupts + */ + XAxiDma_BdRingIntEnable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK); + + /* + * Allocate 1 TxBD + */ + Status = XAxiDma_BdRingAlloc(TxRingPtr, 1, &BdPtr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error allocating TxBD"); + return XST_FAILURE; + } + + /* + * Setup the TxBD + */ + XAxiDma_BdSetBufAddr(BdPtr, (u32)&TxFrame); +#ifndef XPAR_AXIDMA_0_ENABLE_MULTI_CHANNEL + XAxiDma_BdSetLength(BdPtr, TxFrameLength); +#else + XAxiDma_BdSetLength(BdPtr, TxFrameLength, + TxRingPtr->MaxTransferLen); +#endif + + XAxiDma_BdSetCtrl(BdPtr, XAXIDMA_BD_CTRL_TXSOF_MASK | + XAXIDMA_BD_CTRL_TXEOF_MASK); + + /* + * Setup TxBd checksum offload attributes. + * Note that the checksum offload values can be set globally for all + * TxBds when XAxiDma_BdRingClone() is called to setup Tx BD space. + * This would eliminate the need to set them here. + */ + /* Enable hardware checksum computation for the buffer descriptor */ + Status = XAxiDma_BdSetAppWord(BdPtr,BD_USR0_OFFSET,PARTIAL_CSUM_ENABLE); + if(Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error in enabling partial csum offloading"); + return XST_FAILURE; + } + + /* Write Start Offset and Insert Offset into BD */ + Status = XAxiDma_BdSetAppWord(BdPtr,BD_USR1_OFFSET, + ((XAE_HDR_SIZE << TX_CS_INIT_OFFSET) | (TxFrameLength - 2))); + if(Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error in setting csum insert point"); + return XST_FAILURE; + } + + /* Write 0, as the seed value, to the BD */ + Status = XAxiDma_BdSetAppWord(BdPtr,BD_USR2_OFFSET,0); + if(Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error in enabling partial csum offloading"); + return XST_FAILURE; + } + + /* + * Enqueue to HW + */ + Status = XAxiDma_BdRingToHw(TxRingPtr, 1, BdPtr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error committing TxBD to HW"); + return XST_FAILURE; + } + + /* + * Wait for transmission to complete + */ + while (!FramesTx); + /* + * Now that the frame has been sent, post process our TxBDs. + * Since we have only submitted 2 to HW, then there should be only 2 ready + * for post processing. + */ + if (XAxiDma_BdRingFromHw(TxRingPtr, 1, &BdPtr) == 0) { + AxiEthernetUtilErrorTrap("TxBDs were not ready for post processing"); + return XST_FAILURE; + } + + /* + * Examine the TxBDs. + * + * There isn't much to do. The only thing to check would be DMA exception + * bits. But this would also be caught in the error handler. So we just + * return these BDs to the free list + */ + Status = XAxiDma_BdRingFree(TxRingPtr, 1, BdPtr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error freeing up TxBDs"); + return XST_FAILURE; + } + + /* + * Wait for Rx indication + */ + while (!FramesRx); + /* + * Now that the frame has been received, post process our RxBD. + * Since we have only submitted 1 to HW, then there should be only 1 ready + * for post processing. + */ + if (XAxiDma_BdRingFromHw(RxRingPtr, 1, &BdPtr) == 0) { + AxiEthernetUtilErrorTrap("RxBD was not ready for post processing"); + return XST_FAILURE; + } + + /* + * There is no device status to check. If there was a DMA error, it + * should have been reported to the error handler. Check the receive + * length against the transmitted length, then verify the data. + * + * Note in Axi Ethernet case, USR4_OFFSET word in the RX BD is used to store + * the real length of the received packet + */ + BdCurPtr = BdPtr; + BdSts = XAxiDma_BdGetSts(BdCurPtr); + if ((BdSts & XAXIDMA_BD_STS_ALL_ERR_MASK) || + (!(BdSts & XAXIDMA_BD_STS_COMPLETE_MASK))) { + AxiEthernetUtilErrorTrap("Rx Error"); + return XST_FAILURE; + } + else { + RxFrameLength = + (XAxiDma_BdRead(BdCurPtr,XAXIDMA_BD_USR4_OFFSET)) & 0x0000FFFF; + } + + if (RxFrameLength != TxFrameLength) { + AxiEthernetUtilErrorTrap("Length mismatch"); + return XST_FAILURE; + } + + /* + * Verify the checksum as computed by HW. It should add up to 0xFFFF + * if frame was uncorrupted + */ + if ((u16) (XAxiDma_BdRead(BdPtr, XAXIDMA_BD_USR3_OFFSET)) + != RCV_FRM_NOT_CORRUPTED) { + AxiEthernetUtilErrorTrap("Rx checksum incorrect"); + return XST_FAILURE; + } + + /* + * Return the RxBD back to the channel for later allocation. Free the + * exact number we just post processed. + */ + Status = XAxiDma_BdRingFree(RxRingPtr, 1, BdPtr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error freeing up TxBDs"); + return XST_FAILURE; + } + + /* + * Finished this example. If everything worked correctly, all TxBDs + * and RxBDs should be free for allocation. Stop the device. + */ + XAxiEthernet_Stop(AxiEthernetInstancePtr); + + return XST_SUCCESS; +} + + +/*****************************************************************************/ +/** +* +* This example sends and receives a single packet in loopback mode with +* full checksum offloading support. +* +* An Ethernet frame is formed with IP header, TCP header and payload. The +* hardware calculates the IP Header checksum and populates it at the +* appropriate location in the IP header. Similarly, the hardware calculates +* the TCP Pseudo header from IP header and calculates TCP checksum for TCP +* Pseudo header, TCP header and TCP payload. It then populates the checksum +* in the TCP header. +* The Ethernet frame is then looped back and received. The hardware validates +* the IP header checksum and the TCP checksum. +* The example retrieves the checksum validation information from the AXI4- +* Stream Appword2. +* +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* AxiEthernet component. +* @param DmaInstancePtr is a pointer to the instance of the Dma +* component. +* +* @return -XST_SUCCESS to indicate success +* -XST_FAILURE to indicate failure +* +* @note None. +* +******************************************************************************/ +int AxiEthernetSgDmaFullChecksumOffloadExample(XAxiEthernet + *AxiEthernetInstancePtr, XAxiDma *DmaInstancePtr) +{ + int Status; + u32 TxFrameLength; + u32 RxFrameLength; + int PayloadSize = 64; + XAxiDma_BdRing *RxRingPtr = XAxiDma_GetRxRing(DmaInstancePtr); + XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(DmaInstancePtr); + XAxiDma_Bd *BdPtr; + XAxiDma_Bd *BdCurPtr; + u32 BdSts; + u8 DummyIPAddr[4]; + u32 FullCsumStatus; + u8 *IPHdrPntr; + u8 *TCPHdrPntr; + u16 TempShortToCopy; + u8 *PtrToCopyShort; + + /* + * Clear variables shared with callbacks + */ + FramesRx = 0; + FramesTx = 0; + DeviceErrors = 0; + + memset(RxFrame,0,sizeof(RxFrame)); + memset(TxFrame,0,sizeof(TxFrame)); + + /* + * Calculate frame length (not including FCS) + */ + TxFrameLength = XAE_HDR_SIZE + IP_HEADER_LENGTH + TCP_HEADER_LENGTH + + PayloadSize ; + + /* + * Setup the Ethernet frame header. + */ + AxiEthernetUtilFrameHdrFormatMAC(&TxFrame, AxiEthernetMAC); + AxiEthernetUtilFrameHdrFormatType(&TxFrame, IP_VERSION_4); + + /* + * Setup the IP header. + */ + IPHdrPntr = (u8 *)((u8 *)(TxFrame) + XAE_HDR_SIZE); + + /* + * Form the version and IP header length. Version is 4 for IP + * and length is 5 words + */ + *IPHdrPntr++ = (IP_HEADER_VERSION << 4) | IP_HEADER_LEN_IN_WORDS; + + /* Type of service is not important for this example */ + *IPHdrPntr++ = 0x00; + + /* + * Total length in bytes. This will be our payload size in this example + */ + TempShortToCopy = Xil_Htons(PayloadSize + IP_HEADER_LENGTH + + TCP_HEADER_LENGTH); + PtrToCopyShort = (u8 *)(&TempShortToCopy); + *IPHdrPntr++ = PtrToCopyShort[0]; + *IPHdrPntr++ = PtrToCopyShort[1]; + + /* + * Fill the IP Identification (16 bit wide) field. Here it is made + * as zero. + */ + *IPHdrPntr++ = 0; + *IPHdrPntr++ = 0; + + /* + * Fragmentation is not allowed for full checksum offloading. + * Hence both the fragment offset (LS 14 bits) and fragment flags + * (MS 2 bits) are set to 0. + */ + TempShortToCopy = Xil_Htons(0x4000); + PtrToCopyShort = (u8 *)(&TempShortToCopy); + *IPHdrPntr++ = PtrToCopyShort[0]; + *IPHdrPntr++ = PtrToCopyShort[1]; + + /* + * IP time to live. Let us make it 0x3F. Not important in any case for + * this example. IP protocol field is 6 for TCP. + */ + *IPHdrPntr++ = 0x3F; + *IPHdrPntr++ = IP_HEADER_PROTOCOL_TCP; + + /* + * IP header checksum (16 bit wide) is made 0. It will be calculated + * by the hardware and filled in at this place. + */ + *IPHdrPntr++ = 0; + *IPHdrPntr++ = 0; + + /* + * Let us use some source address (172.23.16.1) and the same destination + * address. In any case the packet is looped back in the PHY and these + * addresses are meaningful only for IP header checksum calculation + * and Pseudo-header for TCP checksum calculation. + */ + DummyIPAddr[0] = 172; + DummyIPAddr[1] = 23; + DummyIPAddr[2] = 16; + DummyIPAddr[3] = 1; + memcpy(IPHdrPntr, DummyIPAddr, 4); + IPHdrPntr = IPHdrPntr + 4; + memcpy(IPHdrPntr, DummyIPAddr, 4); + IPHdrPntr = IPHdrPntr + 4; + + /* + * Populate the TCP header fields. + */ + TCPHdrPntr = (u8 *)((u8 *)(TxFrame) + XAE_HDR_SIZE + IP_HEADER_LENGTH); + + /* + * Use some port number for source and destination for the purpose of + * filling up the TCP header. + */ + TempShortToCopy = Xil_Htons(DUMMY_TCP_PORT_1); + PtrToCopyShort = (u8 *)(&TempShortToCopy); + *TCPHdrPntr++ = PtrToCopyShort[0]; + *TCPHdrPntr++ = PtrToCopyShort[1]; + + TempShortToCopy = Xil_Htons(DUMMY_TCP_PORT_2); + PtrToCopyShort = (u8 *)(&TempShortToCopy); + *TCPHdrPntr++ = PtrToCopyShort[0]; + *TCPHdrPntr++ = PtrToCopyShort[1]; + + /* + * Sequence number and Ack number are of no significance in this + * example. + */ + /* Copy TCP Seq number */ + *TCPHdrPntr++ = 0; + *TCPHdrPntr++ = 0; + *TCPHdrPntr++ = 0; + *TCPHdrPntr++ = 0; + + /* Copy TCP Ack number */ + *TCPHdrPntr++ = 0; + *TCPHdrPntr++ = 0; + *TCPHdrPntr++ = 0; + *TCPHdrPntr++ = 0; + + /* Size of TCP header which is 20 bytes (5 words) in normal case. */ + *TCPHdrPntr++ = TCP_HEADER_LEN_IN_WORDS; + *TCPHdrPntr++ = 0xF0; /* Some entry for flags */ + + /* + * TCP Window and TCP Urgent pointer are irrelevant for this + * example. Hence they are made zero. TCP Checksum will be + * calculated and populated in TCP Checksum field. Hence it is + * left as zero. + */ + /* Copy TCP Window */ + *TCPHdrPntr++ = 0; + *TCPHdrPntr++ = 0; + + /* Copy TCP Checksum */ + *TCPHdrPntr++ = 0; + *TCPHdrPntr++ = 0; + + /* Copy TCP Urgent pointer */ + *TCPHdrPntr++ = 0; + *TCPHdrPntr++ = 0; + + /* Now populate the payload data for the TCP packet */ + AxiEthernetUtilFrameSetPayloadData((EthernetFrame *)((u8 *)(TxFrame) + + IP_HEADER_LENGTH + TCP_HEADER_LENGTH), PayloadSize); + + /* + * Flush the TX frame before giving it to DMA TX channel to transmit. + */ + Xil_DCacheFlushRange((u32)&TxFrame, TxFrameLength); + + /* + * Invalidate the RX frame before giving it to DMA RX channel to + * receive data. + */ + Xil_DCacheInvalidateRange((u32)&RxFrame, TxFrameLength); + + /* + * Interrupt coalescing parameters are set to their default settings + * which is to interrupt the processor after every frame has been + * processed by the DMA engine. + */ + Status = XAxiDma_BdRingSetCoalesce(TxRingPtr, 1, 1); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting coalescing for transmit"); + return XST_FAILURE; + } + + Status = XAxiDma_BdRingSetCoalesce(RxRingPtr, 1, 1); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting coalescing for recv"); + return XST_FAILURE; + } + + /* + * Make sure Tx and Rx are enabled + */ + Status = XAxiEthernet_SetOptions(AxiEthernetInstancePtr, + XAE_RECEIVER_ENABLE_OPTION | + XAE_TRANSMITTER_ENABLE_OPTION); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting options"); + return XST_FAILURE; + } + + /* + * Start the Axi Ethernet and enable its ERROR interrupts + */ + XAxiEthernet_Start(AxiEthernetInstancePtr); + XAxiEthernet_IntEnable(AxiEthernetInstancePtr, + XAE_INT_RECV_ERROR_MASK); + + /* + * Enable DMA receive related interrupts + */ + XAxiDma_BdRingIntEnable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK); + + /* + * Allocate 1 RxBD. + */ + Status = XAxiDma_BdRingAlloc(RxRingPtr, 1, &BdPtr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error allocating RxBD"); + return XST_FAILURE; + } + + /* + * Setup the BD. + */ + XAxiDma_BdSetBufAddr(BdPtr, (u32)&RxFrame); +#ifndef XPAR_AXIDMA_0_ENABLE_MULTI_CHANNEL + XAxiDma_BdSetLength(BdPtr, sizeof(RxFrame)); +#else + XAxiDma_BdSetLength(BdPtr, sizeof(RxFrame), + RxRingPtr->MaxTransferLen); +#endif + + XAxiDma_BdSetCtrl(BdPtr, 0); + + /* + * Enqueue to HW + */ + Status = XAxiDma_BdRingToHw(RxRingPtr, 1, BdPtr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error committing RxBD to HW"); + return XST_FAILURE; + } + + /* + * Enable DMA transmit related interrupts + */ + XAxiDma_BdRingIntEnable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK); + + /* + * Allocate 1 TxBD + */ + Status = XAxiDma_BdRingAlloc(TxRingPtr, 1, &BdPtr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error allocating TxBD"); + return XST_FAILURE; + } + + /* + * Setup the TxBD + */ + XAxiDma_BdSetBufAddr(BdPtr, (u32)&TxFrame); +#ifndef XPAR_AXIDMA_0_ENABLE_MULTI_CHANNEL + XAxiDma_BdSetLength(BdPtr, TxFrameLength); +#else + XAxiDma_BdSetLength(BdPtr, TxFrameLength, + TxRingPtr->MaxTransferLen); +#endif + + XAxiDma_BdSetCtrl(BdPtr, XAXIDMA_BD_CTRL_TXSOF_MASK | + XAXIDMA_BD_CTRL_TXEOF_MASK); + + /* + * Setup TxBd checksum offload attributes. + */ + /* Enable hardware checksum computation for the buffer descriptor */ + Status = XAxiDma_BdSetAppWord(BdPtr, BD_USR0_OFFSET, FULL_CSUM_ENABLE); + if(Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error in enabling full csum offloading"); + return XST_FAILURE; + } + + /* + * Enqueue to HW + */ + Status = XAxiDma_BdRingToHw(TxRingPtr, 1, BdPtr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error committing TxBD to HW"); + return XST_FAILURE; + } + + /* + * Wait for transmission to complete + */ + while (!FramesTx); + + /* + * Now that the frame has been sent, post process our TxBDs. + * Since we have only submitted 1 to HW, then there should be only 1 ready + * for post processing. + */ + if (XAxiDma_BdRingFromHw(TxRingPtr, 1, &BdPtr) == 0) { + AxiEthernetUtilErrorTrap("TxBDs were not ready for post processing"); + return XST_FAILURE; + } + + /* + * Examine the TxBDs. + * + * There isn't much to do. The only thing to check would be DMA exception + * bits. But this would also be caught in the error handler. So we just + * return these BDs to the free list + */ + Status = XAxiDma_BdRingFree(TxRingPtr, 1, BdPtr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error freeing up TxBDs"); + return XST_FAILURE; + } + + /* + * Wait for Rx indication + */ + while (!FramesRx); + + /* + * Now that the frame has been received, post process our RxBD. + * Since we have only submitted 1 to HW, then there should be only 1 ready + * for post processing. + */ + if (XAxiDma_BdRingFromHw(RxRingPtr, 1, &BdPtr) == 0) { + AxiEthernetUtilErrorTrap("RxBD was not ready for post processing"); + return XST_FAILURE; + } + + /* + * There is no device status to check. If there was a DMA error, it + * should have been reported to the error handler. Check the receive + * length against the transmitted length, then verify the data. + * + * Note in Axi Ethernet case, USR4_OFFSET word in the RX BD is used to store + * the real length of the received packet + */ + BdCurPtr = BdPtr; + BdSts = XAxiDma_BdGetSts(BdCurPtr); + if ((BdSts & XAXIDMA_BD_STS_ALL_ERR_MASK) || + (!(BdSts & XAXIDMA_BD_STS_COMPLETE_MASK))) { + AxiEthernetUtilErrorTrap("Rx Error"); + return XST_FAILURE; + } + else { + + RxFrameLength = + (XAxiDma_BdRead(BdCurPtr,XAXIDMA_BD_USR4_OFFSET)) & + 0x0000FFFF; + } + + if (RxFrameLength != TxFrameLength) { + AxiEthernetUtilErrorTrap("Length mismatch"); + return XST_FAILURE; + } + + /* + * Read the full checksum validation status from AXI4 Status Word. + */ + FullCsumStatus = (((XAxiDma_BdRead(BdPtr, XAXIDMA_BD_USR2_OFFSET)) & + FULL_CSUM_STATUS_MASK) >> 3); + if (FullCsumStatus != FULL_CSUM_VALIDATED) { + if(FullCsumStatus == IP_TCP_CSUMS_NOT_CHECKED) { + AxiEthernetUtilErrorTrap("IP and TCP checksums not checked"); + return XST_FAILURE; + } + else if(FullCsumStatus == IP_CSUM_OK_TCP_NOT_CHECKED) { + AxiEthernetUtilErrorTrap("IP checksum is OK, TCP checksum not checked for"); + return XST_FAILURE; + } + else if(FullCsumStatus == TCP_CSUM_NOT_CHECKED_IP_NOT_OK) { + AxiEthernetUtilErrorTrap("IP checksum is not correct, TCP checksum not checked for"); + return XST_FAILURE; + } + else if(FullCsumStatus == IP_CSUM_OK_TCP_NOT_OK) { + AxiEthernetUtilErrorTrap("IP checksum is correct, TCP checksum is incorrect"); + return XST_FAILURE; + } + else { + AxiEthernetUtilErrorTrap("IP and TCP checksums not validated because of other reasons"); + return XST_FAILURE; + } + } + + /* + * Return the RxBD back to the channel for later allocation. Free the + * exact number we just post processed. + */ + Status = XAxiDma_BdRingFree(RxRingPtr, 1, BdPtr); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error freeing up TxBDs"); + return XST_FAILURE; + } + + /* + * Finished this example. If everything worked correctly, all TxBDs + * and RxBDs should be free for allocation. Stop the device. + */ + XAxiEthernet_Stop(AxiEthernetInstancePtr); + + return XST_SUCCESS; + +} + +/*****************************************************************************/ +/** +* +* This is the DMA TX callback function to be called by TX interrupt handler. +* This function handles BDs finished by hardware. +* +* @param TxRingPtr is a pointer to TX channel of the DMA engine. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void TxCallBack(XAxiDma_BdRing *TxRingPtr) +{ + /* + * Disable the transmit related interrupts + */ + XAxiDma_BdRingIntDisable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK); + /* + * Increment the counter so that main thread knows something happened + */ + FramesTx++; +} + +/*****************************************************************************/ +/** +* +* This is the DMA TX Interrupt handler function. +* +* @param TxRingPtr is a pointer to TX channel of the DMA engine. +* +* @return None. +* +* @note This Interrupt handler MUST clear pending interrupts before +* handling them by calling the call back. Otherwise the following +* corner case could raise some issue: +* +* A packet got transmitted and a TX interrupt got asserted. If +* the interrupt handler calls the callback before clearing the +* interrupt, a new packet may get transmitted in the callback. +* This new packet then can assert one more TX interrupt before +* the control comes out of the callback function. Now when +* eventually control comes out of the callback function, it will +* never know about the second new interrupt and hence while +* clearing the interrupts, would clear the new interrupt as well +* and will never process it. +* To avoid such cases, interrupts must be cleared before calling +* the callback. +* +******************************************************************************/ +static void TxIntrHandler(XAxiDma_BdRing *TxRingPtr) +{ + u32 IrqStatus; + + /* Read pending interrupts */ + IrqStatus = XAxiDma_BdRingGetIrq(TxRingPtr); + + /* Acknowledge pending interrupts */ + XAxiDma_BdRingAckIrq(TxRingPtr, IrqStatus); + /* + * If no interrupt is asserted, raise error flag, reset the + * hardware to recover from the error, and return with no further + * processing. + */ + if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) { + DeviceErrors++; + AxiEthernetUtilErrorTrap + ("AXIDma: No interrupts asserted in TX status register"); + XAxiDma_Reset(&DmaInstance); + if(!XAxiDma_ResetIsDone(&DmaInstance)) { + AxiEthernetUtilErrorTrap ("AxiDMA: Error: Could not reset\n"); + } + return; + } + + /* + * If error interrupt is asserted, raise error flag, reset the + * hardware to recover from the error, and return with no further + * processing. + */ + if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) { + + AxiEthernetUtilErrorTrap("AXIDMA: TX Error interrupts\n"); + + /* Reset should never fail for transmit channel + */ + XAxiDma_Reset(&DmaInstance); + if(!XAxiDma_ResetIsDone(&DmaInstance)) { + + AxiEthernetUtilErrorTrap ("AXIDMA: Error: Could not reset\n"); + } + + return; + } + + /* + * If Transmit done interrupt is asserted, call TX call back function + * to handle the processed BDs and raise the according flag + */ + if ((IrqStatus & (XAXIDMA_IRQ_DELAY_MASK | XAXIDMA_IRQ_IOC_MASK))) { + TxCallBack(TxRingPtr); + } +} + + +/*****************************************************************************/ +/** +* +* This is the DMA RX callback function to be called by RX interrupt handler. +* This function handles finished BDs by hardware, attaches new buffers to those +* BDs, and give them back to hardware to receive more incoming packets +* +* @param RxRingPtr is a pointer to RX channel of the DMA engine. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void RxCallBack(XAxiDma_BdRing *RxRingPtr) +{ + /* + * Disable the receive related interrupts + */ + XAxiDma_BdRingIntDisable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK); + + /* + * Increment the counter so that main thread knows something + * happened + */ + FramesRx++; +} + + +/*****************************************************************************/ +/** +* +* This is the Receive handler function for examples 1 and 2. +* It will increment a shared counter, receive and validate the frame. +* +* @param RxRingPtr is a pointer to the DMA ring instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void RxIntrHandler(XAxiDma_BdRing *RxRingPtr) +{ + u32 IrqStatus; + + /* Read pending interrupts */ + IrqStatus = XAxiDma_BdRingGetIrq(RxRingPtr); + + /* Acknowledge pending interrupts */ + XAxiDma_BdRingAckIrq(RxRingPtr, IrqStatus); + + /* + * If no interrupt is asserted, raise error flag, reset the + * hardware to recover from the error, and return with no further + * processing. + */ + if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) { + DeviceErrors++; + AxiEthernetUtilErrorTrap + ("AXIDma: No interrupts asserted in RX status register"); + XAxiDma_Reset(&DmaInstance); + if(!XAxiDma_ResetIsDone(&DmaInstance)) { + AxiEthernetUtilErrorTrap ("Could not reset\n"); + } + return; + } + + /* + * If error interrupt is asserted, raise error flag, reset the + * hardware to recover from the error, and return with no further + * processing. + */ + if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) { + + AxiEthernetUtilErrorTrap("AXIDMA: RX Error interrupts\n"); + + /* + * Reset could fail and hang + * NEED a way to handle this or do not call it?? + */ + XAxiDma_Reset(&DmaInstance); + + if(!XAxiDma_ResetIsDone(&DmaInstance)) { + AxiEthernetUtilErrorTrap ("AXIDMA: Could not reset\n"); + } + return; + } + /* + * If Reception done interrupt is asserted, call RX call back function + * to handle the processed BDs and then raise the according flag. + */ + if ((IrqStatus & (XAXIDMA_IRQ_DELAY_MASK | XAXIDMA_IRQ_IOC_MASK))) { + RxCallBack(RxRingPtr); + } +} + + +/*****************************************************************************/ +/** +* +* This is the Error handler callback function and this function increments the +* the error counter so that the main thread knows the number of errors. +* +* @param AxiEthernet is a reference to the Axi Ethernet device instance. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void AxiEthernetErrorHandler(XAxiEthernet *AxiEthernet) +{ + u32 Pending = XAxiEthernet_IntPending(AxiEthernet); + + if (Pending & XAE_INT_RXRJECT_MASK) { + AxiEthernetUtilErrorTrap("AxiEthernet: Rx packet rejected"); + } + + if (Pending & XAE_INT_RXFIFOOVR_MASK) { + AxiEthernetUtilErrorTrap("AxiEthernet: Rx fifo over run"); + } + + XAxiEthernet_IntClear(AxiEthernet, Pending); + + /* + * Bump counter + */ + DeviceErrors++; +} + + +/*****************************************************************************/ +/** +* +* This function setups the interrupt system so interrupts can occur for the +* Axi Ethernet. This function is application-specific since the actual system +* may or may not have an interrupt controller. The Axi Ethernet could be +* directly connected to a processor without an interrupt controller. The user +* should modify this function to fit the application. +* +* @param IntcInstancePtr is a pointer to the instance of the Intc +* component. +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* AxiEthernet component. +* @param DmaInstancePtr is a pointer to the instance of the AXIDMA +* component. +* @param AxiEthernetIntrId is the Interrupt ID and is typically +* XPAR___VEC_ID +* value from xparameters.h. +* @param DmaRxIntrId is the interrupt id for DMA Rx and is typically +* taken from XPAR__CONNECTED_DMARX_INTR +* @param DmaTxIntrId is the interrupt id for DMA Tx and is typically +* taken from XPAR__CONNECTED_DMATX_INTR +* +* @return -XST_SUCCESS to indicate success +* -XST_FAILURE to indicate failure +* +* @note None. +* +******************************************************************************/ +static int AxiEthernetSetupIntrSystem(INTC *IntcInstancePtr, + XAxiEthernet *AxiEthernetInstancePtr, + XAxiDma *DmaInstancePtr, + u16 AxiEthernetIntrId, + u16 DmaRxIntrId, + u16 DmaTxIntrId) +{ + XAxiDma_BdRing * TxRingPtr = XAxiDma_GetTxRing(DmaInstancePtr); + XAxiDma_BdRing * RxRingPtr = XAxiDma_GetRxRing(DmaInstancePtr); + + int Status; +#ifdef XPAR_INTC_0_DEVICE_ID +#ifndef TESTAPP_GEN + /* + * Initialize the interrupt controller and connect the ISR + */ + Status = XIntc_Initialize(IntcInstancePtr, INTC_DEVICE_ID); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Unable to intialize the interrupt controller"); + return XST_FAILURE; + } +#endif + +#if XPAR_INTC_0_HAS_FAST == 1 + + TxRingPtr_Fast = TxRingPtr; + RxRingPtr_Fast = RxRingPtr; + AxiEthernetInstancePtr_Fast = AxiEthernetInstancePtr; + Status = XIntc_ConnectFastHandler(IntcInstancePtr, AxiEthernetIntrId, + (XFastInterruptHandler) AxiEthernetErrorFastHandler); + Status |= XIntc_ConnectFastHandler(IntcInstancePtr, DmaTxIntrId, + (XFastInterruptHandler) TxIntrFastHandler); + Status |= XIntc_ConnectFastHandler(IntcInstancePtr, DmaRxIntrId, + (XFastInterruptHandler) RxIntrFastHandler); +#else + Status = XIntc_Connect(IntcInstancePtr, AxiEthernetIntrId, + (XInterruptHandler)AxiEthernetErrorHandler, + AxiEthernetInstancePtr); + Status |= XIntc_Connect(IntcInstancePtr, DmaTxIntrId, + (XInterruptHandler) TxIntrHandler, TxRingPtr); + Status |= XIntc_Connect(IntcInstancePtr, DmaRxIntrId, + (XInterruptHandler) RxIntrHandler, RxRingPtr); + +#endif + + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Unable to connect ISR to interrupt controller"); + return XST_FAILURE; + } + +#ifndef TESTAPP_GEN + /* + * Start the interrupt controller + */ + Status = XIntc_Start(IntcInstancePtr, XIN_REAL_MODE); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error starting intc"); + return XST_FAILURE; + } +#endif + + + /* + * Enable interrupts from the hardware + */ + XIntc_Enable(IntcInstancePtr, AxiEthernetIntrId); + XIntc_Enable(IntcInstancePtr, DmaTxIntrId); + XIntc_Enable(IntcInstancePtr, DmaRxIntrId); +#else + XScuGic_Config *IntcConfig; + + + /* + * Initialize the interrupt controller driver so that it is ready to + * use. + */ + IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID); + if (NULL == IntcConfig) { + return XST_FAILURE; + } + + Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig, + IntcConfig->CpuBaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + + XScuGic_SetPriorityTriggerType(IntcInstancePtr, DmaTxIntrId, 0xA0, 0x3); + + XScuGic_SetPriorityTriggerType(IntcInstancePtr, DmaRxIntrId, 0xA0, 0x3); + + XScuGic_SetPriorityTriggerType(IntcInstancePtr, AxiEthernetIntrId, 0xA0, 0x3); + /* + * Connect the device driver handler that will be called when an + * interrupt for the device occurs, the handler defined above performs + * the specific interrupt processing for the device. + */ + Status = XScuGic_Connect(IntcInstancePtr, DmaTxIntrId, + (Xil_InterruptHandler)TxIntrHandler, + TxRingPtr); + if (Status != XST_SUCCESS) { + return Status; + } + + Status = XScuGic_Connect(IntcInstancePtr, DmaRxIntrId, + (Xil_InterruptHandler)RxIntrHandler, + RxRingPtr); + if (Status != XST_SUCCESS) { + return Status; + } + + Status = XScuGic_Connect(IntcInstancePtr, AxiEthernetIntrId, + (Xil_InterruptHandler)AxiEthernetErrorHandler, + AxiEthernetInstancePtr); + if (Status != XST_SUCCESS) { + return Status; + } + + XScuGic_Enable(IntcInstancePtr, AxiEthernetIntrId); + XScuGic_Enable(IntcInstancePtr, DmaTxIntrId); + XScuGic_Enable(IntcInstancePtr, DmaRxIntrId); +#endif +#ifndef TESTAPP_GEN + Xil_ExceptionInit(); + + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, + (Xil_ExceptionHandler)INTC_HANDLER, + (void *)(IntcInstancePtr)); + + Xil_ExceptionEnable(); + +#endif + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function disables the interrupts that occur for AxiEthernet. +* +* @param IntcInstancePtr is a pointer to the instance of the Intc +* component. +* @param AxiEthernetIntrId is the Interrupt ID and is typically +* XPAR___VEC_ID +* value from xparameters.h. +* @param DmaRxIntrId is the interrupt id for DMA Rx and is typically +* taken from XPAR__CONNECTED_DMARX_INTR +* @param DmaTxIntrId is the interrupt id for DMA Tx and is typically +* taken from XPAR__CONNECTED_DMATX_INTR +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void AxiEthernetDisableIntrSystem(INTC *IntcInstancePtr, + u16 AxiEthernetIntrId, + u16 DmaRxIntrId, + u16 DmaTxIntrId) +{ +#ifdef XPAR_INTC_0_DEVICE_ID + /* + * Disconnect the interrupts for the DMA TX and RX channels + */ + XIntc_Disconnect(IntcInstancePtr, DmaTxIntrId); + XIntc_Disconnect(IntcInstancePtr, DmaRxIntrId); + + /* + * Disconnect and disable the interrupt for the AxiEthernet device + */ + XIntc_Disconnect(IntcInstancePtr, AxiEthernetIntrId); + +#else + /* + * Disconnect the interrupts for the DMA TX and RX channels + */ + XScuGic_Disconnect(IntcInstancePtr, DmaTxIntrId); + XScuGic_Disconnect(IntcInstancePtr, DmaRxIntrId); + + /* + * Disconnect and disable the interrupt for the AxiEthernet device + */ + XScuGic_Disconnect(IntcInstancePtr, AxiEthernetIntrId); +#endif +} + +#if XPAR_INTC_0_HAS_FAST == 1 +/*****************************************************************************/ +/** +* +* Fast Error Handler which calls AxiEthernetErrorHandler. +* +* @param None +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void AxiEthernetErrorFastHandler(void) +{ + AxiEthernetErrorHandler((XAxiEthernet *)AxiEthernetInstancePtr_Fast); +} + +/*****************************************************************************/ +/** +* +* Fast Tramsmit Handler which calls TxIntrHandler. +* +* @param None +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void TxIntrFastHandler(void) +{ + TxIntrHandler((XAxiDma_BdRing *)TxRingPtr_Fast); +} + +/*****************************************************************************/ +/** +* +* Fast Receive Handler which calls RxIntrHandler. +* +* @param None +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void RxIntrFastHandler(void) +{ + RxIntrHandler((XAxiDma_BdRing *)RxRingPtr_Fast); +} + +#endif diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example_polled.c b/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example_polled.c new file mode 100644 index 00000000..eff71e63 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example_polled.c @@ -0,0 +1,805 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/** +* +* @file xaxiethernet_example_polled.c +* +* Implements examples that utilize the Axi Ethernet's FIFO direct frame transfer +* mode in a polled fashion to send and receive frames. +* +* These examples demonstrate: +* +* - How to perform simple polling send and receive. +* - Advanced frame processing +* - Error handling +* +* Functional guide to example: +* +* - AxiEthernetSingleFramePolledExample() demonstrates the simplest way to send +* and receive frames in polled mode. +* +* - AxiEthernetMultipleFramesPolledExample() demonstrates how to transmit a +* "burst" of frames by queueing up several in the packet FIFO prior to +* transmission. +* +* - AxiEthernetPollForTxStatus() demonstrates how to poll for transmit complete +* status and how to handle error conditions. +* +* - AxiEthernetPollForRxStatus() demonstrates how to poll for receive status and +* how to handle error conditions. +* +* - AxiEthernetResetDevice() demonstrates how to reset the driver/HW without +* losing all configuration settings. +* +* Note that the advanced frame processing algorithms shown here are not limited +* to polled mode operation. The same techniques can be used for FIFO direct +* interrupt driven mode as well. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a asa  4/30/10 First release based on the ll temac driver
+*
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xaxiethernet_example.h" +#include "xllfifo.h" +#include "xil_cache.h" + +#ifdef XPAR_XUARTNS550_NUM_INSTANCES +#include "xuartns550_l.h" +#endif + +/************************** Constant Definitions ****************************/ + +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#ifndef TESTAPP_GEN +#define AXIETHERNET_DEVICE_ID XPAR_AXIETHERNET_0_DEVICE_ID +#define FIFO_DEVICE_ID XPAR_AXI_FIFO_0_DEVICE_ID +#endif + +/************************** Variable Definitions ****************************/ + +EthernetFrame TxFrame; /* Transmit frame buffer */ +EthernetFrame RxFrame; /* Receive frame buffer */ + +XAxiEthernet AxiEthernetInstance; +XLlFifo FifoInstance; + +/************************** Function Prototypes *****************************/ + +int AxiEthernetPolledExample(u16 AxiEthernetDeviceId, u16 FifoDeviceId); +int AxiEthernetSingleFramePolledExample(); +int AxiEthernetMultipleFramesPolledExample(); + +int AxiEthernetPollForTxStatus(); +int AxiEthernetPollForRxStatus(); +int AxiEthernetResetDevice(); + +/*****************************************************************************/ +/** +* +* This is the main function for the AxiEthernet example. This function is not +* included if the example is generated from the TestAppGen test tool. +* +* @param None. +* +* @return -XST_SUCCESS to indicate success +* -XST_FAILURE to indicate failure +* +* +* @note None. +* +****************************************************************************/ +#ifndef TESTAPP_GEN +int main(void) +{ + int Status; +#ifdef XPAR_XUARTNS550_NUM_INSTANCES + XUartNs550_SetBaud(STDIN_BASEADDRESS, XPAR_XUARTNS550_CLOCK_HZ, 9600); + XUartNs550_SetLineControlReg(STDIN_BASEADDRESS, XUN_LCR_8_DATA_BITS); +#endif +#if XPAR_MICROBLAZE_USE_ICACHE + Xil_ICacheInvalidate(); + Xil_ICacheEnable(); +#endif + +#if XPAR_MICROBLAZE_USE_DCACHE + Xil_DCacheInvalidate(); + Xil_DCacheEnable(); +#endif + + AxiEthernetUtilErrorTrap("\r\n--- Enter main() ---"); + AxiEthernetUtilErrorTrap("This test may take several minutes to finish"); + + /* + * Call the AxiEthernet polled example , specify the Device ID + * generated in xparameters.h + */ + Status = AxiEthernetPolledExample(AXIETHERNET_DEVICE_ID, FIFO_DEVICE_ID); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Failed test poll mode fifo"); + return XST_FAILURE; + } + + AxiEthernetUtilErrorTrap("Test passed"); + AxiEthernetUtilErrorTrap("--- Exiting main() ---"); + return XST_SUCCESS; + +} +#endif + +/*****************************************************************************/ +/** +* +* This function demonstrates the usage of the Axi Ethernet by sending and +* receiving frames in polled mode. +* +* +* @param AxiEthernetDeviceId is device ID of the AxiEthernet Device , +* typically XPAR__DEVICE_ID value from +* xparameters.h +* @param FifoDeviceId is device ID of the Fifo device taken from +* xparameters.h +* +* @return -XST_SUCCESS to indicate success +* -XST_FAILURE to indicate failure +* +* @note AxiFifo hardware must be initialized before initializing +* AxiEthernet. Since AxiFifo reset line is connected to the +* AxiEthernet reset line, a reset of AxiFifo hardware during its +* initialization would reset AxiEthernet. +* +******************************************************************************/ +int AxiEthernetPolledExample(u16 AxiEthernetDeviceId, u16 FifoDeviceId) +{ + int Status; + XAxiEthernet_Config *MacCfgPtr; + int LoopbackSpeed; + + /*************************************/ + /* Setup device for first-time usage */ + /*************************************/ + + /* + * Get the configuration of AxiEthernet hardware. + */ + MacCfgPtr = XAxiEthernet_LookupConfig(AxiEthernetDeviceId); + + /* + * Check whether AXIFIFO is present or not + */ + if(MacCfgPtr->AxiDevType != XPAR_AXI_FIFO) { + AxiEthernetUtilErrorTrap + ("Device HW not configured for FIFO mode\r\n"); + return XST_FAILURE; + } + + /* + * Initialize AXIFIFO hardware. AXIFIFO must be initialized before + * AxiEthernet. During AXIFIFO initialization, AXIFIFO hardware is + * reset, and since AXIFIFO reset line is connected to AxiEthernet, + * this would ensure a reset of AxiEthernet. + */ + XLlFifo_Initialize(&FifoInstance, MacCfgPtr->AxiDevBaseAddress); + + /* + * Initialize AxiEthernet hardware. + */ + Status = XAxiEthernet_CfgInitialize(&AxiEthernetInstance, MacCfgPtr, + MacCfgPtr->BaseAddress); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error in initialize"); + return XST_FAILURE; + } + + /* + * Set the MAC address + */ + Status = XAxiEthernet_SetMacAddress(&AxiEthernetInstance, + (u8 *) AxiEthernetMAC); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting MAC address"); + return XST_FAILURE; + } + + + /* + * Set PHY to loopback, speed depends on phy type. + * MII is 100 and all others are 1000. + */ + if (XAxiEthernet_GetPhysicalInterface(&AxiEthernetInstance) == + XAE_PHY_TYPE_MII) { + LoopbackSpeed = AXIETHERNET_LOOPBACK_SPEED; + } else { + LoopbackSpeed = AXIETHERNET_LOOPBACK_SPEED_1G; + } + Status = AxiEthernetUtilEnterLoopback(&AxiEthernetInstance, + LoopbackSpeed); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error setting the PHY loopback"); + return XST_FAILURE; + } + + /* + * Set PHY<-->MAC data clock + */ + Status = XAxiEthernet_SetOperatingSpeed(&AxiEthernetInstance, + (u16)LoopbackSpeed); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Setting the operating speed of the MAC needs a delay. There + * doesn't seem to be register to poll, so please consider this + * during your application design. + */ + AxiEthernetUtilPhyDelay(2); + + /****************************/ + /* Run through the examples */ + /****************************/ + + /* + * Run the Single Frame polled example + */ + Status = AxiEthernetSingleFramePolledExample(); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Run the Multiple Frames polled example + */ + Status = AxiEthernetMultipleFramesPolledExample(); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; + + +} + + +/*****************************************************************************/ +/** +* +* This function demonstrates the usage of the Axi Ethernet by sending and +* receiving a single frame in polled mode. +* +* @param None. +* +* @return -XST_SUCCESS to indicate success +* -XST_FAILURE to indicate failure +* +* @note None. +* +******************************************************************************/ +int AxiEthernetSingleFramePolledExample(void) +{ + u32 FifoFreeBytes; + int PayloadSize = 100; + u32 TxFrameLength; + u32 RxFrameLength; + + /* + * Start the Axi Ethernet device + */ + XAxiEthernet_Start(&AxiEthernetInstance); + + /* + * Setup the packet to be transmitted + */ + AxiEthernetUtilFrameHdrFormatMAC(&TxFrame, AxiEthernetMAC); + AxiEthernetUtilFrameHdrFormatType(&TxFrame, PayloadSize); + AxiEthernetUtilFrameSetPayloadData(&TxFrame, PayloadSize); + + /* + * Clear out the receive packet memory area + */ + AxiEthernetUtilFrameMemClear(&RxFrame); + + /* + * Calculate frame length (not including FCS) + */ + TxFrameLength = XAE_HDR_SIZE + PayloadSize; + + /*******************/ + /* Send the packet */ + /*******************/ + + /* + * Wait for enough room in FIFO to become available + */ + do { + FifoFreeBytes = XLlFifo_TxVacancy(&FifoInstance); + } while (FifoFreeBytes < TxFrameLength); + + /* + * Write the frame data to FIFO + */ + XLlFifo_Write(&FifoInstance, TxFrame, TxFrameLength); + + /* + * Initiate transmit + */ + XLlFifo_TxSetLen(&FifoInstance, TxFrameLength); + + /* + * Wait for status of the transmitted packet + */ + switch (AxiEthernetPollForTxStatus()) { + case XST_SUCCESS:/* Got a sucessfull transmit status */ + break; + + case XST_NO_DATA: /* Timed out */ + AxiEthernetUtilErrorTrap("Tx timeout"); + return XST_FAILURE; + + default: /* Some other error */ + return XST_FAILURE; + } + + /**********************/ + /* Receive the packet */ + /**********************/ + + /* + * Wait for packet Rx + */ + switch (AxiEthernetPollForRxStatus()) { + case XST_SUCCESS:/* Got a sucessfull receive status */ + break; + + case XST_NO_DATA: /* Timed out */ + AxiEthernetUtilErrorTrap("Rx timeout"); + return XST_FAILURE; + + default: /* Some other error */ + return XST_FAILURE; + } + + while(XLlFifo_RxOccupancy(&FifoInstance)) { + /* + * A packet as arrived, get its length + */ + RxFrameLength = XLlFifo_RxGetLen(&FifoInstance); + + /* + * Read the received packet data + */ + XLlFifo_Read(&FifoInstance, &RxFrame, RxFrameLength); + + /* + * Verify the received frame length + */ + if ((RxFrameLength) != TxFrameLength) { + AxiEthernetUtilErrorTrap("Receive length incorrect"); + return XST_FAILURE; + } + + /* + * Validate frame data + */ + if (AxiEthernetUtilFrameVerify(&TxFrame, &RxFrame) != 0) { + AxiEthernetUtilErrorTrap("Receive Data mismatch"); + return XST_FAILURE; + } + } + + /* + * Stop device + */ + XAxiEthernet_Stop(&AxiEthernetInstance); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This example uses polled mode to queue up multiple frames in the packet +* FIFOs before sending them in a single burst. Receive packets are handled in +* a similar way. +* +* @param None. +* +* @return -XST_SUCCESS to indicate success +* -XST_FAILURE to indicate failure +* +* @note None. +* +******************************************************************************/ +int AxiEthernetMultipleFramesPolledExample(void) +{ + u32 FramesToLoopback; + u32 PayloadSize; + u32 TxFrameLength; + u32 RxFrameLength; + u32 FifoFreeBytes; + u32 Index; + + /* + * Start the Axi Ethernet device + */ + XAxiEthernet_Start(&AxiEthernetInstance); + + /* + * Setup the number of frames to loopback (FramesToLoopback) and the + * size of the frame (PayloadSize) to loopback. The default settings + * should work for every case. Modifying the settings can cause + * problems, see discussion below: + * + * If PayloadSize is set small and FramesToLoopback high, then it is + * possible to cause the transmit status FIFO to overflow. + * + * If PayloadSize is set large and FramesToLoopback high, then it is + * possible to cause the transmit packet FIFO to overflow. + * + * Either of these scenarios may be worth trying out to observe how + * the driver reacts. The exact values to cause these types of errors + * will vary due to the sizes of the FIFOs selected at hardware build + * time. But the following settings should create problems for all + * FIFO sizes: + * + * Transmit status FIFO overflow + * PayloadSize = 1 + * FramesToLoopback = 1000 + * + * Transmit packet FIFO overflow + * PayloadSize = 1500 + * FramesToLoopback = 16 + * + * These values should always work without error + * PayloadSize = 100 + * FramesToLoopback = 5 + */ + PayloadSize = 100; + FramesToLoopback = 5; + + /* + * Calculate Tx frame length (not including FCS) + */ + TxFrameLength = XAE_HDR_SIZE + PayloadSize; + + /* + * Setup the packet to be transmitted + */ + AxiEthernetUtilFrameHdrFormatMAC(&TxFrame, AxiEthernetMAC); + AxiEthernetUtilFrameHdrFormatType(&TxFrame, PayloadSize); + AxiEthernetUtilFrameSetPayloadData(&TxFrame, PayloadSize); + + /****************/ + /* Send packets */ + /****************/ + + /* + * Since we may be interested to see what happens when FIFOs overflow, + * don't check for room in the transmit packet FIFO prior to writing + * to it. + */ + + /* + * Write frame data to FIFO + * Fifo core only allows loading and sending one frame at a time. + */ + for (Index = 0; Index < FramesToLoopback; Index++) { + /* Make sure there is room in the FIFO */ + do { + FifoFreeBytes = XLlFifo_TxVacancy(&FifoInstance); + } while (FifoFreeBytes < TxFrameLength); + + XLlFifo_Write(&FifoInstance, TxFrame, TxFrameLength); + XLlFifo_TxSetLen(&FifoInstance, TxFrameLength); + + switch (AxiEthernetPollForTxStatus()) { + case XST_SUCCESS: /* Got a sucessfull transmit status */ + break; + + case XST_NO_DATA: /* Timed out */ + AxiEthernetUtilErrorTrap("Tx timeout"); + return XST_FAILURE; + break; + + default: /* Some other error */ + AxiEthernetResetDevice(); + return XST_FAILURE; + } + } + + /**********************/ + /* Receive the packet */ + /**********************/ + + /* + * Wait for the packets to arrive + * The Fifo core only allows us to pull out one frame at a time. + */ + for (Index = 0; Index < FramesToLoopback; ) { + /* + * Wait for packet Rx + */ + switch (AxiEthernetPollForRxStatus()) { + case XST_SUCCESS: /* Got a successfull receive status */ + break; + + case XST_NO_DATA: /* Timed out */ + AxiEthernetUtilErrorTrap("Rx timeout"); + return XST_FAILURE; + break; + + default: /* Some other error */ + AxiEthernetResetDevice(); + return XST_FAILURE; + } + + while(XLlFifo_RxOccupancy(&FifoInstance)) { + /* + * A packet has arrived, get its length + */ + RxFrameLength = XLlFifo_RxGetLen(&FifoInstance); + + /* + * Verify the received frame length + */ + if ((RxFrameLength) != TxFrameLength) { + AxiEthernetUtilErrorTrap("Receive length incorrect"); + return XST_FAILURE; + } + /* + * Read the received packet data + */ + XLlFifo_Read(&FifoInstance, &RxFrame, RxFrameLength); + + if (AxiEthernetUtilFrameVerify + (&TxFrame, &RxFrame) != 0) { + AxiEthernetUtilErrorTrap("Receive Data Mismatch"); + return XST_FAILURE; + } + + Index++; + } + } + + /* + * Stop device + */ + XAxiEthernet_Stop(&AxiEthernetInstance); + + return XST_SUCCESS; +} + + +/******************************************************************************/ +/** +* This functions polls the Tx status and waits for an indication that a frame +* has been transmitted successfully or a transmit related error has occurred. +* If an error is reported, it handles all the possible error conditions. +* +* @param None. +* +* @return - XST_SUCCESS, Tx has completed +* - XST_NO_DATA, Timeout. Tx failure. +* - XST_FIFO_ERROR, Error in the FIFO. +* +* @note None. +* +******************************************************************************/ +int AxiEthernetPollForTxStatus(void) +{ + int Status = XST_NO_DATA; + int Attempts = 100000; /* + * Number of attempts to get status before + * giving up + */ + + /* + * Wait for transmit complete indication + */ + do { + + if (--Attempts <= 0) + break; /* Give up? */ + + if (XLlFifo_Status(&FifoInstance) & XLLF_INT_TC_MASK) { + XLlFifo_IntClear(&FifoInstance, XLLF_INT_TC_MASK); + Status = XST_SUCCESS; + } + if (XLlFifo_Status(&FifoInstance) & XLLF_INT_ERROR_MASK) { + Status = XST_FIFO_ERROR; + } + + } while (Status == XST_NO_DATA); + + + switch (Status) { + case XST_SUCCESS: /* Frame sent without error */ + case XST_NO_DATA: /* Timeout */ + break; + + case XST_FIFO_ERROR: + AxiEthernetUtilErrorTrap("FIFO error"); + AxiEthernetResetDevice(); + break; + + default: + AxiEthernetUtilErrorTrap("Driver returned unknown transmit status"); + break; + } + + return (Status); +} + + +/******************************************************************************/ +/** +* This functions polls the Rx status and waits for an indication that a frame +* has arrived or a receive related error has occurred. If an error is reported, +* handle all the possible error conditions. +* +* @param None. +* +* @return - XST_SUCCESS, a frame has been received +* - XST_NO_DATA, Timeout. Rx failure. +* - XST_FIFO_ERROR, Error in the FIFO. +* - XST_DATA_LOST, a frame has been dropped +* +* @note None. +* +******************************************************************************/ +int AxiEthernetPollForRxStatus(void) +{ + int Status = XST_NO_DATA; + int Attempts = 1000000; /* Number of times to get a status before + * giving up + */ + + /* + * There are two ways to poll for a received frame: + * + * XAxiEthernet_Recv() can be used and repeatedly called until it + * returns a length, but this method does not provide any error + * detection. + * + * XAxiEthernet_FifoQueryRecvStatus() can be used and this function + * provides more information to handle error conditions. + */ + + /* + * Wait for something to happen + */ + do { + if (--Attempts <= 0) + break; /* Give up? */ + + if (XLlFifo_Status(&FifoInstance) & XLLF_INT_RC_MASK) { + Status = XST_SUCCESS; + } + if (XLlFifo_Status(&FifoInstance) & XLLF_INT_ERROR_MASK) { + Status = XST_FIFO_ERROR; + } + if (XAxiEthernet_GetIntStatus(&AxiEthernetInstance) & + XAE_INT_RXRJECT_MASK) { + Status = XST_DATA_LOST; + } + /* When the RXFIFOOVR bit is set, the RXRJECT bit also + * gets set + */ + if (XAxiEthernet_GetIntStatus(&AxiEthernetInstance) & + XAE_INT_RXFIFOOVR_MASK) { + Status = XST_DATA_LOST; + } + } while (Status == XST_NO_DATA); + + switch (Status) { + case XST_SUCCESS: /* Frame has arrived */ + case XST_NO_DATA: /* Timeout */ + break; + + case XST_DATA_LOST: + AxiEthernetUtilErrorTrap("Frame was dropped"); + break; + + case XST_FIFO_ERROR: + AxiEthernetUtilErrorTrap("FIFO error"); + AxiEthernetResetDevice(); + break; + + default: + AxiEthernetUtilErrorTrap("Driver returned invalid transmit status"); + break; + } + + return (Status); +} + + +/******************************************************************************/ +/** +* This function resets the device but preserves the options set by the user. +* +* @param None. +* +* @return -XST_SUCCESS if reset is successful +* -XST_FAILURE. if reset is not successful +* +* @note None. +* +******************************************************************************/ +int AxiEthernetResetDevice(void) +{ + int Status; + u8 MacSave[6]; + u32 Options; + + /* + * Stop device + */ + XAxiEthernet_Stop(&AxiEthernetInstance); + + /* + * Save the device state + */ + XAxiEthernet_GetMacAddress(&AxiEthernetInstance, MacSave); + Options = XAxiEthernet_GetOptions(&AxiEthernetInstance); + + /* + * Stop and reset both the fifo and the AxiEthernet the devices + */ + XLlFifo_Reset(&FifoInstance); + XAxiEthernet_Reset(&AxiEthernetInstance); + + /* + * Restore the state + */ + Status = XAxiEthernet_SetMacAddress(&AxiEthernetInstance, MacSave); + Status |= XAxiEthernet_SetOptions(&AxiEthernetInstance, Options); + Status |= XAxiEthernet_ClearOptions(&AxiEthernetInstance, ~Options); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Error restoring state after reset"); + return XST_FAILURE; + } + + return XST_SUCCESS; +} diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example_readme.txt b/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example_readme.txt new file mode 100755 index 00000000..d17384ce --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example_readme.txt @@ -0,0 +1,54 @@ +xaxiethernet_example_readme.txt +------------------------------- + +The examples in this directory are provided to give the user some idea of +how the Axi Ethernet and its driver are intended to be used. + +SYSTEM REQUIREMENTS + +The system containing the Axi Ethernet should have the following capabilities: + + - An interrupt controller + - An external memory controller with at least 200KB of RAM available + - A UART to display messages + - The reset line of the device connected to the AxiEthernet AXI4-Stream + interface (AXIDMA or AXIFIFO) must be connected to the reset line of AxiEthernet. + (By default for BSB generated systems this is the case.) + +FILES + +1. xaxiethernet_example.h - Top level include for all examples. + +2. xaxiethernet_example_util.c - Provide various utilities for debugging, and + ethernet frame construction. + +3. xaxiethernet_example_polled.c - Examples using the L1 API found in xaxiethernet.h + in polled mode. HW must be setup for FIFO direct mode. + +4. xaxiethernet_example_intr_fifo.c - Examples using the L1 API found in + xaxiethernet.h in interrupt driven FIFO direct mode. HW must be setup for + FIFO direct mode. + +5. xaxiethernet_example_intr_sgdma.c - Examples using the L1 API found in + xaxiethernet.h in interrupt driven scatter-gather DMA mode. HW must be setup + for SGDMA mode. HW must be setup for checksum offloading for that + specific example to properly execute. + + +INCLUDING EXAMPLES IN EDK + +Each example is independent from the others except for common code found in +xaxiethernet_example_util.c. When including source code files in an EDK SW +application, select xaxiethernet_example_util.c along with one other example +source code file. + + +IMPORTANT NOTES + +* Included HW features are critical as to which examples will run properly. +* The device connected to the AXI4-Stream interface (AXIFIFO or AXIDMA) + of the AxiEthernet must be initialized before AxiEthernet initialization. + Since the reset line of AXIFIFO or AXIDMA is connected to the reset line + of AxiEthernet, AXIDMA/AXIFIFO initialization would reset AxiEthernet. + AxiEthernet hardware initialization routines in the AxiEthernet driver do + not reset the AxiEthernet hardware. diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example_util.c b/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example_util.c new file mode 100644 index 00000000..bb705e5c --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example_util.c @@ -0,0 +1,789 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2014 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/** +* +* @file xaxiethernet_example_util.c +* +* This file implements the utility functions for the Axi Ethernet example code. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a asa  6/30/10 First release based on the ll temac driver
+* 3.01a srt  02/03/13 Added support for SGMII mode (CR 676793).
+*	     02/14/13 Added support for Zynq (CR 681136).
+* 3.02a srt  04/24/13 Modified parameter *_SGMII_PHYADDR to *_PHYADDR, the
+*                     config parameter C_PHYADDR applies to SGMII/1000BaseX
+*	              modes of operation and added support for 1000BaseX mode
+*		      (CR 704195). Added function *_ConfigureInternalPhy()
+*		      for this purpose.
+*	     04/24/13 Added support for RGMII mode.
+* 3.02a srt  08/06/13 Fixed CR 717949:
+*			Configures external Marvel 88E1111 PHY based on the
+*			axi ethernet physical interface type and allows to
+*			operate in specific interface mode without changing
+*			jumpers on the Microblaze board.
+*
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xaxiethernet_example.h" +#if !defined (__MICROBLAZE__) && !defined(__PPC__) +#include "sleep.h" +#endif + +/************************** Variable Definitions ****************************/ + +/* + * Local MAC address + */ +char AxiEthernetMAC[6] = { 0x00, 0x0A, 0x35, 0x01, 0x02, 0x03 }; + +/******************************************************************************/ +/** +* +* Set the MAC addresses in the frame. +* +* @param FramePtr is the pointer to the frame. +* @param DestAddr is the Destination MAC address. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void AxiEthernetUtilFrameHdrFormatMAC(EthernetFrame *FramePtr, char *DestAddr) +{ + char *Frame = (char *) FramePtr; + char *SourceAddress = AxiEthernetMAC; + int Index; + + /* + * Destination address + */ + for (Index = 0; Index < XAE_MAC_ADDR_SIZE; Index++) { + *Frame++ = *DestAddr++; + } + + /* + * Source address + */ + for (Index = 0; Index < XAE_MAC_ADDR_SIZE; Index++) { + *Frame++ = *SourceAddress++; + } +} + +/******************************************************************************/ +/** +* +* Set the frame type for the specified frame. +* +* @param FramePtr is the pointer to the frame. +* @param FrameType is the Type to set in frame. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void AxiEthernetUtilFrameHdrFormatType(EthernetFrame *FramePtr, u16 FrameType) +{ + char *Frame = (char *) FramePtr; + + /* + * Increment to type field + */ + Frame = Frame + 12; + + FrameType = Xil_Htons(FrameType); + /* + * Set the type + */ + *(u16 *) Frame = FrameType; +} + +/******************************************************************************/ +/** +* This function places a pattern in the payload section of a frame. The pattern +* is a 8 bit incrementing series of numbers starting with 0. +* Once the pattern reaches 256, then the pattern changes to a 16 bit +* incrementing pattern: +*
+*   0, 1, 2, ... 254, 255, 00, 00, 00, 01, 00, 02, ...
+* 
+* +* @param FramePtr is a pointer to the frame to change. +* @param PayloadSize is the number of bytes in the payload that will be +* set. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void AxiEthernetUtilFrameSetPayloadData(EthernetFrame *FramePtr, + int PayloadSize) +{ + unsigned BytesLeft = PayloadSize; + u8 *Frame; + u16 Counter = 0; + + /* + * Set the frame pointer to the start of the payload area + */ + Frame = (u8 *) FramePtr + XAE_HDR_SIZE; + + /* + * Insert 8 bit incrementing pattern + */ + while (BytesLeft && (Counter < 256)) { + *Frame++ = (u8) Counter++; + BytesLeft--; + } + + /* + * Switch to 16 bit incrementing pattern + */ + while (BytesLeft) { + *Frame++ = (u8) (Counter >> 8); /* high */ + BytesLeft--; + + if (!BytesLeft) + break; + + *Frame++ = (u8) Counter++; /* low */ + BytesLeft--; + } +} + +/******************************************************************************/ +/** +* +* Set the frame VLAN info for the specified frame. +* +* @param FramePtr is the pointer to the frame. +* @param VlanNumber is the VlanValue insertion position to set in frame. +* @param Vid is the 4 bytes Vlan value (TPID, Priority, CFI, VID) +* to be set in frame. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void AxiEthernetUtilFrameHdrVlanFormatVid(EthernetFrame *FramePtr, + u32 VlanNumber, u32 Vid) +{ + char *Frame = (char *) FramePtr; + + /* + * Increment to type field + */ + Frame = Frame + 12 + (VlanNumber * 4); + + Vid = Xil_Htonl(Vid); + + /* + * Set the type + */ + *(u32 *) Frame = Vid; +} + +/******************************************************************************/ +/** +* +* Set the frame type for the specified frame. +* +* @param FramePtr is the pointer to the frame. +* @param FrameType is the Type to set in frame. +* @param VlanNumber is the VLAN friendly adjusted insertion position to +* set in frame. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void AxiEthernetUtilFrameHdrVlanFormatType(EthernetFrame *FramePtr, + u16 FrameType, u32 VlanNumber) +{ + char *Frame = (char *) FramePtr; + + /* + * Increment to type field + */ + Frame = Frame + 12 + (VlanNumber * 4); + + FrameType = Xil_Htons(FrameType); + + /* + * Set the type + */ + *(u16 *) Frame = FrameType; +} + +/******************************************************************************/ +/** +* This function places a pattern in the payload section of a frame. The pattern +* is a 8 bit incrementing series of numbers starting with 0. +* Once the pattern reaches 256, then the pattern changes to a 16 bit +* incrementing pattern: +*
+*   0, 1, 2, ... 254, 255, 00, 00, 00, 01, 00, 02, ...
+* 
+* +* @param FramePtr is a pointer to the frame to change. +* @param PayloadSize is the number of bytes in the payload that will be set. +* @param VlanNumber is the VLAN friendly adjusted insertion position to +* set in frame. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void AxiEthernetUtilFrameSetVlanPayloadData(EthernetFrame *FramePtr, + int PayloadSize, u32 VlanNumber) +{ + unsigned BytesLeft = PayloadSize; + u8 *Frame; + u16 Counter = 0; + + /* + * Set the frame pointer to the start of the payload area + */ + Frame = (u8 *) FramePtr + XAE_HDR_SIZE + (VlanNumber * 4); + + /* + * Insert 8 bit incrementing pattern + */ + while (BytesLeft && (Counter < 256)) { + *Frame++ = (u8) Counter++; + BytesLeft--; + } + + /* + * Switch to 16 bit incrementing pattern + */ + while (BytesLeft) { + *Frame++ = (u8) (Counter >> 8); /* high */ + BytesLeft--; + + if (!BytesLeft) + break; + + *Frame++ = (u8) Counter++; /* low */ + BytesLeft--; + } +} + +/******************************************************************************/ +/** +* This function verifies the frame data against a CheckFrame. +* +* Validation occurs by comparing the ActualFrame to the header of the +* CheckFrame. If the headers match, then the payload of ActualFrame is +* verified for the same pattern Util_FrameSetPayloadData() generates. +* +* @param CheckFrame is a pointer to a frame containing the 14 byte header +* that should be present in the ActualFrame parameter. +* @param ActualFrame is a pointer to a frame to validate. +* +* @return - XST_SUCCESS if successful. +* - XST_FAILURE in case of failure. +* +* @note None. +* +******************************************************************************/ +int AxiEthernetUtilFrameVerify(EthernetFrame * CheckFrame, + EthernetFrame * ActualFrame) +{ + unsigned char *CheckPtr = (unsigned char *) CheckFrame; + unsigned char *ActualPtr = (unsigned char *) ActualFrame; + u16 BytesLeft; + u16 Counter; + int Index; + + + /* + * Compare the headers + */ + for (Index = 0; Index < XAE_HDR_SIZE; Index++) { + if (CheckPtr[Index] != ActualPtr[Index]) { + return XST_FAILURE; + } + } + + Index = 0; + + BytesLeft = *(u16 *) &ActualPtr[12]; + BytesLeft = Xil_Ntohs(BytesLeft); + /* + * Get the length of the payload, do not use VLAN TPID here. + * TPID needs to be verified. + */ + while ((0x8100 == BytesLeft) || (0x88A8 == BytesLeft) || + (0x9100 == BytesLeft) || (0x9200 == BytesLeft)) { + Index++; + BytesLeft = *(u16 *) &ActualPtr[12+(4*Index)]; + BytesLeft = Xil_Ntohs(BytesLeft); + } + + /* + * Validate the payload + */ + Counter = 0; + ActualPtr = &ActualPtr[14+(4*Index)]; + + /* + * Check 8 bit incrementing pattern + */ + while (BytesLeft && (Counter < 256)) { + if (*ActualPtr++ != (u8) Counter++) { + + return XST_FAILURE; + } + BytesLeft--; + } + + /* + * Check 16 bit incrementing pattern + */ + while (BytesLeft) { + if (*ActualPtr++ != (u8) (Counter >> 8)) { /* high */ + return XST_FAILURE; + } + + BytesLeft--; + + if (!BytesLeft) + break; + + if (*ActualPtr++ != (u8) Counter++) { /* low */ + return XST_FAILURE; + } + + BytesLeft--; + } + + return XST_SUCCESS; +} + +/******************************************************************************/ +/** +* This function sets all bytes of a frame to 0. +* +* @param FramePtr is a pointer to the frame itself. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void AxiEthernetUtilFrameMemClear(EthernetFrame * FramePtr) +{ + u32 *Data32Ptr = (u32 *) FramePtr; + u32 WordsLeft = sizeof(EthernetFrame) / sizeof(u32); + + /* + * Frame should be an integral number of words + */ + while (WordsLeft--) { + *Data32Ptr++ = 0; + } +} + +/******************************************************************************/ +/** +* +* This function detects the PHY address by looking for successful MII status +* register contents (PHY register 1). It looks for a PHY that supports +* auto-negotiation and 10Mbps full-duplex and half-duplex. So, this code +* won't work for PHYs that don't support those features, but it's a bit more +* general purpose than matching a specific PHY manufacturer ID. +* +* Note also that on some (older) Xilinx ML4xx boards, PHY address 0 does not +* properly respond to this query. But, since the default is 0 and asssuming +* no other address responds, then it seems to work OK. +* +* @param The Axi Ethernet driver instance +* +* @return The address of the PHY (defaults to 0 if none detected) +* +* @note None. +* +******************************************************************************/ +/* Use MII register 1 (MII status register) to detect PHY */ +#define PHY_DETECT_REG 1 + +/* Mask used to verify certain PHY features (or register contents) + * in the register above: + * 0x1000: 10Mbps full duplex support + * 0x0800: 10Mbps half duplex support + * 0x0008: Auto-negotiation support + */ +#define PHY_DETECT_MASK 0x1808 + +u32 AxiEthernetDetectPHY(XAxiEthernet * AxiEthernetInstancePtr) +{ + u16 PhyReg; + int PhyAddr; + + for (PhyAddr = 31; PhyAddr >= 0; PhyAddr--) { + XAxiEthernet_PhyRead(AxiEthernetInstancePtr, PhyAddr, + PHY_DETECT_REG, &PhyReg); + + if ((PhyReg != 0xFFFF) && + ((PhyReg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) { + /* Found a valid PHY address */ + return PhyAddr; + } + } + + return 0; /* Default to zero */ +} + +/******************************************************************************/ +/** +* Set PHY to loopback mode. This works with the marvell PHY common on ML40x +* evaluation boards +* +* @param Speed is the loopback speed 10, 100, or 1000 Mbit +* +******************************************************************************/ +/* IEEE PHY Specific definitions */ +#define PHY_R0_CTRL_REG 0 +#define PHY_R3_PHY_IDENT_REG 3 + +#define PHY_R0_RESET 0x8000 +#define PHY_R0_LOOPBACK 0x4000 +#define PHY_R0_ANEG_ENABLE 0x1000 +#define PHY_R0_DFT_SPD_MASK 0x2040 +#define PHY_R0_DFT_SPD_10 0x0000 +#define PHY_R0_DFT_SPD_100 0x2000 +#define PHY_R0_DFT_SPD_1000 0x0040 +#define PHY_R0_ISOLATE 0x0400 + +/* Marvel PHY 88E1111 Specific definitions */ +#define PHY_R20_EXTND_CTRL_REG 20 +#define PHY_R27_EXTND_STS_REG 27 + +#define PHY_R20_DFT_SPD_10 0x20 +#define PHY_R20_DFT_SPD_100 0x50 +#define PHY_R20_DFT_SPD_1000 0x60 +#define PHY_R20_RX_DLY 0x80 + +#define PHY_R27_MAC_CONFIG_GMII 0x000F +#define PHY_R27_MAC_CONFIG_MII 0x000F +#define PHY_R27_MAC_CONFIG_RGMII 0x000B +#define PHY_R27_MAC_CONFIG_SGMII 0x0004 + +/* Marvel PHY 88E1116R Specific definitions */ +#define PHY_R22_PAGE_ADDR_REG 22 +#define PHY_PG2_R21_CTRL_REG 21 + +#define PHY_REG21_10 0x0030 +#define PHY_REG21_100 0x2030 +#define PHY_REG21_1000 0x0070 + +/* Marvel PHY flags */ +#define MARVEL_PHY_88E1111_MODEL 0xC0 +#define MARVEL_PHY_88E1116R_MODEL 0x240 +#define PHY_MODEL_NUM_MASK 0x3F0 + +/******************************************************************************/ +/** +* +* This function sets the PHY to loopback mode. This works with the marvell PHY +* common on ML40x evaluation boards. +* +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* AxiEthernet component. +* @param Speed is the loopback speed 10, 100, or 1000 Mbit. +* +* @return - XST_SUCCESS if successful. +* - XST_FAILURE, in case of failure.. +* +* @note None. +* +******************************************************************************/ +int AxiEthernetUtilEnterLoopback(XAxiEthernet *AxiEthernetInstancePtr, + int Speed) +{ + u16 PhyReg0; + signed int PhyAddr; + u8 PhyType; + u16 PhyModel; + u16 PhyReg20; /* Extended PHY specific Register (Reg 20) + of Marvell 88E1111 PHY */ + u16 PhyReg21; /* Control Register MAC (Reg 21) + of Marvell 88E1116R PHY */ + + /* Get the Phy Interface */ + PhyType = XAxiEthernet_GetPhysicalInterface(AxiEthernetInstancePtr); + + /* Detect the PHY address */ + if (PhyType != XAE_PHY_TYPE_1000BASE_X) { + PhyAddr = AxiEthernetDetectPHY(AxiEthernetInstancePtr); + } else { + PhyAddr = XPAR_AXIETHERNET_0_PHYADDR; + } + + XAxiEthernet_PhyRead(AxiEthernetInstancePtr, PhyAddr, + PHY_R3_PHY_IDENT_REG, &PhyModel); + PhyModel = PhyModel & PHY_MODEL_NUM_MASK; + + /* Clear the PHY of any existing bits by zeroing this out */ + PhyReg0 = PhyReg20 = PhyReg21 = 0; + + switch (Speed) { + case XAE_SPEED_10_MBPS: + PhyReg0 |= PHY_R0_DFT_SPD_10; + PhyReg20 |= PHY_R20_DFT_SPD_10; + PhyReg21 |= PHY_REG21_10; + break; + + case XAE_SPEED_100_MBPS: + PhyReg0 |= PHY_R0_DFT_SPD_100; + PhyReg20 |= PHY_R20_DFT_SPD_100; + PhyReg21 |= PHY_REG21_100; + break; + + case XAE_SPEED_1000_MBPS: + PhyReg0 |= PHY_R0_DFT_SPD_1000; + PhyReg20 |= PHY_R20_DFT_SPD_1000; + PhyReg21 |= PHY_REG21_1000; + break; + + default: + AxiEthernetUtilErrorTrap("Intg_LinkSpeed not 10, 100, or 1000 mbps"); + return XST_FAILURE; + } + + /* RGMII mode Phy specific registers initialization */ + if ((PhyType == XAE_PHY_TYPE_RGMII_2_0) || + (PhyType == XAE_PHY_TYPE_RGMII_1_3)) { + if (PhyModel == MARVEL_PHY_88E1111_MODEL) { + PhyReg20 |= PHY_R20_RX_DLY; + /* + * Adding Rx delay. Configuring loopback speed. + */ + XAxiEthernet_PhyWrite(AxiEthernetInstancePtr, + PhyAddr, PHY_R20_EXTND_CTRL_REG, + PhyReg20); + } else if (PhyModel == MARVEL_PHY_88E1116R_MODEL) { + /* + * Switching to PAGE2 + */ + XAxiEthernet_PhyWrite(AxiEthernetInstancePtr, + PhyAddr, + PHY_R22_PAGE_ADDR_REG, 2); + /* + * Adding Tx and Rx delay. Configuring loopback speed. + */ + XAxiEthernet_PhyWrite(AxiEthernetInstancePtr, + PhyAddr, + PHY_PG2_R21_CTRL_REG, PhyReg21); + /* + * Switching to PAGE0 + */ + XAxiEthernet_PhyWrite(AxiEthernetInstancePtr, + PhyAddr, + PHY_R22_PAGE_ADDR_REG, 0); + } + PhyReg0 &= (~PHY_R0_ANEG_ENABLE); + } + + /* Configure interface modes */ + if (PhyModel == MARVEL_PHY_88E1111_MODEL) { + if ((PhyType == XAE_PHY_TYPE_RGMII_2_0) || + (PhyType == XAE_PHY_TYPE_RGMII_1_3)) { + XAxiEthernet_PhyWrite(AxiEthernetInstancePtr, + PhyAddr, PHY_R27_EXTND_STS_REG, + PHY_R27_MAC_CONFIG_RGMII); + } else if (PhyType == XAE_PHY_TYPE_SGMII) { + XAxiEthernet_PhyWrite(AxiEthernetInstancePtr, + PhyAddr, PHY_R27_EXTND_STS_REG, + PHY_R27_MAC_CONFIG_SGMII); + } else if ((PhyType == XAE_PHY_TYPE_GMII) || + (PhyType == XAE_PHY_TYPE_MII)) { + XAxiEthernet_PhyWrite(AxiEthernetInstancePtr, + PhyAddr, PHY_R27_EXTND_STS_REG, + PHY_R27_MAC_CONFIG_GMII ); + } + } + + /* Set the speed and put the PHY in reset, then put the PHY in loopback */ + XAxiEthernet_PhyWrite(AxiEthernetInstancePtr, PhyAddr, + PHY_R0_CTRL_REG, + PhyReg0 | PHY_R0_RESET); + AxiEthernetUtilPhyDelay(AXIETHERNET_PHY_DELAY_SEC); + XAxiEthernet_PhyRead(AxiEthernetInstancePtr,PhyAddr, + PHY_R0_CTRL_REG, &PhyReg0); + XAxiEthernet_PhyWrite(AxiEthernetInstancePtr, PhyAddr, + PHY_R0_CTRL_REG, + PhyReg0 | PHY_R0_LOOPBACK); + + if ((PhyType == XAE_PHY_TYPE_SGMII) || + (PhyType == XAE_PHY_TYPE_1000BASE_X)) { + AxiEthernetUtilConfigureInternalPhy(AxiEthernetInstancePtr, Speed); + } + + AxiEthernetUtilPhyDelay(1); + + return XST_SUCCESS; +} + +/******************************************************************************/ +/** +* +* This function is called by example code when an error is detected. It +* can be set as a breakpoint with a debugger or it can be used to print out the +* given message if there is a UART or STDIO device. +* +* @param Message is the text explaining the error +* +* @return None +* +* @note None +* +******************************************************************************/ +void AxiEthernetUtilErrorTrap(char *Message) +{ + static int Count = 0; + + Count++; + +#ifdef STDOUT_BASEADDRESS + xil_printf("%s\r\n", Message); +#endif +} + +/******************************************************************************/ +/** +* +* For Microblaze we use an assembly loop that is roughly the same regardless of +* optimization level, although caches and memory access time can make the delay +* vary. Just keep in mind that after resetting or updating the PHY modes, +* the PHY typically needs time to recover. +* +* @return None +* +* @note None +* +******************************************************************************/ +void AxiEthernetUtilPhyDelay(unsigned int Seconds) +{ +#if defined (__MICROBLAZE__) || defined(__PPC__) + static int WarningFlag = 0; + + /* If MB caches are disabled or do not exist, this delay loop could + * take minutes instead of seconds (e.g., 30x longer). Print a warning + * message for the user (once). If only MB had a built-in timer! + */ + if (((mfmsr() & 0x20) == 0) && (!WarningFlag)) { + WarningFlag = 1; + } + +#define ITERS_PER_SEC (XPAR_CPU_CORE_CLOCK_FREQ_HZ / 6) + asm volatile ("\n" + "1: \n\t" + "addik r7, r0, %0 \n\t" + "2: \n\t" + "addik r7, r7, -1 \n\t" + "bneid r7, 2b \n\t" + "or r0, r0, r0 \n\t" + "bneid %1, 1b \n\t" + "addik %1, %1, -1 \n\t" + :: "i"(ITERS_PER_SEC), "d" (Seconds)); +#else + sleep(Seconds); +#endif +} + +/******************************************************************************/ +/** +* +* This function configures the internal phy for SGMII and 1000baseX modes. +* * +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* AxiEthernet component. +* @param Speed is the loopback speed 10, 100, or 1000 Mbit. +* +* @return - XST_SUCCESS if successful. +* - XST_FAILURE, in case of failure.. +* +* @note None. +* +******************************************************************************/ +int AxiEthernetUtilConfigureInternalPhy(XAxiEthernet *AxiEthernetInstancePtr, + int Speed) +{ + u16 PhyReg0; + signed int PhyAddr; + + PhyAddr = XPAR_AXIETHERNET_0_PHYADDR; + + /* Clear the PHY of any existing bits by zeroing this out */ + PhyReg0 = 0; + XAxiEthernet_PhyRead(AxiEthernetInstancePtr, PhyAddr, + PHY_R0_CTRL_REG, &PhyReg0); + + PhyReg0 &= (~PHY_R0_ANEG_ENABLE); + PhyReg0 &= (~PHY_R0_ISOLATE); + + switch (Speed) { + case XAE_SPEED_10_MBPS: + PhyReg0 |= PHY_R0_DFT_SPD_10; + break; + case XAE_SPEED_100_MBPS: + PhyReg0 |= PHY_R0_DFT_SPD_100; + break; + case XAE_SPEED_1000_MBPS: + PhyReg0 |= PHY_R0_DFT_SPD_1000; + break; + default: + AxiEthernetUtilErrorTrap( + "Intg_LinkSpeed not 10, 100, or 1000 mbps\n\r"); + return XST_FAILURE; + } + + AxiEthernetUtilPhyDelay(1); + XAxiEthernet_PhyWrite(AxiEthernetInstancePtr, PhyAddr, + PHY_R0_CTRL_REG, PhyReg0); + return XST_SUCCESS; +} diff --git a/XilinxProcessorIPLib/drivers/axiethernet/src/Makefile b/XilinxProcessorIPLib/drivers/axiethernet/src/Makefile new file mode 100644 index 00000000..f3fbe7da --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/src/Makefile @@ -0,0 +1,27 @@ +COMPILER= +ARCHIVER= +CP=cp +COMPILER_FLAGS= +EXTRA_COMPILER_FLAGS= +LIB=libxil.a + +RELEASEDIR=../../../lib +INCLUDEDIR=../../../include +INCLUDES=-I./. -I${INCLUDEDIR} + +INCLUDEFILES=xaxiethernet.h xaxiethernet_hw.h xdebug.h +LIBSOURCES=*.c +OUTS = *.o + + +libs: + echo "Compiling axiethernet" + $(COMPILER) $(COMPILER_FLAGS) $(EXTRA_COMPILER_FLAGS) $(INCLUDES) $(LIBSOURCES) + $(ARCHIVER) -r ${RELEASEDIR}/${LIB} ${OUTS} + make clean + +include: + ${CP} ${INCLUDEFILES} ${INCLUDEDIR} + +clean: + rm -rf ${OUTS} diff --git a/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet.c b/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet.c new file mode 100644 index 00000000..263d234d --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet.c @@ -0,0 +1,1771 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2015 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/** +* +* @file xaxiethernet.c +* +* The APIs in this file takes care of the primary functionalities of the driver. +* The APIs in this driver take care of the following: +* - Starting or stopping the Axi Ethernet device +* - Initializing and resetting the Axi Ethernet device +* - Setting MAC address and speed/duplex of the device +* - Provide means for controlling the PHY and communicating with it. +* - Turn on/off various features/options provided by the Axi Ethernet +* device. +* See xaxiethernet.h for a detailed description of the driver. +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a asa  6/30/10 First release based on the ll temac driver
+* 1.02a asa  2/16/11 Made changes in XAxiEthernet_Reset to insert delays.
+* 3.02a srt  4/13/13 Removed Warnings (CR 704998).
+*
+* 
+******************************************************************************/ + +/***************************** Include Files *********************************/ +#include "xaxiethernet.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + +static void InitHw(XAxiEthernet *InstancePtr); /* HW reset */ + +/************************** Variable Definitions *****************************/ + +xdbg_stmnt(int indent_on = 0;) +xdbg_stmnt(u32 _xaxiethernet_rir_value;) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_CfgInitialize initializes an AXI Ethernet device along with the +* InstancePtr that references it. +* +* The PHY is setup independently from the Ethernet core. Use the MII or +* whatever other interface may be present for setup. +* +* @param InstancePtr references the memory instance to be associated +* with the AXI Ethernet core instance upon initialization. +* @param CfgPtr references the structure holding the hardware +* configuration for the Axi Ethernet core to initialize. +* @param EffectiveAddress is the processor address used to access the +* base address of the AXI Ethernet instance. In systems with an +* MMU and virtual memory, EffectiveAddress is the +* virtual address mapped to the physical in +* ConfigPtr->Config.BaseAddress. In systems without +* an active MMU, EffectiveAddress should be set to the +* same value as ConfigPtr->Config.BaseAddress. +* +* @return XST_SUCCESS. +* +* @note None. +* +******************************************************************************/ +int XAxiEthernet_CfgInitialize(XAxiEthernet *InstancePtr, + XAxiEthernet_Config *CfgPtr, + u32 EffectiveAddress) +{ + /* Verify arguments */ + Xil_AssertNonvoid(InstancePtr != NULL); + + /* Clear instance memory and make copy of configuration */ + memset(InstancePtr, 0, sizeof(XAxiEthernet)); + memcpy(&InstancePtr->Config, CfgPtr, sizeof(XAxiEthernet_Config)); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_CfgInitialize\n"); + + /* Set device base address */ + InstancePtr->Config.BaseAddress = EffectiveAddress; + + /* Reset the hardware and set default options */ + InstancePtr->IsReady = XIL_COMPONENT_IS_READY; + + XAxiEthernet_Reset(InstancePtr); + + xdbg_printf(XDBG_DEBUG_GENERAL, + "AxiTEthernet_CfgInitialize: returning SUCCESS\n"); + return XST_SUCCESS; +} + + +/*****************************************************************************/ +/** +* XAxiEthernet_Start starts the Axi Ethernet device as follows: +* - Enable transmitter if XAE_TRANSMIT_ENABLE_OPTION is set +* - Enable receiver if XAE_RECEIVER_ENABLE_OPTION is set +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @return None. +* +* @note None. +* +* +******************************************************************************/ +void XAxiEthernet_Start(XAxiEthernet *InstancePtr) +{ + u32 Reg; + + /* Assert bad arguments and conditions */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + + /* If already started, then there is nothing to do */ + if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) { + return; + } + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_Start\n"); + + /* Enable transmitter if not already enabled */ + if (InstancePtr->Options & XAE_TRANSMITTER_ENABLE_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, "enabling transmitter\n"); + Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_TC_OFFSET); + if (!(Reg & XAE_TC_TX_MASK)) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "transmitter not enabled, enabling now\n"); + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_TC_OFFSET, + Reg | XAE_TC_TX_MASK); + } + xdbg_printf(XDBG_DEBUG_GENERAL, "transmitter enabled\n"); + } + + /* Enable receiver */ + if (InstancePtr->Options & XAE_RECEIVER_ENABLE_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, "enabling receiver\n"); + Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_RCW1_OFFSET); + if (!(Reg & XAE_RCW1_RX_MASK)) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "receiver not enabled, enabling now\n"); + + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_RCW1_OFFSET, + Reg | XAE_RCW1_RX_MASK); + } + xdbg_printf(XDBG_DEBUG_GENERAL, "receiver enabled\n"); + } + + /* Mark as started */ + InstancePtr->IsStarted = XIL_COMPONENT_IS_STARTED; + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_Start: done\n"); +} + +/*****************************************************************************/ +/** +* XAxiEthernet_Stop gracefully stops the Axi Ethernet device as follows: +* - Disable all interrupts from this device +* - Disable the receiver +* +* XAxiEthernet_Stop does not modify any of the current device options. +* +* Since the transmitter is not disabled, frames currently in internal buffers +* or in process by a DMA engine are allowed to be transmitted. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @return None +* +* @note None. +* +* +******************************************************************************/ +void XAxiEthernet_Stop(XAxiEthernet *InstancePtr) +{ + u32 Reg; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + + /* If already stopped, then there is nothing to do */ + if (InstancePtr->IsStarted == 0) { + return; + } + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_Stop\n"); + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_Stop: disabling interrupts\n"); + + /* Disable interrupts */ + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_IE_OFFSET, 0); + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_Stop: disabling receiver\n"); + + /* Disable the receiver */ + Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_RCW1_OFFSET); + Reg &= ~XAE_RCW1_RX_MASK; + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_RCW1_OFFSET, Reg); + + /* + * Stopping the receiver in mid-packet causes a dropped packet + * indication from HW. Clear it. + */ + /* get the interrupt pending register */ + Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_IP_OFFSET); + if (Reg & XAE_INT_RXRJECT_MASK) { + /* set the interrupt status register to clear the interrupt */ + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_IS_OFFSET, XAE_INT_RXRJECT_MASK); + } + + /* Mark as stopped */ + InstancePtr->IsStarted = 0; + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_Stop: done\n"); +} + + +/*****************************************************************************/ +/** +* XAxiEthernet_Reset does not perform a soft reset of the AxiEthernet core. +* AxiEthernet hardware is reset by the device connected to the AXI4-Stream +* interface. +* This function inserts some delay before proceeding to check for MgtRdy bit. +* The delay is necessary to be at a safe side. It takes a while for the reset +* process to complete and for any of the AxiEthernet registers to be accessed. +* It then checks for MgtRdy bit in IS register to know if AxiEthernet reset +* is completed or not. Subsequently it calls one more driver function to +* complete the AxiEthernet hardware initialization. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @note It is the responsibility of the user to reset the AxiEthernet +* hardware before using it. AxiEthernet hardware should be reset +* through the device connected to the AXI4-Stream interface of +* AxiEthernet. +* +******************************************************************************/ +void XAxiEthernet_Reset(XAxiEthernet *InstancePtr) +{ + volatile u32 TimeoutLoops; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* + * Add delay of 10000 loops to give enough time to the core to come + * out of reset. Till the time core comes out of reset none of the + * AxiEthernet registers are accessible including the IS register. + */ + TimeoutLoops = XAE_LOOPS_TO_COME_OUT_OF_RST; + while (TimeoutLoops > 0) { + TimeoutLoops--; + } + + /* + * Check the status of the MgtRdy bit in the interrupt status + * registers. This must be done to allow the MGT clock to become stable + * for the Sgmii and 1000BaseX PHY interfaces. No other register reads + * will be valid until this bit is valid. + * The bit is always a 1 for all other PHY interfaces. + */ + TimeoutLoops = XAE_RST_DELAY_LOOPCNT_VAL; + while (TimeoutLoops && + (! (XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_IS_OFFSET) & XAE_INT_MGTRDY_MASK))) { + TimeoutLoops--; + } + + if(0 == TimeoutLoops) { + Xil_AssertVoidAlways(); + } + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_Reset\n"); + + /* Stop the device and reset HW */ + XAxiEthernet_Stop(InstancePtr); + InstancePtr->Options = XAE_DEFAULT_OPTIONS; + + /* Setup HW */ + InitHw(InstancePtr); +} + + +/****************************************************************************** +* +* InitHw (internal use only) performs a one-time setup of a Axi Ethernet device. +* The setup performed here only need to occur once after any reset. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @note None. +* +* +******************************************************************************/ +static void InitHw(XAxiEthernet *InstancePtr) +{ + u32 Reg; + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet InitHw\n"); + + + /* Disable the receiver */ + Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_RCW1_OFFSET); + Reg &= ~XAE_RCW1_RX_MASK; + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_RCW1_OFFSET, Reg); + + /* + * Stopping the receiver in mid-packet causes a dropped packet + * indication from HW. Clear it. + */ + /* Get the interrupt pending register */ + Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_IP_OFFSET); + if (Reg & XAE_INT_RXRJECT_MASK) { + /* + * Set the interrupt status register to clear the pending + * interrupt + */ + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_IS_OFFSET, XAE_INT_RXRJECT_MASK); + } + + /* + * Sync default options with HW but leave receiver and transmitter + * disabled. They get enabled with XAxiEthernet_Start() if + * XAE_TRANSMITTER_ENABLE_OPTION and XAE_RECEIVER_ENABLE_OPTION + * are set + */ + XAxiEthernet_SetOptions(InstancePtr, InstancePtr->Options & + ~(XAE_TRANSMITTER_ENABLE_OPTION | + XAE_RECEIVER_ENABLE_OPTION)); + + XAxiEthernet_ClearOptions(InstancePtr, ~InstancePtr->Options); + + /* Set default MDIO divisor */ + XAxiEthernet_PhySetMdioDivisor(InstancePtr, XAE_MDIO_DIV_DFT); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet InitHw: done\n"); +} + +/*****************************************************************************/ +/** + * XAxiEthernet_SetMacAddress sets the MAC address for the Axi Ethernet device, + * specified by InstancePtr to the MAC address specified by + * AddressPtr. + * The Axi Ethernet device must be stopped before calling this function. + * + * @param InstancePtr is a pointer to the Axi Ethernet instance to be + * worked on. + * @param AddressPtr is a reference to the 6-byte MAC address to set. + * + * @return + * - XST_SUCCESS on successful completion. + * - XST_DEVICE_IS_STARTED if the Axi Ethernet device has not + * stopped, + * + * @note + * This routine also supports the extended/new VLAN and multicast mode. The + * XAE_RAF_NEWFNCENBL_MASK bit dictates which offset will be configured. + * + ******************************************************************************/ +int XAxiEthernet_SetMacAddress(XAxiEthernet *InstancePtr, void *AddressPtr) +{ + u32 MacAddr; + u8 *Aptr = (u8 *) AddressPtr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(AddressPtr != NULL); + + + /* Be sure device has been stopped */ + if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) { + return (XST_DEVICE_IS_STARTED); + } + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_SetMacAddress: setting mac address to:0x%08x%8x%8x%8x%8x%8x\n", + Aptr[0], Aptr[1], Aptr[2], Aptr[3], Aptr[4], Aptr[5]); + + /* Prepare MAC bits in either UAW0/UAWL */ + MacAddr = Aptr[0]; + MacAddr |= Aptr[1] << 8; + MacAddr |= Aptr[2] << 16; + MacAddr |= Aptr[3] << 24; + /* Check to see if it is in extended/new mode. */ + if (!(XAxiEthernet_IsExtFuncCap(InstancePtr))) { + /* + * Set the MAC bits [31:0] in UAW0. + * Having Aptr be unsigned type prevents the following + * operations from sign extending. + */ + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_UAW0_OFFSET, MacAddr); + + /* There are reserved bits in UAW1 so don't affect them */ + MacAddr = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_UAW1_OFFSET); + MacAddr &= ~XAE_UAW1_UNICASTADDR_MASK; + + /* Set MAC bits [47:32] in UAW1 */ + MacAddr |= Aptr[4]; + MacAddr |= Aptr[5] << 8; + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_UAW1_OFFSET, MacAddr); + + return (XST_SUCCESS); + } else { /* Extended mode */ + /* + * Set the MAC bits [31:0] in UAWL register. + * Having Aptr be unsigned type prevents the following + * operations from sign extending. + */ + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_UAWL_OFFSET, MacAddr); + + /* Set MAC bits [47:32] in UAWU register. */ + MacAddr = 0; + MacAddr |= Aptr[4]; + MacAddr |= Aptr[5] << 8; + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_UAWU_OFFSET, MacAddr); + + return (XST_SUCCESS); + } +} + + +/*****************************************************************************/ +/** + * XAxiEthernet_GetMacAddress gets the MAC address for the Axi Ethernet, + * specified by InstancePtr into the memory buffer specified by + * AddressPtr. + * + * @param InstancePtr is a pointer to the Axi Ethernet instance to be + * worked on. + * @param AddressPtr references the memory buffer to store the retrieved + * MAC address. This memory buffer must be at least 6 bytes in + * length. + * + * @return None. + * + * @note + * + * This routine also supports the extended/new VLAN and multicast mode. The + * XAE_RAF_NEWFNCENBL_MASK bit dictates which offset will be configured. + * + ******************************************************************************/ +void XAxiEthernet_GetMacAddress(XAxiEthernet *InstancePtr, void *AddressPtr) +{ + u32 MacAddr; + u8 *Aptr = (u8 *) AddressPtr; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(AddressPtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + + /* Check to see if it is in extended/new mode. */ + if (!(XAxiEthernet_IsExtFuncCap(InstancePtr))) { + /* Read MAC bits [31:0] in UAW0 */ + MacAddr = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_UAW0_OFFSET); + Aptr[0] = (u8) MacAddr; + Aptr[1] = (u8) (MacAddr >> 8); + Aptr[2] = (u8) (MacAddr >> 16); + Aptr[3] = (u8) (MacAddr >> 24); + + /* Read MAC bits [47:32] in UAW1 */ + MacAddr = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_UAW1_OFFSET); + Aptr[4] = (u8) MacAddr; + Aptr[5] = (u8) (MacAddr >> 8); + } else { /* Extended/new mode */ + /* Read MAC bits [31:0] in UAWL register */ + MacAddr = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_UAWL_OFFSET); + Aptr[0] = (u8) MacAddr; + Aptr[1] = (u8) (MacAddr >> 8); + Aptr[2] = (u8) (MacAddr >> 16); + Aptr[3] = (u8) (MacAddr >> 24); + + /* Read MAC bits [47:32] in UAWU register */ + MacAddr = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_UAWU_OFFSET); + Aptr[4] = (u8) MacAddr; + Aptr[5] = (u8) (MacAddr >> 8); + } +} + + +/*****************************************************************************/ +/** + * XAxiEthernet_UpdateDepOption check and update dependent options for + * new/extended features. This is a helper function that is meant to be called + * by XAxiEthernet_SetOptions() and XAxiEthernet_ClearOptions(). + * + * @param InstancePtr is a pointer to the Axi Ethernet instance to be + * worked on. + * + * @return Dependent options that are required to set/clear per + * hardware requirement. + * + * @note + * + * This helper function collects the dependent OPTION(s) per hardware design. + * When conflicts arises, extended features have precedence over legacy ones. + * Two operations to be considered, + * 1. Adding extended options. If XATE_VLAN_OPTION is enabled and enable one of + * extended VLAN options, XATE_VLAN_OPTION should be off and configure to + * hardware. + * However, axi-ethernet instance Options variable still holds + * XATE_VLAN_OPTION so when all of the extended feature are removed, + * XATE_VLAN_OPTION can be effective and configured to hardware. + * 2. Removing extended options. Remove extended option can not just remove + * the selected extended option and dependent options. All extended + * options need to be verified and remained when one or more extended + * options are enabled. + * + * Dependent options are : + * - XAE_VLAN_OPTION, + * - XAE_JUMBO_OPTION + * - XAE_FCS_INSERT_OPTION, + * - XAE_FCS_STRIP_OPTION + * - XAE_PROMISC_OPTION. + * + ******************************************************************************/ +static u32 XAxiEthernet_UpdateDepOptions(XAxiEthernet *InstancePtr) +{ + /* + * This is a helper function for XAxiEthernet_[Set|Clear]Options(), + * verification has been done before invoke this function. + */ + u32 DepOptions = InstancePtr->Options; + + /* + * The extended/new features require some OPTIONS to be on/off per + * hardware design. We determine these extended/new functions here + * first and also on/off other OPTIONS later. So that dependent + * OPTIONS are in sync and _[Set|Clear]Options() can be performed + * seamlessly. + */ + + /* Enable extended multicast option */ + if (DepOptions & XAE_EXT_MULTICAST_OPTION) { + /* + * When extended multicast module is enabled in HW, + * XAE_PROMISC_OPTION is required to be enabled. + */ + if (XAxiEthernet_IsExtMcast(InstancePtr)) { + DepOptions |= XAE_PROMISC_OPTION; + xdbg_printf(XDBG_DEBUG_GENERAL, + "CheckDepOptions: enabling ext multicast\n"); + } else { + xdbg_printf(XDBG_DEBUG_ERROR, + "EXT MULTICAST is not built in hardware\n"); + } + } + + /* Enable extended transmit VLAN translation option */ + if (DepOptions & XAE_EXT_TXVLAN_TRAN_OPTION) { + /* + * Check if hardware is built with extend TX VLAN translation. + * if not, output an information message. + */ + if (XAxiEthernet_IsTxVlanTran(InstancePtr)) { + DepOptions |= XAE_FCS_INSERT_OPTION; + DepOptions &= ~XAE_VLAN_OPTION; + xdbg_printf(XDBG_DEBUG_GENERAL, + "CheckDepOptions: enabling ext Tx VLAN trans\n"); + } else { + xdbg_printf(XDBG_DEBUG_GENERAL, + "TX VLAN TRANSLATION is not built in hardware\n"); + } + } + + /* Enable extended receive VLAN translation option */ + if (DepOptions & XAE_EXT_RXVLAN_TRAN_OPTION) { + /* + * Check if hardware is built with extend RX VLAN translation. + * if not, output an information message. + */ + if (XAxiEthernet_IsRxVlanTran(InstancePtr)) { + DepOptions |= XAE_FCS_STRIP_OPTION; + DepOptions &= ~XAE_VLAN_OPTION; + xdbg_printf(XDBG_DEBUG_GENERAL, + "CheckDepOptions: enabling ext Rx VLAN trans\n"); + } else { + xdbg_printf(XDBG_DEBUG_GENERAL, + "RX VLAN TRANSLATION is not built in hardware\n"); + } + } + + /* Enable extended transmit VLAN tag option */ + if (DepOptions & XAE_EXT_TXVLAN_TAG_OPTION) { + /* + * Check if hardware is built with extend TX VLAN tagging. + * if not, output an information message. + */ + if (XAxiEthernet_IsTxVlanTag(InstancePtr)) { + DepOptions |= XAE_FCS_INSERT_OPTION; + DepOptions &= ~XAE_VLAN_OPTION; + DepOptions |= XAE_JUMBO_OPTION; + xdbg_printf(XDBG_DEBUG_GENERAL, + "CheckDepOptions: enabling ext Tx VLAN tag\n"); + } else { + xdbg_printf(XDBG_DEBUG_ERROR, + "TX VLAN TAG is not built in hardware\n"); + } + } + + /* Enable extended receive VLAN tag option */ + if (DepOptions & XAE_EXT_RXVLAN_TAG_OPTION) { + /* + * Check if hardware is built with extend RX VLAN tagging. + * if not, output an information message. + */ + if (XAxiEthernet_IsRxVlanTag(InstancePtr)) { + DepOptions |= XAE_FCS_STRIP_OPTION; + DepOptions &= ~XAE_VLAN_OPTION; + DepOptions |= XAE_JUMBO_OPTION; + xdbg_printf(XDBG_DEBUG_GENERAL, + "CheckDepOptions: enabling ext Rx VLAN tag\n"); + } else { + xdbg_printf(XDBG_DEBUG_GENERAL, + "RX VLAN TAG is not built in hardware\n"); + } + } + + /* Enable extended transmit VLAN strip option */ + if (DepOptions & XAE_EXT_TXVLAN_STRP_OPTION) { + /* + * Check if hardware is built with extend TX VLAN stripping. + * if not, output an information message. + */ + if (XAxiEthernet_IsTxVlanStrp(InstancePtr)) { + DepOptions |= XAE_FCS_INSERT_OPTION; + DepOptions &= ~XAE_VLAN_OPTION; + DepOptions |= XAE_JUMBO_OPTION; + xdbg_printf(XDBG_DEBUG_GENERAL, + "CheckDepOptions: enabling ext Tx VLAN strip\n"); + } else { + xdbg_printf(XDBG_DEBUG_ERROR, + "TX VLAN STRIP is not built in hardware\n"); + } + } + + /* Enable extended receive VLAN strip option */ + if (DepOptions & XAE_EXT_RXVLAN_STRP_OPTION) { + /* + * Check if hardware is built with extend RX VLAN stripping. + * if not, output an information message. + */ + if (XAxiEthernet_IsRxVlanStrp(InstancePtr)) { + DepOptions |= XAE_FCS_STRIP_OPTION; + DepOptions &= ~XAE_VLAN_OPTION; + DepOptions |= XAE_JUMBO_OPTION; + xdbg_printf(XDBG_DEBUG_GENERAL, + "CheckDepOptions: enabling ext Rx VLAN strip\n"); + } else { + xdbg_printf(XDBG_DEBUG_ERROR, + "RX VLAN STRIP is not built in hardware\n"); + } + } + + /* + * Options and dependent Options together is what hardware and user + * are happy with. But we still need to keep original options + * in case option(s) are set/cleared, overall options can be managed. + * Return DepOptions to XAxiEthernet_[Set|Clear]Options for final + * configuration. + */ + return(DepOptions); +} + +/*****************************************************************************/ +/** +* XAxiEthernet_SetOptions enables the options, Options for the +* Axi Ethernet, specified by InstancePtr. Axi Ethernet should be +* stopped with XAxiEthernet_Stop() before changing options. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param Options is a bitmask of OR'd XAE_*_OPTION values for options to +* set. Options not specified are not affected. +* +* @return +* - XST_SUCCESS on successful completion. +* - XST_DEVICE_IS_STARTED if the device has not been stopped. +* +* +* @note +* See xaxiethernet.h for a description of the available options. +* +* +******************************************************************************/ +int XAxiEthernet_SetOptions(XAxiEthernet *InstancePtr, u32 Options) +{ + u32 Reg; /* Generic register contents */ + u32 RegRcw1; /* Reflects original contents of RCW1 */ + u32 RegTc; /* Reflects original contents of TC */ + u32 RegNewRcw1; /* Reflects new contents of RCW1 */ + u32 RegNewTc; /* Reflects new contents of TC */ + u32 DepOptions; /* Required dependent options for new features */ + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* Be sure device has been stopped */ + if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) { + return (XST_DEVICE_IS_STARTED); + } + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_SetOptions\n"); + + /* + * Set options word to its new value. + * The step is required before calling _UpdateDepOptions() since + * we are operating on updated options. + */ + InstancePtr->Options |= Options; + + /* + * There are options required to be on/off per hardware requirement. + * Invoke _UpdateDepOptions to check hardware availability and update + * options accordingly. + */ + DepOptions = XAxiEthernet_UpdateDepOptions(InstancePtr); + + /* + * New/extended function bit should be on if any new/extended features + * are on and hardware is built with them. + */ + if (DepOptions & (XAE_EXT_MULTICAST_OPTION | + XAE_EXT_TXVLAN_TRAN_OPTION | + XAE_EXT_RXVLAN_TRAN_OPTION | + XAE_EXT_TXVLAN_TAG_OPTION | + XAE_EXT_RXVLAN_TAG_OPTION | + XAE_EXT_TXVLAN_STRP_OPTION | + XAE_EXT_RXVLAN_STRP_OPTION)) { + + XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress, + XAE_RAF_OFFSET, + XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress, + XAE_RAF_OFFSET) | XAE_RAF_NEWFNCENBL_MASK); + } + + /* + * Many of these options will change the RCW1 or TC registers. + * To reduce the amount of IO to the device, group these options here + * and change them all at once. + */ + /* Get current register contents */ + RegRcw1 = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_RCW1_OFFSET); + RegTc = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_TC_OFFSET); + RegNewRcw1 = RegRcw1; + RegNewTc = RegTc; + + xdbg_printf(XDBG_DEBUG_GENERAL, + "current control regs: RCW1: 0x%0x; TC: 0x%0x\n", + RegRcw1, RegTc); + xdbg_printf(XDBG_DEBUG_GENERAL, + "Options: 0x%0x; default options: 0x%0x\n",Options, + XAE_DEFAULT_OPTIONS); + + /* Turn on jumbo packet support for both Rx and Tx */ + if (DepOptions & XAE_JUMBO_OPTION) { + RegNewTc |= XAE_TC_JUM_MASK; + RegNewRcw1 |= XAE_RCW1_JUM_MASK; + } + + /* Turn on VLAN packet support for both Rx and Tx */ + if (DepOptions & XAE_VLAN_OPTION) { + RegNewTc |= XAE_TC_VLAN_MASK; + RegNewRcw1 |= XAE_RCW1_VLAN_MASK; + } + + /* Turn on FCS stripping on receive packets */ + if (DepOptions & XAE_FCS_STRIP_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "setOptions: enabling fcs stripping\n"); + RegNewRcw1 &= ~XAE_RCW1_FCS_MASK; + } + + /* Turn on FCS insertion on transmit packets */ + if (DepOptions & XAE_FCS_INSERT_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "setOptions: enabling fcs insertion\n"); + RegNewTc &= ~XAE_TC_FCS_MASK; + } + + /* Turn on length/type field checking on receive packets */ + if (DepOptions & XAE_LENTYPE_ERR_OPTION) { + RegNewRcw1 &= ~XAE_RCW1_LT_DIS_MASK; + } + + /* Enable transmitter */ + if (DepOptions & XAE_TRANSMITTER_ENABLE_OPTION) { + RegNewTc |= XAE_TC_TX_MASK; + } + + /* Enable receiver */ + if (DepOptions & XAE_RECEIVER_ENABLE_OPTION) { + RegNewRcw1 |= XAE_RCW1_RX_MASK; + } + + /* Change the TC or RCW1 registers if they need to be modified */ + if (RegTc != RegNewTc) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "setOptions: writing tc: 0x%0x\n", RegNewTc); + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_TC_OFFSET, RegNewTc); + } + + if (RegRcw1 != RegNewRcw1) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "setOptions: writing rcw1: 0x%0x\n", RegNewRcw1); + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_RCW1_OFFSET, RegNewRcw1); + } + + /* + * Rest of options twiddle bits of other registers. Handle them one at + * a time + */ + + /* Turn on flow control */ + if (DepOptions & XAE_FLOW_CONTROL_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "setOptions: enabling flow control\n"); + Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_FCC_OFFSET); + Reg |= XAE_FCC_FCRX_MASK; + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_FCC_OFFSET, Reg); + } + xdbg_printf(XDBG_DEBUG_GENERAL, + "setOptions: rcw1 is now (fcc):0x%0x\n", + XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_RCW1_OFFSET)); + + /* Turn on promiscuous frame filtering (all frames are received ) */ + if (DepOptions & XAE_PROMISC_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "setOptions: enabling promiscuous mode\n"); + Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_FMI_OFFSET); + Reg |= XAE_FMI_PM_MASK; + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_FMI_OFFSET, Reg); + } + xdbg_printf(XDBG_DEBUG_GENERAL, + "setOptions: rcw1 is now (afm):0x%0x\n", + XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_RCW1_OFFSET)); + + /* Allow broadcast address filtering */ + if (DepOptions & XAE_BROADCAST_OPTION) { + Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_RAF_OFFSET); + Reg &= ~XAE_RAF_BCSTREJ_MASK; + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_RAF_OFFSET, Reg); + } + xdbg_printf(XDBG_DEBUG_GENERAL, + "setOptions: rcw1 is now (raf):0x%0x\n", + XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_RCW1_OFFSET)); + + /* Allow multicast address filtering */ + if (DepOptions & (XAE_MULTICAST_OPTION | XAE_EXT_MULTICAST_OPTION)) { + Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_RAF_OFFSET); + Reg &= ~XAE_RAF_MCSTREJ_MASK; + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_RAF_OFFSET, Reg); + } + xdbg_printf(XDBG_DEBUG_GENERAL, + "setOptions: rcw1 is now (raf2): 0x%0x\n", + XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_RCW1_OFFSET)); + + xdbg_printf(XDBG_DEBUG_GENERAL, + "setOptions: rcw1 is now (raf2):0x%0x\n", + XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_RCW1_OFFSET)); + + /* + * The remaining options not handled here are managed elsewhere in the + * driver. No register modifications are needed at this time. + * Reflecting the option in InstancePtr->Options is good enough for + * now. + */ + /* Enable extended multicast option */ + if (DepOptions & XAE_EXT_MULTICAST_OPTION) { + XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress, + XAE_RAF_OFFSET, + XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress, + XAE_RAF_OFFSET) | XAE_RAF_EMULTIFLTRENBL_MASK); + } + + /* + * New/extended [TX|RX] VLAN translation option does not have specific + * bits to on/off. + */ + + /* Enable extended transmit VLAN tag option */ + if (DepOptions & XAE_EXT_TXVLAN_TAG_OPTION) { + Reg = XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress, + XAE_RAF_OFFSET); + Reg = (Reg & ~XAE_RAF_TXVTAGMODE_MASK) | + (XAE_DEFAULT_TXVTAG_MODE << + XAE_RAF_TXVTAGMODE_SHIFT); + XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress, + XAE_RAF_OFFSET, Reg); + } + + /* Enable extended receive VLAN tag option */ + if (DepOptions & XAE_EXT_RXVLAN_TAG_OPTION) { + Reg = XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress, + XAE_RAF_OFFSET); + Reg = (Reg & ~XAE_RAF_RXVTAGMODE_MASK) | + (XAE_DEFAULT_RXVTAG_MODE << + XAE_RAF_RXVTAGMODE_SHIFT); + XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress, + XAE_RAF_OFFSET, Reg); + } + + /* Enable extended transmit VLAN strip option */ + if (Options & XAE_EXT_TXVLAN_STRP_OPTION) { + Reg = XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress, + XAE_RAF_OFFSET); + Reg = (Reg & ~XAE_RAF_TXVSTRPMODE_MASK) | + (XAE_DEFAULT_TXVSTRP_MODE << + XAE_RAF_TXVSTRPMODE_SHIFT); + XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress, + XAE_RAF_OFFSET, Reg); + } + + /* Enable extended receive VLAN strip option */ + if (Options & XAE_EXT_RXVLAN_STRP_OPTION) { + Reg = XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress, + XAE_RAF_OFFSET); + Reg = (Reg & ~XAE_RAF_RXVSTRPMODE_MASK) | + (XAE_DEFAULT_RXVSTRP_MODE << + XAE_RAF_RXVSTRPMODE_SHIFT); + XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress, + XAE_RAF_OFFSET, Reg); + } + + + + /* + * The remaining options not handled here are managed elsewhere in the + * driver. No register modifications are needed at this time. + * Reflecting the option in InstancePtr->Options is good enough for + * now. + */ + xdbg_printf(XDBG_DEBUG_GENERAL, "setOptions: returning SUCCESS\n"); + return (XST_SUCCESS); +} + +/*****************************************************************************/ +/** +* XAxiEthernet_ClearOptions clears the options, Options for the +* Axi Ethernet, specified by InstancePtr. Axi Ethernet should be stopped +* with XAxiEthernet_Stop() before changing options. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param Options is a bitmask of OR'd XAE_*_OPTION values for options to +* clear. Options not specified are not affected. +* +* @return +* - XST_SUCCESS on successful completion. +* - XST_DEVICE_IS_STARTED if the device has not been stopped. +* +* @note +* See xaxiethernet.h for a description of the available options. +* +******************************************************************************/ +int XAxiEthernet_ClearOptions(XAxiEthernet *InstancePtr, u32 Options) +{ + u32 Reg; /* Generic */ + u32 RegRcw1; /* Reflects original contents of RCW1 */ + u32 RegTc; /* Reflects original contents of TC */ + u32 RegNewRcw1; /* Reflects new contents of RCW1 */ + u32 RegNewTc; /* Reflects new contents of TC */ + u32 DepOptions; /* Required dependent options for new features */ + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_ClearOptions: 0x%08x\n", + Options); + /* Be sure device has been stopped */ + if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) { + return (XST_DEVICE_IS_STARTED); + } + + /* + * Set options word to its new value. + * The step is required before calling _UpdateDepOptions() since + * we are operating on updated options. + */ + InstancePtr->Options &= ~Options; + + /* + * There are options required to be on/off per hardware requirement. + * Invoke _UpdateDepOptions to check hardware availability and update + * options accordingly. + */ + DepOptions = ~(XAxiEthernet_UpdateDepOptions(InstancePtr)); + + /* + * New/extended function bit should be off if none of new/extended + * features is on after hardware is validated and gone through + * _UpdateDepOptions(). + */ + if (!(~(DepOptions) & (XAE_EXT_MULTICAST_OPTION | + XAE_EXT_TXVLAN_TRAN_OPTION | + XAE_EXT_RXVLAN_TRAN_OPTION | + XAE_EXT_TXVLAN_TAG_OPTION | + XAE_EXT_RXVLAN_TAG_OPTION | + XAE_EXT_TXVLAN_STRP_OPTION | + XAE_EXT_RXVLAN_STRP_OPTION))) { + XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress, + XAE_RAF_OFFSET, + XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress, + XAE_RAF_OFFSET) & ~XAE_RAF_NEWFNCENBL_MASK); + } + + /* + * Many of these options will change the RCW1 or TC registers. + * Group these options here and change them all at once. What we are + * trying to accomplish is to reduce the amount of IO to the device + */ + + /* Get the current register contents */ + RegRcw1 = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_RCW1_OFFSET); + RegTc = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_TC_OFFSET); + RegNewRcw1 = RegRcw1; + RegNewTc = RegTc; + + /* Turn off jumbo packet support for both Rx and Tx */ + if (DepOptions & XAE_JUMBO_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_ClearOptions: disabling jumbo\n"); + RegNewTc &= ~XAE_TC_JUM_MASK; + RegNewRcw1 &= ~XAE_RCW1_JUM_MASK; + } + + /* Turn off VLAN packet support for both Rx and Tx */ + if (DepOptions & XAE_VLAN_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_ClearOptions: disabling vlan\n"); + RegNewTc &= ~XAE_TC_VLAN_MASK; + RegNewRcw1 &= ~XAE_RCW1_VLAN_MASK; + } + + /* Turn off FCS stripping on receive packets */ + if (DepOptions & XAE_FCS_STRIP_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_ClearOptions: disabling fcs strip\n"); + RegNewRcw1 |= XAE_RCW1_FCS_MASK; + } + + /* Turn off FCS insertion on transmit packets */ + if (DepOptions & XAE_FCS_INSERT_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_ClearOptions: disabling fcs insert\n"); + RegNewTc |= XAE_TC_FCS_MASK; + } + + /* Turn off length/type field checking on receive packets */ + if (DepOptions & XAE_LENTYPE_ERR_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_ClearOptions: disabling lentype err\n"); + RegNewRcw1 |= XAE_RCW1_LT_DIS_MASK; + } + + /* Disable transmitter */ + if (DepOptions & XAE_TRANSMITTER_ENABLE_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_ClearOptions: disabling transmitter\n"); + RegNewTc &= ~XAE_TC_TX_MASK; + } + + /* Disable receiver */ + if (DepOptions & XAE_RECEIVER_ENABLE_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_ClearOptions: disabling receiver\n"); + RegNewRcw1 &= ~XAE_RCW1_RX_MASK; + } + + /* Change the TC and RCW1 registers if they need to be + * modified + */ + if (RegTc != RegNewTc) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_ClearOptions: setting TC: 0x%0x\n", RegNewTc); + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_TC_OFFSET, RegNewTc); + } + + if (RegRcw1 != RegNewRcw1) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_ClearOptions: setting RCW1: 0x%0x\n",RegNewRcw1); + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_RCW1_OFFSET, RegNewRcw1); + } + + /* + * Rest of options twiddle bits of other registers. Handle them one at + * a time + */ + + /* Turn off flow control */ + if (DepOptions & XAE_FLOW_CONTROL_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_ClearOptions: disabling flow control\n"); + Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_FCC_OFFSET); + Reg &= ~XAE_FCC_FCRX_MASK; + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_FCC_OFFSET, Reg); + } + + /* Turn off promiscuous frame filtering */ + if (DepOptions & XAE_PROMISC_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_ClearOptions: disabling promiscuous mode\n"); + Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_FMI_OFFSET); + Reg &= ~XAE_FMI_PM_MASK; + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_FMI_OFFSET, Reg); + } + + /* Disable broadcast address filtering */ + if (DepOptions & XAE_BROADCAST_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_ClearOptions: disabling broadcast mode\n"); + Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_RAF_OFFSET); + Reg |= XAE_RAF_BCSTREJ_MASK; + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_RAF_OFFSET, Reg); + } + + /* Disable multicast address filtering */ + if ((DepOptions & XAE_MULTICAST_OPTION) && + (DepOptions & XAE_EXT_MULTICAST_OPTION)) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_ClearOptions:disabling multicast mode\n"); + Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_RAF_OFFSET); + Reg |= XAE_RAF_MCSTREJ_MASK; + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_RAF_OFFSET, Reg); + } + + /* Disable extended multicast option */ + if (DepOptions & XAE_EXT_MULTICAST_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_ClearOptions:disabling extended multicast mode\n"); + XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress, + XAE_RAF_OFFSET, + XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress, + XAE_RAF_OFFSET) & ~XAE_RAF_EMULTIFLTRENBL_MASK); + } + + /* Disable extended transmit VLAN tag option */ + if (DepOptions & XAE_EXT_TXVLAN_TAG_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_ClearOptions:disabling extended TX VLAN tag mode\n"); + XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress, + XAE_RAF_OFFSET, + XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress, + XAE_RAF_OFFSET) & ~XAE_RAF_TXVTAGMODE_MASK); + } + + /* Disable extended receive VLAN tag option */ + if (DepOptions & XAE_EXT_RXVLAN_TAG_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_ClearOptions:disabling extended RX VLAN tag mode\n"); + XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress, + XAE_RAF_OFFSET, + XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress, + XAE_RAF_OFFSET) & ~XAE_RAF_RXVTAGMODE_MASK); + } + + /* Disable extended transmit VLAN strip option */ + if (DepOptions & XAE_EXT_TXVLAN_STRP_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_ClearOptions:disabling extended TX VLAN strip mode\n"); + XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress, + XAE_RAF_OFFSET, + XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress, + XAE_RAF_OFFSET) & ~XAE_RAF_TXVSTRPMODE_MASK); + } + + /* Disable extended receive VLAN strip option */ + if (DepOptions & XAE_EXT_RXVLAN_STRP_OPTION) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_ClearOptions:disabling extended RX VLAN strip mode\n"); + XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress, + XAE_RAF_OFFSET, + XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress, + XAE_RAF_OFFSET) & ~XAE_RAF_RXVSTRPMODE_MASK); + } + + /* + * The remaining options not handled here are managed elsewhere in the + * driver. No register modifications are needed at this time. + * Reflecting the option in InstancePtr->Options is good enough for + * now. + */ + xdbg_printf(XDBG_DEBUG_GENERAL, "ClearOptions: returning SUCCESS\n"); + return (XST_SUCCESS); +} + +/*****************************************************************************/ +/** +* XAxiEthernet_GetOptions returns the current option settings. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return Returns a bitmask of XAE_*_OPTION constants, +* each bit specifying an option that is currently active. +* +* @note +* See xaxiethernet.h for a description of the available options. +* +******************************************************************************/ +u32 XAxiEthernet_GetOptions(XAxiEthernet *InstancePtr) +{ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + return (InstancePtr->Options); +} + +/*****************************************************************************/ +/** + * XAxiEthernet_GetOperatingSpeed gets the current operating link speed. This + * may be the value set by XAxiEthernet_SetOperatingSpeed() or a hardware + * default. + * + * @param InstancePtr is a pointer to the Axi Ethernet instance to be + * worked on. + * + * @return Returns the link speed in units of megabits per second (10 / + * 100 / 1000). + * Can return a value of 0, in case it does not get a valid + * speed from EMMC. + * + * @note None. + * + ******************************************************************************/ +u16 XAxiEthernet_GetOperatingSpeed(XAxiEthernet *InstancePtr) +{ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_GetOperatingSpeed\n"); + switch (XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_EMMC_OFFSET) & XAE_EMMC_LINKSPEED_MASK) { + + case XAE_EMMC_LINKSPD_1000: + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_GetOperatingSpeed: returning 1000\n"); + return XAE_SPEED_1000_MBPS; + + case XAE_EMMC_LINKSPD_100: + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_GetOperatingSpeed: returning 100\n"); + return XAE_SPEED_100_MBPS; + + case XAE_EMMC_LINKSPD_10: + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_GetOperatingSpeed: returning 10\n"); + return (XAE_SPEED_10_MBPS); + + default: + return (0); + } +} + + +/*****************************************************************************/ +/** + * XAxiEthernet_SetOperatingSpeed sets the current operating link speed. For + * any traffic to be passed, this speed must match the current + * MII/GMII/SGMII/RGMII link speed. + * + * @param InstancePtr references the Axi Ethernet on which to + * operate. + * @param Speed is the speed to set in units of Mbps. + * Valid values are 10, 100, or 1000. + * + * @return - XST_SUCCESS on successful setting of speed. + * - XST_FAILURE, if the speed cannot be set for the present + * harwdare configuration. + * + * @note None. + * + * + ******************************************************************************/ +int XAxiEthernet_SetOperatingSpeed(XAxiEthernet *InstancePtr, u16 Speed) +{ + u32 EmmcReg; + u8 TemacType; + u8 PhyType; + u8 SetSpeed = TRUE; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid((Speed == XAE_SPEED_10_MBPS) || + (Speed == XAE_SPEED_100_MBPS) || + (Speed == XAE_SPEED_1000_MBPS)); + + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_SetOperatingSpeed\n"); + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_SetOperatingSpeed: setting speed to:%d (0x%0x)\n", + Speed, Speed); + + TemacType = XAxiEthernet_GetTemacType(InstancePtr); + PhyType = XAxiEthernet_GetPhysicalInterface(InstancePtr); + (void) (TemacType); + + /* + * The following code checks for all allowable speed conditions before + * writing to the register. Please refer to the hardware specs for + * more information on it. + * For PHY type 1000Base-x, 10 and 100 Mbps are not supported. + * For soft/hard Axi Ethernet core, 1000 Mbps is supported in all PHY + * types except MII. + */ + if((Speed == XAE_SPEED_10_MBPS) || (Speed == XAE_SPEED_100_MBPS)) { + if(PhyType == XAE_PHY_TYPE_1000BASE_X) { + SetSpeed = FALSE; + } + } + else { + if((Speed == XAE_SPEED_1000_MBPS) && + (PhyType == XAE_PHY_TYPE_MII)) { + SetSpeed = FALSE; + } + } + + if(SetSpeed == TRUE) { + /* + * Get the current contents of the EMAC config register and + * zero out speed bits + */ + EmmcReg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_EMMC_OFFSET) & ~XAE_EMMC_LINKSPEED_MASK; + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_SetOperatingSpeed: current speed: 0x%0x\n", + EmmcReg); + switch (Speed) { + case XAE_SPEED_10_MBPS: + break; + + case XAE_SPEED_100_MBPS: + EmmcReg |= XAE_EMMC_LINKSPD_100; + break; + + case XAE_SPEED_1000_MBPS: + EmmcReg |= XAE_EMMC_LINKSPD_1000; + break; + + default: + return (XST_FAILURE); + } + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_SetOperatingSpeed: new speed: 0x%0x\n", + EmmcReg); + /* Set register and return */ + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_EMMC_OFFSET, EmmcReg); + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_SetOperatingSpeed: done\n"); + return (XST_SUCCESS); + } + else { + xdbg_printf(XDBG_DEBUG_ERROR, + "Speed not compatible with the Axi Ethernet Phy type\n"); + return (XST_FAILURE); + } + +} + +/*****************************************************************************/ +/** +* XAxiEthernet_SetBadFrmRcvOption is used to enable the bad frame receive +* option. If enabled, this option ensures that bad receive frames are allowed +* and passed to the AXI4-Stream interface as if they are good frames. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return None. +* +* @note None +* +******************************************************************************/ +void XAxiEthernet_SetBadFrmRcvOption(XAxiEthernet *InstancePtr) +{ + u32 Reg; + + Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_RAF_OFFSET); + Reg |= XAE_RAF_RXBADFRMEN_MASK; + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_RAF_OFFSET, Reg); +} + +/*****************************************************************************/ +/** +* XAxiEthernet_ClearBadFrmRcvOption is used to disable the bad frame receive +* option. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XAxiEthernet_ClearBadFrmRcvOption(XAxiEthernet *InstancePtr) +{ + u32 Reg; + + Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_RAF_OFFSET); + Reg &= ~XAE_RAF_RXBADFRMEN_MASK; + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_RAF_OFFSET, Reg); +} + +/*****************************************************************************/ +/** +* XAxiEthernet_DisableControlFrameLenCheck is used to disable the length check +* for control frames (pause frames). This means once the API is called, control +* frames larger than the minimum frame length are accepted. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XAxiEthernet_DisableControlFrameLenCheck(XAxiEthernet *InstancePtr) +{ + u32 RegRcw1; + + /* Get the current register contents */ + RegRcw1 = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_RCW1_OFFSET); + RegRcw1 |= XAE_RCW1_CL_DIS_MASK; + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_RCW1_OFFSET, RegRcw1); +} + +/*****************************************************************************/ +/** +* XAxiEthernet_EnableControlFrameLenCheck is used to enable the length check +* for control frames (pause frames). After calling the API, all control frames +* received will be checked for proper length (less than minimum frame length). +* By default, upon normal start up, control frame length check is enabled. +* Hence this API needs to be called only if previously the control frame length +* check has been disabled by calling the API +* XAxiEthernet_DisableControlFrameLenCheck. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XAxiEthernet_EnableControlFrameLenCheck(XAxiEthernet *InstancePtr) +{ + u32 RegRcw1; + + /* Get the current register contents */ + RegRcw1 = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_RCW1_OFFSET); + RegRcw1 &= ~XAE_RCW1_CL_DIS_MASK; + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_RCW1_OFFSET, RegRcw1); +} + +/*****************************************************************************/ +/** +* XAxiEthernet_PhySetMdioDivisor sets the MDIO clock divisor in the +* Axi Ethernet,specified by InstancePtr to the value, Divisor. +* This function must be called once after each reset prior to accessing +* MII PHY registers. +* +* From the Virtex-6(TM) and Spartan-6 (TM) Embedded Tri-Mode Ethernet +* MAC User's Guide, the following equation governs the MDIO clock to the PHY: +* +*
+* 			f[HOSTCLK]
+*	f[MDC] = -----------------------
+*			(1 + Divisor) * 2
+* 
+* +* where f[HOSTCLK] is the bus clock frequency in MHz, and f[MDC] is the +* MDIO clock frequency in MHz to the PHY. Typically, f[MDC] should not +* exceed 2.5 MHz. Some PHYs can tolerate faster speeds which means faster +* access. +* +* @param InstancePtr references the Axi Ethernet instance on which to +* operate. +* @param Divisor is the divisor value to set within the range of 0 to +* XAE_MDIO_MC_CLK_DVD_MAX. +* +* @note None. +* +******************************************************************************/ +void XAxiEthernet_PhySetMdioDivisor(XAxiEthernet *InstancePtr, u8 Divisor) +{ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY) + Xil_AssertVoid(Divisor <= XAE_MDIO_MC_CLOCK_DIVIDE_MAX); + + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_PhySetMdioDivisor\n"); + + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_MDIO_MC_OFFSET, + (u32) Divisor | XAE_MDIO_MC_MDIOEN_MASK); +} + +/*****************************************************************************/ +/* +* XAxiEthernet_PhyRead reads the specified PHY register, RegiseterNum +* on the PHY specified by PhyAddress into PhyDataPtr. +* This Ethernet driver does not require the device to be stopped before reading +* from the PHY. It is the responsibility of the calling code to stop the +* device if it is deemed necessary. +* +* Note that the Axi Ethernet hardware provides the ability to talk to a PHY +* that adheres to the Media Independent Interface (MII) as defined in the +* IEEE 802.3 standard. +* +* It is important that calling code set up the MDIO clock with +* XAxiEthernet_PhySetMdioDivisor() prior to accessing the PHY with this +* function. +* +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param PhyAddress is the address of the PHY to be written (multiple +* PHYs supported). +* @param RegisterNum is the register number, 0-31, of the specific PHY +* register to write. +* @param PhyDataPtr is a reference to the location where the 16-bit +* result value is stored. +* +* @return None. +* +* +* @note +* +* There is the possibility that this function will not return if the hardware +* is broken (i.e., it never sets the status bit indicating that the write is +* done). If this is of concern, the calling code should provide a mechanism +* suitable for recovery. +* +******************************************************************************/ +void XAxiEthernet_PhyRead(XAxiEthernet *InstancePtr, u32 PhyAddress, + u32 RegisterNum, u16 *PhyDataPtr) +{ + u32 MdioCtrlReg = 0; + + /* + * Verify that each of the inputs are valid. + */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(PhyAddress <= XAE_PHY_ADDR_LIMIT); + Xil_AssertVoid(RegisterNum <= XAE_PHY_REG_NUM_LIMIT); + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_PhyRead: BaseAddress: 0x%08x\n", + InstancePtr->Config.BaseAddress); + + /* + * Wait till MDIO interface is ready to accept a new transaction. + */ + while (!(XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_MDIO_MCR_OFFSET) & XAE_MDIO_MCR_READY_MASK)) { + ; + } + + MdioCtrlReg = ((PhyAddress << XAE_MDIO_MCR_PHYAD_SHIFT) & + XAE_MDIO_MCR_PHYAD_MASK) | + ((RegisterNum << XAE_MDIO_MCR_REGAD_SHIFT) + & XAE_MDIO_MCR_REGAD_MASK) | + XAE_MDIO_MCR_INITIATE_MASK | + XAE_MDIO_MCR_OP_READ_MASK; + + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_MDIO_MCR_OFFSET, MdioCtrlReg); + + + /* + * Wait till MDIO transaction is completed. + */ + while (!(XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_MDIO_MCR_OFFSET) & XAE_MDIO_MCR_READY_MASK)) { + ; + } + + /* Read data */ + *PhyDataPtr = (u16) XAxiEthernet_ReadReg + (InstancePtr->Config.BaseAddress,XAE_MDIO_MRD_OFFSET); + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_PhyRead: Value retrieved: 0x%0x\n", *PhyDataPtr); + +} + + +/*****************************************************************************/ +/* +* XAxiEthernet_PhyWrite writes PhyData to the specified PHY register, +* RegiseterNum on the PHY specified by PhyAddress. This Ethernet +* driver does not require the device to be stopped before writing to the PHY. +* It is the responsibility of the calling code to stop the device if it is +* deemed necessary. +* +* Note that the Axi Ethernet hardware provides the ability to talk to a PHY +* that adheres to the Media Independent Interface (MII) as defined in the +* IEEE 802.3 standard. +* +* It is important that calling code set up the MDIO clock with +* XAxiEthernet_PhySetMdioDivisor() prior to accessing the PHY with this +* function. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param PhyAddress is the address of the PHY to be written (multiple +* PHYs supported). +* @param RegisterNum is the register number, 0-31, of the specific PHY +* register to write. +* @param PhyData is the 16-bit value that will be written to the +* register. +* +* @return None. +* +* @note +* +* There is the possibility that this function will not return if the hardware +* is broken (i.e., it never sets the status bit indicating that the write is +* done). If this is of concern, the calling code should provide a mechanism +* suitable for recovery. +* +******************************************************************************/ +void XAxiEthernet_PhyWrite(XAxiEthernet *InstancePtr, u32 PhyAddress, + u32 RegisterNum, u16 PhyData) +{ + u32 MdioCtrlReg = 0; + + /* + * Verify that each of the inputs are valid. + */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(PhyAddress <= XAE_PHY_ADDR_LIMIT); + Xil_AssertVoid(RegisterNum <= XAE_PHY_REG_NUM_LIMIT); + + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_PhyWrite\n"); + + /* + * Wait till the MDIO interface is ready to accept a new transaction. + */ + while (!(XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_MDIO_MCR_OFFSET) & XAE_MDIO_MCR_READY_MASK)) { + ; + } + + MdioCtrlReg = ((PhyAddress << XAE_MDIO_MCR_PHYAD_SHIFT) & + XAE_MDIO_MCR_PHYAD_MASK) | + ((RegisterNum << XAE_MDIO_MCR_REGAD_SHIFT) & + XAE_MDIO_MCR_REGAD_MASK) | + XAE_MDIO_MCR_INITIATE_MASK | + XAE_MDIO_MCR_OP_WRITE_MASK; + + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_MDIO_MWD_OFFSET, PhyData); + + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_MDIO_MCR_OFFSET, MdioCtrlReg); + + /* + * Wait till the MDIO interface is ready to accept a new transaction. + */ + while (!(XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_MDIO_MCR_OFFSET) & XAE_MDIO_MCR_READY_MASK)) { + ; + } + +} diff --git a/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet.h b/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet.h new file mode 100644 index 00000000..debb0c3f --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet.h @@ -0,0 +1,1480 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2015 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/** +* +* @file xaxiethernet.h +* +* The Xilinx AXI Ethernet MAC driver component. This driver supports hard +* Ethernet core for Virtex-6(TM) devices and soft Ethernet core for +* Spartan-6(TM) and other supported devices. The supported speed can be +* 10/100/1000 Mbps and can reach upto 2000/2500 Mbps (1000Base-X versions). +* +* For a full description of AXI Ethernet features, please see the hardware +* spec. +* This driver supports the following features: +* - Memory mapped access to host interface registers +* - Virtual memory support +* - Unicast, broadcast, and multicast receive address filtering +* - Full duplex operation +* - Automatic source address insertion or overwrite (programmable) +* - Automatic PAD & FCS insertion and stripping (programmable) +* - Flow control +* - VLAN frame support +* - Pause frame support +* - Jumbo frame support +* - Partial and full checksum offload +* - Extended multicast addresses to 2**23. +* - Extended VLAN translation, tagging and stripping supports. +* +*

Driver Description

+* +* The device driver enables higher layer software (e.g., an application) to +* configure a Axi Ethernet device. It is intended that this driver be used in +* cooperation with another driver (FIFO or DMA) for data communication. This +* device driver can support multiple devices even when those devices have +* significantly different configurations. +* +*

Initialization & Configuration

+* +* The XAxiEthernet_Config structure can be used by the driver to configure +* itself. This configuration structure is typically created by the tool-chain +* based on hardware build properties, although, other methods are allowed and +* currently used in some systems. +* +* To support multiple runtime loading and initialization strategies employed +* by various operating systems, the driver instance can be initialized using +* the XAxiEthernet_CfgInitialze() routine. +* +*

Interrupts and Asynchronous Callbacks

+* +* The driver has no dependencies on the interrupt controller. It provides +* no interrupt handlers. The application/OS software should set up its own +* interrupt handlers if required. +* +*

Device Reset

+* +* When a Axi Ethernet device is connected up to a FIFO or DMA core in hardware, +* errors may be reported on one of those cores (FIFO or DMA) such that it can +* be determined that the Axi Ethernet device needs to be reset. If a reset is +* performed, the calling code should also reconfigure and reapply the proper +* settings in the Axi Ethernet device. +* +* When a Axi Ethernet device reset is required, XAxiEthernet_Reset() should +* be utilized. +* +*

Virtual Memory

+* +* This driver may be used in systems with virtual memory support by passing +* the appropriate value for the EffectiveAddress parameter to the +* XAxiEthernet_CfgInitialize() routine. +* +*

Transfering Data

+* +* The Axi Ethernet core by itself is not capable of transmitting or receiving +* data in any meaningful way. Instead the Axi Ethernet device need to be +* connected to a FIFO or DMA core in hardware. +* +* This Axi Ethernet driver is modeled in a similar fashion where the +* application code or O/S adapter driver needs to make use of a separate FIFO +* or DMA driver in connection with this driver to establish meaningful +* communication over Ethernet. +* +*

Checksum Offloading

+* +* If configured, the device can compute a 16-bit checksum from frame data. In +* most circumstances this can lead to a substantial gain in throughput. +* +* The checksum offload settings for each frame sent or received are +* transmitted through the AXI4-Stream interface in hardware. What this means +* is that the checksum offload feature is indirectly controlled in the +* Axi Ethernet device through the driver for DMA core connected +* to the Axi Ethernet device. +* +* Refer to the documentation for DMA driver used for data +* communication on how to set the values for the relevant AXI4-Stream control +* words. +* +* Since this hardware implementation is general purpose in nature system +* software must perform pre and post frame processing to obtain the desired +* results for the types of packets being transferred. Most of the time this +* will be TCP/IP traffic. +* +* TCP/IP and UDP/IP frames contain separate checksums for the IP header and +* UDP/TCP header+data. +* For partial checksum offloading (enabled while configuring the hardware), +* the IP header checksum cannot be offloaded. Many stacks that support +* offloading will compute the IP header if required and use hardware to compute +* the UDP/TCP header+data checksum. There are other complications concerning +* the IP pseudo header that must be taken into consideration. Readers should +* consult a TCP/IP design reference for more details. +* +* For full checksum offloading (enabled while configuring the hardware), the +* IPv4 checksum calculation and validation can also be offloaded at the +* harwdare. Full checksum offload is supported only under certain conditions. +* IP checksum offload will be supported on valid IP datagrams that meet the +* following conditions. +* - If present, the VLAN header is 4 bytes long +* - Encapsulation into the Ethernet frame is either Ethernet II or Ethernet +* SNAP format +* - Only IPv4 is supported. IPv6 is not supported. +* - IP header is a valid length +* TCP/UDP checksum offloading will be supported on valid TCP/UDP segments that +* meet the following conditions. +* - Encapsulated in IPv4 (IPv6 is not supported) +* - Good IP header checksum +* - No fragmentation +* - TCP or UDP segment +* When full checksum offload is enabled, the hardware does the following: +* - Calculates the IP header checksum and inserts it in the IP header. +* - Calculates the TCP/UDP Pseudo header from IP header. +* - Calculates TCP/UDP header from, TCP/UDP psedu header, TCP/UDP header +* and TCP/UDP payload. +* - On the receive path, it again calculates all the above and validates +* for IP header checksum and TCP/UDP checksum. +* +* There are certain device options that will affect the checksum calculation +* performed by hardware for Tx: +* +* - FCS insertion disabled (XAE_FCS_INSERT_OPTION): software is required to +* calculate and insert the FCS value at the end of the frame, but the +* checksum must be known ahead of time prior to calculating the FCS. +* Therefore checksum offloading cannot be used in this situation. +* +* And for Rx: +* +* - FCS/PAD stripping disabled (XAE_FCS_STRIP_OPTION): The 4 byte FCS at the +* end of frame will be included in the hardware calculated checksum. +* software must subtract out this data. +* +* - FCS/PAD stripping disabled (XAE_FCS_STRIP_OPTION): For frames smaller +* than 64 bytes, padding will be included in the hardware calculated +* checksum. +* software must subtract out this data. It may be better to allow the +* TCP/IP stack verify checksums for this type of packet. +* +* - VLAN enabled (XAE_VLAN_OPTION): The 4 extra bytes in the Ethernet header +* affect the hardware calculated checksum. software must subtract out the +* 1st two 16-bit words starting at the 15th byte. +* +*

Transmit Checksum Offloading

+* +* For partial checksum offloading, for the TX path, the software can specify +* where in the frame the checksum calculation is to start, where the result +* should be inserted, and a seed value. The checksum is calculated from +* the start point through the end of frame. +* +* For full checksum offloading, for the TX path, the software just need to +* enable Full Checksum offload in the appropriate AXI4-Stream Control word on +* a per packet basis. +* +* The checksum offloading settings are sent in the transmit AXI4 Stream control +* words. The relevant control word fields are described in brief below. +* Refer to the Axi Ethernet hardware specification for more details. +* +*

AXI4-Stream Control Word 0:

+*
+*	Bits  1-0  : Transmit Checksum Enable: 	01 - Partial checsum offload,
+*						10 - Full checksum offload
+*						00 - No checksum offloading
+*						11 - Not used, reserved
+*	Bits 27-2  : Reserved
+*	Bits 31-28 : Used for AXI4-Stream Control Mode flag
+*
+* +*

AXI4-Stream Control Word 1:

+*
+*	Bits 31-16 (MSB): Transmit Checksum Calculation Starting Point: Offset
+*			  in the frame where checksum calculation should begin.
+*			  Relevant only for partial checksum offloading.
+*	Bits 15-0  (LSB): Transmit Checksum Insertion Point: Frame offset where
+*			  the computed checksum value is stored, which should be
+*			  in the TCP or UDP header.
+*			  Relevant only for partial checksum offloading.
+*   
+* +*

AXI4-Stream Control Word 2:

+*
+*	Bits 31-16 (MSB): Reserved
+*	Bits  0-15 (LSB): Transmit Checksum Calculation Initial Value: Checksum
+*			  seed value.
+*			  Relevant only for partial checksum offloading.
+*
+* +*

Receive Checksum Offloading

+* +* For partial checksum offload on the RX path, the 15th byte to end of frame +* is check summed. This range of bytes is the entire Ethernet payload (for +* non-VLAN frames). +* +* For full checksum offload on the RX path, both the IP and TCP checksums are +* validated if the packet meets the specified conditions. +* +* The checksum offloading information is sent in the receive AXI4-Stream +* status words. There are 4 relevant status words available. However +* only the relevant status words are described in brief below. +* Refer to the Axi Ethernet hardware specification for more details. +* +*

AXI4-Stream Status Word 0:

+*
+*	Bits 31-28 (MSB): Always 0x5 to represent receive status frame
+*	Bits 27-16	: Undefined
+*	Bits 15-0  (LSB): MCAST_ADR_U. Upper 16 bits of the multicast
+*			  destination address of the frame.
+*
+*

AXI4-Stream Status Word 1:

+*
+* Bits 31-0 : MCAST_ADR_L. The lower 32 bits of the multicast +* destination address. +* +*

AXI4-Stream Status Word 2:

+* +* Bits 5-3 : Specifies the receive full checksum status. This +* is relevant only for full checksum offloading. +* 000 -> Neither the IP header nor the TCP/UDP +* checksums were checked. +* 001 -> The IP header checksum was checked and was +* correct. The TCP/UDP checksum was not checked. +* 010 -> Both the IP header checksum and the TCP +* checksum were checked and were correct. +* 011 -> Both the IP header checksum and the UDP +* checksum were checked and were correct. +* 100 -> Reserved. +* 101 -> The IP header checksum was checked and was +* incorrect. The TCP/UDP checksum was not +* checked. +* 110 -> The IP header checksum was checked and is +* correct but the TCP checksum was checked +* and was incorrect. +* 111 -> The IP header checksum was checked and is +* correct but the UDP checksum was checked and +* was incorrect. +* +*

AXI4-Stream Status Word 3:

+* Bits 31-16 : T_L_TPID. This is the value of 13th and 14th byte +* of the frame. +* Bits 15-0 : Receive Raw Checksum: Computed checksum value +* +*

AXI4-Stream Status Word 3:

+* Bits 31-16 : VLAN_TAG. Value of 15th and 16th byte of the +* frame. +* Bits 15-0 : RX_BYTECNT. Received frame length. +* +* +*

Extended multicast

+* (XAE_EXT_MULTICAST_OPTION): Allow and perform address filtering more than 4 +* multicast addresses. Hardware requires to enable promiscuous mode +* (XAE_PROMISCUOUS_OPTION) and disable legacy multicast mode +* (XAE_MULTICAST_OPTION) for this feature to work. +* +*

Extended VLAN

+* +*

TX/RX VLAN stripping

+* (XAE_EXT_[T|R]XVLAN_STRP_OPTION) handles transmit/receive one VLAN tag +* stripping in Ethernet frames. To enable this option, hardware requires to +* build with this feature and enable (XAE_FCS_INSERT_OPTION), +* (XAE_FCS_STRP_OPTION) and disable (XAE_VLAN_OPTION). Supports three modes, +* -XAE_VSTRP_NONE : no stripping +* -XAE_VSTRP_ALL : strip one tag from all frames +* -XAE_VSTRP_SELECT : strip one tag from selected frames +* +*

TX/RX VLAN translation

+* (XATE_EXT_[T|R]XVLAN_TRAN_OPTION) handles transmit/receive one VLAN tag +* translation in Ethernet frames. To enable this option, hardware requires to +* build with this feature and enable (XATE_FCS_INSERT_OPTION), +* (XAE_FCS_STRP_OPTION), and disable (XAE_VLAN_OPTION). +* +*

TX/RX VLAN tagging

+* (XAE_EXT_[T|R]XVLAN_TAG_OPTION) adds transmit/receive one VLAN tag in +* Ethernet frames. To enable this option, hardware requires to build with this +* feature and enable (XAE_FCS_INSERT_OPTION), (XAE_FCS_STRP_OPTION), +* (XAE_JUMBO_OPTION) and disable (XAE_VLAN_OPTION). Support four modes, +* -XAE_VTAG_NONE : no tagging +* -XAE_VTAG_ALL : tag all frames +* -XAE_VTAG_EXISTED : tag already tagged frames +* -XAE_VTAG_SELECT : tag selected already tagged frames +* +*

PHY Communication

+* +* Prior to PHY access, the MDIO clock must be setup. This driver will set a +* safe default that should work with AXI4-Lite bus speeds of up to 150 MHz +* and keep the MDIO clock below 2.5 MHz. If the user wishes faster access to +* the PHY then the clock divisor can be set to a different value (see +* XAxiEthernet_PhySetMdioDivisor()). +* +* MII register access is performed through the functions XAxiEthernet_PhyRead() +* and XAxiEthernet_PhyWrite(). +* +*

Link Sync

+* +* When the device is used in a multi speed environment, the link speed must be +* explicitly set using XAxiEthernet_SetOperatingSpeed() and must match the +* speed PHY has negotiated. If the speeds are mismatched, then the MAC will not +* pass traffic. +* +* The application/OS software may use the AutoNegotiation interrupt to be +* notified when the PHY has completed auto-negotiation. +* +*

Asserts

+* +* Asserts are used within all Xilinx drivers to enforce constraints on argument +* values. Asserts can be turned off on a system-wide basis by defining, at +* compile time, the NDEBUG identifier. By default, asserts are turned on and it +* is recommended that users leave asserts on during development. For deployment +* use -DNDEBUG compiler switch to remove assert code. +* +*

Driver Errata

+* +* - A dropped receive frame indication may be reported by the driver after +* calling XAxiEthernet_Stop() followed by XAxiEthernet_Start(). This can +* occur if a frame is arriving when stop is called. +* - On Rx with checksum offloading enabled and FCS/PAD stripping disabled, +* FCS and PAD data will be included in the checksum result. +* - On Tx with checksum offloading enabled and auto FCS insertion disabled, +* the user calculated FCS will be included in the checksum result. +* +* @note +* +* Xilinx drivers are typically composed of two components, one is the driver +* and the other is the adapter. The driver is independent of OS and processor +* and is intended to be highly portable. The adapter is OS-specific and +* facilitates communication between the driver and an OS. +*

+* This driver is intended to be RTOS and processor independent. Any needs for +* dynamic memory management, threads or thread mutual exclusion, or cache +* control must be satisfied by the layer above this driver. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- ---------------------------------------------------------
+* 1.00a asa  6/30/10  First release based on the ll temac driver
+* 1.01a asa  12/10/10 Added macros XAxiEthernet_IsRxFullCsum and
+*		      XAxiEthernet_IsTxFullCsum for supporting full checksum
+*		      offload. The full checksum offload is only supported in
+*		      newer versions of the core, please refer to the core
+*		      HW datasheet.
+* 1.02a asa  2/16/11  Inserted a delay in the driver function
+*		      XAxiEthernet_Reset in file xaxiethernet.c. This is done
+*		      because immediately after a core reset none of the
+*		      AxiEthernet registers are accessible for some duration.
+*		      Changed the value of XAE_LOOPS_TO_COME_OUT_OF_RST to
+*		      10000 in file xaxiethernet_hw.h.
+*
+* 2.00a asa  8/29/11  A new major version of AxiEthernet driver is being
+*		      released to accomodate the change in avb software. The
+*		      AxiEthernet hardware v3_00_a has the latest avb
+*		      hardware which needs a corresponding change in avb
+*		      software (released in examples/avb folder). This change
+*		      in avb software is not backwards compatible (which
+*		      means this avb software will not work with older
+*		      axiethernet hardware).
+*		      Hence a new major version of axiethernet is being
+*		      released.
+*		      Added defines for Ability Reg, Identification Reg, Rx max
+*		      Frame and Tx Max Frame registers.
+*		      Changed define for TEMAC RGMII/SGMII Config (PHYC) Reg.
+*
+* 3.00a asa  4/10/12  A new major version of AxiEthernet is being released to
+*		      accomodate the change in AVB example. From AxiEthernet
+*		      core version 3.01a onwards the AVB implementation has
+*		      changed. The AVB module is now a part of AxiEthernet IP.
+*		      Because of this change, the AVB example works only
+*		      when promiscuous mode is not enabled (unlike earlier
+*		      implementation where promiscuous mode was required for
+*		      AVB example to work). Hence the file xavb_example.c is
+*		      changed so that the core is not put in promiscuous mode.
+*		      Also since AVB is a part of AxiEthernet some of the
+*		      register mappings in xavb_hw.h has changed.
+*		      These changes are not backward compatible which means
+*		      this changed example will not work for previous versions
+*		      of cores.
+*		      Hence a new major version of axiethernet is being
+*		      released.
+* 3.01a srt  02/03/13 - Added support for SGMII mode (CR 676793)
+*	     	      - Added support for IPI designs (CR 698249)
+*	     02/14/13 - Added support for Zynq (CR 681136)
+* 3.02a srt  04/13/13 - Removed Warnings (CR 704998).
+*            04/24/13 - Modified parameter *_SGMII_PHYADDR to *_PHYADDR, the
+*                       config parameter C_PHYADDR applies to SGMII/1000BaseX
+*	                modes of operation
+*	     04/24/13 - Added support for 1000BaseX mode in examples (_util.c)
+*		        (CR 704195)
+*	     04/24/13 - Added support for RGMII mode in examples (_util.c)
+* 3.02a srt  08/06/13 - Fixed CR 727634:
+*			  Modified FifoHandler() function logic of FIFO
+*			  interrupt example to reflect the bit changes in
+*			  the Interrupt Status Register as per the latest
+*			  AXI FIFO stream IP.
+*		      - Fixed CR 721141:
+*			  Added support to handle multiple instances of
+*			  AxiEthernet FIFO interface (CR 721141)
+*		      - Fixed CR 717949:
+*			  Configures external Marvel 88E1111 PHY based on the
+*			  AXI Ethernet physical interface type and allows to
+*			  operate in specific interface mode without changing
+*			  jumpers on the Microblaze boards. This change is in
+*			  example_util.c
+* 3.02a adk 15/11/13 - Fixed CR 761035 removed dependency with fifo in MDD file
+* 4.0   adk 19/12/13 - Updated as per the New Tcl API's
+*		asa 30/01/14 - Added defines for 1588 registers and bit masks
+*					   Added config parameter for SGMII over LVDS
+*
+* 4.1  adk 21/04/14 - Fixed CR:780537 Changes are Made in the file
+* 		      axiethernet test-app tcl
+* 4.2  adk 08/08/14 - Fixed CR:810643 SDK generated 'xparamters.h' erroneously
+*		      generated with errors due to part of '#define' misplaced
+*		      changes are made in the driver tcl file.
+* 4.3 adk 29/10/14 -  Added support for generating parameters for SGMII/1000BaseX
+*		      modes When IP is configured with the PCS/PMA core.
+*		      Changes are made in the driver tcl file (CR 828796).
+* 4.4  adk  8/1/15 -  Fixed TCL errors when axiethernet is configured with the
+*		      Axi stream fifo (CR 835605). Changes are made in the
+*		      driver tcl file.
+* 
+* +******************************************************************************/ + +#ifndef XAXIETHERNET_H /* prevent circular inclusions */ +#define XAXIETHERNET_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xenv.h" +#include "xstatus.h" +#include "xil_assert.h" +#include "xaxiethernet_hw.h" + +/************************** Constant Definitions *****************************/ + +/** @name Configuration options + * + * The following are device configuration options. See the + * XAxiEthernet_SetOptions, XAxiEthernet_ClearOptions and + * XAxiEthernet_GetOptions routines for information on how to use + * options. + * + * The default state of the options are also noted below. + * + * @{ + */ + +/**< XAE_PROMISC_OPTION specifies the Axi Ethernet device to accept all + * incoming packets. + * This driver sets this option to disabled (cleared) by default. + */ +#define XAE_PROMISC_OPTION 0x00000001 + +/**< XAE_JUMBO_OPTION specifies the Axi Ethernet device to accept jumbo + * frames for transmit and receive. + * This driver sets this option to disabled (cleared) by default. + */ +#define XAE_JUMBO_OPTION 0x00000002 + +/**< XAE_VLAN_OPTION specifies the Axi Ethernet device to enable VLAN support + * for transmit and receive. + * This driver sets this option to disabled (cleared) by default. + */ +#define XAE_VLAN_OPTION 0x00000004 + +/**< XAE_FLOW_CONTROL_OPTION specifies the Axi Ethernet device to recognize + * received flow control frames. + * This driver sets this option to enabled (set) by default. + */ +#define XAE_FLOW_CONTROL_OPTION 0x00000008 + +/**< XAE_FCS_STRIP_OPTION specifies the Axi Ethernet device to strip FCS and + * PAD from received frames. Note that PAD from VLAN frames is not stripped. + * This driver sets this option to enabled (set) by default. + */ +#define XAE_FCS_STRIP_OPTION 0x00000010 + +/**< XAE_FCS_INSERT_OPTION specifies the Axi Ethernet device to generate the + * FCS field and add PAD automatically for outgoing frames. + * This driver sets this option to enabled (set) by default. + */ +#define XAE_FCS_INSERT_OPTION 0x00000020 + +/**< XAE_LENTYPE_ERR_OPTION specifies the Axi Ethernet device to enable + * Length/Type error checking (mismatched type/length field) for received + * frames. + * This driver sets this option to enabled (set) by default. + */ +#define XAE_LENTYPE_ERR_OPTION 0x00000040 + +/**< XAE_TRANSMITTER_ENABLE_OPTION specifies the Axi Ethernet device + * transmitter to be enabled. + * This driver sets this option to enabled (set) by default. + */ +#define XAE_TRANSMITTER_ENABLE_OPTION 0x00000080 + +/**< XAE_RECEIVER_ENABLE_OPTION specifies the Axi Ethernet device receiver to + * be enabled. + * This driver sets this option to enabled (set) by default. + */ +#define XAE_RECEIVER_ENABLE_OPTION 0x00000100 + +/**< XAE_BROADCAST_OPTION specifies the Axi Ethernet device to receive frames + * sent to the broadcast Ethernet address. + * This driver sets this option to enabled (set) by default. + */ +#define XAE_BROADCAST_OPTION 0x00000200 + +/**< XAE_MULTICAST_OPTION specifies the Axi Ethernet device to receive frames + * sent to Ethernet addresses that are programmed into the Multicast Address + * Table (MAT). + * This driver sets this option to disabled (cleared) by default. + */ +#define XAE_MULTICAST_OPTION 0x00000400 + +/**< XAE_EXT_MULTICAST_OPTION specifies the Axi Ethernet device to receive + * frames sent to Ethernet addresses that are programmed into the Multicast + * Address Table. + * This driver sets this option to be dependent on HW configuration + * by default. + */ +#define XAE_EXT_MULTICAST_OPTION 0x00000800 + +/**< XAE_EXT_TXVLAN_TRAN_OPTION specifies the Axi Ethernet device to enable + * transmit VLAN translation. + * This driver sets this option to be dependent on HW configuration + * by default. + */ +#define XAE_EXT_TXVLAN_TRAN_OPTION 0x00001000 + +/**< XAE_EXT_RXVLAN_TRAN_OPTION specifies the Axi Ethernet device to enable + * receive VLAN translation. + * This driver sets this option to be dependent on HW configuration + * by default. + */ +#define XAE_EXT_RXVLAN_TRAN_OPTION 0x00002000 + +/**< XAE_EXT_TXVLAN_TAG_OPTION specifies the Axi Ethernet device to enable + * transmit VLAN tagging. + * This driver sets this option to be dependent during HW build time + * by default. + */ +#define XAE_EXT_TXVLAN_TAG_OPTION 0x00004000 + +/**< XAE_EXT_RXVLAN_TAG_OPTION specifies the Axi Ethernet device to enable + * receive VLAN tagging. + * This driver sets this option to be dependent during HW build time + * by default. + */ +#define XAE_EXT_RXVLAN_TAG_OPTION 0x00008000 + +/**< XAE_EXT_TXVLAN_STRP_OPTION specifies the Axi Ethernet device to enable + * transmit VLAN stripping. + * This driver sets this option to be dependent during HW build time + * by default. + */ +#define XAE_EXT_TXVLAN_STRP_OPTION 0x00010000 + +/**< XAE_EXT_RXVLAN_STRP_OPTION specifies the Axi Ethernet device to enable + * receive VLAN stripping. + * This driver sets this option to be dependent during HW build time + * by default. + */ +#define XAE_EXT_RXVLAN_STRP_OPTION 0x00020000 + + +#define XAE_DEFAULT_OPTIONS \ + (XAE_FLOW_CONTROL_OPTION | \ + XAE_BROADCAST_OPTION | \ + XAE_FCS_INSERT_OPTION | \ + XAE_FCS_STRIP_OPTION | \ + XAE_LENTYPE_ERR_OPTION | \ + XAE_TRANSMITTER_ENABLE_OPTION | \ + XAE_RECEIVER_ENABLE_OPTION) +/**< XAE_DEFAULT_OPTIONS specify the options set in XAxiEthernet_Reset() and + * XAxiEthernet_CfgInitialize() + */ +/*@}*/ + + +#define XAE_MULTI_MAT_ENTRIES 4 /**< Number of storable addresses in + * the Multicast Address Table + */ + +#define XAE_MDIO_DIV_DFT 29 /**< Default MDIO clock divisor */ + +/* + * The next few constants help upper layers determine the size of memory + * pools used for Ethernet buffers and descriptor lists. + */ +#define XAE_MAC_ADDR_SIZE 6 /* MAC addresses are 6 bytes */ +#define XAE_MTU 1500 /* Max MTU size of an Ethernet + * frame + */ +#define XAE_JUMBO_MTU 8982 /* Max MTU size of a jumbo + * Ethernet frame + */ +#define XAE_HDR_SIZE 14 /* Size of an Ethernet header*/ +#define XAE_HDR_VLAN_SIZE 18 /* Size of an Ethernet header + * with VLAN + */ +#define XAE_TRL_SIZE 4 /* Size of an Ethernet trailer + * (FCS) + */ +#define XAE_MAX_FRAME_SIZE (XAE_MTU + XAE_HDR_SIZE + XAE_TRL_SIZE) +#define XAE_MAX_VLAN_FRAME_SIZE (XAE_MTU + XAE_HDR_VLAN_SIZE + XAE_TRL_SIZE) +#define XAE_MAX_JUMBO_FRAME_SIZE (XAE_JUMBO_MTU + XAE_HDR_SIZE + XAE_TRL_SIZE) + +/* + * Constant values returned by XAxiEthernet_GetPhysicalInterface(). Note that + * these values match design parameters from the Axi Ethernet spec. + */ +#define XAE_PHY_TYPE_MII 0 +#define XAE_PHY_TYPE_GMII 1 +#define XAE_PHY_TYPE_RGMII_1_3 2 +#define XAE_PHY_TYPE_RGMII_2_0 3 +#define XAE_PHY_TYPE_SGMII 4 +#define XAE_PHY_TYPE_1000BASE_X 5 + +#define XAE_TPID_MAX_ENTRIES 4 /* Number of storable TPIDs in + * Table + */ + +/* + * Constant values pass into XAxiEthernet_SetV[tag|Strp]Mode() and returned by + * XAxiEthernet_GetV[tag|Strp]Mode(). + */ +#define XAE_VTAG_NONE 0 /* No tagging */ +#define XAE_VTAG_ALL 1 /* Tag all frames */ +#define XAE_VTAG_EXISTED 2 /* Tag already tagged frames */ +#define XAE_VTAG_SELECT 3 /* + * Tag selected already tagged + * frames + */ +#define XAE_DEFAULT_TXVTAG_MODE XAE_VTAG_ALL +#define XAE_DEFAULT_RXVTAG_MODE XAE_VTAG_ALL + +#define XAE_VSTRP_NONE 0 /* No stripping */ +#define XAE_VSTRP_ALL 1 /* Strip one tag from all + * frames + */ +#define XAE_VSTRP_SELECT 3 /* Strip one tag from selected + * frames + */ +#define XAE_DEFAULT_TXVSTRP_MODE XAE_VSTRP_ALL +#define XAE_DEFAULT_RXVSTRP_MODE XAE_VSTRP_ALL + +#define XAE_RX 1 /* Receive direction */ +#define XAE_TX 2 /* Transmit direction */ + +#define XAE_SOFT_TEMAC_10_100_MBPS 0 +#define XAE_SOFT_TEMAC_10_100_1000_MBPS 1 +#define XAE_HARD_TEMC 2 + +/**************************** Type Definitions *******************************/ + + +/** + * This typedef contains configuration information for a Axi Ethernet device. + */ +typedef struct XAxiEthernet_Config { + u16 DeviceId; /**< DeviceId is the unique ID of the device */ + u32 BaseAddress;/**< BaseAddress is the physical base address of the + * device's registers + */ + u8 TemacType; /**< Temac Type can have 3 possible values. They are + * 0 for SoftTemac at 10/100 Mbps, 1 for SoftTemac + * at 10/100/1000 Mbps and 2 for Vitex6 Hard Temac + */ + u8 TxCsum; /**< TxCsum indicates that the device has checksum + * offload on the Tx channel or not. + */ + u8 RxCsum; /**< RxCsum indicates that the device has checksum + * offload on the Rx channel or not. + */ + u8 PhyType; /**< PhyType indicates which type of PHY interface is + * used (MII, GMII, RGMII, etc. + */ + u8 TxVlanTran; /**< TX VLAN Translation indication */ + u8 RxVlanTran; /**< RX VLAN Translation indication */ + u8 TxVlanTag; /**< TX VLAN tagging indication */ + u8 RxVlanTag; /**< RX VLAN tagging indication */ + u8 TxVlanStrp; /**< TX VLAN stripping indication */ + u8 RxVlanStrp; /**< RX VLAN stripping indication */ + u8 ExtMcast; /**< Extend multicast indication */ + u8 Stats; /**< Statistics gathering option */ + u8 Avb; /**< Avb option */ + u8 EnableSgmiiOverLvds; /**< Enable LVDS option */ + + u8 TemacIntr; /**< Axi Ethernet interrupt ID */ + + int AxiDevType; /**< AxiDevType is the type of device attached to the + * Axi Ethernet's AXI4-Stream interface. + */ + u32 AxiDevBaseAddress; /**< AxiDevBaseAddress is the base address of + * the device attached to the Axi Ethernet's + * AXI4-Stream interface. + */ + u8 AxiFifoIntr; /**< AxiFifoIntr interrupt ID (unused if DMA) */ + u8 AxiDmaRxIntr;/**< Axi DMA RX interrupt ID (unused if FIFO) */ + u8 AxiDmaTxIntr;/**< Axi DMA TX interrupt ID (unused if FIFO) */ +} XAxiEthernet_Config; + + +/** + * struct XAxiEthernet is the type for Axi Ethernet driver instance data. + * The calling code is required to use a unique instance of this structure + * for every Axi Ethernet device used in the system. A reference to a structure + * of this type is then passed to the driver API functions. + */ +typedef struct XAxiEthernet { + XAxiEthernet_Config Config; /**< Hardware configuration */ + u32 IsStarted; /**< Device is currently started */ + u32 IsReady; /**< Device is initialized and ready */ + u32 Options; /**< Current options word */ + u32 Flags; /**< Internal driver flags */ +} XAxiEthernet; + + +/***************** Macros (Inline Functions) Definitions *********************/ + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsStarted reports if the device is in the started or stopped +* state. To be in the started state, the calling code must have made a +* successful call to XAxiEthernet_Start. To be in the stopped state, +* XAxiEthernet_Stop or XAxiEthernet_CfgInitialize function must +* have been called. +* +* @param InstancePtr is a pointer to the of Axi Ethernet instance to be +* worked on. +* +* @return +* - TRUE if the device has been started. +* - FALSE.if the device has not been started +* +* @note C-style signature: +* u32 XAxiEthernet_IsStarted(XAxiEthernet *InstancePtr) +* + ******************************************************************************/ +#define XAxiEthernet_IsStarted(InstancePtr) \ + (((InstancePtr)->IsStarted == XIL_COMPONENT_IS_STARTED) ? TRUE : FALSE) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsDma reports if the device is currently connected to DMA. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @return +* - TRUE if the Axi Ethernet device is connected DMA. +* - FALSE.if the Axi Ethernet device is NOT connected to DMA +* +* @note C-style signature: +* u32 XAxiEthernet_IsDma(XAxiEthernet *InstancePtr) +* +******************************************************************************/ +#define XAxiEthernet_IsDma(InstancePtr) \ + (((InstancePtr)->Config.AxiDevType == XPAR_AXI_DMA) ? TRUE: FALSE) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsFifo reports if the device is currently connected to a fifo +* core. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return +* - TRUE if the Axi Ethernet device is connected to a fifo +* - FALSE if the Axi Ethernet device is NOT connected to a fifo. +* +* @note C-style signature: +* u32 XAxiEthernet_IsFifo(XAxiEthernet *InstancePtr) +* +******************************************************************************/ +#define XAxiEthernet_IsFifo(InstancePtr) \ + (((InstancePtr)->Config.AxiDevType == XPAR_AXI_FIFO) ? TRUE: FALSE) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_AxiDevBaseAddress reports the base address of the core connected +* to the Axi Ethernet's Axi4 Stream interface. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return The base address of the core connected to the Axi Ethernet's +* streaming interface. +* +* @note C-style signature: +* u32 XAxiEthernet_AxiDevBaseAddress(XAxiEthernet *InstancePtr) +* +******************************************************************************/ +#define XAxiEthernet_AxiDevBaseAddress(InstancePtr) \ + ((InstancePtr)->Config.AxiDevBaseAddress) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsRecvFrameDropped determines if the device thinks it has +* dropped a receive frame. The device interrupt status register is read to +* determine this. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return +* - TRUE if a frame has been dropped +* - FALSE if a frame has NOT been dropped. +* +* @note C-style signature: +* u32 XAxiEthernet_IsRecvFrameDropped(XAxiEthernet *InstancePtr) +* +******************************************************************************/ +#define XAxiEthernet_IsRecvFrameDropped(InstancePtr) \ + ((XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress, \ + XAE_IS_OFFSET) & XAE_INT_RXRJECT_MASK) ? TRUE : FALSE) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsRxPartialCsum determines if the device is configured with +* partial checksum offloading on the receive channel. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @return +* - TRUE if the device is configured with partial checksum +* offloading on the receive channel. +* - FALSE.if the device is not configured with partial checksum +* offloading on the receive side. +* +* @note C-style signature: +* u32 XAxiEthernet_IsRxPartialCsum(XAxiEthernet *InstancePtr) +* +******************************************************************************/ +#define XAxiEthernet_IsRxPartialCsum(InstancePtr) \ + ((((InstancePtr)->Config.RxCsum) == 0x01) ? TRUE : FALSE) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsTxPartialCsum determines if the device is configured with +* partial checksum offloading on the transmit channel. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return +* - TRUE if the device is configured with partial checksum +* offloading on the transmit side. +* - FALSE.if the device is not configured with partial checksum +* offloading on the transmit side. +* +* @note C-style signature: +* u32 XAxiEthernet_IsTxPartialCsum(XAxiEthernet *InstancePtr) +* +******************************************************************************/ +#define XAxiEthernet_IsTxPartialCsum(InstancePtr) \ + ((((InstancePtr)->Config.TxCsum) == 0x01) ? TRUE : FALSE) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsRxFullCsum determines if the device is configured with full +* checksum offloading on the receive channel. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @return +* - TRUE if the device is configured with full checksum +* offloading on the receive channel. +* - FALSE.if the device is not configured with full checksum +* offloading on the receive side. +* +* @note C-style signature: +* u32 XAxiEthernet_IsRxFullCsum(XAxiEthernet *InstancePtr) +* +******************************************************************************/ +#define XAxiEthernet_IsRxFullCsum(InstancePtr) \ + ((((InstancePtr)->Config.RxCsum) == 0x02) ? TRUE : FALSE) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsTxFullCsum determines if the device is configured with full +* checksum offloading on the transmit channel. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return +* - TRUE if the device is configured with full checksum +* offloading on the transmit side. +* - FALSE.if the device is not configured with full checksum +* offloading on the transmit side. +* +* @note C-style signature: +* u32 XAxiEthernet_IsTxFullCsum(XAxiEthernet *InstancePtr) +* +******************************************************************************/ +#define XAxiEthernet_IsTxFullCsum(InstancePtr) \ + ((((InstancePtr)->Config.TxCsum) == 0x02) ? TRUE : FALSE) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_GetPhysicalInterface returns the type of PHY interface being +* used by the given instance, specified by InstancePtr. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return The Physical Interface type which is one of XAE_PHY_TYPE_x +* where x is MII, GMII, RGMII_1_3, RGMII_2_0, SGMII, or +* 1000BASE_X (defined in xaxiethernet.h). +* +* @note C-style signature: +* int XAxiEthernet_GetPhysicalInterface(XAxiEthernet +* *InstancePtr) +* +******************************************************************************/ +#define XAxiEthernet_GetPhysicalInterface(InstancePtr) \ + ((InstancePtr)->Config.PhyType) + +/****************************************************************************/ +/** +* +* XAxiEthernet_GetIntStatus returns a bit mask of the interrupt status +* register (ISR). XAxiEthernet_GetIntStatus can be used to query the status +* without having to have interrupts enabled. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return Returns a bit mask of the interrupt status conditions. The +* mask will be a set of bit wise or'd values from the +* XAE_INT_*_MASK definitions in xaxitemac_hw.h file. +* +* @note C-style signature: +* u32 XAxiEthernet_GetIntStatus(XAxiEthernet *InstancePtr) +* +*****************************************************************************/ +#define XAxiEthernet_GetIntStatus(InstancePtr) \ + XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress, XAE_IS_OFFSET) + +/****************************************************************************/ +/** +* +* XAxiEthernet_IntEnable enables the interrupts specified in Mask. The +* corresponding interrupt for each bit set to 1 in Mask, will be +* enabled. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @param Mask contains a bit mask of the interrupts to enable. The mask +* can be formed using a set of bit wise or'd values from the +* XAE_INT_*_MASK definitions in xaxitemac_hw.h file. +* +* @return None. +* +* @note C-style signature: +* void XAxiEthernet_IntEnable(XAxiEthernet *InstancePtr, +* u32 Mask) +* +*****************************************************************************/ +#define XAxiEthernet_IntEnable(InstancePtr, Mask) \ + XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress, \ + XAE_IE_OFFSET, \ + XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress, \ + XAE_IE_OFFSET) | ((Mask) & XAE_INT_ALL_MASK)); + +/****************************************************************************/ +/** +* +* XAxiEthernet_IntDisable disables the interrupts specified in Mask. The +* corresponding interrupt for each bit set to 1 in Mask, will be +* disabled. In other words, XAxiEthernet_IntDisable uses the "set a bit to +* clear it" scheme. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param Mask contains a bit mask of the interrupts to disable. The mask +* can be formed using a set of bit wise or'd values from the +* XAE_INT_*_MASK definitions in xaxitemac_hw.h file +* +* @return None. +* +* @note C-style signature: +* void XAxiEthernet_IntDisable(XAxiEthernet *InstancePtr, +* u32 Mask) +* +*****************************************************************************/ +#define XAxiEthernet_IntDisable(InstancePtr, Mask) \ + XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress, \ + XAE_IE_OFFSET, \ + XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress, \ + XAE_IE_OFFSET) & ~((Mask) & XAE_INT_ALL_MASK)); + +/****************************************************************************/ +/** +* +* XAxiEthernet_IntPending returns a bit mask of the pending interrupts. Each +* bit set to 1 in the return value represents a pending interrupt. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return Returns a bit mask of the interrupts that are pending. The mask +* will be a set of bit wise or'd values from the +* XAE_INT_*_MASK definitions in xaxitemac_hw.h file. +* +* @note C-style signature: +* u32 XAxiEthernet_IntPending(XAxiEthernet *InstancePtr) +* +*****************************************************************************/ +#define XAxiEthernet_IntPending(InstancePtr) \ + XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress, XAE_IP_OFFSET) + +/****************************************************************************/ +/** +* +* XAxiEthernet_IntClear clears pending interrupts specified in Mask. +* The corresponding pending interrupt for each bit set to 1 in Mask, +* will be cleared. In other words, XAxiEthernet_IntClear uses the "set a bit to +* clear it" scheme. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param Mask contains a bit mask of the pending interrupts to clear. +* The mask can be formed using a set of bit wise or'd values from +* the XAE_INT_*_MASK definitions in xaxitemac_hw.h +* file. +* +* @note C-style signature: +* void XAxiEthernet_IntClear(XAxiEthernet *InstancePtr, +* u32 Mask) +* +*****************************************************************************/ +#define XAxiEthernet_IntClear(InstancePtr, Mask) \ + XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress, \ + XAE_IS_OFFSET, ((Mask) & XAE_INT_ALL_MASK)) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsExtFuncCap determines if the device is capable of the +* new/extend VLAN and multicast features. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return +* - TRUE if the device is capable and configured with extended +* Multicast and VLAN Tagging/Stripping and Translation. +* - TRUE if the device is NOT capable and NOT configured with +* extended Multicast and VLAN Tagging/Stripping and +* Translation. +* +* @note C-style signature: +* u32 XAxiEthernet_IsExtFuncCap(XAxiEthernet *InstancePtr) +* + *****************************************************************************/ +#define XAxiEthernet_IsExtFuncCap(InstancePtr) \ + ((XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress, \ + XAE_RAF_OFFSET) & XAE_RAF_NEWFNCENBL_MASK) ? \ + TRUE : FALSE) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsExtMcastEnable determines if the extended multicast features +* is enabled. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return +* - TRUE if the extended multicast features are enabled. +* - FALSE if the extended multicast features are NOT enabled +* +* @note : This function indicates when extended Multicast is enabled in +* HW, extended multicast mode in wrapper can be tested. +* +* C-style signature: +* u32 XAxiEthernet_IsExtMcastEnable(XAxiEthernet *InstancePtr) +* +*****************************************************************************/ +#define XAxiEthernet_IsExtMcastEnable(InstancePtr) \ + ((XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress, \ + XAE_RAF_OFFSET) & XAE_RAF_EMULTIFLTRENBL_MASK) ? \ + TRUE : FALSE) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsExtMcast determines if the device is built with new/extended +* multicast features. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return +* - TRUE if the device is built with extended multicast features. +* - FALSE if the device is not built with the extended multicast +* features. +* +* @note This function indicates when hardware is built with extended +* Multicast feature. +* +* C-style signature: +* u32 XAxiEthernet_IsExtMcast(XAxiEthernet *InstancePtr) +* +*****************************************************************************/ +#define XAxiEthernet_IsExtMcast(InstancePtr) \ + (((InstancePtr)->Config.ExtMcast) ? TRUE : FALSE) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsTxVlanStrp determines if the device is configured with transmit +* VLAN stripping on the transmit channel. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return +* - TRUE if the device is configured with +* VLAN stripping on the Transmit channel. +* - FALSE if the device is NOT configured with +* VLAN stripping on the Transmit channel. +* +* @note C-style signature: +* u32 XAxiEthernet_IsTxVlanStrp(XAxiEthernet *InstancePtr) +* +*****************************************************************************/ +#define XAxiEthernet_IsTxVlanStrp(InstancePtr) \ + (((InstancePtr)->Config.TxVlanStrp) ? TRUE : FALSE) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsRxVlanStrp determines if the device is configured with receive +* VLAN stripping on the receive channel. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return +* - TRUE if the device is configured with +* VLAN stripping on the Receive channel. +* - FALSE if the device is NOT configured with +* VLAN stripping on the Receive channel. +* +* @note C-style signature: +* u32 XAxiEthernet_IsRxVlanTran(XAxiEthernet *InstancePtr) +* + *****************************************************************************/ +#define XAxiEthernet_IsRxVlanStrp(InstancePtr) \ + (((InstancePtr)->Config.RxVlanStrp) ? TRUE : FALSE) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsTxVlanTran determines if the device is configured with +* transmit VLAN translation on the transmit channel. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return +* - TRUE if the device is configured with +* VLAN translation on the Transmit channel. +* - FALSE if the device is NOT configured with +* VLAN translation on the Transmit channel. +* +* @note C-style signature: +* u32 XAxiEthernet_IsTxVlanTran(XAxiEthernet *InstancePtr) +* +*****************************************************************************/ +#define XAxiEthernet_IsTxVlanTran(InstancePtr) \ + (((InstancePtr)->Config.TxVlanTran) ? TRUE : FALSE) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsRxVlanTran determines if the device is configured with receive +* VLAN translation on the receive channel. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return +* - TRUE if the device is configured with +* VLAN translation on the Receive channel. +* - FALSE if the device is NOT configured with +* VLAN translation on the Receive channel. +* +* @note C-style signature: +* u32 XAxiEthernet_IsRxVlanTran(XAxiEthernet *InstancePtr) +* +*****************************************************************************/ +#define XAxiEthernet_IsRxVlanTran(InstancePtr) \ + (((InstancePtr)->Config.RxVlanTran) ? TRUE : FALSE) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsTxVlanTag determines if the device is configured with transmit +* VLAN tagging on the transmit channel. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return +* - TRUE if the device is configured with +* VLAN tagging on the Transmit channel. +* - FALSE if the device is NOT configured with +* VLAN tagging on the Transmit channel. +* +* @note C-style signature: +* u32 XAxiEthernet_IsTxVlanTag(XAxiEthernet *InstancePtr) +* +*****************************************************************************/ +#define XAxiEthernet_IsTxVlanTag(InstancePtr) \ + (((InstancePtr)->Config.TxVlanTag) ? TRUE : FALSE) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsRxVlanTag determines if the device is configured with receive +* VLAN tagging on the receive channel. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return +* - TRUE if the device is configured with +* VLAN tagging on the Receive channel. +* - FALSE if the device is NOT configured with +* VLAN tagging on the Receive channel. +* +* @note C-style signature: +* u32 XAxiEthernet_IsRxVlanTag(XAxiEthernet *InstancePtr) +* + *****************************************************************************/ +#define XAxiEthernet_IsRxVlanTag(InstancePtr) \ + (((InstancePtr)->Config.RxVlanTag) ? TRUE : FALSE) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_GetTemacType returns the Axi Ethernet type of the core. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return +* - Returns the values of TemacType, which can be +* XAE_SOFT_TEMAC_10_100_MBPS (0) for Soft Temac Core with +* speed 10/100 Mbps. +* XAE_SOFT_TEMAC_10_100_1000_MBPS (1) for Soft Temac core with +* speed 10/100/1000 Mbps +* XAE_HARD_TEMC (2) for Hard Temac Core for Virtex-6 +* +* @note C-style signature: +* u32 XAxiEthernet_GetTemacType(XAxiEthernet *InstancePtr) +* + *****************************************************************************/ +#define XAxiEthernet_GetTemacType(InstancePtr) \ + ((InstancePtr)->Config.TemacType) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsAvbConfigured returns determines if Ethernet AVB.is configured +* in the harwdare or not. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return +* - TRUE if the device is configured with +* Ethernet AVB. +* - FALSE if the device is NOT configured with +* Ethernet AVB. +* +* @note C-style signature: +* u32 XAxiEthernet_IsAvbConfigured(XAxiEthernet *InstancePtr) +* + *****************************************************************************/ +#define XAxiEthernet_IsAvbConfigured(InstancePtr) \ + (((InstancePtr)->Config.Avb) ? TRUE : FALSE) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsSgmiiOverLvdsEnabled determines if SGMII over LVDS is enabled +* in the harwdare or not. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return +* - TRUE if the device is configured with +* SGMII over LVDS. +* - FALSE if the device is NOT configured with +* SGMII over LVDS. +* +* @note C-style signature: +* u32 XAxiEthernet_IsSgmiiOverLvdsEnabled(XAxiEthernet *InstancePtr) +* + *****************************************************************************/ +#define XAxiEthernet_IsSgmiiOverLvdsEnabled(InstancePtr) \ + (((InstancePtr)->Config.EnableSgmiiOverLvds) ? TRUE : FALSE) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsStatsConfigured returns determines if Statistics gathering. +* is configured in the harwdare or not. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return +* - TRUE if the device is configured with +* statistics gathering. +* - FALSE if the device is NOT configured with +* statistics gathering. +* +* @note C-style signature: +* u32 XAxiEthernet_IsStatsConfigured(XAxiEthernet *InstancePtr) +* + *****************************************************************************/ +#define XAxiEthernet_IsStatsConfigured(InstancePtr) \ + (((InstancePtr)->Config.Stats) ? TRUE : FALSE) + +/************************** Function Prototypes ******************************/ + +/* + * Initialization functions in xaxiethernet.c + */ +int XAxiEthernet_CfgInitialize(XAxiEthernet *InstancePtr, + XAxiEthernet_Config *CfgPtr,u32 VirtualAddress); +void XAxiEthernet_Start(XAxiEthernet *InstancePtr); +void XAxiEthernet_Stop(XAxiEthernet *InstancePtr); +void XAxiEthernet_Reset(XAxiEthernet *InstancePtr); + +/* + * Initialization functions in xaxitemac_sinit.c + */ +XAxiEthernet_Config *XAxiEthernet_LookupConfig(u16 DeviceId); + +/* + * MAC configuration/control functions in xaxitemac_control.c + */ +int XAxiEthernet_SetOptions(XAxiEthernet *InstancePtr, u32 Options); +int XAxiEthernet_ClearOptions(XAxiEthernet *InstancePtr, u32 Options); +u32 XAxiEthernet_GetOptions(XAxiEthernet *InstancePtr); + +int XAxiEthernet_SetMacAddress(XAxiEthernet *InstancePtr, void *AddressPtr); +void XAxiEthernet_GetMacAddress(XAxiEthernet *InstancePtr, void *AddressPtr); + +int XAxiEthernet_SetMacPauseAddress(XAxiEthernet *InstancePtr, + void *AddressPtr); +void XAxiEthernet_GetMacPauseAddress(XAxiEthernet *InstancePtr, + void *AddressPtr); +int XAxiEthernet_SendPausePacket(XAxiEthernet *InstancePtr, u16 PauseValue); + +int XAxiEthernet_GetSgmiiStatus(XAxiEthernet *InstancePtr, u16 *SpeedPtr); +int XAxiEthernet_GetRgmiiStatus(XAxiEthernet *InstancePtr, u16 *SpeedPtr, + int *IsFullDuplexPtr, int *IsLinkUpPtr); +u16 XAxiEthernet_GetOperatingSpeed(XAxiEthernet *InstancePtr); +int XAxiEthernet_SetOperatingSpeed(XAxiEthernet *InstancePtr, u16 Speed); + +void XAxiEthernet_SetBadFrmRcvOption(XAxiEthernet *InstancePtr); +void XAxiEthernet_ClearBadFrmRcvOption(XAxiEthernet *InstancePtr); + +void XAxiEthernet_DisableControlFrameLenCheck(XAxiEthernet *InstancePtr); +void XAxiEthernet_EnableControlFrameLenCheck(XAxiEthernet *InstancePtr); + +void XAxiEthernet_PhySetMdioDivisor(XAxiEthernet *InstancePtr, u8 Divisor); +void XAxiEthernet_PhyRead(XAxiEthernet *InstancePtr, u32 PhyAddress, + u32 RegisterNum, u16 *PhyDataPtr); +void XAxiEthernet_PhyWrite(XAxiEthernet *InstancePtr, u32 PhyAddress, + u32 RegisterNum, u16 PhyData); +int XAxiEthernet_MulticastAdd(XAxiEthernet *InstancePtr, void *AddressPtr, + int Entry); +void XAxiEthernet_MulticastGet(XAxiEthernet *InstancePtr, void *AddressPtr, + int Entry); +int XAxiEthernet_MulticastClear(XAxiEthernet *InstancePtr, int Entry); + +int XAxiEthernet_SetTpid(XAxiEthernet *InstancePtr, u16 Tpid, u8 Entry); +int XAxiEthernet_ClearTpid(XAxiEthernet *InstancePtr, u8 Entry); +void XAxiEthernet_GetTpid(XAxiEthernet *InstancePtr, u16 *TpidPtr, u8 Entry); + +int XAxiEthernet_SetVTagMode(XAxiEthernet *InstancePtr, u32 Mode, int Dir); +void XAxiEthernet_GetVTagMode(XAxiEthernet *InstancePtr, u8 *ModePtr, int Dir); + +int XAxiEthernet_SetVStripMode(XAxiEthernet *InstancePtr, u32 Mode, int Dir); +void XAxiEthernet_GetVStripMode(XAxiEthernet *InstancePtr, u8 *ModePtr, + int Dir); + +int XAxiEthernet_SetVTagValue(XAxiEthernet *InstancePtr, u32 VTagValue, + int Dir); +void XAxiEthernet_GetVTagValue(XAxiEthernet *InstancePtr, u32 *VTagValuePtr, + int Dir); + +int XAxiEthernet_SetVidTable(XAxiEthernet *InstancePtr, u32 Entry, u32 Vid, + u8 Strip, u8 Tag, int Dir); +void XAxiEthernet_GetVidTable(XAxiEthernet *InstancePtr, u32 Entry, u32 *VidPtr, + u8 *StripPtr, u8 *TagPtr, int Dir); + +int XAxiEthernet_AddExtMulticastGroup(XAxiEthernet *InstancePtr, + void *AddressPtr); +int XAxiEthernet_ClearExtMulticastGroup(XAxiEthernet *InstancePtr, + void *AddressPtr); +int XAxiEthernet_GetExtMulticastGroup(XAxiEthernet *InstancePtr, + void *AddressPtr); +void XAxiEthernet_DumpExtMulticastGroup(XAxiEthernet *InstancePtr); + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ diff --git a/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet_control.c b/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet_control.c new file mode 100644 index 00000000..293cb200 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet_control.c @@ -0,0 +1,1712 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2015 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/** +* +* @file xaxiethernet_control.c +* +* This file has driver APIs related to the controlling of the extended +* features of the AXI Ethernet device. Please note that APIs for turning on/off +* any of the driver features are present in axiethernet.c. This file takes care +* of controlling these features. +* - Normal/extended multicast filtering +* - Normal/extended VLAN features +* - RGMII/SGMII features +* +* See xaxiethernet.h for a detailed description of the driver. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a asa  6/30/10 First release based on the ll temac driver
+* 
+*****************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xaxiethernet.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + + +/************************** Variable Definitions *****************************/ + +/*****************************************************************************/ +/** +* XAxiEthernet_MulticastAdd adds the Ethernet address, AddressPtr to the +* Axi Ethernet device's multicast filter list, at list index Entry. The +* address referenced by AddressPtr may be of any unicast, multicast, or +* broadcast address form. The hardware for the Axi Ethernet device can hold up +* to XAE_MULTI_MAT_ENTRIES addresses in this filter list.

+* +* The device must be stopped to use this function.

+* +* Once an Ethernet address is programmed, the Axi Ethernet device will begin +* receiving data sent from that address. The Axi Ethernet hardware does not +* have a control bit to disable multicast filtering. The only way to prevent +* the Axi Ethernet device from receiving messages from an Ethernet address in +* the Multicast Address Table (MAT) is to clear it with +* XAxiEthernet_MulticastClear(). +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param AddressPtr is a pointer to the 6-byte Ethernet address to set. +* The previous address at the location Entry (if any) is +* overwritten with the value at AddressPtr. +* @param Entry is the hardware storage location to program this address +* and must be between 0 to (XAE_MULTI_MAT_ENTRIES - 1). +* +* @return +* - XST_SUCCESS on successful completion. +* - XST_DEVICE_IS_STARTED.if the Axi Ethernet device is not +* stopped. +* +* @note +* +* This routine works only with normal multicast filtering feature. A maximum +* of 4 multicast addresses can be stored in the HW provided multicast table. +* +* To use the extended multicast feature, extended multicast filtering must +* be enabled by using driver API XAxiEthernet_SetOptions with proper option +* fields set. Once extended multicast filtering is enabled, the APIs +* XAxiEthernet_[Add|Clear|Get]ExtMulticastGroup() must be used to manage +* multicast address groups. +* +******************************************************************************/ +int XAxiEthernet_MulticastAdd(XAxiEthernet *InstancePtr, void *AddressPtr, + int Entry) +{ + u32 Af0Reg; + u32 Af1Reg; + u32 FmiReg; + u8 *Aptr = (u8 *) AddressPtr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(AddressPtr != NULL); + Xil_AssertNonvoid(Entry < XAE_MULTI_MAT_ENTRIES); + + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_MulticastAdd\n"); + + /* The device must be stopped before clearing the multicast hash + * table. + */ + if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_MulticastAdd: returning DEVICE_IS_STARTED\n"); + return (XST_DEVICE_IS_STARTED); + } + + /* Set MAC bits [31:0] */ + Af0Reg = Aptr[0]; + Af0Reg |= Aptr[1] << 8; + Af0Reg |= Aptr[2] << 16; + Af0Reg |= Aptr[3] << 24; + + /* Set MAC bits [47:32] */ + Af1Reg = Aptr[4]; + Af1Reg |= Aptr[5] << 8; + + + FmiReg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_FMI_OFFSET); + FmiReg &= 0xFFFFFF00; + FmiReg |= (Entry); + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_FMI_OFFSET, FmiReg); + + /* Add in MAT address */ + xdbg_printf(XDBG_DEBUG_GENERAL, "Setting MAT entry: %d\n", Entry); + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_AF0_OFFSET, Af0Reg); + + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_AF1_OFFSET, Af1Reg); + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** +* XAxiEthernet_MulticastGet gets the Ethernet address stored at +* index Entry in the Axi Ethernet device's multicast filter list.

+* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param AddressPtr references the memory buffer to store the retrieved +* Ethernet address. This memory buffer must be at least 6 bytes +* in length. +* @param Entry is the hardware storage location from which to retrieve +* the address and must be between 0 to (XAE_MULTI_MAT_ENTRIES - 1) +* +* @return None. +* +* @note +* +* This routine works only with normal multicast filtering feature. A maximum +* of 4 multicast addresses can be stored in the HW provided multicast table. +* +* To use the extended multicast feature, extended multicast filtering must +* be enabled by using driver API XAxiEthernet_SetOptions with proper option +* fields set. Once extended multicast filtering is enabled, the APIs +* XAxiEthernet_[Add|Clear|Get]ExtMulticastGroup() must be used to manage +* multicast address groups. +* +******************************************************************************/ +void XAxiEthernet_MulticastGet(XAxiEthernet *InstancePtr, void *AddressPtr, + int Entry) +{ + u32 Af0Reg; + u32 Af1Reg; + u32 FmiReg; + u8 *Aptr = (u8 *) AddressPtr; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertVoid(AddressPtr != NULL); + Xil_AssertVoid(Entry < XAE_MULTI_MAT_ENTRIES); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_MulticastGet\n"); + + + FmiReg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_FMI_OFFSET); + FmiReg &= 0xFFFFFF00; + FmiReg |= (Entry); + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_FMI_OFFSET, FmiReg); + + + Af0Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_AF0_OFFSET); + Af1Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_AF1_OFFSET); + + /* Copy the address to the user buffer */ + Aptr[0] = (u8) Af0Reg; + Aptr[1] = (u8) (Af0Reg >> 8); + Aptr[2] = (u8) (Af0Reg >> 16); + Aptr[3] = (u8) (Af0Reg >> 24); + Aptr[4] = (u8) Af1Reg; + Aptr[5] = (u8) (Af1Reg >> 8); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_MulticastGet: done\n"); +} + +/*****************************************************************************/ +/** +* XAxiEthernet_MulticastClear clears the Ethernet address stored at index +* Entry in the Axi Ethernet device's multicast filter list.

+* +* The device must be stopped to use this function.

+* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param Entry is the HW storage location used when this address was +* added. It must be between 0 to (XAE_MULTI_MAT_ENTRIES - 1). +* +* @return +* - XST_SUCCESS on successful completion. +* - XST_DEVICE_IS_STARTED.if the Axi Ethernet device is not +* stopped. +* +* @note +* +* This routine works only with normal multicast filtering feature. A maximum +* of 4 multicast addresses can be stored in the HW provided multicast table. +* +* To use the extended multicast feature, extended multicast filtering must +* be enabled by using driver API XAxiEthernet_SetOptions with proper option +* fields set. Once extended multicast filtering is enabled, the APIs +* XAxiEthernet_[Add|Clear|Get]ExtMulticastGroup() must be used to manage +* multicast address groups. +* +******************************************************************************/ +int XAxiEthernet_MulticastClear(XAxiEthernet *InstancePtr, int Entry) +{ + u32 FmiReg; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(Entry < XAE_MULTI_MAT_ENTRIES); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_MulticastClear\n"); + + /* + * The device must be stopped before clearing the multicast hash + * table. + */ + if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_MulticastClear:returning DEVICE_IS_STARTED\n"); + return (XST_DEVICE_IS_STARTED); + } + + FmiReg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_FMI_OFFSET); + FmiReg &= 0xFFFFFF00; + FmiReg |= (Entry); + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_FMI_OFFSET, FmiReg); + + + /* Clear the entry by writing 0:0:0:0:0:0 to it */ + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_AF0_OFFSET, 0); + + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_AF1_OFFSET, 0); + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_MulticastClear: returning SUCCESS\n"); + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** +* XAxiEthernet_SetMacPauseAddress sets the MAC address used for pause frames +* to AddressPtr. AddressPtr will be the address the Axi Ethernet +* device will recognize as being for pause frames. Pause frames transmitted +* with XAxiEthernet_SendPausePacket() will also use this address. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param AddressPtr is a pointer to the 6-byte Ethernet address to set. +* +* @return +* - XST_SUCCESS on successful completion. +* - XST_DEVICE_IS_STARTED if the Axi Ethernet device is not +* stopped. +* +* @note None. +* +******************************************************************************/ +int XAxiEthernet_SetMacPauseAddress(XAxiEthernet *InstancePtr, + void *AddressPtr) +{ + u32 MacAddr; + u8 *Aptr = (u8 *) AddressPtr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(AddressPtr != NULL); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_SetMacPauseAddress\n"); + + /* Be sure device has been stopped */ + if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_SetMacPauseAddress:returning DEVICE_IS_STARTED\n"); + return (XST_DEVICE_IS_STARTED); + } + + /* Set the MAC bits [31:0] in RCW0 register */ + MacAddr = Aptr[0]; + MacAddr |= Aptr[1] << 8; + MacAddr |= Aptr[2] << 16; + MacAddr |= Aptr[3] << 24; + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_RCW0_OFFSET, MacAddr); + + /* RCW1 contains other info that must be preserved */ + MacAddr = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_RCW1_OFFSET); + MacAddr &= ~XAE_RCW1_PAUSEADDR_MASK; + + /* Set MAC bits [47:32] */ + MacAddr |= Aptr[4]; + MacAddr |= Aptr[5] << 8; + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_RCW1_OFFSET, MacAddr); + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_SetMacPauseAddress: returning SUCCESS\n"); + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** +* XAxiEthernet_GetMacPauseAddress gets the MAC address used for pause frames +* for the Axi Ethernet device specified by InstancePtr. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param AddressPtr references the memory buffer to store the retrieved +* MAC address. This memory buffer must be at least 6 bytes in +* length. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XAxiEthernet_GetMacPauseAddress(XAxiEthernet *InstancePtr, + void *AddressPtr) +{ + u32 MacAddr; + u8 *Aptr = (u8 *) AddressPtr; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertVoid(AddressPtr != NULL); + + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_SetMacPauseAddress\n"); + + /* Read MAC bits [31:0] in ERXC0 */ + MacAddr = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_RCW0_OFFSET); + Aptr[0] = (u8) MacAddr; + Aptr[1] = (u8) (MacAddr >> 8); + Aptr[2] = (u8) (MacAddr >> 16); + Aptr[3] = (u8) (MacAddr >> 24); + + /* Read MAC bits [47:32] in RCW1 */ + MacAddr = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_RCW1_OFFSET); + Aptr[4] = (u8) MacAddr; + Aptr[5] = (u8) (MacAddr >> 8); + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_SetMacPauseAddress: done\n"); +} + +/*****************************************************************************/ +/** +* XAxiEthernet_SendPausePacket sends a pause packet with the value of +* PauseValue. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param PauseValue is the pause value in units of 512 bit times. +* +* @return +* - XST_SUCCESS on successful completion. +* - XST_DEVICE_IS_STARTED if the Axi Ethernet device is not +* stopped. +* +* @note None. +* +******************************************************************************/ +int XAxiEthernet_SendPausePacket(XAxiEthernet *InstancePtr, u16 PauseValue) +{ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_SetMacPauseAddress\n"); + + /* Make sure device is ready for this operation */ + if (InstancePtr->IsStarted != XIL_COMPONENT_IS_STARTED) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_SendPausePacket:returning DEVICE_IS_STOPPED\n"); + return (XST_DEVICE_IS_STOPPED); + } + + /* Send flow control frame */ + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, XAE_TPF_OFFSET, + (u32) PauseValue & XAE_TPF_TPFV_MASK); + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_SendPausePacket: returning SUCCESS\n"); + return (XST_SUCCESS); +} + +/*****************************************************************************/ +/** +* XAxiEthernet_GetSgmiiStatus get the state of the link when using the SGMII +* media interface. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param SpeedPtr references the location to store the result, which is +* the auto negotiated link speed in units of Mbits/sec, either 0, +* 10, 100, or 1000. +* +* @return +* - XST_SUCCESS on successful completion. +* - XST_NO_FEATURE if the Axi Ethernet device is not using an +* SGMII interface, +* +* @note Currently SGMII PHY does not support half duplex mode. +* +******************************************************************************/ +int XAxiEthernet_GetSgmiiStatus(XAxiEthernet *InstancePtr, u16 *SpeedPtr) +{ + int PhyType; + u32 EgmicReg; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(SpeedPtr != NULL); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_GetSgmiiStatus\n"); + + /* Make sure PHY is SGMII */ + PhyType = XAxiEthernet_GetPhysicalInterface(InstancePtr); + if (PhyType != XAE_PHY_TYPE_SGMII) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_GetSgmiiStatus: returning NO_FEATURE\n"); + return (XST_NO_FEATURE); + } + + /* Get the current contents of RGMII/SGMII config register */ + EgmicReg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_PHYC_OFFSET); + + /* Extract speed */ + switch (EgmicReg & XAE_PHYC_SGMIILINKSPEED_MASK) { + case XAE_PHYC_SGLINKSPD_10: + *SpeedPtr = XAE_SPEED_10_MBPS; + break; + + case XAE_PHYC_SGLINKSPD_100: + *SpeedPtr = XAE_SPEED_100_MBPS; + break; + + case XAE_PHYC_SGLINKSPD_1000: + *SpeedPtr = XAE_SPEED_1000_MBPS; + break; + + default: + *SpeedPtr = 0; + } + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_GetSgmiiStatus: returning SUCCESS\n"); + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** +* XAxiEthernet_GetRgmiiStatus get the state of the link when using the RGMII +* media interface. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param SpeedPtr references the location to store the result, which is +* the auto negotiated link speed in units of Mbits/sec, +* either 0, 10, 100, or 1000. +* @param IsFullDuplexPtr references the value that is set by this +* function to indicate full duplex operation. +* IsFullDuplexPtr is set to TRUE when the RGMII link is +* operating in full duplex mode, otherwise it is set to FALSE. +* @param IsLinkUpPtr references the value that is set by this function +* to indicate the link status.IsLinkUpPtr is set to TRUE +* when the RGMII link up, otherwise it is set to FALSE. +* +* @return +* - XST_SUCCESS on successful completion. +* - XST_NO_FEATURE if the Axi Ethernet device is not using an +* RGMII interface, +* +* @note None. +* +******************************************************************************/ +int XAxiEthernet_GetRgmiiStatus(XAxiEthernet *InstancePtr, u16 *SpeedPtr, + int *IsFullDuplexPtr, int *IsLinkUpPtr) +{ + int PhyType; + u32 EgmicReg; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(SpeedPtr != NULL); + Xil_AssertNonvoid(IsFullDuplexPtr != NULL); + Xil_AssertNonvoid(IsLinkUpPtr != NULL); + + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_GetRgmiiStatus\n"); + + /* Make sure PHY is RGMII */ + PhyType = XAxiEthernet_GetPhysicalInterface(InstancePtr); + if ((PhyType != XAE_PHY_TYPE_RGMII_1_3) && + (PhyType != XAE_PHY_TYPE_RGMII_2_0)) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_GetRgmiiStatus: returning NO_FEATURE\n"); + return (XST_NO_FEATURE); + } + + /* Get the current contents of RGMII/SGMII config register */ + EgmicReg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_PHYC_OFFSET); + + /* Extract speed */ + switch (EgmicReg & XAE_PHYC_RGMIILINKSPEED_MASK) { + case XAE_PHYC_RGLINKSPD_10: + *SpeedPtr = XAE_SPEED_10_MBPS; + break; + + case XAE_PHYC_RGLINKSPD_100: + *SpeedPtr = XAE_SPEED_100_MBPS; + break; + + case XAE_PHYC_RGLINKSPD_1000: + *SpeedPtr = XAE_SPEED_1000_MBPS; + break; + + default: + *SpeedPtr = 0; + } + + /* Extract duplex and link status */ + if (EgmicReg & XAE_PHYC_RGMIIHD_MASK) { + *IsFullDuplexPtr = FALSE; + } else { + *IsFullDuplexPtr = TRUE; + } + + if (EgmicReg & XAE_PHYC_RGMIILINK_MASK) { + *IsLinkUpPtr = TRUE; + } else { + *IsLinkUpPtr = FALSE; + } + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_GetRgmiiStatus: returning SUCCESS\n"); + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** +* XAxiEthernet_SetTpid sets the VLAN Tag Protocol Identifier(TPID). +* +* Four values can be configured - 0x8100, 0x9100, 0x9200, 0x88A8. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param Tpid is a hex value to be added to the TPID table. The four +* values that can be added are 0x8100, 0x9100, 0x9200, 0x88A8. +* @param Entry is the hardware storage location to program this address +* and must be between 0..XAE_TPID_MAX_ENTRIES. +* +* @return +* - XST_SUCCESS on successful completion. +* - XST_DEVICE_IS_STARTED, if the Axi Ethernet device is not +* stopped. +* - XST_NO_FEATURE if the Axi Ethernet does not enable or have +* the VLAN tag capability. +* - XST_INVALID_PARAM if Tpid is not one of supported values. +* +* @note The device must be stopped to use this function. +* +*****************************************************************************/ +int XAxiEthernet_SetTpid(XAxiEthernet *InstancePtr, u16 Tpid, u8 Entry) +{ + u32 RegTpid; + u32 RegTpidOffset; + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(Entry < XAE_TPID_MAX_ENTRIES); + + /* The device must be stopped before modify VLAN TPID */ + if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_SetTpid: returning DEVICE_IS_STARTED\n"); + return (XST_DEVICE_IS_STARTED); + } + + /* Check hw capability */ + if (!XAxiEthernet_IsExtFuncCap(InstancePtr)) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_SetTpid: returning DEVICE_NO_FEATURE\n"); + return (XST_NO_FEATURE); + } + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_SetTpid\n"); + + /* Verify TPID */ + switch (Tpid) { + case 0x8100: + case 0x88a8: + case 0x9100: + case 0x9200: + break; + default: + return (XST_INVALID_PARAM); + } + + /* Determine which register to operate on */ + if (Entry < 2) { + RegTpidOffset = XAE_TPID0_OFFSET; + } else { + RegTpidOffset = XAE_TPID1_OFFSET; + } + + RegTpid = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + RegTpidOffset); + + /* Determine upper/lower 16 bits to operate on */ + if (Entry % 2) { + /* Program HW */ + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + RegTpidOffset, (RegTpid & XAE_TPID_0_MASK) | + (Tpid << 16)); + } else { + /* Program HW */ + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + RegTpidOffset, (RegTpid & XAE_TPID_1_MASK) | + Tpid); + } + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_SetTpid: returning SUCCESS\n"); + return (XST_SUCCESS); +} + +/*****************************************************************************/ +/** +* XAxiEthernet_ClearTpid clears the VLAN Tag Protocol Identifier(TPID). +* +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param Entry is the hardware storage location to program this address +* and must be between 0..XAE_TPID_MAX_ENTRIES. +* +* @return +* - XST_SUCCESS on successful completion. +* - XST_DEVICE_IS_STARTED if the Axi Ethernet device is not +* stopped. +* - XST_NO_FEATURE if the Axi Ethernet does not enable or have +* the VLAN tag capability. +* +* @note The device must be stopped to use this function. +* +*****************************************************************************/ +int XAxiEthernet_ClearTpid(XAxiEthernet *InstancePtr, u8 Entry) +{ + u32 RegTpid; + u32 RegTpidOffset; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(Entry < XAE_TPID_MAX_ENTRIES); + + /* The device must be stopped before modify VLAN TPID */ + if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_ClearTpid: returning DEVICE_IS_STARTED\n"); + return (XST_DEVICE_IS_STARTED); + } + + /* Check hw capability */ + if (!XAxiEthernet_IsExtFuncCap(InstancePtr)) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_ClearTpid: returning DEVICE_NO_FEATURE\n"); + return (XST_NO_FEATURE); + } + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_ClearExtTpid\n"); + + /* Determine which register to operate on */ + if (Entry < 2) { + RegTpidOffset = XAE_TPID0_OFFSET; + } else { + RegTpidOffset = XAE_TPID1_OFFSET; + } + + RegTpid = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + RegTpidOffset); + + /* Determine upper/lower 16 bits to operate on */ + if (Entry % 2) { + /* Program HW */ + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + RegTpidOffset, (RegTpid & XAE_TPID_1_MASK)); + } else { + /* Program HW */ + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + RegTpidOffset, (RegTpid & XAE_TPID_0_MASK)); + } + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_ClearTpid: returning SUCCESS\n"); + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** +* XAxiEthernet_GetTpid gets the VLAN Tag Protocol Identifier value (TPID). +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param TpidPtr references the location to store the result. +* @param Entry is the hardware storage location to program this address +* and must be between 0..XAE_TPID_MAX_ENTRIES. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAxiEthernet_GetTpid(XAxiEthernet *InstancePtr, u16 *TpidPtr, u8 Entry) +{ + u32 RegTpid; + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertVoid(TpidPtr != NULL); + Xil_AssertVoid(Entry < XAE_TPID_MAX_ENTRIES); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_GetTpid\n"); + + if (Entry < 2) { + RegTpid = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_TPID0_OFFSET); + } else { + RegTpid = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_TPID1_OFFSET); + } + + if (Entry % 2) { + *TpidPtr = (RegTpid >> 16); + } else { + *TpidPtr = (RegTpid & XAE_TPID_0_MASK); + } + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_GetTpid: done\n"); +} + + +/*****************************************************************************/ +/** +* XAxiEthernet_SetVTagMode configures the VLAN tagging mode. +* +* Four modes can be configured, +* - XAE_VTAG_NONE for no tagging. +* - XAE_VTAG_ALL to tag all frames. +* - XAE_VTAG_EXISTED to tag already tagged frames. +* - XAE_VTAG_SELECT to tag selected already tagged frames based on VID +* value. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param Mode is the VLAN tag mode. Value must be between b'00-b'11. +* @param Dir must be either XAE_TX or XAE_RX. +* +* @return +* - XST_SUCCESS. on successful completion. +* - XST_DEVICE_IS_STARTED if the Axi Ethernet device is not +* stopped. +* - XST_NO_FEATURE if the Axi Ethernet does not enable or have +* the TX VLAN tag capability. +* - XST_INVALID_PARAM if Mode is not one of supported modes. +* +* @note +* +* The device must be stopped to use this function.

+* +* The fourth mode (specified by XAE_VTAG_SELECT) requires a method for +* specifying which tagged frames should receive an additional VLAN tag. +* The VLAN translation table 'tag enabled' is referenced. That configuration +* is handled in XAxiEthernet_SetVidTable(). +* +* Mode value shifting is handled in this function. No shifting is required to +* call this function. +* +*****************************************************************************/ +int XAxiEthernet_SetVTagMode(XAxiEthernet *InstancePtr, u32 Mode, int Dir) +{ + u32 RegRaf; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid((Dir == XAE_TX) || (Dir == XAE_RX)); + + /* The device must be stopped before modify TX VLAN Tag mode */ + if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_SetVTagMode:returning DEVICE_IS_STARTED\n"); + return (XST_DEVICE_IS_STARTED); + } + + /* Check hw capability */ + if (!XAxiEthernet_IsExtFuncCap(InstancePtr)) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_SetVTagMode: returning DEVICE_NO_FEATURE\n"); + return (XST_NO_FEATURE); + } + + /* Mode has to be one of the supported values */ + switch (Mode) { + case XAE_VTAG_NONE: + case XAE_VTAG_ALL: + case XAE_VTAG_EXISTED: + case XAE_VTAG_SELECT: + break; + default: + return (XST_INVALID_PARAM); + } + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_SetVTagMode\n"); + + /* Program HW */ + RegRaf = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_RAF_OFFSET); + /* Transmit direction */ + if (XAE_TX == Dir) { + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_RAF_OFFSET, ((RegRaf & ~XAE_RAF_TXVTAGMODE_MASK) | + (Mode << XAE_RAF_TXVTAGMODE_SHIFT))); + } else { /* Receive direction */ + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_RAF_OFFSET, ((RegRaf & ~XAE_RAF_RXVTAGMODE_MASK) | + (Mode << XAE_RAF_RXVTAGMODE_SHIFT))); + } + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_SetVTagMode: returning SUCCESS\n"); + + return (XST_SUCCESS); +} + +/*****************************************************************************/ +/** +* XAxiEthernet_GetVTagMode gets VLAN tagging mode. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be + worked on. +* @param ModePtr references the location to store the VLAN tag mode. +* Value is between b'00-b'11. +* @param Dir must be either XAE_TX or XAE_RX. +* +* @return None. +* +* @note +* +* The device must be stopped to use this function.

+* Mode value shifting is handled in this function. No shifting is required to +* call this function. +* +*****************************************************************************/ +void XAxiEthernet_GetVTagMode(XAxiEthernet *InstancePtr, u8 *ModePtr, int Dir) +{ + u32 RegRaf; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertVoid(ModePtr != NULL); + Xil_AssertVoid((Dir == XAE_TX) || (Dir == XAE_RX)); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_GetVTagMode\n"); + + /* Access HW configuration */ + RegRaf = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_RAF_OFFSET); + /* Transmit direction */ + if (XAE_TX == Dir) { + *ModePtr = (RegRaf & XAE_RAF_TXVTAGMODE_MASK) >> + XAE_RAF_TXVTAGMODE_SHIFT; + } else { /* Receive direction */ + *ModePtr = (RegRaf & XAE_RAF_RXVTAGMODE_MASK) >> + XAE_RAF_RXVTAGMODE_SHIFT; + } + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_GetVTagMode: done\n"); + +} + + +/*****************************************************************************/ +/** +* XAxiEthernet_SetVStripMode configures the VLAN strip mode. +* +* Three modes can be configured : +* - XAE_VSTRP_NONE for no stripping. +* - XAE_VSTRP_ALL to strip one tag from all frames. +* - XAE_VSTRP_SELECT to strip one tag from already selected tagged frames +* based on VID value. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param Mode is the VLAN strip mode. Value must be b'00, b'01, or b'11. +* @param Dir must be either XAE_TX or XAE_RX. +* +* @return +* - XST_SUCCESS on successful completion., returns XST_SUCCESS. +* - XST_DEVICE_IS_STARTED if the Axi Ethernet device is not +* stopped. +* - XST_NO_FEATURE if the Axi Ethernet does not enable or have +* the TX VLAN strip capability. +* - XST_INVALID_PARAM if Mode is not one of supported modes. +* +* @note +* +* The device must be stopped to use this function.

+* The third mode (specified by XAE_VSTRP_SELECT) requires a method for +* specifying which tagged frames should be stripped. The VLAN translation +* table 'stripped enabled' is referenced. That configuration is handled in +* XAxiEthernet_SetVidTable(). +* +* Mode value shifting is handled in this function. No shifting is required to +* call this function. +* +*****************************************************************************/ +int XAxiEthernet_SetVStripMode(XAxiEthernet *InstancePtr, u32 Mode, int Dir) +{ + u32 RegRaf; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid((Dir == XAE_TX) || (Dir == XAE_RX)); + + /* The device must be stopped before modify TX VLAN Tag mode */ + if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_SetVStripMode: returning DEVICE_IS_STARTED\n"); + return (XST_DEVICE_IS_STARTED); + } + + /* Check HW capability */ + if (!XAxiEthernet_IsExtFuncCap(InstancePtr)) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_SetVStripMode:returning DEVICE_NO_FEATURE\n"); + return (XST_NO_FEATURE); + } + + /* Mode has to be one of the supported values */ + switch (Mode) { + case XAE_VSTRP_NONE: + case XAE_VSTRP_ALL: + case XAE_VSTRP_SELECT: + break; + default: + return (XST_INVALID_PARAM); + } + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_SetStripMode\n"); + + /* Program HW */ + RegRaf = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_RAF_OFFSET); + /* Transmit direction */ + if (XAE_TX == Dir) { + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_RAF_OFFSET, ((RegRaf & ~XAE_RAF_TXVSTRPMODE_MASK) | + (Mode << XAE_RAF_TXVSTRPMODE_SHIFT))); + } else { /* Receive direction */ + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_RAF_OFFSET, ((RegRaf & ~XAE_RAF_RXVSTRPMODE_MASK) | + (Mode << XAE_RAF_RXVSTRPMODE_SHIFT))); + } + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_SetVStripMode:returning SUCCESS\n"); + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** +* XAxiEthernet_GetVStripMode gets the VLAN stripping mode. +* +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param ModePtr references the location to store the VLAN strip mode +* returned by this function. Value is b'00, b'01 or b'11. +* Refer XAE_VTSRAP_* in xaxiethernet.h file for the details. +* @param Dir must be either XAE_TX or XAE_RX. +* +* @return None. +* +* @note +* +* Mode value shifting is handled in this function. No shifting is required to +* call this function. +* +*****************************************************************************/ +void XAxiEthernet_GetVStripMode(XAxiEthernet *InstancePtr, u8 *ModePtr, + int Dir) +{ + u32 RegRaf; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertVoid(ModePtr != NULL); + Xil_AssertVoid((Dir == XAE_TX) || (Dir == XAE_RX)); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_GetVStripMode\n"); + + /* Access HW configuration */ + RegRaf = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_RAF_OFFSET); + /* Transmit direction */ + if (XAE_TX == Dir) { + *ModePtr = (RegRaf & XAE_RAF_TXVSTRPMODE_MASK) >> + XAE_RAF_TXVSTRPMODE_SHIFT; + } else { /* Receive direction */ + *ModePtr = (RegRaf & XAE_RAF_RXVSTRPMODE_MASK) >> + XAE_RAF_RXVSTRPMODE_SHIFT; + } + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_GetVStripMode: done\n"); +} + + +/*****************************************************************************/ +/** +* XAxiEthernet_SetVTagValue configures the VLAN tagging value. +* +* The device must be stopped to use this function.

+* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param VTagValue is the VLAN tag value to be configured. A 32bit +* value. +* TPID, one of the following 16 bit values, +* 0x8100, 0x88a8, 0x9100, 0x9200. +* Priority, 3 bits +* CFI, 1 bit +* VID, 12 bits +* @param Dir must be either XAE_TX or XAE_RX. +* +* @return +* - XST_SUCCESS on successful completion, returns . +* - XST_DEVICE_IS_STARTED if the Axi Ethernet device is not +* stopped. +* - XST_NO_FEATURE if the Axi Ethernet does not enable/have +* TX VLAN tag capability. +* - XST_INVALID_PARAM, if the TPID is not one the four supported +* values. +* +* @note +* +* The four supported TPID values are 0x8100, 0x88a8, 0x9100, 0x9200. +* XAxiEthernet_SetVTagValue performs verification on TPID only. +* +* Ethernet VLAN frames' VLAN type/length(2B) and tag control information(2B). +* Bit layout : bbbb bbbb bbbb bbbb bbb b bbbb bbbb bbbb +* \ / | | \ VID (12b) / +* \ / | CFI bit (1b) +* TPID (16b) priority bit (3b) +* +*****************************************************************************/ +int XAxiEthernet_SetVTagValue(XAxiEthernet *InstancePtr, u32 VTagValue, + int Dir) +{ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid((Dir == XAE_TX) || (Dir == XAE_RX)); + + /* The device must be stopped before modifying TX VLAN Tag value */ + if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_SetVTagValue:returning DEVICE_IS_STARTED\n"); + return (XST_DEVICE_IS_STARTED); + } + + /* Check HW capability */ + if (!XAxiEthernet_IsExtFuncCap(InstancePtr)) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_SetVTagValue:returning DEVICE_NO_FEATURE\n"); + return (XST_NO_FEATURE); + } + + /* Verify TPID */ + switch (VTagValue >> 16) { + case 0x8100: + case 0x88a8: + case 0x9100: + case 0x9200: + break; + default: + return (XST_INVALID_PARAM); + } + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_SetVTagValue\n"); + + /* Program HW */ + /* Transmit direction */ + if (XAE_TX == Dir) { + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_TTAG_OFFSET, VTagValue); + } else { /* Receive direction */ + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_RTAG_OFFSET, VTagValue); + } + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_SetVTagValue:returning SUCCESS\n"); + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** +* XAxiEthernet_GetVTagValue gets the configured VLAN tagging value. +* +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param VTagValuePtr references the location to store the result. +* Format is TPID, one of the following 16 bit values, +* 0x8100, 0x88a8, 0x9100, 0x9200. +* Priority, 3 bits +* CFI, 1 bit +* VID, 12 bits +* @param Dir must be either XAE_TX or XAE_RX. +* +* @return None. +* +* @note +* +* Ethernet VLAN frames' VLAN type/length(2B) and tag control information(2B). +* Bit layout : bbbb bbbb bbbb bbbb bbb b bbbb bbbb bbbb +* \ / | | \ VID (12b) / +* \ / | CFI bit (1b) +* TPID (16b) priority bit (3b) +* +*****************************************************************************/ +void XAxiEthernet_GetVTagValue(XAxiEthernet *InstancePtr, u32 *VTagValuePtr, + int Dir) +{ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertVoid(VTagValuePtr != NULL); + Xil_AssertVoid((Dir == XAE_TX) || (Dir == XAE_RX)); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_GetVTagValue\n"); + + /* Transmit direction */ + if (XAE_TX == Dir) { + *VTagValuePtr = XAxiEthernet_ReadReg + (InstancePtr->Config.BaseAddress, + XAE_TTAG_OFFSET); + } + else { /* Receive direction */ + *VTagValuePtr = XAxiEthernet_ReadReg( + InstancePtr->Config.BaseAddress, + XAE_RTAG_OFFSET); + } + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_GetVTagValue: done\n"); +} + + +/*****************************************************************************/ +/** +* XAxiEthernet_SetVidTable sets VID table includes new VLAN ID, strip +* and tag enable bits. +* +* The device must be stopped to use this function.

+* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param Entry is the hardware storage location/index to program updated +* VID value, strip, or tag value. +* The value must be between 0..0xFFF. +* @param Vid is updated/translated Vid value to be programmed. +* @param Strip is strip enable indication for Vid. +* @param Tag is tag enable indication for Vid. +* @param Dir must be either XAE_TX or XAE_RX. +* +* @return +* - XST_SUCCESS on successful completion. +* - XST_DEVICE_IS_STARTED if the Axi Ethernet device is not +* stopped. +* - XST_NO_FEATURE if the Axi Ethernet does not enable/have +* extended functionalities. +* +* @note +* +* The hardware requires the table to be 'indexed' with Entry and must be +* 0x000..0xFFF. +* +* Bits layout is bbbb bbbb bbbb b b +* VLAN ID (12b), | | +* | VLAN double tag enable bit +* VLAN strip enable bit +* +* To disable translation indexed by Entry, Set Vid = Entry. +* +*****************************************************************************/ +int XAxiEthernet_SetVidTable(XAxiEthernet *InstancePtr, u32 Entry, u32 Vid, + u8 Strip, u8 Tag, int Dir) +{ + u32 Reg; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(Entry <= XAE_MAX_VLAN_TABL_ENTRY); + Xil_AssertNonvoid((Dir == XAE_TX) || (Dir == XAE_RX)); + Xil_AssertNonvoid(Vid <= XAE_MAX_VLAN_TABL_ENTRY); + Xil_AssertNonvoid(Strip <= XAE_VLAN_TABL_STRP_FLD_LEN); + Xil_AssertNonvoid(Tag <= XAE_VLAN_TABL_TAG_FLD_LEN); + + /* The device must be stopped before modify TX VLAN Tag value */ + if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_SetVidTable:returning DEVICE_IS_STARTED\n"); + return (XST_DEVICE_IS_STARTED); + } + + /* Check HW capability */ + if (!XAxiEthernet_IsExtFuncCap(InstancePtr)) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_SetVidTable:returning DEVICE_NO_FEATURE\n"); + return (XST_NO_FEATURE); + } + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_SetVidTable\n"); + + /* Program HW */ + Reg = (Vid << XAE_VLAN_TABL_VID_START_OFFSET) | + (Strip << XAE_VLAN_TABL_STRP_STRT_OFFSET) | Tag; + /* Transmit direction */ + if (XAE_TX == Dir) { + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_TX_VLAN_DATA_OFFSET + + (Entry << XAE_VLAN_TABL_VID_START_OFFSET), Reg); + } else { /* Receive direction */ + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_RX_VLAN_DATA_OFFSET + + (Entry << XAE_VLAN_TABL_VID_START_OFFSET), Reg); + } + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_SetVidTable: returning SUCCESS\n"); + return (XST_SUCCESS); +} + +/*****************************************************************************/ +/** +* XAxiEthernet_GetVidTable gets VID table content includes new VLAN ID, strip +* and tag enable bits. +* +* The device must be stopped to use this function.

+* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param Entry is the hardware storage location/index to program +* updated VID value, strip, or tag value. The value must be +* between 0..0xFFF. +* @param VidPtr references the location to store the result. +* This function stores the Vid value indexed by Entry into +* this location. +* @param StripPtr references the location to store the result. +* This function stores the strip enable bit value indexed +* by Entry into this location. +* @param TagPtr references the location to store the result. This +* function stores the tag enable bit value indexed by Entry +* into this location. +* @param Dir must be either XAE_TX or XAE_RX. +* +* @return None. +* +* @note +* +* The hardware requires the table to be 'indexed' with Entry and +* must be 0x000..0xFFF. +* +* Bits layout is bbbb bbbb bbbb b b +* VLAN ID (12b), | | +* | VLAN double tag enable bit +* VLAN strip enable bit +* +*****************************************************************************/ +void XAxiEthernet_GetVidTable(XAxiEthernet *InstancePtr, u32 Entry, + u32 *VidPtr, u8 *StripPtr, u8 *TagPtr, int Dir) +{ + u32 Reg; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertVoid(Entry <= XAE_MAX_VLAN_TABL_ENTRY); + Xil_AssertVoid(VidPtr != NULL); + Xil_AssertVoid(StripPtr != NULL); + Xil_AssertVoid(TagPtr != NULL); + Xil_AssertVoid((Dir == XAE_TX) || (Dir == XAE_RX)); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_GetVidTable\n"); + + /* Transmit direction */ + if (XAE_TX == Dir) { + Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_TX_VLAN_DATA_OFFSET + + (Entry << XAE_VLAN_TABL_VID_START_OFFSET)); + } else { /* Receive direction */ + Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_RX_VLAN_DATA_OFFSET + + (Entry << XAE_VLAN_TABL_VID_START_OFFSET)); + } + + *VidPtr = (Reg >> XAE_VLAN_TABL_VID_START_OFFSET); + *StripPtr = (Reg >> XAE_VLAN_TABL_STRP_STRT_OFFSET) & + XAE_VLAN_TABL_STRP_ENTRY_MASK; + *TagPtr = Reg & XAE_VLAN_TABL_TAG_ENTRY_MASK; + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_GetVidTable: done\n"); +} + + +/*****************************************************************************/ +/** +* XAxiEthernet_AddExtMulticastGroup adds an entry to the multicast Ethernet +* address table. The new entry, represents a group of MAC addresses +* based on the contents of AddressPtr. AddressPtr is one member of the MAC +* address set in the newly added entry. +* +* The device must be stopped to use this function.

+* +* Once an Ethernet address is programmed, the Axi Ethernet device will begin +* receiving data sent from that address. The Axi Ethernet hardware does not +* have a control bit to disable multicast filtering. The only way to prevent +* the Axi Ethernet device from receiving messages from an Ethernet address in +* the multicast table is to clear it with +* XAxiEthernet_ClearExtMulticastGroup(). +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param AddressPtr is a pointer to the 6-byte Ethernet address to add. +* +* @return +* - XST_SUCCESS.on successful completion. +* - XST_DEVICE_IS_STARTED if the Axi Ethernet device is not +* stopped. +* - XST_INVALID_PARAM if the input MAC address is not between +* 01:00:5E:00:00:00 and 01:00:5E:7F:FF:FF per RFC1112. +* +* @note +* +* This routine consider all 2**23 possible multicast Ethernet addresses to be +* 8Mx1 bit or 1M bytes memory area. All defined multicast addresses are from +* 01.00.5E.00.00.00 to 01.00.5E.7F.FF.FF +* The most significant 25 bit out of 48 bit are static, so they will not be +* part of calculation. +* +* The hardware requires to 'index' with bit 22-8, 15 bits in +* total. The least significant byte/8 bits are considered a group. +* +* This API operates at a group (256 MAC addresses) for hardware to do the +* first layer address filtering. It is user's responsibility to provision +* this table appropriately. +* +*****************************************************************************/ +int XAxiEthernet_AddExtMulticastGroup(XAxiEthernet *InstancePtr, + void *AddressPtr) +{ + u8 *Aptr = (u8 *) AddressPtr; + u32 Loc; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(AddressPtr != NULL); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_AddExtMulticastGroup\n"); + + /* + * The device must be stopped before setting the multicast table. + */ + if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_AddExtMulticastGroup:returning DEVICE_IS_STARTED\n"); + + return (XST_DEVICE_IS_STARTED); + } + + /* Check HW capability */ + if (!XAxiEthernet_IsExtFuncCap(InstancePtr) || + !XAxiEthernet_IsExtMcastEnable(InstancePtr)) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_AddExtMulticastGroup:returning DEVICE_NO_FEATURE\n"); + return (XST_NO_FEATURE); + } + + /* + * Verify if address is a good/valid multicast address, between + * 01:00:5E:00:00:00 to 01:00:5E:7F:FF:FF per RFC1112. + * This address is referenced to be index to the table. + */ + if ((0x01 != Aptr[0]) || (0x00 != Aptr[1]) || (0x5e != Aptr[2]) || + (0x0 != (Aptr[3] & 0x80))) + return (XST_INVALID_PARAM); + + /* + * Program hardware table, index : bit 22-8. Bit 23 is 0, + * when passed the if statement above. + * note: if the index/bits changed, need to revisit calculation. + */ + Loc = Aptr[3]; + Loc = Loc << 8; + Loc |= Aptr[4]; + + /* Word aligned address access */ + Loc = Loc << 2; + + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_MCAST_TABLE_OFFSET + Loc, 0x01); + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_AddExtMulticastGroup: returning SUCCESS\n"); + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** +* XAxiEthernet_ClearExtMulticastGroup clears input multicast Ethernet address +* group from table. +* +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param AddressPtr is a pointer to the 6-byte Ethernet address to clear. +* +* @return +* - XST_SUCCESS on successful completion, returns XST_SUCCESS. +* - XST_DEVICE_IS_STARTED if the Axi Ethernet device is not +* stopped +* - XST_INVALID_PARAM if input MAC address is not between +* 01:00:5E:00:00:00 and 01:00:5E:7F:FF:FF per RFC1112. +* +* @note +* +* Please reference XAxiEthernet_AddExtMulticastGroup for multicast address +* index and bit value calculation. +* +* In table, hardware requires to 'index' with bit 22-8, 15 bits in +* total. The least significant byte/8 bits are considered a group. +* +* There is a scenario that might introduce issues: +* When multicast tables are programmed initially to accept +* 01:00:5E:12:34:56 and 01:00:5E:12:34:78 but later decided to clear +* 01:00:5E:12:34:78. Without validating all possible combinations at the +* indexed entry, multicast table might be misconfigured and drop +* frames. +* +* When clearing a multicast address table entry, note that a whole group of +* mac addresses will no longer be accepted - this because an entry in the +* table represents multiple(256) mac addresses. +* +* The device must be stopped to use this function.

+* This API operates at a group (256 MAC addresses) level for hardware to +* perform the first layer address filtering. It is user's responsibility to +* provision this table appropriately. +* +*****************************************************************************/ +int XAxiEthernet_ClearExtMulticastGroup(XAxiEthernet *InstancePtr, + void *AddressPtr) +{ + u8 *Aptr = (u8 *) AddressPtr; + u32 Loc; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(AddressPtr != NULL); + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_ClearExtMulticastGroup\n"); + + /* + * The device must be stopped before clearing the multicast table. + */ + if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_ClearExtMulticastGroup:returning DEVICE_IS_STARTED\n"); + return (XST_DEVICE_IS_STARTED); + } + + /* Check HW capability */ + if (!XAxiEthernet_IsExtFuncCap(InstancePtr) || + !XAxiEthernet_IsExtMcastEnable(InstancePtr)) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_ClearExtMulticastGroup:returning DEVICE_NO_FEATURE\n"); + return (XST_NO_FEATURE); + } + + /* + * Verify if address is a good/valid multicast address, between + * 01:00:5E:00:00:00 to 01:00:5E:7F:FF:FF per RFC1112. + * This address is referenced to be index to the table. + */ + if ((0x01 != Aptr[0]) || (0x00 != Aptr[1]) || (0x5e != Aptr[2]) || + (0x0 != (Aptr[3] & 0x80))) + return (XST_INVALID_PARAM); + + Loc = Aptr[3]; + Loc = Loc << 8; + Loc |= Aptr[4]; + + /* Word aligned address access */ + Loc = Loc << 2; + + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_MCAST_TABLE_OFFSET + Loc, 0x00); + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_ClearExtMulticastGroup: returning SUCCESS\n"); + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** +* XAxiEthernet_GetExtMulticastGroup returns whether the given Ethernet address +* group is stored in the table. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param AddressPtr is a pointer to the 6-byte Ethernet address. +* +* @return +* - TRUE if it is an acceptable multicast MAC address +* and the group is present in the table. +* - FALSE if it is not a valid multicast MAC address +* or the group was not found in the table. +* +* @note +* +* In the table, hardware requires to 'index' with bit 22-8, 15 bits in +* total. The least significant byte/8 bits are considered a group. +* This API operates at a group (256 MAC addresses) level. +* +*****************************************************************************/ +int XAxiEthernet_GetExtMulticastGroup(XAxiEthernet *InstancePtr, + void *AddressPtr) +{ + u8 *Aptr = (u8 *) AddressPtr; + u32 Loc; + u8 Bit; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid(AddressPtr != NULL); + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_GetExtMulticastGroup\n"); + + /* + * Verify if address is a good/valid multicast address, between + * 01:00:5E:00:00:00 to 01:00:5E:7F:FF:FF per RFC1112. + * This address is referenced to be index to the table. + */ + if ((0x01 != Aptr[0]) || (0x00 != Aptr[1]) || (0x5e != Aptr[2]) || + (0x0 != (Aptr[3] & 0x80))) + return (FALSE); + + Loc = Aptr[3]; + Loc = Loc << 8; + Loc |= Aptr[4]; + + /* + * Word aligned address access + */ + Loc = Loc << 2; + + Bit = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_MCAST_TABLE_OFFSET + Loc); + + if (Bit) { + return (TRUE); + } else { + return (FALSE); + } + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_GetExtMulticastGroup:done\n"); +} + + +/*****************************************************************************/ +/** +* XAxiEthernet_DumpExtMulticastGroup dumps ALL provisioned acceptable multicast +* MAC in the Axi Ethernet device's multicast table. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return None. +* +* @note +* +* Hardware requires to 'index' with bit 22-8, 15 bits in +* total. The least significant byte/8 bits are considered a set. +* +* This API operates at a set (256 MAC addresses) level. +* +*****************************************************************************/ +void XAxiEthernet_DumpExtMulticastGroup(XAxiEthernet *InstancePtr) +{ + u32 Loc; + u32 Index; + u8 Bit; + char MacAddr[6]; + + Xil_AssertVoid(InstancePtr != NULL); + + /* + * Pre-populated these bytes, we know and guarantee these if + * provisioned through the XAxiEthernet_AddExtMulticastGroup(). + */ + MacAddr[0] = 0x01; + MacAddr[1] = 0x00; + MacAddr[2] = 0x5E; + + for (Index = 0; Index < (1 << 15); Index++) { + MacAddr[3] = Index << 16; + MacAddr[4] = Index << 8; + MacAddr[5] = 0; + + Loc = MacAddr[3]; + Loc |= MacAddr[4] << 8; + + /* Word aligned address access */ + Loc = Loc << 2; + + Bit = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_MCAST_TABLE_OFFSET + Loc); + if (Bit) { + xdbg_printf(XDBG_DEBUG_GENERAL, + "%x:%x:%x:%x:%x:%x\n", MacAddr[5], MacAddr[4], + MacAddr[3], MacAddr[2], MacAddr[1], MacAddr[0]); + } + } +} diff --git a/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet_g.c b/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet_g.c new file mode 100644 index 00000000..39418a56 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet_g.c @@ -0,0 +1,64 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2015 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +#include "xparameters.h" +#include "xaxiethernet.h" + +/* +* The configuration table for devices +*/ + +XAxiEthernet_Config XAxiEthernet_ConfigTable[] = { + { + XPAR_AXIETHERNET_0_DEVICE_ID, + XPAR_AXIETHERNET_0_BASEADDR, + XPAR_AXIETHERNET_0_TEMAC_TYPE, + XPAR_AXIETHERNET_0_TXCSUM, + XPAR_AXIETHERNET_0_RXCSUM, + XPAR_AXIETHERNET_0_PHY_TYPE, + XPAR_AXIETHERNET_0_TXVLAN_TRAN, + XPAR_AXIETHERNET_0_RXVLAN_TRAN, + XPAR_AXIETHERNET_0_TXVLAN_TAG, + XPAR_AXIETHERNET_0_RXVLAN_TAG, + XPAR_AXIETHERNET_0_TXVLAN_STRP, + XPAR_AXIETHERNET_0_RXVLAN_STRP, + XPAR_AXIETHERNET_0_MCAST_EXTEND, + XPAR_AXIETHERNET_0_STATS, + XPAR_AXIETHERNET_0_AVB, + XPAR_AXIETHERNET_0_ENABLE_SGMII_OVER_LVDS, + XPAR_AXIETHERNET_0_INTR, + XPAR_AXIETHERNET_0_CONNECTED_TYPE, + XPAR_AXIETHERNET_0_CONNECTED_BASEADDR, + XPAR_AXIETHERNET_0_CONNECTED_FIFO_INTR, + 0xFF, + 0xFF + } +}; diff --git a/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet_hw.h b/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet_hw.h new file mode 100644 index 00000000..824c6968 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet_hw.h @@ -0,0 +1,960 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2015 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/** +* +* @file xaxiethernet_hw.h +* +* This header file contains identifiers and macros that can be used to access +* the Axi Ethernet device. The driver APIs/functions are defined in +* xaxiethernet.h. +* +* @note +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- ---------------------------------------------------------
+* 1.00a asa  6/30/10 First release for Axi Ethernet driver
+* 1.02a asa  2/16/11 Changes the value of XAE_LOOPS_TO_COME_OUT_OF_RST to
+*		     10000.
+* 2.00a asa  8/29/11 Added defines for Ability Reg, Identification Reg, Rx max
+*		     Frame and Tx Max Frame registers.
+*		     Changed define for TEMAC RGMII/SGMII Config (PHYC) Reg.
+* 
+ +******************************************************************************/ +#ifndef XAXIETHERNET_HW_H /* prevent circular inclusions */ +#define XAXIETHERNET_HW_H /* by using protection macros */ + +/***************************** Include Files *********************************/ + +#include "xdebug.h" + +#include "xil_io.h" +#include "xil_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************** Constant Definitions *****************************/ + +/* + * Register offset definitions. Unless otherwise noted, register access is + * 32 bit. + */ + +/** @name Axi Ethernet registers offset + * @{ + */ +#define XAE_RAF_OFFSET 0x00000000 /**< Reset and Address filter */ +#define XAE_TPF_OFFSET 0x00000004 /**< Tx Pause Frame */ +#define XAE_IFGP_OFFSET 0x00000008 /**< Tx Inter-frame gap adjustment*/ +#define XAE_IS_OFFSET 0x0000000C /**< Interrupt status */ +#define XAE_IP_OFFSET 0x00000010 /**< Interrupt pending */ +#define XAE_IE_OFFSET 0x00000014 /**< Interrupt enable */ +#define XAE_TTAG_OFFSET 0x00000018 /**< Tx VLAN TAG */ +#define XAE_RTAG_OFFSET 0x0000001C /**< Rx VLAN TAG */ +#define XAE_UAWL_OFFSET 0x00000020 /**< Unicast address word lower */ +#define XAE_UAWU_OFFSET 0x00000024 /**< Unicast address word upper */ +#define XAE_TPID0_OFFSET 0x00000028 /**< VLAN TPID0 register */ +#define XAE_TPID1_OFFSET 0x0000002C /**< VLAN TPID1 register */ + +/* + * Statistics Counter Registers are from offset 0x200 to 0x3FF + * They are defined from offset 0x200 to 0x34C in this device. + * The offsets from 0x350 to 0x3FF are reserved. + * The counters are 64 bit. + * The Least Significant Word (LSW) are stored in one 32 bit register and + * the Most Significant Word (MSW) are stored in one 32 bit register + */ +/* Start of Statistics Counter Registers Definitions */ +#define XAE_RXBL_OFFSET 0x00000200 /**< Received Bytes, LSW */ +#define XAE_RXBU_OFFSET 0x00000204 /**< Received Bytes, MSW */ +#define XAE_TXBL_OFFSET 0x00000208 /**< Transmitted Bytes, LSW */ +#define XAE_TXBU_OFFSET 0x0000020C /**< Transmitted Bytes, MSW */ +#define XAE_RXUNDRL_OFFSET 0x00000210 /**< Count of undersize(less than + * 64 bytes) frames received, + * LSW + */ +#define XAE_RXUNDRU_OFFSET 0x00000214 /**< Count of undersize(less than + * 64 bytes) frames received, + * MSW + */ +#define XAE_RXFRAGL_OFFSET 0x00000218 /**< Count of undersized(less + * than 64 bytes) and bad FCS + * frames received, LSW + */ +#define XAE_RXFRAGU_OFFSET 0x0000021C /**< Count of undersized(less + * than 64 bytes) and bad FCS + * frames received, MSW + */ +#define XAE_RX64BL_OFFSET 0x00000220 /**< Count of 64 bytes frames + * received, LSW + */ +#define XAE_RX64BU_OFFSET 0x00000224 /**< Count of 64 bytes frames + * received, MSW + */ +#define XAE_RX65B127L_OFFSET 0x00000228 /**< Count of 65-127 bytes + * Frames received, LSW + */ +#define XAE_RX65B127U_OFFSET 0x0000022C /**< Count of 65-127 bytes + * Frames received, MSW + */ +#define XAE_RX128B255L_OFFSET 0x00000230 /**< Count of 128-255 bytes + * Frames received, LSW + */ +#define XAE_RX128B255U_OFFSET 0x00000234 /**< Count of 128-255 bytes + * frames received, MSW + */ +#define XAE_RX256B511L_OFFSET 0x00000238 /**< Count of 256-511 bytes + * Frames received, LSW + */ +#define XAE_RX256B511U_OFFSET 0x0000023C /**< Count of 256-511 bytes + * frames received, MSW + */ +#define XAE_RX512B1023L_OFFSET 0x00000240 /**< Count of 512-1023 bytes + * frames received, LSW + */ +#define XAE_RX512B1023U_OFFSET 0x00000244 /**< Count of 512-1023 bytes + * frames received, MSW + */ +#define XAE_RX1024BL_OFFSET 0x00000248 /**< Count of 1024-MAX bytes + * frames received, LSW + */ +#define XAE_RX1024BU_OFFSET 0x0000024C /**< Count of 1024-MAX bytes + * frames received, MSW + */ +#define XAE_RXOVRL_OFFSET 0x00000250 /**< Count of oversize frames + * received, LSW + */ +#define XAE_RXOVRU_OFFSET 0x00000254 /**< Count of oversize frames + * received, MSW + */ +#define XAE_TX64BL_OFFSET 0x00000258 /**< Count of 64 bytes frames + * transmitted, LSW + */ +#define XAE_TX64BU_OFFSET 0x0000025C /**< Count of 64 bytes frames + * transmitted, MSW + */ +#define XAE_TX65B127L_OFFSET 0x00000260 /**< Count of 65-127 bytes + * frames transmitted, LSW + */ +#define XAE_TX65B127U_OFFSET 0x00000264 /**< Count of 65-127 bytes + * frames transmitted, MSW + */ +#define XAE_TX128B255L_OFFSET 0x00000268 /**< Count of 128-255 bytes + * frames transmitted, LSW + */ +#define XAE_TX128B255U_OFFSET 0x0000026C /**< Count of 128-255 bytes + * frames transmitted, MSW + */ +#define XAE_TX256B511L_OFFSET 0x00000270 /**< Count of 256-511 bytes + * frames transmitted, LSW + */ +#define XAE_TX256B511U_OFFSET 0x00000274 /**< Count of 256-511 bytes + * frames transmitted, MSW + */ +#define XAE_TX512B1023L_OFFSET 0x00000278 /**< Count of 512-1023 bytes + * frames transmitted, LSW + */ +#define XAE_TX512B1023U_OFFSET 0x0000027C /**< Count of 512-1023 bytes + * frames transmitted, MSW + */ +#define XAE_TX1024L_OFFSET 0x00000280 /**< Count of 1024-MAX bytes + * frames transmitted, LSW + */ +#define XAE_TX1024U_OFFSET 0x00000284 /**< Count of 1024-MAX bytes + * frames transmitted, MSW + */ +#define XAE_TXOVRL_OFFSET 0x00000288 /**< Count of oversize frames + * transmitted, LSW + */ +#define XAE_TXOVRU_OFFSET 0x0000028C /**< Count of oversize frames + * transmitted, MSW + */ +#define XAE_RXFL_OFFSET 0x00000290 /**< Count of frames received OK, + * LSW + */ +#define XAE_RXFU_OFFSET 0x00000294 /**< Count of frames received OK, + * MSW + */ +#define XAE_RXFCSERL_OFFSET 0x00000298 /**< Count of frames received with + * FCS error and at least 64 + * bytes, LSW + */ +#define XAE_RXFCSERU_OFFSET 0x0000029C /**< Count of frames received with + * FCS error and at least 64 + * bytes,MSW + */ +#define XAE_RXBCSTFL_OFFSET 0x000002A0 /**< Count of broadcast frames + * received, LSW + */ +#define XAE_RXBCSTFU_OFFSET 0x000002A4 /**< Count of broadcast frames + * received, MSW + */ +#define XAE_RXMCSTFL_OFFSET 0x000002A8 /**< Count of multicast frames + * received, LSW + */ +#define XAE_RXMCSTFU_OFFSET 0x000002AC /**< Count of multicast frames + * received, MSW + */ +#define XAE_RXCTRFL_OFFSET 0x000002B0 /**< Count of control frames + * received, LSW + */ +#define XAE_RXCTRFU_OFFSET 0x000002B4 /**< Count of control frames + * received, MSW + */ +#define XAE_RXLTERL_OFFSET 0x000002B8 /**< Count of frames received + * with length error, LSW + */ +#define XAE_RXLTERU_OFFSET 0x000002BC /**< Count of frames received + * with length error, MSW + */ +#define XAE_RXVLANFL_OFFSET 0x000002C0 /**< Count of VLAN tagged + * frames received, LSW + */ +#define XAE_RXVLANFU_OFFSET 0x000002C4 /**< Count of VLAN tagged frames + * received, MSW + */ +#define XAE_RXPFL_OFFSET 0x000002C8 /**< Count of pause frames received, + * LSW + */ +#define XAE_RXPFU_OFFSET 0x000002CC /**< Count of pause frames received, + * MSW + */ +#define XAE_RXUOPFL_OFFSET 0x000002D0 /**< Count of control frames + * received with unsupported + * opcode, LSW + */ +#define XAE_RXUOPFU_OFFSET 0x000002D4 /**< Count of control frames + * received with unsupported + * opcode, MSW + */ +#define XAE_TXFL_OFFSET 0x000002D8 /**< Count of frames transmitted OK, + * LSW + */ +#define XAE_TXFU_OFFSET 0x000002DC /**< Count of frames transmitted OK, + * MSW + */ +#define XAE_TXBCSTFL_OFFSET 0x000002E0 /**< Count of broadcast frames + * transmitted OK, LSW + */ +#define XAE_TXBCSTFU_OFFSET 0x000002E4 /**< Count of broadcast frames + * transmitted, MSW + */ +#define XAE_TXMCSTFL_OFFSET 0x000002E8 /**< Count of multicast frames + * transmitted, LSW + */ +#define XAE_TXMCSTFU_OFFSET 0x000002EC /**< Count of multicast frames + * transmitted, MSW + */ +#define XAE_TXUNDRERL_OFFSET 0x000002F0 /**< Count of frames transmitted + * underrun error, LSW + */ +#define XAE_TXUNDRERU_OFFSET 0x000002F4 /**< Count of frames transmitted + * underrun error, MSW + */ +#define XAE_TXCTRFL_OFFSET 0x000002F8 /**< Count of control frames + * transmitted, LSW + */ +#define XAE_TXCTRFU_OFFSET 0x000002FC /**< Count of control frames, + * transmitted, MSW + */ +#define XAE_TXVLANFL_OFFSET 0x00000300 /**< Count of VLAN tagged frames + * transmitted, LSW + */ +#define XAE_TXVLANFU_OFFSET 0x00000304 /**< Count of VLAN tagged + * frames transmitted, MSW + */ +#define XAE_TXPFL_OFFSET 0x00000308 /**< Count of pause frames + * transmitted, LSW + */ +#define XAE_TXPFU_OFFSET 0x0000030C /**< Count of pause frames + * transmitted, MSW + */ +#define XAE_TXSCL_OFFSET 0x00000310 /**< Single Collision Frames + * Transmitted OK, LSW + */ +#define XAE_TXSCU_OFFSET 0x00000314 /**< Single Collision Frames + * Transmitted OK, MSW + */ +#define XAE_TXMCL_OFFSET 0x00000318 /**< Multiple Collision Frames + * Transmitted OK, LSW + */ +#define XAE_TXMCU_OFFSET 0x0000031C /**< Multiple Collision Frames + * Transmitted OK, MSW + */ +#define XAE_TXDEFL_OFFSET 0x00000320 /**< Deferred Tx Frames, LSW */ +#define XAE_TXDEFU_OFFSET 0x00000324 /**< Deferred Tx Frames, MSW */ +#define XAE_TXLTCL_OFFSET 0x00000328 /**< Frames transmitted with late + * Collisions, LSW + */ +#define XAE_TXLTCU_OFFSET 0x0000032C /**< Frames transmitted with late + * Collisions, MSW + */ +#define XAE_TXAECL_OFFSET 0x00000330 /**< Frames aborted with excessive + * Collisions, LSW + */ +#define XAE_TXAECU_OFFSET 0x00000334 /**< Frames aborted with excessive + * Collisions, MSW + */ +#define XAE_TXEDEFL_OFFSET 0x00000338 /**< Transmit Frames with excessive + * Defferal, LSW + */ +#define XAE_TXEDEFU_OFFSET 0x0000033C /**< Transmit Frames with excessive + * Defferal, MSW + */ +#define XAE_RXAERL_OFFSET 0x00000340 /**< Frames received with alignment + * errors, LSW + */ +#define XAE_RXAERU_OFFSET 0x0000034C /**< Frames received with alignment + * errors, MSW + */ +/* End of Statistics Counter Registers Offset definitions */ + +#define XAE_RCW0_OFFSET 0x00000400 /**< Rx Configuration Word 0 */ +#define XAE_RCW1_OFFSET 0x00000404 /**< Rx Configuration Word 1 */ +#define XAE_TC_OFFSET 0x00000408 /**< Tx Configuration */ +#define XAE_FCC_OFFSET 0x0000040C /**< Flow Control Configuration */ +#define XAE_EMMC_OFFSET 0x00000410 /**< EMAC mode configuration */ +#define XAE_RXFC_OFFSET 0x00000414 /**< Rx Max Frm Config Register */ +#define XAE_TXFC_OFFSET 0x00000418 /**< Tx Max Frm Config Register */ +#define XAE_TX_TIMESTAMP_ADJ_OFFSET 0x0000041C /**< Transmitter time stamp + * adjust control Register + */ +#define XAE_PHYC_OFFSET 0x00000420 /**< RGMII/SGMII configuration */ + +/* 0x00000424 to 0x000004F4 are reserved */ + +#define XAE_IDREG_OFFSET 0x000004F8 /**< Identification Register */ +#define XAE_ARREG_OFFSET 0x000004FC /**< Ability Register */ +#define XAE_MDIO_MC_OFFSET 0x00000500 /**< MII Management Config */ +#define XAE_MDIO_MCR_OFFSET 0x00000504 /**< MII Management Control */ +#define XAE_MDIO_MWD_OFFSET 0x00000508 /**< MII Management Write Data */ +#define XAE_MDIO_MRD_OFFSET 0x0000050C /**< MII Management Read Data */ + +/* 0x00000510 to 0x000005FC are reserved */ + +#define XAE_MDIO_MIS_OFFSET 0x00000600 /**< MII Management Interrupt + * Status + */ +/* 0x00000604-0x0000061C are reserved */ + +#define XAE_MDIO_MIP_OFFSET 0x00000620 /**< MII Management Interrupt + * Pending register offse + */ +/* 0x00000624-0x0000063C are reserved */ + +#define XAE_MDIO_MIE_OFFSET 0x00000640 /**< MII Management Interrupt + * Enable register offset + */ +/* 0x00000644-0x0000065C are reserved */ + +#define XAE_MDIO_MIC_OFFSET 0x00000660 /**< MII Management Interrupt + * Clear register offset. + */ + +/* 0x00000664-0x000006FC are reserved */ + +#define XAE_UAW0_OFFSET 0x00000700 /**< Unicast address word 0 */ +#define XAE_UAW1_OFFSET 0x00000704 /**< Unicast address word 1 */ +#define XAE_FMI_OFFSET 0x00000708 /**< Filter Mask Index */ +/* 0x0000070C is reserved */ +#define XAE_AF0_OFFSET 0x00000710 /**< Address Filter 0 */ +#define XAE_AF1_OFFSET 0x00000714 /**< Address Filter 1 */ + +/* 0x00000718-0x00003FFC are reserved */ + +/* + * Transmit VLAN Table is from 0x00004000 to 0x00007FFC + * This offset defines an offset to table that has provisioned transmit + * VLAN data. The VLAN table will be used by hardware to provide + * transmit VLAN tagging, stripping, and translation. + */ +#define XAE_TX_VLAN_DATA_OFFSET 0x00004000 /**< TX VLAN data table address */ + + +/* + * Receive VLAN Data Table is from 0x00008000 to 0x0000BFFC + * This offset defines an offset to table that has provisioned receive + * VLAN data. The VLAN table will be used by hardware to provide + * receive VLAN tagging, stripping, and translation. + */ +#define XAE_RX_VLAN_DATA_OFFSET 0x00008000 /**< RX VLAN data table address */ + +/* 0x0000C000-0x0000FFFC are reserved */ + +/* 0x00010000-0x00013FFC are Ethenet AVB address offset */ + +/* 0x00014000-0x0001FFFC are reserved */ + +/* + * Extended Multicast Address Table is from 0x0020000 to 0x0003FFFC. + * This offset defines an offset to table that has provisioned multicast + * addresses. It is stored in BRAM and will be used by hardware to provide + * first line of address matching when a multicast frame is reveived. It + * can minimize the use of CPU/software hence minimize performance impact. + */ +#define XAE_MCAST_TABLE_OFFSET 0x00020000 /**< Multicast table address */ +/*@}*/ + + +/* Register masks. The following constants define bit locations of various + * bits in the registers. Constants are not defined for those registers + * that have a single bit field representing all 32 bits. For further + * information on the meaning of the various bit masks, refer to the HW spec. + */ + +/** @name Reset and Address Filter (RAF) Register bit definitions. + * These bits are associated with the XAE_RAF_OFFSET register. + * @{ + */ +#define XAE_RAF_MCSTREJ_MASK 0x00000002 /**< Reject receive + * multicast destination + * address + */ +#define XAE_RAF_BCSTREJ_MASK 0x00000004 /**< Reject receive + * broadcast destination + * address + */ +#define XAE_RAF_TXVTAGMODE_MASK 0x00000018 /**< Tx VLAN TAG mode */ +#define XAE_RAF_RXVTAGMODE_MASK 0x00000060 /**< Rx VLAN TAG mode */ +#define XAE_RAF_TXVSTRPMODE_MASK 0x00000180 /**< Tx VLAN STRIP mode */ +#define XAE_RAF_RXVSTRPMODE_MASK 0x00000600 /**< Rx VLAN STRIP mode */ +#define XAE_RAF_NEWFNCENBL_MASK 0x00000800 /**< New function mode */ +#define XAE_RAF_EMULTIFLTRENBL_MASK 0x00001000 /**< Exteneded Multicast + * Filtering mode + */ +#define XAE_RAF_STATSRST_MASK 0x00002000 /**< Statistics Counter + * Reset + */ +#define XAE_RAF_RXBADFRMEN_MASK 0x00004000 /**< Receive Bad Frame + * Enable + */ +#define XAE_RAF_TXVTAGMODE_SHIFT 3 /**< Tx Tag mode shift bits */ +#define XAE_RAF_RXVTAGMODE_SHIFT 5 /**< Rx Tag mode shift bits */ +#define XAE_RAF_TXVSTRPMODE_SHIFT 7 /**< Tx strip mode shift bits*/ +#define XAE_RAF_RXVSTRPMODE_SHIFT 9 /**< Rx Strip mode shift bits*/ +/*@}*/ + +/** @name Transmit Pause Frame Register (TPF) bit definitions + * @{ + */ +#define XAE_TPF_TPFV_MASK 0x0000FFFF /**< Tx pause frame value */ +/*@}*/ + +/** @name Transmit Inter-Frame Gap Adjustement Register (TFGP) bit definitions + * @{ + */ +#define XAE_TFGP_IFGP_MASK 0x0000007F /**< Transmit inter-frame + * gap adjustment value + */ +/*@}*/ + +/** @name Interrupt Status/Enable/Mask Registers bit definitions + * The bit definition of these three interrupt registers are the same. + * These bits are associated with the XAE_IS_OFFSET, XAE_IP_OFFSET, and + * XAE_IE_OFFSET registers. + * @{ + */ +#define XAE_INT_HARDACSCMPLT_MASK 0x00000001 /**< Hard register + * access complete + */ +#define XAE_INT_AUTONEG_MASK 0x00000002 /**< Auto negotiation + * complete + */ +#define XAE_INT_RXCMPIT_MASK 0x00000004 /**< Rx complete */ +#define XAE_INT_RXRJECT_MASK 0x00000008 /**< Rx frame rejected */ +#define XAE_INT_RXFIFOOVR_MASK 0x00000010 /**< Rx fifo overrun */ +#define XAE_INT_TXCMPIT_MASK 0x00000020 /**< Tx complete */ +#define XAE_INT_RXDCMLOCK_MASK 0x00000040 /**< Rx Dcm Lock */ +#define XAE_INT_MGTRDY_MASK 0x00000080 /**< MGT clock Lock */ +#define XAE_INT_PHYRSTCMPLT_MASK 0x00000100 /**< Phy Reset complete */ + +#define XAE_INT_ALL_MASK 0x0000003F /**< All the ints */ + +#define XAE_INT_RECV_ERROR_MASK \ + (XAE_INT_RXRJECT_MASK | XAE_INT_RXFIFOOVR_MASK) /**< INT bits that + * indicate receive + * errors + */ +/*@}*/ + + +/** @name TPID Register (TPID) bit definitions + * @{ + */ +#define XAE_TPID_0_MASK 0x0000FFFF /**< TPID 0 */ +#define XAE_TPID_1_MASK 0xFFFF0000 /**< TPID 1 */ +/*@}*/ + + +/** @name Receive Configuration Word 1 (RCW1) Register bit definitions + * @{ + */ +#define XAE_RCW1_RST_MASK 0x80000000 /**< Reset */ +#define XAE_RCW1_JUM_MASK 0x40000000 /**< Jumbo frame enable */ +#define XAE_RCW1_FCS_MASK 0x20000000 /**< In-Band FCS enable + * (FCS not stripped) */ +#define XAE_RCW1_RX_MASK 0x10000000 /**< Receiver enable */ +#define XAE_RCW1_VLAN_MASK 0x08000000 /**< VLAN frame enable */ +#define XAE_RCW1_LT_DIS_MASK 0x02000000 /**< Length/type field valid check + * disable + */ +#define XAE_RCW1_CL_DIS_MASK 0x01000000 /**< Control frame Length check + * disable + */ +#define XAE_RCW1_1588_TIMESTAMP_EN_MASK 0x00400000 /**< Inband 1588 time + * stamp enable + */ +#define XAE_RCW1_PAUSEADDR_MASK 0x0000FFFF /**< Pause frame source + * address bits [47:32].Bits + * [31:0] are stored in register + * RCW0 + */ +/*@}*/ + + +/** @name Transmitter Configuration (TC) Register bit definitions + * @{ + */ +#define XAE_TC_RST_MASK 0x80000000 /**< Reset */ +#define XAE_TC_JUM_MASK 0x40000000 /**< Jumbo frame enable */ +#define XAE_TC_FCS_MASK 0x20000000 /**< In-Band FCS enable + * (FCS not generated) + */ +#define XAE_TC_TX_MASK 0x10000000 /**< Transmitter enable */ +#define XAE_TC_VLAN_MASK 0x08000000 /**< VLAN frame enable */ +#define XAE_TC_IFG_MASK 0x02000000 /**< Inter-frame gap adjustment + * enable + */ +#define XAE_TC_1588_CMD_EN_MASK 0x00400000 /**< 1588 Cmd field enable */ +/*@}*/ + + +/** @name Flow Control Configuration (FCC) Register Bit definitions + * @{ + */ +#define XAE_FCC_FCRX_MASK 0x20000000 /**< Rx flow control enable */ +#define XAE_FCC_FCTX_MASK 0x40000000 /**< Tx flow control enable */ +/*@}*/ + + +/** @name Ethernet MAC Mode Configuration (EMMC) Register bit definitions + * @{ + */ +#define XAE_EMMC_LINKSPEED_MASK 0xC0000000 /**< Link speed */ +#define XAE_EMMC_RGMII_MASK 0x20000000 /**< RGMII mode enable */ +#define XAE_EMMC_SGMII_MASK 0x10000000 /**< SGMII mode enable */ +#define XAE_EMMC_GPCS_MASK 0x08000000 /**< 1000BaseX mode enable*/ +#define XAE_EMMC_HOST_MASK 0x04000000 /**< Host interface enable*/ +#define XAE_EMMC_TX16BIT 0x02000000 /**< 16 bit Tx client + * enable + */ +#define XAE_EMMC_RX16BIT 0x01000000 /**< 16 bit Rx client + * enable + */ +#define XAE_EMMC_LINKSPD_10 0x00000000 /**< Link Speed mask for + * 10 Mbit + */ +#define XAE_EMMC_LINKSPD_100 0x40000000 /**< Link Speed mask for 100 + * Mbit + */ +#define XAE_EMMC_LINKSPD_1000 0x80000000 /**< Link Speed mask for + * 1000 Mbit + */ +/*@}*/ + + +/** @name RGMII/SGMII Configuration (PHYC) Register bit definitions + * @{ + */ +#define XAE_PHYC_SGMIILINKSPEED_MASK 0xC0000000 /**< SGMII link speed mask*/ +#define XAE_PHYC_RGMIILINKSPEED_MASK 0x0000000C /**< RGMII link speed */ +#define XAE_PHYC_RGMIIHD_MASK 0x00000002 /**< RGMII Half-duplex */ +#define XAE_PHYC_RGMIILINK_MASK 0x00000001 /**< RGMII link status */ +#define XAE_PHYC_RGLINKSPD_10 0x00000000 /**< RGMII link 10 Mbit */ +#define XAE_PHYC_RGLINKSPD_100 0x00000004 /**< RGMII link 100 Mbit */ +#define XAE_PHYC_RGLINKSPD_1000 0x00000008 /**< RGMII link 1000 Mbit */ +#define XAE_PHYC_SGLINKSPD_10 0x00000000 /**< SGMII link 10 Mbit */ +#define XAE_PHYC_SGLINKSPD_100 0x40000000 /**< SGMII link 100 Mbit */ +#define XAE_PHYC_SGLINKSPD_1000 0x80000000 /**< SGMII link 1000 Mbit */ +/*@}*/ + + +/** @name MDIO Management Configuration (MC) Register bit definitions + * @{ + */ +#define XAE_MDIO_MC_MDIOEN_MASK 0x00000040 /**< MII management enable*/ +#define XAE_MDIO_MC_CLOCK_DIVIDE_MAX 0x3F /**< Maximum MDIO divisor */ +/*@}*/ + + +/** @name MDIO Management Control Register (MCR) Register bit definitions + * @{ + */ +#define XAE_MDIO_MCR_PHYAD_MASK 0x1F000000 /**< Phy Address Mask */ +#define XAE_MDIO_MCR_PHYAD_SHIFT 24 /**< Phy Address Shift */ +#define XAE_MDIO_MCR_REGAD_MASK 0x001F0000 /**< Reg Address Mask */ +#define XAE_MDIO_MCR_REGAD_SHIFT 16 /**< Reg Address Shift */ +#define XAE_MDIO_MCR_OP_MASK 0x0000C000 /**< Operation Code Mask */ +#define XAE_MDIO_MCR_OP_SHIFT 13 /**< Operation Code Shift */ +#define XAE_MDIO_MCR_OP_READ_MASK 0x00008000 /**< Op Code Read Mask */ +#define XAE_MDIO_MCR_OP_WRITE_MASK 0x00004000 /**< Op Code Write Mask */ +#define XAE_MDIO_MCR_INITIATE_MASK 0x00000800 /**< Ready Mask */ +#define XAE_MDIO_MCR_READY_MASK 0x00000080 /**< Ready Mask */ + +/*@}*/ + +/** @name MDIO Interrupt Enable/Mask/Status Registers bit definitions + * The bit definition of these three interrupt registers are the same. + * These bits are associated with the XAE_IS_OFFSET, XAE_IP_OFFSET, and + * XAE_IE_OFFSET registers. + * @{ + */ +#define XAE_MDIO_INT_MIIM_RDY_MASK 0x00000001 /**< MIIM Interrupt */ +/*@}*/ + + +/** @name Axi Ethernet Unicast Address Register Word 1 (UAW1) Register Bit + * definitions + * @{ + */ +#define XAE_UAW1_UNICASTADDR_MASK 0x0000FFFF /**< Station address bits + * [47:32] + * Station address bits [31:0] + * are stored in register + * UAW0 */ +/*@}*/ + + +/** @name Filter Mask Index (FMI) Register bit definitions + * @{ + */ +#define XAE_FMI_PM_MASK 0x80000000 /**< Promiscuous mode + * enable + */ +#define XAE_FMI_IND_MASK 0x00000003 /**< Index Mask */ + +/*@}*/ + + +/** @name Extended multicast buffer descriptor bit mask + * @{ + */ +#define XAE_BD_RX_USR2_BCAST_MASK 0x00000004 +#define XAE_BD_RX_USR2_IP_MCAST_MASK 0x00000002 +#define XAE_BD_RX_USR2_MCAST_MASK 0x00000001 +/*@}*/ + +/** @name Axi Ethernet Multicast Address Register Word 1 (MAW1) + * @{ + */ +#define XAE_MAW1_RNW_MASK 0x00800000 /**< Multicast address + * table register read + * enable + */ +#define XAE_MAW1_ADDR_MASK 0x00030000 /**< Multicast address + * table register address + */ +#define XAE_MAW1_MULTICADDR_MASK 0x0000FFFF /**< Multicast address + * bits [47:32] + * Multicast address + * bits [31:0] are stored + * in register MAW0 + */ +#define XAE_MAW1_MATADDR_SHIFT_MASK 16 /**< Number of bits to shift + * right to align with + * XAE_MAW1_CAMADDR_MASK + */ +/*@}*/ + + +/** @name Other Constant definitions used in the driver + * @{ + */ + +#define XAE_SPEED_10_MBPS 10 /**< Speed of 10 Mbps */ +#define XAE_SPEED_100_MBPS 100 /**< Speed of 100 Mbps */ +#define XAE_SPEED_1000_MBPS 1000 /**< Speed of 1000 Mbps */ + +#define XAE_SOFT_TEMAC_LOW_SPEED 0 /**< For soft cores with 10/100 + * Mbps speed. + */ +#define XAE_SOFT_TEMAC_HIGH_SPEED 1 /**< For soft cores with + * 10/100/1000 Mbps speed. + */ +#define XAE_HARD_TEMAC_TYPE 2 /**< For hard TEMAC cores used + * virtex-6. + */ +#define XAE_PHY_ADDR_LIMIT 31 /**< Max limit while accessing + * and searching for available + * PHYs. + */ +#define XAE_PHY_REG_NUM_LIMIT 31 /**< Max register limit in PHY + * as mandated by the spec. + */ +#define XAE_LOOPS_TO_COME_OUT_OF_RST 10000 /**< Number of loops in the driver + * API to wait for before + * returning a failure case. + */ + +#define XAE_RST_DELAY_LOOPCNT_VAL 200 /**< Timeout in ticks used + * while checking if the core + * had come out of reset. The + * exact tick time is defined + * in each case/loop where it + * will be used + */ +#define XAE_VLAN_TABL_STRP_FLD_LEN 1 /**< Strip field length in vlan + * table used for extended + * vlan features. + */ +#define XAE_VLAN_TABL_TAG_FLD_LEN 1 /**< Tag field length in vlan + * table used for extended + * vlan features. + */ +#define XAE_MAX_VLAN_TABL_ENTRY 0xFFF /**< Max possible number of + * entries in vlan table used + * for extended vlan + * features. + */ +#define XAE_VLAN_TABL_VID_START_OFFSET 2 /**< VID field start offset in + * each entry in the VLAN + * table. + */ +#define XAE_VLAN_TABL_STRP_STRT_OFFSET 1 /**< Strip field start offset + * in each entry in the VLAN + * table. + */ +#define XAE_VLAN_TABL_STRP_ENTRY_MASK 0x01 /**< Mask used to extract the + * the strip field from an + * entry in VLAN table. + */ +#define XAE_VLAN_TABL_TAG_ENTRY_MASK 0x01 /**< Mask used to extract the + * the tag field from an + * entry in VLAN table. + */ + +/*@}*/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ +xdbg_stmnt(extern int indent_on); + +#define XAxiEthernet_indent(RegOffset) \ + ((indent_on && ((RegOffset) >= XAE_RAF_OFFSET) && ((RegOffset) <= \ + XAE_AF1_OFFSET)) ? "\t" : "") + + +#define XAxiEthernet_reg_name(RegOffset) \ + (((RegOffset) == XAE_RAF_OFFSET) ? "XAE_RAF_OFFSET": \ + ((RegOffset) == XAE_TPF_OFFSET) ? "XAE_TPF_OFFSET": \ + ((RegOffset) == XAE_IFGP_OFFSET) ? "XAE_IFGP_OFFSET": \ + ((RegOffset) == XAE_IS_OFFSET) ? "XAE_IS_OFFSET": \ + ((RegOffset) == XAE_IP_OFFSET) ? "XAE_IP_OFFSET": \ + ((RegOffset) == XAE_IE_OFFSET) ? "XAE_IE_OFFSET": \ + ((RegOffset) == XAE_TTAG_OFFSET) ? "XAE_TTAG_OFFSET": \ + ((RegOffset) == XAE_RTAG_OFFSET) ? "XAE_RTAG_OFFSET": \ + ((RegOffset) == XAE_UAWL_OFFSET) ? "XAE_UAWL_OFFSET": \ + ((RegOffset) == XAE_UAWU_OFFSET) ? "XAE_UAWU_OFFSET": \ + ((RegOffset) == XAE_TPID0_OFFSET) ? "XAE_TPID0_OFFSET": \ + ((RegOffset) == XAE_TPID1_OFFSET) ? "XAE_TPID1_OFFSET": \ + ((RegOffset) == XAE_RCW0_OFFSET) ? "XAE_RCW0_OFFSET": \ + ((RegOffset) == XAE_RCW1_OFFSET) ? "XAE_RCW1_OFFSET": \ + ((RegOffset) == XAE_TC_OFFSET) ? "XAE_TC_OFFSET": \ + ((RegOffset) == XAE_FCC_OFFSET) ? "XAE_FCC_OFFSET": \ + ((RegOffset) == XAE_EMMC_OFFSET) ? "XAE_EMMC_OFFSET": \ + ((RegOffset) == XAE_PHYC_OFFSET) ? "XAE_PHYC_OFFSET": \ + ((RegOffset) == XAE_UAW0_OFFSET) ? "XAE_UAW0_OFFSET": \ + ((RegOffset) == XAE_UAW1_OFFSET) ? "XAE_UAW1_OFFSET": \ + ((RegOffset) == XAE_FMI_OFFSET) ? "XAE_FMI_OFFSET": \ + ((RegOffset) == XAE_AF0_OFFSET) ? "XAE_AF0_OFFSET": \ + ((RegOffset) == XAE_AF1_OFFSET) ? "XAE_AF1_OFFSET": \ + ((RegOffset) == XAE_TXBL_OFFSET) ? "XAE_TXBL_OFFSET": \ + ((RegOffset) == XAE_TXBU_OFFSET) ? "XAE_TXBU_OFFSET": \ + ((RegOffset) == XAE_RXBL_OFFSET) ? "XAE_RXBL_OFFSET": \ + ((RegOffset) == XAE_RXBU_OFFSET) ? "XAE_RXBU_OFFSET": \ + ((RegOffset) == XAE_RXUNDRL_OFFSET) ? "XAE_RXUNDRL_OFFSET": \ + ((RegOffset) == XAE_RXUNDRU_OFFSET) ? "XAE_RXUNDRU_OFFSET": \ + ((RegOffset) == XAE_RXFRAGL_OFFSET) ? "XAE_RXFRAGL_OFFSET": \ + ((RegOffset) == XAE_RXFRAGU_OFFSET) ? "XAE_RXFRAGU_OFFSET": \ + ((RegOffset) == XAE_RX64BL_OFFSET) ? "XAE_RX64BL_OFFSET": \ + ((RegOffset) == XAE_RX64BU_OFFSET) ? "XAE_RX64BU_OFFSET": \ + ((RegOffset) == XAE_RX65B127L_OFFSET) ? "XAE_RX65B127L_OFFSET": \ + ((RegOffset) == XAE_RX65B127U_OFFSET) ? "XAE_RX65B127U_OFFSET": \ + ((RegOffset) == XAE_RX128B255L_OFFSET) ? "XAE_RX128B255L_OFFSET": \ + ((RegOffset) == XAE_RX128B255U_OFFSET) ? "XAE_RX128B255U_OFFSET": \ + ((RegOffset) == XAE_RX256B511L_OFFSET) ? "XAE_RX256B511L_OFFSET": \ + ((RegOffset) == XAE_RX256B511U_OFFSET) ? "XAE_RX256B511U_OFFSET": \ + ((RegOffset) == XAE_RX512B1023L_OFFSET) ? "XAE_RX512B1023L_OFFSET": \ + ((RegOffset) == XAE_RX512B1023U_OFFSET) ? "XAE_RX512B1023U_OFFSET": \ + ((RegOffset) == XAE_RX1024BL_OFFSET) ? "XAE_RX1024L_OFFSET": \ + ((RegOffset) == XAE_RX1024BU_OFFSET) ? "XAE_RX1024U_OFFSET": \ + ((RegOffset) == XAE_RXOVRL_OFFSET) ? "XAE_RXOVRL_OFFSET": \ + ((RegOffset) == XAE_RXOVRU_OFFSET) ? "XAE_RXOVRU_OFFSET": \ + ((RegOffset) == XAE_TX64BL_OFFSET) ? "XAE_TX64BL_OFFSET": \ + ((RegOffset) == XAE_TX64BU_OFFSET) ? "XAE_TX64BU_OFFSET": \ + ((RegOffset) == XAE_TX65B127L_OFFSET) ? "XAE_TX65B127L_OFFSET": \ + ((RegOffset) == XAE_TX65B127U_OFFSET) ? "XAE_TX65B127U_OFFSET": \ + ((RegOffset) == XAE_TX128B255L_OFFSET) ? "XAE_TX128B255L_OFFSET": \ + ((RegOffset) == XAE_TX128B255U_OFFSET) ? "XAE_TX128B255U_OFFSET": \ + ((RegOffset) == XAE_TX256B511L_OFFSET) ? "XAE_TX256B511L_OFFSET": \ + ((RegOffset) == XAE_TX256B511U_OFFSET) ? "XAE_TX256B511U_OFFSET": \ + ((RegOffset) == XAE_TX512B1023L_OFFSET) ? "XAE_TX512B1023L_OFFSET": \ + ((RegOffset) == XAE_TX512B1023U_OFFSET) ? "XAE_TX512B1023U_OFFSET": \ + ((RegOffset) == XAE_TX1024L_OFFSET) ? "XAE_TX1024L_OFFSET": \ + ((RegOffset) == XAE_TX1024U_OFFSET) ? "XAE_TX1024U_OFFSET": \ + ((RegOffset) == XAE_TXOVRL_OFFSET) ? "XAE_TXOVRL_OFFSET": \ + ((RegOffset) == XAE_TXOVRU_OFFSET) ? "XAE_TXOVRU_OFFSET": \ + ((RegOffset) == XAE_RXFL_OFFSET) ? "XAE_RXFL_OFFSET": \ + ((RegOffset) == XAE_RXFU_OFFSET) ? "XAE_RXFU_OFFSET": \ + ((RegOffset) == XAE_RXFCSERL_OFFSET) ? "XAE_RXFCSERL_OFFSET": \ + ((RegOffset) == XAE_RXFCSERU_OFFSET) ? "XAE_RXFCSERU_OFFSET": \ + ((RegOffset) == XAE_RXBCSTFL_OFFSET) ? "XAE_RXBCSTFL_OFFSET": \ + ((RegOffset) == XAE_RXBCSTFU_OFFSET) ? "XAE_RXBCSTFU_OFFSET": \ + ((RegOffset) == XAE_RXMCSTFL_OFFSET) ? "XAE_RXMCSTFL_OFFSET": \ + ((RegOffset) == XAE_RXMCSTFU_OFFSET) ? "XAE_RXMCSTFU_OFFSET": \ + ((RegOffset) == XAE_RXCTRFL_OFFSET) ? "XAE_RXCTRFL_OFFSET": \ + ((RegOffset) == XAE_RXCTRFU_OFFSET) ? "XAE_RXCTRFU_OFFSET": \ + ((RegOffset) == XAE_RXLTERL_OFFSET) ? "XAE_RXLTERL_OFFSET": \ + ((RegOffset) == XAE_RXLTERU_OFFSET) ? "XAE_RXLTERU_OFFSET": \ + ((RegOffset) == XAE_RXVLANFL_OFFSET) ? "XAE_RXVLANFL_OFFSET": \ + ((RegOffset) == XAE_RXVLANFU_OFFSET) ? "XAE_RXVLANFU_OFFSET": \ + ((RegOffset) == XAE_RXPFL_OFFSET) ? "XAE_RXFL_OFFSET": \ + ((RegOffset) == XAE_RXPFU_OFFSET) ? "XAE_RXFU_OFFSET": \ + ((RegOffset) == XAE_RXUOPFL_OFFSET) ? "XAE_RXUOPFL_OFFSET": \ + ((RegOffset) == XAE_RXUOPFU_OFFSET) ? "XAE_RXUOPFU_OFFSET": \ + ((RegOffset) == XAE_TXFL_OFFSET) ? "XAE_TXFL_OFFSET": \ + ((RegOffset) == XAE_TXFU_OFFSET) ? "XAE_TXFU_OFFSET": \ + ((RegOffset) == XAE_TXBCSTFL_OFFSET) ? "XAE_TXBCSTFL_OFFSET": \ + ((RegOffset) == XAE_TXBCSTFU_OFFSET) ? "XAE_TXBCSTFU_OFFSET": \ + ((RegOffset) == XAE_TXMCSTFL_OFFSET) ? "XAE_TXMCSTFL_OFFSET": \ + ((RegOffset) == XAE_TXMCSTFU_OFFSET) ? "XAE_TXMCSTFU_OFFSET": \ + ((RegOffset) == XAE_TXUNDRERL_OFFSET) ? "XAE_TXUNDRERL_OFFSET": \ + ((RegOffset) == XAE_TXUNDRERU_OFFSET) ? "XAE_TXUNDRERU_OFFSET": \ + ((RegOffset) == XAE_TXCTRFL_OFFSET) ? "XAE_TXCTRFL_OFFSET": \ + ((RegOffset) == XAE_TXCTRFU_OFFSET) ? "XAE_TXCTRFU_OFFSET": \ + ((RegOffset) == XAE_TXVLANFL_OFFSET) ? "XAE_TXVLANFL_OFFSET": \ + ((RegOffset) == XAE_TXVLANFU_OFFSET) ? "XAE_TXVLANFU_OFFSET": \ + ((RegOffset) == XAE_TXPFL_OFFSET) ? "XAE_TXPFL_OFFSET": \ + ((RegOffset) == XAE_TXPFU_OFFSET) ? "XAE_TXPFU_OFFSET": \ + ((RegOffset) == XAE_TXSCL_OFFSET) ? "XAE_TXSCL_OFFSET": \ + ((RegOffset) == XAE_TXSCU_OFFSET) ? "XAE_TXSCU_OFFSET": \ + ((RegOffset) == XAE_TXMCL_OFFSET) ? "XAE_TXMCL_OFFSET": \ + ((RegOffset) == XAE_TXMCU_OFFSET) ? "XAE_TXMCU_OFFSET": \ + ((RegOffset) == XAE_TXDEFL_OFFSET) ? "XAE_TXDEFL_OFFSET": \ + ((RegOffset) == XAE_TXDEFU_OFFSET) ? "XAE_TXDEFU_OFFSET": \ + ((RegOffset) == XAE_TXLTCL_OFFSET) ? "XAE_TXLTCL_OFFSET": \ + ((RegOffset) == XAE_TXLTCU_OFFSET) ? "XAE_TXLTCU_OFFSET": \ + ((RegOffset) == XAE_TXAECL_OFFSET) ? "XAE_TXAECL_OFFSET": \ + ((RegOffset) == XAE_TXAECU_OFFSET) ? "XAE_TXAECU_OFFSET": \ + ((RegOffset) == XAE_TXEDEFL_OFFSET) ? "XAE_TXEDEFL_OFFSET": \ + ((RegOffset) == XAE_TXEDEFU_OFFSET) ? "XAE_TXEDEFU_OFFSET": \ + ((RegOffset) == XAE_RXAERL_OFFSET) ? "XAE_RXAERL_OFFSET": \ + ((RegOffset) == XAE_RXAERU_OFFSET) ? "XAE_RXAERU_OFFSET": \ + "unknown") + +#define XAxiEthernet_print_reg_o(BaseAddress, RegOffset, Value) \ + xdbg_printf(XDBG_DEBUG_TEMAC_REG, "%s0x%0x -> %s(0x%0x)\n", \ + XAxiEthernet_indent(RegOffset), (Value), \ + XAxiEthernet_reg_name(RegOffset), (RegOffset)) \ + +#define XAxiEthernet_print_reg_i(BaseAddress, RegOffset, Value) \ + xdbg_printf(XDBG_DEBUG_TEMAC_REG, "%s%s(0x%0x) -> 0x%0x\n", \ + XAxiEthernet_indent(RegOffset), \ + XAxiEthernet_reg_name(RegOffset),(RegOffset), (Value)) \ + +/****************************************************************************/ +/** +* +* XAxiEthernet_ReadReg returns the value read from the register specified by +* RegOffset. +* +* @param BaseAddress is the base address of the Axi Ethernet device. +* @param RegOffset is the offset of the register to be read. +* +* @return Returns the 32-bit value of the register. +* +* @note C-style signature: +* u32 XAxiEthernet_ReadReg(u32 BaseAddress, u32 RegOffset) +* +*****************************************************************************/ +#ifdef DEBUG +#define XAxiEthernet_ReadReg(BaseAddress, RegOffset) \ +({ \ + u32 value; \ + value = Xil_In32(((BaseAddress) + (RegOffset))); \ + XAxiEthernet_print_reg_i((BaseAddress), (RegOffset), value); \ +}) +#else +#define XAxiEthernet_ReadReg(BaseAddress, RegOffset) \ + (Xil_In32(((BaseAddress) + (RegOffset)))) +#endif + +/****************************************************************************/ +/** +* +* XAxiEthernet_WriteReg, writes Data to the register specified by +* RegOffset. +* +* @param BaseAddress is the base address of the Axi Ethernet device. +* @param RegOffset is the offset of the register to be written. +* @param Data is the 32-bit value to write to the register. +* +* @return None. +* +* @note +* C-style signature: +* void XAxiEthernet_WriteReg(u32 BaseAddress, u32 RegOffset, u32 Data) +* +*****************************************************************************/ +#ifdef DEBUG +#define XAxiEthernet_WriteReg(BaseAddress, RegOffset, Data) \ +({ \ + XAxiEthernet_print_reg_o((BaseAddress), (RegOffset), (Data)); \ + Xil_Out32(((BaseAddress) + (RegOffset)), (Data)); \ +}) +#else +#define XAxiEthernet_WriteReg(BaseAddress, RegOffset, Data) \ + Xil_Out32(((BaseAddress) + (RegOffset)), (Data)) +#endif + + +#ifdef __cplusplus + } +#endif + +#endif /* end of protection macro */ diff --git a/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet_porting_guide.h b/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet_porting_guide.h new file mode 100644 index 00000000..1945a931 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet_porting_guide.h @@ -0,0 +1,180 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2015 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xaxiethernet_porting_guide.h +* +* This is a guide on how to move from using the ll temac driver to use the +* xaxiethernet driver. +* +* The AXI Ethernet IP is based on the XPS_LL TEMAC IP. +* There are few changes in the IP and some of them are listed below +* - The Interface to access the IP is now AXI instead of the PLBV46 +* - AXI4 streaming interfaces is used instead of LL (Local Link) +* - All indirect accesses to Ethernet core registers have been removed. +* - The AxiEthernet reset line is connected to the reset line of the +* device connected to the AXI4-Stream interface. Hence any reset +* of the connected device would reset AxiEthernet. +* +* Please read the HW Device specification of the AXI Ethernet IP for further +* information. +* +* +* The AXI Ethernet can be used in a DMA mode using the AXI DMA or +* used in a FIFO mode using the AXI Streaming FIFO. +* +* There is a new driver for AXI DMA which is used by the AXi Ethernet. Please +* refer the xaxidma_porting_guide.h provided as a part of the AXI DMA driver to +* see the differences from the LL DMA driver. +* +* The LL FIFO driver is a common driver for the LL FIFO and the +* AXI Streaming FIFO. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a ASA   07/18/10 First release
+*
+* 
+* +* Overview +* +* The API for xaxiethernet driver are similar to xlltemac driver. The prefix for the +* API functions and structures is XAxiEthernet_ for the xaxiethernet driver. +* +* The prefix for all hash-defines (option masks or generic hash-defined constants) +* start with XAE_. +* +* The Axi Ethernet API "XAxiEthernet_Reset" is different from the corresponding +* LLTEMAC API "XLlTemac_Reset". The AxiEthernet version does not do a soft +* reset of the AxiEthernet hardware. Since AxiEthernet hardware could only be +* reset through the device connected to the AxiEthernet AXI4-Stream interface, +* the user must ensure that AxiEthernet hardware initialization happens after +* the initialization of the other device. +* +* These are the classification of the APIs +* - APIs that only have prefix changes +* - APIs that have been renamed +* - APIs that are new + +* +* Note that data structures have different prefix of XAxiEthernet_. Those API +* functions, that have data structures with prefix change, are considered as +* prefix change. +* +* API Functions That Only Have Prefix Changes +* +* Most of the functions have the prefix change and are given below +*
+*         xlltemac driver		|	xaxiethernet driver
+* ---------------------------------------------------------------------------------
+*    XLlTemac_IsStarted(...)		|	XAxiEthernet_IsStarted(...)
+*    XLlTemac_IsDma(...)		|	XAxiEthernet_IsDma(...)
+*    XLlTemac_IsFifo(...)		|	XAxiEthernet_IsFifo(...)
+*    XLlTemac_LlDevBaseAddress(...)	|	XAxiEthernet_AxiDevBaseAddress(...)
+*    XLlTemac_IsRecvFrameDropped(...)	|	XAxiEthernet_IsRecvFrameDropped(...)
+*    XLlTemac_GetPhysicalInterface(...)	|	XAxiEthernet_GetPhysicalInterface(...)
+*    XLlTemac_IntEnable(...)		|	XAxiEthernet_IntEnable(...)
+*    XLlTemac_IntDisable(...)		|	XAxiEthernet_IntDisable(...)
+*    XLlTemac_IntPending(...)		|	XAxiEthernet_IntPending(...)
+*    XLlTemac_IntClear(...)		|	XAxiEthernet_IntClear(...)
+*    XLlTemac_IsExtFuncCap(...)		|	XAxiEthernet_IsExtFuncCap(...)
+*    XLlTemac_IsExtMcastEnable(...)	|	XAxiEthernet_IsExtMcastEnable(...)
+*    XLlTemac_IsExtMcast(...)		|	XAxiEthernet_IsExtMcast(...)
+*    XLlTemac_IsTxVlanStrp(...)		|	XAxiEthernet_IsTxVlanStrp(...)
+*    XLlTemac_IsRxVlanStrp(...)		|	XAxiEthernet_IsRxVlanStrp(...)
+*    XLlTemac_IsTxVlanTran(...)		|	XAxiEthernet_IsTxVlanTran(...)
+*    XLlTemac_IsRxVlanTran(...)		|	XAxiEthernet_IsRxVlanTran(...)
+*    XLlTemac_IsTxVlanTag(...)		|	XAxiEthernet_IsTxVlanTag(...)
+*    XLlTemac_IsRxVlanTag(...)		|	XAxiEthernet_IsRxVlanTag(...)
+*    XLlTemac_SetOptions (...)		|	XAxiEthernet_SetOptions(...)
+*    XLlTemac_ClearOptions(...)		|	XAxiEthernet_ClearOptions(...)
+*    XLlTemac_GetOptions(...)		|	XAxiEthernet_GetOptions(...)
+*    XLlTemac_SetMacAddress(...)	|	XAxiEthernet_SetMacAddress(...)
+*    XLlTemac_GetMacAddress(...)	|	XAxiEthernet_GetMacAddress(...)
+*    XLlTemac_SetMacPauseAddress(...)	|	XAxiEthernet_SetMacPauseAddress(...)
+*    XLlTemac_GetMacPauseAddress(...)	|	XAxiEthernet_GetMacPauseAddress(...)
+*    XLlTemac_SendPausePacket(...)	|	XAxiEthernet_SendPausePacket(...)
+*    XLlTemac_GetSgmiiStatus(...)	|	XAxiEthernet_GetSgmiiStatus(...)
+*    XLlTemac_GetRgmiiStatus(...)	|	XAxiEthernet_GetRgmiiStatus(...)
+*... XLlTemac_GetOperatingSpeed(...)	|	XAxiEthernet_GetOperatingSpeed(...)
+*    XLlTemac_SetOperatingSpeed(...)	|	XAxiEthernet_SetOperatingSpeed(...)
+*    XLlTemac_PhySetMdioDivisor(...)	|	XAxiEthernet_PhySetMdioDivisor(...)
+*    XLlTemac_PhyRead(...)		|	XAxiEthernet_PhyRead(...)
+*    XLlTemac_PhyWrite(...)		|	XAxiEthernet_PhyWrite(...)
+*    XLlTemac_MulticastAdd(...)		|	XAxiEthernet_MulticastAdd(...)
+*    XLlTemac_MulticastGet(...)		|	XAxiEthernet_MulticastGet(...)
+*    XLlTemac_MulticastClear(...)	|	XAxiEthernet_MulticastClear(...)
+*    XLlTemac_SetTpid(...)		|	XAxiEthernet_SetTpid(...)
+*    XLlTemac_ClearTpid(...)		|	XAxiEthernet_ClearTpid(...)
+*    XLlTemac_GetTpid(...)		|	XAxiEthernet_GetTpid(...)
+*    XLlTemac_SetVTagMode(...)		|	XAxiEthernet_SetVTagMode(...)
+*    XLlTemac_GetVTagMode(...)		|	XAxiEthernet_GetVTagMode(...)
+*    XLlTemac_SetVStripMode(...)	|	XAxiEthernet_SetVStripMode(...)
+*    XLlTemac_GetVStripMode(...)	|	XAxiEthernet_GetVStripMode(...)
+*    XLlTemac_SetVTagValue(...)		|	XAxiEthernet_SetVTagValue(...)
+*    XLlTemac_GetVTagValue(...)		|	XAxiEthernet_GetVTagValue(...)
+*    XLlTemac_SetVidTable(...)		|	XAxiEthernet_SetVidTable(...)
+*    XLlTemac_GetVidTable(...)		|	XAxiEthernet_GetVidTable(...)
+*    XLlTemac_AddExtMulticastGroup(...)	|	XAxiEthernet_AddExtMulticastGroup(...)
+*    XLlTemac_ClearExtMulticastGroup(..)|	XAxiEthernet_ClearExtMulticastGroup(...)
+*    XLlTemac_GetExtMulticastGroup(...)	|	XAxiEthernet_GetExtMulticastGroup(...)
+*    XLlTemac_DumpExtMulticastGroup(..)	|	XAxiEthernet_DumpExtMulticastGroup(...)
+
+*
+* +* API Function names that have changed +* +*
+*         xlltemac driver		|	xaaxiethernet driver
+* -----------------------------------------------------------------------
+* XLlTemac_IsRxCsum(...)		|	XAxiEthernet_IsRxPartialCsum(...)
+* XLlTemac_IsTxCsum(...)		|	XAxiEthernet_IsTxPartialCsum(...)
+* XLlTemac_Status(...)			|	XAxiEthernet_GetIntStatus
+* 
+* +* +* API Functions That Are New API Functions +* +* - XAxiEthernet_GetTemacType(...) +* - XAxiEthernet_IsAvbConfigured(...) +* - XAxiEthernet_IsStatsConfigured(...) +* - XAxiEthernet_SetBadFrmRcvOption((...); +* - XAxiEthernet_ClearBadFrmRcvOption(...); +* - XAxiEthernet_DisableControlFrameLenCheck(...) +* - XAxiEthernet_EnableControlFrameLenCheck(...) +* +* +******************************************************************************/ diff --git a/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet_sinit.c b/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet_sinit.c new file mode 100644 index 00000000..f3f0af05 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet_sinit.c @@ -0,0 +1,95 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2015 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/** +* +* @file xaxiethernet_sinit.c +* +* This file contains static initialzation functionality for Axi Ethernet driver. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a asa  6/30/10 First release
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" +#include "xaxiethernet.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + +/*****************************************************************************/ +/** +* XAxiEthernet_LookupConfig returns a reference to an XAxiEthernet_Config +* structure based on an unique device id, DeviceId. The return value +* will refer to an entry in the device configuration table defined in the +* xaxiethernet_g.c file. +* +* @param DeviceId is the unique device ID of the device for the lookup +* operation. +* +* @return +* - Returns a reference to a config record in the +* configuration table (in xaxiethernet_g.c) corresponding to +* DeviceId, or NULL +* - NULL if no match is found. +* +******************************************************************************/ +XAxiEthernet_Config *XAxiEthernet_LookupConfig(u16 DeviceId) +{ + extern XAxiEthernet_Config XAxiEthernet_ConfigTable[]; + XAxiEthernet_Config *CfgPtr = NULL; + int Index; + + for (Index = 0; Index < XPAR_XAXIETHERNET_NUM_INSTANCES; Index++) { + if (XAxiEthernet_ConfigTable[Index].DeviceId == DeviceId) { + CfgPtr = &XAxiEthernet_ConfigTable[Index]; + break; + } + } + + return (CfgPtr); +} diff --git a/XilinxProcessorIPLib/drivers/axiethernet/src/xdebug.h b/XilinxProcessorIPLib/drivers/axiethernet/src/xdebug.h new file mode 100644 index 00000000..7d7dc5a7 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/src/xdebug.h @@ -0,0 +1,84 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2015 Xilinx, Inc. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +#ifndef XDEBUG +#define XDEBUG + +#undef DEBUG + +#if defined(DEBUG) && !defined(NDEBUG) + +#ifndef XDEBUG_WARNING +#define XDEBUG_WARNING +#warning DEBUG is enabled +#endif + +int printf(const char *format, ...); + +#define XDBG_DEBUG_ERROR 0x00000001 /* error condition messages */ +#define XDBG_DEBUG_GENERAL 0x00000002 /* general debug messages */ +#define XDBG_DEBUG_ALL 0xFFFFFFFF /* all debugging data */ + +#define XDBG_DEBUG_FIFO_REG 0x00000100 /* display register reads/writes */ +#define XDBG_DEBUG_FIFO_RX 0x00000101 /* receive debug messages */ +#define XDBG_DEBUG_FIFO_TX 0x00000102 /* transmit debug messages */ +#define XDBG_DEBUG_FIFO_ALL 0x0000010F /* all fifo debug messages */ + +#define XDBG_DEBUG_TEMAC_REG 0x00000400 /* display register reads/writes */ +#define XDBG_DEBUG_TEMAC_RX 0x00000401 /* receive debug messages */ +#define XDBG_DEBUG_TEMAC_TX 0x00000402 /* transmit debug messages */ +#define XDBG_DEBUG_TEMAC_ALL 0x0000040F /* all temac debug messages */ + +#define XDBG_DEBUG_TEMAC_ADPT_RX 0x00000800 /* receive debug messages */ +#define XDBG_DEBUG_TEMAC_ADPT_TX 0x00000801 /* transmit debug messages */ +#define XDBG_DEBUG_TEMAC_ADPT_IOCTL 0x00000802 /* ioctl debug messages */ +#define XDBG_DEBUG_TEMAC_ADPT_MISC 0x00000803 /* debug msg for other routines */ +#define XDBG_DEBUG_TEMAC_ADPT_ALL 0x0000080F /* all temac adapter debug messages */ + +#define xdbg_current_types (XDBG_DEBUG_ERROR | XDBG_DEBUG_GENERAL | XDBG_DEBUG_FIFO_REG | XDBG_DEBUG_TEMAC_REG) + +#define xdbg_stmnt(x) x + +/* ANSI Syntax */ +#define xdbg_printf(type, ...) (((type) & xdbg_current_types) ? printf (__VA_ARGS__) : 0) + + +#else /* defined(DEBUG) && !defined(NDEBUG) */ + +#define xdbg_stmnt(x) + +/* ANSI Syntax */ +#define xdbg_printf(...) + + +#endif /* defined(DEBUG) && !defined(NDEBUG) */ + +#endif /* XDEBUG */