aboutsummaryrefslogtreecommitdiffstats
path: root/firmware/usrp3/x300
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/usrp3/x300')
-rw-r--r--firmware/usrp3/x300/CMakeLists.txt36
-rwxr-xr-xfirmware/usrp3/x300/x300_debug.py167
-rw-r--r--firmware/usrp3/x300/x300_defs.h75
-rw-r--r--firmware/usrp3/x300/x300_init.c168
-rw-r--r--firmware/usrp3/x300/x300_init.h18
-rw-r--r--firmware/usrp3/x300/x300_main.c470
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;
+}