diff options
Diffstat (limited to 'firmware/usrp3/x300')
-rw-r--r-- | firmware/usrp3/x300/CMakeLists.txt | 36 | ||||
-rwxr-xr-x | firmware/usrp3/x300/x300_debug.py | 167 | ||||
-rw-r--r-- | firmware/usrp3/x300/x300_defs.h | 75 | ||||
-rw-r--r-- | firmware/usrp3/x300/x300_init.c | 168 | ||||
-rw-r--r-- | firmware/usrp3/x300/x300_init.h | 18 | ||||
-rw-r--r-- | firmware/usrp3/x300/x300_main.c | 470 |
6 files changed, 934 insertions, 0 deletions
diff --git a/firmware/usrp3/x300/CMakeLists.txt b/firmware/usrp3/x300/CMakeLists.txt new file mode 100644 index 000000000..5e6134885 --- /dev/null +++ b/firmware/usrp3/x300/CMakeLists.txt @@ -0,0 +1,36 @@ +# +# Copyright 2010-2014 Ettus Research LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +######################################################################## +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +include_directories(${CMAKE_SOURCE_DIR}/../../host/lib/usrp/x300) + +list(APPEND x300_sources x300_init.c x300_main.c) + +######################################################################## +set(GEN_OUTPUTS_BIN_SIZE 0x7fff) +SET(CMAKE_C_FLAGS_DEBUG -DX300_DEBUG_UART) + +add_executable(x300_main.elf ${x300_sources}) +target_link_libraries(x300_main.elf usrp3fw) +GEN_OUTPUTS(x300_main.elf x300) + +INSTALL( + FILES ${CMAKE_CURRENT_BINARY_DIR}/x300_main.bin + DESTINATION share/uhd/images + RENAME usrp_x300_fw.bin +) diff --git a/firmware/usrp3/x300/x300_debug.py b/firmware/usrp3/x300/x300_debug.py new file mode 100755 index 000000000..c9bcbb138 --- /dev/null +++ b/firmware/usrp3/x300/x300_debug.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python +# +# Copyright 2010-2011 Ettus Research LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +import optparse +import math +import socket +import struct + + +######################################################################## +# constants +######################################################################## +B250_FW_COMMS_UDP_PORT = 49152 + +B250_FW_COMMS_FLAGS_ACK = 1 +B250_FW_COMMS_FLAGS_ERROR = 2 +B250_FW_COMMS_FLAGS_POKE32 = 4 +B250_FW_COMMS_FLAGS_PEEK32 = 8 + +#UDP_CTRL_PORT = 49183 +UDP_MAX_XFER_BYTES = 1024 +UDP_TIMEOUT = 3 +#USRP2_FW_PROTO_VERSION = 11 #should be unused after r6 + +#REG_ARGS_FMT = '!LLLLLB15x' +#REG_IP_FMT = '!LLLL20x' +REG_PEEK_POKE_FMT = '!LLLL' + + +_seq = -1 +def seq(): + global _seq + _seq = _seq+1 + return _seq + + +######################################################################## +# helper functions +######################################################################## + +def unpack_reg_peek_poke_fmt(s): + return struct.unpack(REG_PEEK_POKE_FMT,s) #(flags, seq, addr, data) + +def pack_reg_peek_poke_fmt(flags, seq, addr, data): + return struct.pack(REG_PEEK_POKE_FMT, flags, seq, addr, data); + +######################################################################## +# Burner class, holds a socket and send/recv routines +######################################################################## +class ctrl_socket(object): + def __init__(self, addr): + self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + self._sock.settimeout(UDP_TIMEOUT) + self._sock.connect((addr, B250_FW_COMMS_UDP_PORT)) + self.set_callbacks(lambda *a: None, lambda *a: None) + #self.init_update() #check that the device is there + + def set_callbacks(self, progress_cb, status_cb): + self._progress_cb = progress_cb + self._status_cb = status_cb + + def send_and_recv(self, pkt): + self._sock.send(pkt) + return self._sock.recv(UDP_MAX_XFER_BYTES) + + def read_router_stats(self): + print + print(" "), + ports = [' eth0',' eth1',' radio0',' radio1',' compute0',' compute1',' compute2',' pcie'] + for in_prt in ports: + print("%s" % in_prt), + print(" Egress Port") + print(" "), + for in_prt in range (0, 8): + print("____________"), + print + for in_prt in range (0, 8): + print("%s |" % ports[in_prt]), + for out_prt in range (0, 8): + out_pkt = pack_reg_peek_poke_fmt(B250_FW_COMMS_FLAGS_PEEK32|B250_FW_COMMS_FLAGS_ACK, seq(), 0xA000+256+((in_prt*8+out_prt)*4), 0) + in_pkt = self.send_and_recv(out_pkt) + (flags, rxseq, addr, data) = unpack_reg_peek_poke_fmt(in_pkt) + if flags & B250_FW_COMMS_FLAGS_ERROR == B250_FW_COMMS_FLAGS_ERROR: + raise Exception("B250 peek returns error code") + print("%10d " % (data)), + print + print + print("Ingress Port") + print + + + def peek(self,peek_addr): + out_pkt = pack_reg_peek_poke_fmt(B250_FW_COMMS_FLAGS_PEEK32|B250_FW_COMMS_FLAGS_ACK, seq(), peek_addr, 0) + in_pkt = self.send_and_recv(out_pkt) + (flags, rxseq, addr, data) = unpack_reg_peek_poke_fmt(in_pkt) + if flags & B250_FW_COMMS_FLAGS_ERROR == B250_FW_COMMS_FLAGS_ERROR: + raise Exception("B250 peek of address %d returns error code" % (addr)) + print("PEEK of address %d(0x%x) reads %d(0x%x)" % (addr,addr,data,data)) + + def poke(self,poke_addr,poke_data): + out_pkt = pack_reg_peek_poke_fmt(B250_FW_COMMS_FLAGS_POKE32|B250_FW_COMMS_FLAGS_ACK, seq(), poke_addr, poke_data) + in_pkt = self.send_and_recv(out_pkt) + (flags, rxseq, addr, data) = unpack_reg_peek_poke_fmt(in_pkt) + if flags & B250_FW_COMMS_FLAGS_ERROR == B250_FW_COMMS_FLAGS_ERROR: + raise Exception("B250 peek of address %d returns error code" % (addr)) + print("POKE of address %d(0x%x) with %d(0x%x)" % (poke_addr,poke_addr,poke_data,poke_data) ) + + +######################################################################## +# command line options +######################################################################## +def get_options(): + parser = optparse.OptionParser() + parser.add_option("--addr", type="string", help="USRP-N2XX device address", default='') + parser.add_option("--list", action="store_true", help="list possible network devices", default=False) + parser.add_option("--peek", type="int", help="Read from memory map", default=None) + parser.add_option("--poke", type="int", help="Write to memory map", default=None) + parser.add_option("--data", type="int", help="Data for poke", default=None) + parser.add_option("--stats", action="store_true", help="Display SuperMIMO Network Stats", default=False) + (options, args) = parser.parse_args() + + return options + + +######################################################################## +# main +######################################################################## +if __name__=='__main__': + options = get_options() + + + if options.list: + print('Possible network devices:') + print(' ' + '\n '.join(enumerate_devices())) + exit() + + if not options.addr: raise Exception('no address specified') + + status = ctrl_socket(addr=options.addr) + + if options.stats: + status.read_router_stats() + + + if options.peek is not None: + addr = options.peek + status.peek(addr) + + if options.poke is not None and options.data is not None: + addr = options.poke + data = options.data + status.poke(addr,data) diff --git a/firmware/usrp3/x300/x300_defs.h b/firmware/usrp3/x300/x300_defs.h new file mode 100644 index 000000000..65c5d5a23 --- /dev/null +++ b/firmware/usrp3/x300/x300_defs.h @@ -0,0 +1,75 @@ + +// Copyright 2014 Ettus Research LLC + +#ifndef INCLUDED_X300_DEFS_H +#define INCLUDED_X300_DEFS_H + +#define CPU_CLOCK 166666667 +#define MAIN_RAM_BASE 0x0000 +#define PKT_RAM0_BASE 0x8000 +#define XGE0_BASE 0xC000 +#define XGE1_BASE 0xD000 +#define BOOT_LDR_BASE 0xFC00 +#define UART0_BASE 0xfd00 +#define UART0_BAUD 115200 +#define UART1_BASE 0xf900 +#define UART1_BAUD 115200 +#define I2C0_BASE 0xfe00 +#define I2C1_BASE 0xff00 +#define I2C2_BASE 0xfc00 +#define SET0_BASE 0xa000 +#define RB0_BASE 0xa000 //same as set +#define SETXB_BASE 0xb000 + +#define ETH1G +//#define ETH10G + +//eeprom map for mboard addrs +#define MBOARD_EEPROM_ADDR 0x50 + +// Setting Regs Memeory Map +static const int SR_LEDS = 0; +static const int SR_SW_RST = 1; +static const int SR_CLOCK_CTRL = 2; +static const int SR_XB_LOCAL = 3; +static const int SR_SFPP_CTRL = 4; +static const int SR_SPI = 32; +static const int SR_ETHINT0 = 40; +static const int SR_ETHINT1 = 56; + +//led shifts for SR_LEDS +static const int LED_ACT1 = (1 << 5); +static const int LED_ACT2 = (1 << 4); +static const int LED_LINK1 = (1 << 3); +static const int LED_LINK2 = (1 << 2); +static const int LED_LINKSTAT = (1 << 1); +static const int LED_LINKACT = (1 << 0); + +// Readback Memory Map +static const int RB_COUNTER = 0; +static const int RB_SPI_RDY = 1; +static const int RB_SPI_DATA = 2; +static const int RB_ETH_TYPE0 = 4; +static const int RB_ETH_TYPE1 = 5; +static const int RB_SFPP_STATUS0 = 8; +static const int RB_SFPP_STATUS1 = 9; + +// Bootloader Memory Map +static const int BL_ADDRESS = 0; +static const int BL_DATA = 1; + +#define SW_RST_PHY 0x01 +#define SW_RST_RADIO 0x02 +#define SW_RST_RADIO_PLL 0x04 + +//eth framer constants +#define ETH_FRAMER_SRC_MAC_HI 0 +#define ETH_FRAMER_SRC_MAC_LO 1 +#define ETH_FRAMER_SRC_IP_ADDR 2 +#define ETH_FRAMER_SRC_UDP_PORT 3 +#define ETH_FRAMER_DST_RAM_ADDR 4 +#define ETH_FRAMER_DST_IP_ADDR 5 +#define ETH_FRAMER_DST_UDP_MAC 6 +#define ETH_FRAMER_DST_MAC_LO 7 + +#endif /* INCLUDED_X300_DEFS_H */ diff --git a/firmware/usrp3/x300/x300_init.c b/firmware/usrp3/x300/x300_init.c new file mode 100644 index 000000000..66fb120f3 --- /dev/null +++ b/firmware/usrp3/x300/x300_init.c @@ -0,0 +1,168 @@ +#include "x300_init.h" +#include "x300_defs.h" +#include "ethernet.h" +#include "mdelay.h" +#include <wb_utils.h> +#include <wb_uart.h> +#include <wb_i2c.h> +#include <stdint.h> +#include <stdbool.h> +#include <printf.h> +#include <wb_pkt_iface64.h> +#include <u3_net_stack.h> +#include <link_state_route_proto.h> +#include <udp_uart.h> +#include "x300_fw_common.h" +#include <print_addrs.h> + +static wb_pkt_iface64_config_t pkt_config; + +struct x300_eeprom_map +{ + //indentifying numbers + unsigned char revision[2]; + unsigned char product[2]; + uint8_t _pad0[4]; + + //all the mac addrs + uint8_t mac_addr0[6]; + uint8_t _pad1[2]; + uint8_t mac_addr1[6]; + uint8_t _pad2[2]; + + //all the IP addrs + uint32_t gateway; + uint32_t subnet[4]; + uint32_t ip_addr[4]; + uint8_t _pad3[16]; +}; + +static struct x300_eeprom_map default_map = { + .mac_addr0 = X300_DEFAULT_MAC_ADDR_0, + .mac_addr1 = X300_DEFAULT_MAC_ADDR_1, + .gateway = X300_DEFAULT_GATEWAY, + .subnet = { + X300_DEFAULT_NETMASK_ETH0_1G, + X300_DEFAULT_NETMASK_ETH1_1G, + X300_DEFAULT_NETMASK_ETH0_10G, + X300_DEFAULT_NETMASK_ETH1_10G + }, + .ip_addr = { + X300_DEFAULT_IP_ETH0_1G, + X300_DEFAULT_IP_ETH1_1G, + X300_DEFAULT_IP_ETH0_10G, + X300_DEFAULT_IP_ETH1_10G + }, +}; + +const void *pick_inited_field(const void *eeprom, const void *def, const size_t len) +{ + bool all_ones = true; + bool all_zeros = true; + for (size_t i = 0; i < len; i++) + { + const uint8_t b = ((const uint8_t *)eeprom)[i]; + if (b != 0x00) all_zeros = false; + if (b != 0xff) all_ones = false; + } + if (all_zeros) return def; + if (all_ones) return def; + return eeprom; +} + +static void init_network(void) +{ + pkt_config = wb_pkt_iface64_init(PKT_RAM0_BASE, 0x1ffc); + printf("PKT RAM0 BASE 0x%x\n", (&pkt_config)->base); + u3_net_stack_init(&pkt_config); + + link_state_route_proto_init(); + + //read everything from eeprom + static const uint8_t eeprom_cmd[2] = {0, 0}; //the command is 16 bits of address offset + struct x300_eeprom_map eeprom_map = default_map; + wb_i2c_write(I2C1_BASE, MBOARD_EEPROM_ADDR, eeprom_cmd, 2); + wb_i2c_read(I2C1_BASE, MBOARD_EEPROM_ADDR, (uint8_t *)(&eeprom_map), sizeof(eeprom_map)); + + //determine interface number + const size_t eth0no = wb_peek32(SR_ADDR(RB0_BASE, RB_ETH_TYPE0))? 2 : 0; + const size_t eth1no = wb_peek32(SR_ADDR(RB0_BASE, RB_ETH_TYPE1))? 3 : 1; + + //pick the address from eeprom or default + const eth_mac_addr_t *my_mac0 = (const eth_mac_addr_t *)pick_inited_field(&eeprom_map.mac_addr0, &default_map.mac_addr0, 6); + const eth_mac_addr_t *my_mac1 = (const eth_mac_addr_t *)pick_inited_field(&eeprom_map.mac_addr1, &default_map.mac_addr1, 6); + const struct ip_addr *my_ip0 = (const struct ip_addr *)pick_inited_field(&eeprom_map.ip_addr[eth0no], &default_map.ip_addr[eth0no], 4); + const struct ip_addr *subnet0 = (const struct ip_addr *)pick_inited_field(&eeprom_map.subnet[eth0no], &default_map.subnet[eth0no], 4); + const struct ip_addr *my_ip1 = (const struct ip_addr *)pick_inited_field(&eeprom_map.ip_addr[eth1no], &default_map.ip_addr[eth1no], 4); + const struct ip_addr *subnet1 = (const struct ip_addr *)pick_inited_field(&eeprom_map.subnet[eth1no], &default_map.subnet[eth1no], 4); + + //init eth0 + u3_net_stack_init_eth(0, my_mac0, my_ip0, subnet0); + wb_poke32(SR_ADDR(SET0_BASE, SR_ETHINT0 + 8 + 0), (my_mac0->addr[5] << 0) | (my_mac0->addr[4] << 8) | (my_mac0->addr[3] << 16) | (my_mac0->addr[2] << 24)); + wb_poke32(SR_ADDR(SET0_BASE, SR_ETHINT0 + 8 + 1), (my_mac0->addr[1] << 0) | (my_mac0->addr[0] << 8)); + wb_poke32(SR_ADDR(SET0_BASE, SR_ETHINT0 + 8 + 2), my_ip0->addr); + wb_poke32(SR_ADDR(SET0_BASE, SR_ETHINT0 + 8 + 4), 0/*nofwd*/); + wb_poke32(SR_ADDR(SET0_BASE, SR_ETHINT0 + 8 + 5), (ICMP_IRQ << 8) | 0); //no fwd: type, code + + //init eth1 + u3_net_stack_init_eth(1, my_mac1, my_ip1, subnet1); + wb_poke32(SR_ADDR(SET0_BASE, SR_ETHINT1 + 8 + 0), (my_mac1->addr[5] << 0) | (my_mac1->addr[4] << 8) | (my_mac1->addr[3] << 16) | (my_mac1->addr[2] << 24)); + wb_poke32(SR_ADDR(SET0_BASE, SR_ETHINT1 + 8 + 1), (my_mac1->addr[1] << 0) | (my_mac1->addr[0] << 8)); + wb_poke32(SR_ADDR(SET0_BASE, SR_ETHINT1 + 8 + 2), my_ip1->addr); + wb_poke32(SR_ADDR(SET0_BASE, SR_ETHINT1 + 8 + 4), 0/*nofwd*/); + wb_poke32(SR_ADDR(SET0_BASE, SR_ETHINT1 + 8 + 5), (ICMP_IRQ << 8) | 0); //no fwd: type, code +} + +static void putc(void *p, char c) +{ +#ifdef X300_DEBUG_UART + wb_uart_putc(UART1_BASE, c); +#endif +} + +void x300_init(void) +{ + //first - uart + wb_uart_init(UART0_BASE, CPU_CLOCK/UART0_BAUD); + wb_uart_init(UART1_BASE, CPU_CLOCK/UART1_BAUD); + init_printf(NULL,putc); + //udp_uart_init(UART0_BASE, X300_GPSDO_UDP_PORT); + + //now we can init the rest with prints + printf("X300 ZPU Init Begin -- CPU CLOCK is %d MHz\n", CPU_CLOCK/1000000); + + //i2c rate init + wb_i2c_init(I2C0_BASE, CPU_CLOCK); + wb_i2c_init(I2C1_BASE, CPU_CLOCK); + wb_i2c_init(I2C2_BASE, CPU_CLOCK); + + //hold phy in reset + wb_poke32(SR_ADDR(SET0_BASE, SR_SW_RST), SW_RST_PHY); + + printf("DEBUG: eth0 is %2dG\n",(wb_peek32(SR_ADDR(RB0_BASE, RB_ETH_TYPE0))==1) ? 10 : 1); + printf("DEBUG: eth1 is %2dG\n",(wb_peek32(SR_ADDR(RB0_BASE, RB_ETH_TYPE1))==1) ? 10 : 1); + + //setup net stack and eth state machines + init_network(); + + //phy reset release + wb_poke32(SR_ADDR(SET0_BASE, SR_SW_RST), 0); + + // For eth interfaces, initialize the PHY's + mdelay(100); + if (wb_peek32(SR_ADDR(RB0_BASE, RB_ETH_TYPE0)) == 1) { + xge_ethernet_init(0); + } + if (wb_peek32(SR_ADDR(RB0_BASE, RB_ETH_TYPE1)) == 1) { + xge_ethernet_init(1); + } + + //print network summary + for (uint8_t e = 0; e < ethernet_ninterfaces(); e++) + { + printf(" MAC%u: %s\n", (int)e, mac_addr_to_str(u3_net_stack_get_mac_addr(e))); + printf(" IP%u: %s\n", (int)e, ip_addr_to_str(u3_net_stack_get_ip_addr(e))); + printf(" SUBNET%u: %s\n", (int)e, ip_addr_to_str(u3_net_stack_get_subnet(e))); + printf(" BCAST%u: %s\n", (int)e, ip_addr_to_str(u3_net_stack_get_bcast(e))); + } +} diff --git a/firmware/usrp3/x300/x300_init.h b/firmware/usrp3/x300/x300_init.h new file mode 100644 index 000000000..324033779 --- /dev/null +++ b/firmware/usrp3/x300/x300_init.h @@ -0,0 +1,18 @@ + +// Copyright 2012 Ettus Research LLC + +#ifndef INCLUDED_B250_INIT_H +#define INCLUDED_B250_INIT_H + +void x300_init(void); + +void x300_serial_loader_run1(void); + +typedef enum + { + DCO_156p25, + DCO_125, + DCO_10 + } dco_freq_t; + +#endif /* INCLUDED_B250_INIT_H */ diff --git a/firmware/usrp3/x300/x300_main.c b/firmware/usrp3/x300/x300_main.c new file mode 100644 index 000000000..d865e1d09 --- /dev/null +++ b/firmware/usrp3/x300/x300_main.c @@ -0,0 +1,470 @@ +// Copyright 2013-2014 Ettus Research LLC + +#include "x300_init.h" +#include "x300_defs.h" +#include "x300_fw_common.h" +#include "xge_phy.h" +#include "ethernet.h" +#include "chinch.h" +#include "mdelay.h" + +#include <wb_utils.h> +#include <wb_uart.h> +#include <udp_uart.h> +#include <u3_net_stack.h> +#include <link_state_route_proto.h> +#include <printf.h> +#include <string.h> +#include <print_addrs.h> + +static uint32_t *shmem = (uint32_t *) X300_FW_SHMEM_BASE; + +/*********************************************************************** + * Setup call for udp framer + **********************************************************************/ +void program_udp_framer( + const uint8_t ethno, + const uint32_t sid, + const struct ip_addr *dst_ip, + const uint16_t dst_port, + const uint16_t src_port +) +{ + const eth_mac_addr_t *dst_mac = u3_net_stack_arp_cache_lookup(dst_ip); + const size_t ethbase = (ethno == 0)? SR_ETHINT0 : SR_ETHINT1; + const size_t vdest = (sid >> 16) & 0xff; + printf("handle_udp_prog_framer sid %u vdest %u\n", sid, vdest); + + //setup source framer + const eth_mac_addr_t *src_mac = u3_net_stack_get_mac_addr(ethno); + wb_poke32(SR_ADDR(SET0_BASE, ethbase + ETH_FRAMER_SRC_MAC_HI), + (((uint32_t)src_mac->addr[0]) << 8) | (((uint32_t)src_mac->addr[1]) << 0)); + wb_poke32(SR_ADDR(SET0_BASE, ethbase + ETH_FRAMER_SRC_MAC_LO), + (((uint32_t)src_mac->addr[2]) << 24) | (((uint32_t)src_mac->addr[3]) << 16) | + (((uint32_t)src_mac->addr[4]) << 8) | (((uint32_t)src_mac->addr[5]) << 0)); + wb_poke32(SR_ADDR(SET0_BASE, ethbase + ETH_FRAMER_SRC_IP_ADDR), u3_net_stack_get_ip_addr(ethno)->addr); + wb_poke32(SR_ADDR(SET0_BASE, ethbase + ETH_FRAMER_SRC_UDP_PORT), src_port); + + //setup destination framer + wb_poke32(SR_ADDR(SET0_BASE, ethbase + ETH_FRAMER_DST_RAM_ADDR), vdest); + wb_poke32(SR_ADDR(SET0_BASE, ethbase + ETH_FRAMER_DST_IP_ADDR), dst_ip->addr); + wb_poke32(SR_ADDR(SET0_BASE, ethbase + ETH_FRAMER_DST_UDP_MAC), + (((uint32_t)dst_port) << 16) | + (((uint32_t)dst_mac->addr[0]) << 8) | (((uint32_t)dst_mac->addr[1]) << 0)); + wb_poke32(SR_ADDR(SET0_BASE, ethbase + ETH_FRAMER_DST_MAC_LO), + (((uint32_t)dst_mac->addr[2]) << 24) | (((uint32_t)dst_mac->addr[3]) << 16) | + (((uint32_t)dst_mac->addr[4]) << 8) | (((uint32_t)dst_mac->addr[5]) << 0)); +} + +/*********************************************************************** + * Handler for UDP framer program packets + **********************************************************************/ +void handle_udp_prog_framer( + const uint8_t ethno, + const struct ip_addr *src, const struct ip_addr *dst, + const uint16_t src_port, const uint16_t dst_port, + const void *buff, const size_t num_bytes +) +{ + if (buff == NULL) { + /* We got here from ICMP_DUR undeliverable packet */ + /* Future space for hooks to tear down streaming radios etc */ + } + else { + const uint32_t sid = ((const uint32_t *)buff)[1]; + program_udp_framer(ethno, sid, src, src_port, dst_port); + } +} + +/*********************************************************************** + * Handler for peek and poke host packets + **********************************************************************/ +void handle_udp_fw_comms( + const uint8_t ethno, + const struct ip_addr *src, const struct ip_addr *dst, + const uint16_t src_port, const uint16_t dst_port, + const void *buff, const size_t num_bytes +) +{ + if (buff == NULL) { + /* We got here from ICMP_DUR undeliverable packet */ + /* Future space for hooks to tear down streaming radios etc */ + } else { + const x300_fw_comms_t *request = (const x300_fw_comms_t *)buff; + x300_fw_comms_t reply; memcpy(&reply, buff, sizeof(reply)); + + //check for error and set error flag + if (num_bytes < sizeof(x300_fw_comms_t)) { + reply.flags |= X300_FW_COMMS_FLAGS_ERROR; + } + //otherwise, run the actions set by the flags + else { + if (request->flags & X300_FW_COMMS_FLAGS_PEEK32) + { + if (request->addr & 0x00100000) { + chinch_peek32(request->addr & 0x000FFFFF, &reply.data); + } else { + reply.data = wb_peek32(request->addr); + } + } + if (request->flags & X300_FW_COMMS_FLAGS_POKE32) + { + if (request->addr & 0x00100000) { + chinch_poke32(request->addr & 0x000FFFFF, request->data); + } else { + wb_poke32(request->addr, request->data); + } + } + } + + //send a reply if ack requested + if (request->flags & X300_FW_COMMS_FLAGS_ACK) { + u3_net_stack_send_udp_pkt(ethno, src, dst_port, src_port, &reply, sizeof(reply)); + } + } +} + +/*********************************************************************** + * Handler for FPGA programming packets + **********************************************************************/ +void handle_udp_fpga_prog( + const uint8_t ethno, + const struct ip_addr *src, const struct ip_addr *dst, + const uint16_t src_port, const uint16_t dst_port, + const void *buff, const size_t num_bytes +) +{ + const x300_fpga_prog_t *request = (const x300_fpga_prog_t *)buff; + x300_fpga_prog_flags_t reply = {0}; + bool status = true; + + if (buff == NULL) { + return; + } else if (num_bytes < offsetof(x300_fpga_prog_t, data)) { + reply.flags |= X300_FPGA_PROG_FLAGS_ERROR; + } else { + if (request->flags & X300_FPGA_PROG_FLAGS_INIT) { + STATUS_MERGE(chinch_flash_init(), status); + } else if (request->flags & X300_FPGA_PROG_FLAGS_CLEANUP) { + chinch_flash_cleanup(); + } else if (request->flags & X300_FPGA_PROG_CONFIGURE) { + //This is a self-destructive operation and will most likely not return an ack. + chinch_start_config(); + } else if (request->flags & X300_FPGA_PROG_CONFIG_STATUS) { + if (chinch_get_config_status() != CHINCH_CONFIG_COMPLETED) + reply.flags |= X300_FPGA_PROG_FLAGS_ERROR; + } else { + STATUS_MERGE(chinch_flash_select_sector(request->sector), status); + if (request->flags & X300_FPGA_PROG_FLAGS_ERASE) + STATUS_CHAIN(chinch_flash_erase_sector(), status); + + uint32_t num_buff_writes = (request->size / CHINCH_FLASH_MAX_BUF_WRITES) + + (request->size % CHINCH_FLASH_MAX_BUF_WRITES == 0 ? 0 : 1); + uint32_t data_idx = 0; + for (uint32_t buf_wr_i = 0; (buf_wr_i < num_buff_writes) && status; buf_wr_i++) { + uint32_t wr_len = (request->size - data_idx) >= CHINCH_FLASH_MAX_BUF_WRITES ? + CHINCH_FLASH_MAX_BUF_WRITES : (request->size - data_idx); + + STATUS_MERGE(chinch_flash_write_buf((request->index + data_idx)*2, + (uint16_t*)request->data+data_idx, wr_len), status); + data_idx += wr_len; + } + + if (request->flags & X300_FPGA_PROG_FLAGS_VERIFY) { + uint16_t data[request->size]; + STATUS_MERGE(chinch_flash_read_buf(request->index*2, data, request->size), status); + for (uint32_t i = 0; i < request->size; i++) { + status &= (data[i] == request->data[i]); + } + } + } + } + if (!status) reply.flags |= X300_FPGA_PROG_FLAGS_ERROR; + + //send a reply if ack requested + if (request->flags & X300_FPGA_PROG_FLAGS_ACK) + { + u3_net_stack_send_udp_pkt(ethno, src, dst_port, src_port, &reply, sizeof(reply)); + } +} + +/*********************************************************************** + * Handler for MTU detection + **********************************************************************/ +void handle_udp_mtu_detect( + const uint8_t ethno, + const struct ip_addr *src, const struct ip_addr *dst, + const uint16_t src_port, const uint16_t dst_port, + const void *buff, const size_t num_bytes +) +{ + const x300_mtu_t *request = (const x300_mtu_t *) buff; + x300_mtu_t reply; + + if (buff == NULL) { + return; + } else if (!(request->flags & X300_MTU_DETECT_ECHO_REQUEST)) { + printf("DEBUG: MTU detect got unknown request\n"); + reply.flags |= X300_MTU_DETECT_ERROR; + } + + reply.flags |= X300_MTU_DETECT_ECHO_REPLY; + reply.size = num_bytes; + + u3_net_stack_send_udp_pkt(ethno, src, dst_port, src_port, &reply, request->size); +} + + +/*********************************************************************** + * Deal with host claims and claim timeout + **********************************************************************/ +static void handle_claim(void) +{ + static uint32_t last_time = 0; + static size_t timeout = 0; + + //time is 0 if the claim was forfeit + if (shmem[X300_FW_SHMEM_CLAIM_TIME] == 0) + { + shmem[X300_FW_SHMEM_CLAIM_STATUS] = 0; + } + //if the time changes, reset timeout + else if (last_time != shmem[X300_FW_SHMEM_CLAIM_TIME]) + { + shmem[X300_FW_SHMEM_CLAIM_STATUS] = 1; + timeout = 0; + } + //otherwise increment for timeout + else timeout++; + + //always stash the last seen time + last_time = shmem[X300_FW_SHMEM_CLAIM_TIME]; + + //the claim has timed out after 2 seconds + if (timeout > 2000) shmem[X300_FW_SHMEM_CLAIM_STATUS] = 0; +} + +/*********************************************************************** + * LED blinky logic and support utilities + **********************************************************************/ +static uint32_t get_xbar_total(const uint8_t port) +{ + #define get_xbar_stat(in_prt, out_prt) \ + wb_peek32(RB0_BASE+256+(((in_prt)*8+(out_prt))*4)) + uint32_t total = 0; + for (size_t i = 0; i < 8; i++) + { + total += get_xbar_stat(port, i); + } + for (size_t i = 0; i < 8; i++) + { + total += get_xbar_stat(i, port); + } + if (port < 2) //also netstack if applicable + { + total += u3_net_stack_get_stat_counts(port); + } + return total; +} + +static size_t popcntll(uint64_t num) +{ + size_t total = 0; + for (size_t i = 0; i < sizeof(num)*8; i++) + { + total += (num >> i) & 0x1; + } + return total; +} + +static void update_leds(void) +{ + //update activity status for all ports + uint64_t activity_shreg[8]; + for (size_t i = 0; i < 8; i++) + { + static uint32_t last_total[8]; + const uint32_t total = get_xbar_total(i); + activity_shreg[i] <<= 1; + activity_shreg[i] |= (total == last_total[i])? 0 : 1; + last_total[i] = total; + } + + static uint32_t counter = 0; + counter++; + + const size_t cnt0 = popcntll(activity_shreg[0]); + const size_t cnt1 = popcntll(activity_shreg[1]); + const bool act0 = cnt0*8 > (counter % 64); + const bool act1 = cnt1*8 > (counter % 64); + const bool link0 = ethernet_get_link_up(0); + const bool link1 = ethernet_get_link_up(1); + const bool claimed = shmem[X300_FW_SHMEM_CLAIM_STATUS]; + + wb_poke32(SET0_BASE + SR_LEDS*4, 0 + | (link0? LED_LINK2 : 0) + | (link1? LED_LINK1 : 0) + | (act0? LED_ACT2 : 0) + | (act1? LED_ACT1 : 0) + | ((act0 || act1)? LED_LINKACT : 0) + | (claimed? LED_LINKSTAT : 0) + ); +} + +/*********************************************************************** + * Send periodic GARPs to keep network hardware informed + **********************************************************************/ +static void garp(void) +{ + static size_t count = 0; + if (count++ < 60000) return; //60 seconds + count = 0; + for (size_t e = 0; e < ethernet_ninterfaces(); e++) + { + if (!ethernet_get_link_up(e)) continue; + u3_net_stack_send_arp_request(e, u3_net_stack_get_ip_addr(e)); + } +} + +/*********************************************************************** + * UART handlers - interacts between UART and SHMEM + **********************************************************************/ +static void handle_uarts(void) +{ + //pool allocations - always update shmem with location + #define NUM_POOL_WORDS32 64 + static uint32_t rxpool[NUM_POOL_WORDS32]; + static uint32_t txpool[NUM_POOL_WORDS32]; + shmem[X300_FW_SHMEM_UART_RX_ADDR] = (uint32_t)rxpool; + shmem[X300_FW_SHMEM_UART_TX_ADDR] = (uint32_t)txpool; + shmem[X300_FW_SHMEM_UART_WORDS32] = NUM_POOL_WORDS32; + + //////////////////////////////////////////////////////////////////// + // RX UART - get available characters and post to the shmem buffer + //////////////////////////////////////////////////////////////////// + static uint32_t rxoffset = 0; + for (int rxch = wb_uart_getc(UART0_BASE); rxch != -1; rxch = wb_uart_getc(UART0_BASE)) + { + rxoffset++; + const int shift = ((rxoffset%4) * 8); + static uint32_t rxword32 = 0; + if (shift == 0) rxword32 = 0; + rxword32 |= ((uint32_t) rxch & 0xFF) << shift; + rxpool[(rxoffset/4) % NUM_POOL_WORDS32] = rxword32; + shmem[X300_FW_SHMEM_UART_RX_INDEX] = rxoffset; + } + + //////////////////////////////////////////////////////////////////// + // TX UART - check for characters in the shmem buffer and send them + //////////////////////////////////////////////////////////////////// + static uint32_t txoffset = 0; + while (txoffset != shmem[X300_FW_SHMEM_UART_TX_INDEX]) + { + const int shift = ((txoffset%4) * 8); + const int txch = txpool[txoffset/4] >> shift; + wb_uart_putc(UART0_BASE, txch); + txoffset = (txoffset+1) % (NUM_POOL_WORDS32*4); + } +} + +/*********************************************************************** + * update the link state periodic update + **********************************************************************/ +static void update_forwarding(const uint8_t e) +{ + /* FIXME: This code is broken. + * It blindly enables forwarding without regard to whether or not + * packets can be forwarded. If one of the Ethernet interfaces is not + * connected, data backs up until the first interface becomes unresponsive. + * + * //update forwarding rules + * uint32_t forward = 0; + * if (!link_state_route_proto_causes_cycle_cached(e, (e+1)%2)) + * { + * forward |= (1 << 0); //forward bcast + * forward |= (1 << 1); //forward not mac dest + * } + * const uint32_t eth_base = (e == 0)? SR_ETHINT0 : SR_ETHINT1; + * wb_poke32(SR_ADDR(SET0_BASE, eth_base + 8 + 4), forward); + */ + +} + +static void handle_link_state(void) +{ + //update shmem entries to keep it persistent + size_t map_len = 0; + shmem[X300_FW_SHMEM_ROUTE_MAP_ADDR] = (uint32_t)link_state_route_get_node_mapping(&map_len); + shmem[X300_FW_SHMEM_ROUTE_MAP_LEN] = map_len; + + static size_t count = 0; + if (count--) return; + count = 2000; //repeat every ~2 seconds + + link_state_route_proto_tick(); + for (size_t e = 0; e < ethernet_ninterfaces(); e++) + { + if (ethernet_get_link_up(e)) + { + link_state_route_proto_update(e); + link_state_route_proto_flood(e); + } + + //update forwarding if something changed + bool before = link_state_route_proto_causes_cycle_cached(e, (e+1)%2); + link_state_route_proto_update_cycle_cache(e); + if (before != link_state_route_proto_causes_cycle_cached(e, (e+1)%2)) + update_forwarding(e); + /* + printf("is there a cycle %s -> %s? %s\n", + ip_addr_to_str(u3_net_stack_get_ip_addr(e)), + ip_addr_to_str(u3_net_stack_get_ip_addr((e+1)%2)), + link_state_route_proto_causes_cycle_cached(e, (e+1)%2)? "YES" : "no"); + //*/ + } +} + +/*********************************************************************** + * Main loop runs all the handlers + **********************************************************************/ +int main(void) +{ + x300_init(); + u3_net_stack_register_udp_handler(X300_FW_COMMS_UDP_PORT, &handle_udp_fw_comms); + u3_net_stack_register_udp_handler(X300_VITA_UDP_PORT, &handle_udp_prog_framer); + u3_net_stack_register_udp_handler(X300_FPGA_PROG_UDP_PORT, &handle_udp_fpga_prog); + u3_net_stack_register_udp_handler(X300_MTU_DETECT_UDP_PORT, &handle_udp_mtu_detect); + + uint32_t last_cronjob = 0; + + while(true) + { + //jobs that happen once every ms + const uint32_t ticks_now = wb_peek32(SR_ADDR(RB0_BASE, RB_COUNTER)); + const uint32_t ticks_passed = ticks_now - last_cronjob; + static const uint32_t tick_delta = CPU_CLOCK/1000; + if (ticks_passed > tick_delta) + { + handle_link_state(); //deal with router table update + handle_claim(); //deal with the host claim register + update_leds(); //run the link and activity leds + garp(); //send periodic garps + xge_poll_sfpp_status(0); // Every so often poll XGE Phy to look for SFP+ hotplug events. + xge_poll_sfpp_status(1); // Every so often poll XGE Phy to look for SFP+ hotplug events. + last_cronjob = wb_peek32(SR_ADDR(RB0_BASE, RB_COUNTER)); + } + + //run the network stack - poll and handle + u3_net_stack_handle_one(); + + //run the PCIe listener - poll and fwd to wishbone + forward_pcie_user_xact_to_wb(); + + //run the udp uart handler for incoming serial data + handle_uarts(); //udp_uart_poll(); + + //always reload the compat number into the shmem to keep it persistent + shmem[X300_FW_SHMEM_COMPAT_NUM] = (X300_FW_COMPAT_MAJOR << 16) | X300_FW_COMPAT_MINOR; + } + return 0; +} |