diff options
| -rw-r--r-- | firmware/usrp3/x300/x300_defs.h | 2 | ||||
| -rw-r--r-- | firmware/usrp3/x300/x300_init.c | 44 | ||||
| -rw-r--r-- | firmware/usrp3/x300/x300_init.h | 5 | ||||
| -rw-r--r-- | firmware/usrp3/x300/x300_main.c | 47 | ||||
| -rw-r--r-- | host/lib/usrp/mboard_eeprom.cpp | 72 | ||||
| -rw-r--r-- | host/lib/usrp/x300/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | host/lib/usrp/x300/x300_fw_common.h | 29 | ||||
| -rw-r--r-- | host/lib/usrp/x300/x300_impl.cpp | 95 | ||||
| -rw-r--r-- | host/lib/usrp/x300/x300_impl.hpp | 9 | ||||
| -rw-r--r-- | host/lib/usrp/x300/x300_mb_eeprom.cpp | 190 | ||||
| -rw-r--r-- | host/lib/usrp/x300/x300_mb_eeprom.hpp | 37 | ||||
| -rw-r--r-- | host/lib/usrp/x300/x300_regs.hpp | 3 | 
12 files changed, 417 insertions, 117 deletions
diff --git a/firmware/usrp3/x300/x300_defs.h b/firmware/usrp3/x300/x300_defs.h index e9e9f34fa..ed756d6fd 100644 --- a/firmware/usrp3/x300/x300_defs.h +++ b/firmware/usrp3/x300/x300_defs.h @@ -9,7 +9,7 @@  #define PKT_RAM0_BASE 0x8000  #define SFP0_MAC_BASE 0xC000  #define SFP1_MAC_BASE 0xD000 -#define BOOT_LDR_BASE 0xFC00 +#define BOOT_LDR_BASE 0xFA00  #define UART0_BASE 0xfd00  #define UART0_BAUD 115200  #define UART1_BASE 0xf900 diff --git a/firmware/usrp3/x300/x300_init.c b/firmware/usrp3/x300/x300_init.c index 57c1faa2c..61d4f4190 100644 --- a/firmware/usrp3/x300/x300_init.c +++ b/firmware/usrp3/x300/x300_init.c @@ -1,5 +1,4 @@  #include "x300_init.h" -#include "x300_defs.h"  #include "ethernet.h"  #include "cron.h"  #include <wb_utils.h> @@ -17,27 +16,7 @@  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 = { +static x300_eeprom_map_t default_map = {      .mac_addr0 = X300_DEFAULT_MAC_ADDR_0,      .mac_addr1 = X300_DEFAULT_MAC_ADDR_1,      .gateway = X300_DEFAULT_GATEWAY, @@ -70,7 +49,7 @@ const void *pick_inited_field(const void *eeprom, const void *def, const size_t      return eeprom;  } -static void init_network(void) +static void init_network(x300_eeprom_map_t *eeprom_map)  {      pkt_config = wb_pkt_iface64_init(PKT_RAM0_BASE, 0x1ffc);      u3_net_stack_init(&pkt_config); @@ -79,21 +58,20 @@ static void init_network(void)      //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)); +    wb_i2c_read(I2C1_BASE, MBOARD_EEPROM_ADDR, (uint8_t *)(eeprom_map), sizeof(x300_eeprom_map_t));      //determine interface number      const size_t eth0no = wb_peek32(SR_ADDR(RB0_BASE, RB_SFP0_TYPE))? 2 : 0;      const size_t eth1no = wb_peek32(SR_ADDR(RB0_BASE, RB_SFP1_TYPE))? 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); +    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); @@ -126,7 +104,7 @@ static uint32_t get_counter_val()      return wb_peek32(SR_ADDR(RB0_BASE, RB_COUNTER));  } -void x300_init(void) +void x300_init(x300_eeprom_map_t *eeprom_map)  {      //first - uart      wb_uart_init(UART0_BASE, CPU_CLOCK/UART0_BAUD); @@ -153,7 +131,7 @@ void x300_init(void)      wb_poke32(SR_ADDR(SET0_BASE, SR_SW_RST), SW_RST_PHY);      //setup net stack and eth state machines -    init_network(); +    init_network(eeprom_map);      //phy reset release      wb_poke32(SR_ADDR(SET0_BASE, SR_SW_RST), 0); diff --git a/firmware/usrp3/x300/x300_init.h b/firmware/usrp3/x300/x300_init.h index 324033779..2e93340f6 100644 --- a/firmware/usrp3/x300/x300_init.h +++ b/firmware/usrp3/x300/x300_init.h @@ -4,7 +4,10 @@  #ifndef INCLUDED_B250_INIT_H  #define INCLUDED_B250_INIT_H -void x300_init(void); +#include "x300_defs.h" +#include "x300_fw_common.h" + +void x300_init(x300_eeprom_map_t *eeprom_map);  void x300_serial_loader_run1(void); diff --git a/firmware/usrp3/x300/x300_main.c b/firmware/usrp3/x300/x300_main.c index f255fe96c..c5e4fc88a 100644 --- a/firmware/usrp3/x300/x300_main.c +++ b/firmware/usrp3/x300/x300_main.c @@ -240,7 +240,7 @@ static void handle_claim(void)      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; +    if (timeout > 200) shmem[X300_FW_SHMEM_CLAIM_STATUS] = 0;  }  /*********************************************************************** @@ -264,36 +264,17 @@ static uint32_t get_xbar_total(const uint32_t 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[16]; -    for (uint32_t i = 0; i < 16; i++) -    { -        static uint32_t last_total[16]; -        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++; +    static uint32_t last_total0 = 0; +    static uint32_t last_total1 = 0; +    const uint32_t total0 = get_xbar_total(0); +    const uint32_t total1 = get_xbar_total(1); +    const bool act0 = (total0 != last_total0); +    const bool act1 = (total1 != last_total1); +    last_total0 = total0; +    last_total1 = total1; -    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]; @@ -314,7 +295,7 @@ static void update_leds(void)  static void garp(void)  {      static size_t count = 0; -    if (count++ < 60000) return; //60 seconds +    if (count++ < 3000) return; //30 seconds      count = 0;      for (size_t e = 0; e < ethernet_ninterfaces(); e++)      { @@ -428,7 +409,7 @@ static void handle_link_state(void)   **********************************************************************/  int main(void)  { -    x300_init(); +    x300_init((x300_eeprom_map_t *)&shmem[X300_FW_SHMEM_IDENT]);      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); @@ -438,10 +419,10 @@ int main(void)      while(true)      { -        //jobs that happen once every ms +        //jobs that happen once every 10ms          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; +        static const uint32_t tick_delta = CPU_CLOCK/100;          if (ticks_passed > tick_delta)          {              poll_sfpp_status(0); // Every so often poll XGE Phy to look for SFP+ hotplug events. @@ -450,7 +431,7 @@ int main(void)              handle_claim(); //deal with the host claim register              update_leds(); //run the link and activity leds              garp(); //send periodic garps -            last_cronjob = wb_peek32(SR_ADDR(RB0_BASE, RB_COUNTER)); +            last_cronjob = ticks_now;          }          //run the network stack - poll and handle diff --git a/host/lib/usrp/mboard_eeprom.cpp b/host/lib/usrp/mboard_eeprom.cpp index f10e0319a..4cf58cd05 100644 --- a/host/lib/usrp/mboard_eeprom.cpp +++ b/host/lib/usrp/mboard_eeprom.cpp @@ -235,52 +235,88 @@ struct x300_eeprom_map  static void load_x300(mboard_eeprom_t &mb_eeprom, i2c_iface &iface)  { +    byte_vector_t bytes = iface.read_eeprom(X300_EEPROM_ADDR, 0, sizeof (struct x300_eeprom_map)); + +    if (bytes.size() == 0) +    { +        return; +    } +      //extract the revision number      mb_eeprom["revision"] = uint16_bytes_to_string( -        iface.read_eeprom(X300_EEPROM_ADDR, offsetof(x300_eeprom_map, revision), 2) +            byte_vector_t( +            bytes.begin() + offsetof(x300_eeprom_map, revision), +            bytes.begin() + (offsetof(x300_eeprom_map, revision)+2))      );      //extract the revision compat number      mb_eeprom["revision_compat"] = uint16_bytes_to_string( -        iface.read_eeprom(X300_EEPROM_ADDR, offsetof(x300_eeprom_map, revision_compat), 2) +            byte_vector_t( +            bytes.begin() + offsetof(x300_eeprom_map, revision_compat), +            bytes.begin() + (offsetof(x300_eeprom_map, revision_compat)+2))      );      //extract the product code      mb_eeprom["product"] = uint16_bytes_to_string( -        iface.read_eeprom(X300_EEPROM_ADDR, offsetof(x300_eeprom_map, product), 2) +            byte_vector_t( +            bytes.begin() + offsetof(x300_eeprom_map, product), +            bytes.begin() + (offsetof(x300_eeprom_map, product)+2))      );      //extract the mac addresses -    mb_eeprom["mac-addr0"] = mac_addr_t::from_bytes(iface.read_eeprom( -        X300_EEPROM_ADDR, offsetof(x300_eeprom_map, mac_addr0), 6 -    )).to_string(); -    mb_eeprom["mac-addr1"] = mac_addr_t::from_bytes(iface.read_eeprom( -        X300_EEPROM_ADDR, offsetof(x300_eeprom_map, mac_addr1), 6 -    )).to_string(); +    mb_eeprom["mac-addr0"] = mac_addr_t::from_bytes( +            byte_vector_t( +            bytes.begin() + offsetof(x300_eeprom_map, mac_addr0), +            bytes.begin() + (offsetof(x300_eeprom_map, mac_addr0)+6)) +    ).to_string(); +    mb_eeprom["mac-addr1"] = mac_addr_t::from_bytes( +            byte_vector_t( +            bytes.begin() + offsetof(x300_eeprom_map, mac_addr1), +            bytes.begin() + (offsetof(x300_eeprom_map, mac_addr1)+6)) +    ).to_string();      //extract the ip addresses      boost::asio::ip::address_v4::bytes_type ip_addr_bytes; -    byte_copy(iface.read_eeprom(X300_EEPROM_ADDR, offsetof(x300_eeprom_map, gateway), 4), ip_addr_bytes); +    byte_copy( +            byte_vector_t( +            bytes.begin() + offsetof(x300_eeprom_map, gateway), +            bytes.begin() + (offsetof(x300_eeprom_map, gateway)+4)), +            ip_addr_bytes +    );      mb_eeprom["gateway"] = boost::asio::ip::address_v4(ip_addr_bytes).to_string();      for (size_t i = 0; i < 4; i++)      {          const std::string n(1, i+'0'); -        byte_copy(iface.read_eeprom(X300_EEPROM_ADDR, offsetof(x300_eeprom_map, ip_addr)+(i*4), 4), ip_addr_bytes); +        byte_copy( +                byte_vector_t( +                bytes.begin() + (offsetof(x300_eeprom_map, ip_addr)+(i*4)), +                bytes.begin() + (offsetof(x300_eeprom_map, ip_addr)+(i*4)+4)), +                ip_addr_bytes +        );          mb_eeprom["ip-addr"+n] = boost::asio::ip::address_v4(ip_addr_bytes).to_string(); -        byte_copy(iface.read_eeprom(X300_EEPROM_ADDR, offsetof(x300_eeprom_map, subnet)+(i*4), 4), ip_addr_bytes); +        byte_copy( +                byte_vector_t( +                bytes.begin() + (offsetof(x300_eeprom_map, subnet)+(i*4)), +                bytes.begin() + (offsetof(x300_eeprom_map, subnet)+(i*4)+4)), +                ip_addr_bytes +        );          mb_eeprom["subnet"+n] = boost::asio::ip::address_v4(ip_addr_bytes).to_string();      }      //extract the serial -    mb_eeprom["serial"] = bytes_to_string(iface.read_eeprom( -        X300_EEPROM_ADDR, offsetof(x300_eeprom_map, serial), SERIAL_LEN -    )); +    mb_eeprom["serial"] = bytes_to_string( +            byte_vector_t( +            bytes.begin() + offsetof(x300_eeprom_map, serial), +            bytes.begin() + (offsetof(x300_eeprom_map, serial)+SERIAL_LEN)) +    );      //extract the name -    mb_eeprom["name"] = bytes_to_string(iface.read_eeprom( -        X300_EEPROM_ADDR, offsetof(x300_eeprom_map, name), NAME_MAX_LEN -    )); +    mb_eeprom["name"] = bytes_to_string( +            byte_vector_t( +            bytes.begin() + offsetof(x300_eeprom_map, name), +            bytes.begin() + (offsetof(x300_eeprom_map, name)+NAME_MAX_LEN)) +    );  }  static void store_x300(const mboard_eeprom_t &mb_eeprom, i2c_iface &iface) diff --git a/host/lib/usrp/x300/CMakeLists.txt b/host/lib/usrp/x300/CMakeLists.txt index ea237b008..5f8e83e1c 100644 --- a/host/lib/usrp/x300/CMakeLists.txt +++ b/host/lib/usrp/x300/CMakeLists.txt @@ -34,6 +34,7 @@ IF(ENABLE_X300)          ${CMAKE_CURRENT_SOURCE_DIR}/x300_dboard_iface.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/x300_clock_ctrl.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/x300_image_loader.cpp +        ${CMAKE_CURRENT_SOURCE_DIR}/x300_mb_eeprom.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/cdecode.c      )  ENDIF(ENABLE_X300) diff --git a/host/lib/usrp/x300/x300_fw_common.h b/host/lib/usrp/x300/x300_fw_common.h index aae0f769c..b83449666 100644 --- a/host/lib/usrp/x300/x300_fw_common.h +++ b/host/lib/usrp/x300/x300_fw_common.h @@ -32,7 +32,7 @@ extern "C" {  #define X300_REVISION_COMPAT 7  #define X300_REVISION_MIN    2  #define X300_FW_COMPAT_MAJOR 5 -#define X300_FW_COMPAT_MINOR 0 +#define X300_FW_COMPAT_MINOR 1  #define X300_FPGA_COMPAT_MAJOR 0x21  //shared memory sections - in between the stack and the program space @@ -49,6 +49,9 @@ extern "C" {  #define X300_FW_SHMEM_UART_WORDS32 10  #define X300_FW_SHMEM_ROUTE_MAP_ADDR 11  #define X300_FW_SHMEM_ROUTE_MAP_LEN 12 +#define X300_FW_SHMEM_IDENT 13 // (13-39) EEPROM values in use +#define X300_FW_SHMEM_DEBUG 128 +#define X300_FW_SHMEM_ADDR(offset) X300_FW_SHMEM_BASE + (4 * (offset))  #define X300_FW_NUM_BYTES (1 << 15) //64k  #define X300_FW_COMMS_MTU (1 << 13) //8k @@ -94,6 +97,30 @@ extern "C" {  typedef struct  { +    //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]; + +    //names and serials +    unsigned char name[23]; +    unsigned char serial[9]; +} x300_eeprom_map_t; + +typedef struct +{      uint32_t flags;      uint32_t sequence;      uint32_t addr; diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index 50a7f3ded..d6e2a6fdc 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -18,6 +18,7 @@  #include "x300_impl.hpp"  #include "x300_lvbitx.hpp"  #include "x310_lvbitx.hpp" +#include "x300_mb_eeprom.hpp"  #include "apply_corrections.hpp"  #include <boost/algorithm/string.hpp>  #include <boost/asio.hpp> @@ -121,12 +122,16 @@ static device_addrs_t x300_find_with_addr(const device_addr_t &hint)                  false /* Suppress timeout errors */              ); -            if (x300_impl::is_claimed(zpu_ctrl)) continue; //claimed by another process              new_addr["fpga"] = get_fpga_option(zpu_ctrl);              i2c_core_100_wb32::sptr zpu_i2c = i2c_core_100_wb32::make(zpu_ctrl, I2C1_BASE); -            i2c_iface::sptr eeprom16 = zpu_i2c->eeprom16(); -            const mboard_eeprom_t mb_eeprom(*eeprom16, "X300"); +            x300_mb_eeprom_iface::sptr eeprom_iface = x300_mb_eeprom_iface::make(zpu_ctrl, zpu_i2c); +            const mboard_eeprom_t mb_eeprom(*eeprom_iface, "X300"); +            if (mb_eeprom.size() == 0 or x300_impl::claim_status(zpu_ctrl) == x300_impl::CLAIMED_BY_OTHER) +            { +                // Skip device claimed by another process +                continue; +            }              new_addr["name"] = mb_eeprom["name"];              new_addr["serial"] = mb_eeprom["serial"];              switch (x300_impl::get_mb_type_from_eeprom(mb_eeprom)) { @@ -221,7 +226,6 @@ static device_addrs_t x300_find_pcie(const device_addr_t &hint, bool explicit_qu                  //We don't put this zpu_ctrl in the registry because we need                  //a persistent niriok_proxy associated with the object              } -            if (x300_impl::is_claimed(zpu_ctrl)) continue; //claimed by another process              //Attempt to autodetect the FPGA type              if (not hint.has_key("fpga")) { @@ -229,8 +233,13 @@ static device_addrs_t x300_find_pcie(const device_addr_t &hint, bool explicit_qu              }              i2c_core_100_wb32::sptr zpu_i2c = i2c_core_100_wb32::make(zpu_ctrl, I2C1_BASE); -            i2c_iface::sptr eeprom16 = zpu_i2c->eeprom16(); -            const mboard_eeprom_t mb_eeprom(*eeprom16, "X300"); +            x300_mb_eeprom_iface::sptr eeprom_iface = x300_mb_eeprom_iface::make(zpu_ctrl, zpu_i2c); +            const mboard_eeprom_t mb_eeprom(*eeprom_iface, "X300"); +            if (mb_eeprom.size() == 0 or x300_impl::claim_status(zpu_ctrl) == x300_impl::CLAIMED_BY_OTHER) +            { +                // Skip device claimed by another process +                continue; +            }              new_addr["name"] = mb_eeprom["name"];              new_addr["serial"] = mb_eeprom["serial"];          } @@ -307,12 +316,7 @@ device_addrs_t x300_find(const device_addr_t &hint_)          {              UHD_MSG(error) << "X300 Network discovery unknown error " << std::endl;          } -        BOOST_FOREACH(const device_addr_t &reply_addr, reply_addrs) -        { -            device_addrs_t new_addrs = x300_find_with_addr(reply_addr); -            addrs.insert(addrs.begin(), new_addrs.begin(), new_addrs.end()); -        } -        return addrs; +        return reply_addrs;      }      if (!hint.has_key("resource")) @@ -671,6 +675,10 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)                      mb.get_pri_eth().addr, BOOST_STRINGIZE(X300_FW_COMMS_UDP_PORT)));      } +    // Claim device +    if (not try_to_claim(mb.zpu_ctrl)) { +        throw uhd::runtime_error("Failed to claim device"); +    }      mb.claimer_task = uhd::task::make(boost::bind(&x300_impl::claimer_loop, this, mb.zpu_ctrl));      //extract the FW path for the X300 @@ -726,7 +734,7 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)      // setup the mboard eeprom      ////////////////////////////////////////////////////////////////////      UHD_MSG(status) << "Loading values from EEPROM..." << std::endl; -    i2c_iface::sptr eeprom16 = mb.zpu_i2c->eeprom16(); +    x300_mb_eeprom_iface::sptr eeprom16 = x300_mb_eeprom_iface::make(mb.zpu_ctrl, mb.zpu_i2c);      if (dev_addr.has_key("blank_eeprom"))      {          UHD_MSG(warning) << "Obliterating the motherboard EEPROM..." << std::endl; @@ -1011,8 +1019,7 @@ x300_impl::~x300_impl(void)              mb.claimer_task.reset();              {   //Critical section                  boost::mutex::scoped_lock(pcie_zpu_iface_registry_mutex); -                mb.zpu_ctrl->poke32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_CLAIM_TIME), 0); -                mb.zpu_ctrl->poke32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_CLAIM_SRC), 0); +                release(mb.zpu_ctrl);                  //If the process is killed, the entire registry will disappear so we                  //don't need to worry about unclean shutdowns here.                  get_pcie_zpu_iface_registry().pop(mb.get_pri_eth().addr); @@ -1465,24 +1472,58 @@ void x300_impl::set_mb_eeprom(i2c_iface::sptr i2c, const mboard_eeprom_t &mb_eep  void x300_impl::claimer_loop(wb_iface::sptr iface)  { -    {   //Critical section -        boost::mutex::scoped_lock(claimer_mutex); -        iface->poke32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_CLAIM_TIME), uint32_t(time(NULL))); -        iface->poke32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_CLAIM_SRC), get_process_hash()); -    } +    claim(iface);      boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); //1 second  } -bool x300_impl::is_claimed(wb_iface::sptr iface) +x300_impl::claim_status_t x300_impl::claim_status(wb_iface::sptr iface)  { -    boost::mutex::scoped_lock(claimer_mutex); - -    //If timed out then device is definitely unclaimed -    if (iface->peek32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_CLAIM_STATUS)) == 0) -        return false; +    //If timed out, then device is definitely unclaimed +    if (iface->peek32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_CLAIM_STATUS)) == 0) +        return UNCLAIMED;      //otherwise check claim src to determine if another thread with the same src has claimed the device -    return iface->peek32(SR_ADDR(X300_FW_SHMEM_BASE, X300_FW_SHMEM_CLAIM_SRC)) != get_process_hash(); +    uint32_t hash = iface->peek32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_CLAIM_SRC)); +    return (hash == get_process_hash() ? CLAIMED_BY_US : CLAIMED_BY_OTHER); +} + +void x300_impl::claim(wb_iface::sptr iface) +{ +    iface->poke32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_CLAIM_TIME), uint32_t(time(NULL))); +    iface->poke32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_CLAIM_SRC), get_process_hash()); +} + +bool x300_impl::try_to_claim(wb_iface::sptr iface, long timeout) +{ +    boost::system_time start_time = boost::get_system_time(); +    while (1) +    { +        claim_status_t status = claim_status(iface); +        if (status == UNCLAIMED) +        { +            claim(iface); +            // It takes the claimer 10ms to update status, so wait 20ms before verifying claim +            boost::this_thread::sleep(boost::posix_time::milliseconds(20)); +            continue; +        } +        if (status == CLAIMED_BY_US) +        { +            break; +        } +        if (boost::get_system_time() - start_time > boost::posix_time::milliseconds(timeout)) +        { +            // Another process owns the device - give up +            return false; +        } +        boost::this_thread::sleep(boost::posix_time::milliseconds(100)); +    } +    return true; +} + +void x300_impl::release(wb_iface::sptr iface) +{ +    iface->poke32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_CLAIM_TIME), 0); +    iface->poke32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_CLAIM_SRC), 0);  }  /*********************************************************************** diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp index e292e2d68..81d8cd3ba 100644 --- a/host/lib/usrp/x300/x300_impl.hpp +++ b/host/lib/usrp/x300/x300_impl.hpp @@ -129,9 +129,12 @@ public:      void setup_mb(const size_t which, const uhd::device_addr_t &);      ~x300_impl(void); -    // used by x300_find_with_addr to find X300 devices. -    static boost::mutex claimer_mutex;  //All claims and checks in this process are serialized -    static bool is_claimed(uhd::wb_iface::sptr); +    // device claim functions +    enum claim_status_t {UNCLAIMED, CLAIMED_BY_US, CLAIMED_BY_OTHER}; +    static claim_status_t claim_status(uhd::wb_iface::sptr iface); +    static void claim(uhd::wb_iface::sptr iface); +    static bool try_to_claim(uhd::wb_iface::sptr iface, long timeout = 2000); +    static void release(uhd::wb_iface::sptr iface);      enum x300_mboard_t {          USRP_X300_MB, USRP_X310_MB, UNKNOWN diff --git a/host/lib/usrp/x300/x300_mb_eeprom.cpp b/host/lib/usrp/x300/x300_mb_eeprom.cpp new file mode 100644 index 000000000..e39b36af8 --- /dev/null +++ b/host/lib/usrp/x300/x300_mb_eeprom.cpp @@ -0,0 +1,190 @@ +// +// Copyright 2013-2016 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/>. +// + +/* + * x300_mb_eeprom_iface + * This interface was created to prevent MB EEPROM corruption while reading + * data during discovery.  For devices with firmware version newer than 5.0, + * the EEPROM data is read into firmware memory and available without + * claiming the device.  For devices with firmware versions 5.0 and older, + * the code makes sure to claim the device before driving the I2C bus.  This + * has the unfortunate side effect of preventing multiple processes from + * discovering the device simultaneously, but is far better than having EEPROM + * corruption. + */ + +#include "x300_mb_eeprom.hpp" +#include "x300_fw_common.h" +#include "x300_regs.hpp" +#include "x300_impl.hpp" +#include <uhd/exception.hpp> +#include <uhd/utils/platform.hpp> +#include <uhd/utils/msg.hpp> +#include <uhd/utils/byteswap.hpp> +#include <boost/thread.hpp> + +using namespace uhd; + +static const uint32_t X300_FW_SHMEM_IDENT_MIN_VERSION = 0x50001; + +class x300_mb_eeprom_iface_impl : public x300_mb_eeprom_iface +{ +public: + +    x300_mb_eeprom_iface_impl(wb_iface::sptr wb, i2c_iface::sptr i2c) : _wb(wb), _i2c(i2c) +    { +        _compat_num = _wb->peek32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_COMPAT_NUM)); +    } + +    ~x300_mb_eeprom_iface_impl() +    { +        /* NOP */ +    } + +    /*! +     * Write bytes over the i2c. +     * \param addr the address +     * \param buf the vector of bytes +     */ +    void write_i2c( +        uint16_t addr, +        const byte_vector_t &buf +    ) +    { +        UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR); +        if (x300_impl::claim_status(_wb) != x300_impl::CLAIMED_BY_US) +        { +            throw uhd::io_error("Attempted to write MB EEPROM without claim to device."); +        } +        _i2c->write_i2c(addr, buf); +    } + +    /*! +     * Read bytes over the i2c. +     * \param addr the address +     * \param num_bytes number of bytes to read +     * \return a vector of bytes +     */ +    byte_vector_t read_i2c( +        uint16_t addr, +        size_t num_bytes +    ) +    { +        UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR); +        byte_vector_t bytes; +        if (_compat_num > X300_FW_SHMEM_IDENT_MIN_VERSION) +        { +            bytes = read_eeprom(addr, 0, num_bytes); +        } else { +            x300_impl::claim_status_t status = x300_impl::claim_status(_wb); +            // Claim device before driving the I2C bus +            if (status == x300_impl::CLAIMED_BY_US or x300_impl::try_to_claim(_wb)) +            { +                bytes = _i2c->read_i2c(addr, num_bytes); +                if (status != x300_impl::CLAIMED_BY_US) +                { +                    // We didn't originally have the claim, so give it up +                    x300_impl::release(_wb); +                } +            } +        } +        return bytes; +    } + +    /*! +     * Write bytes to an eeprom. +     * \param addr the address +     * \param offset byte offset +     * \param buf the vector of bytes +     */ +    void write_eeprom( +        uint16_t addr, +        uint16_t offset, +        const byte_vector_t &buf +    ) +    { +        UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR); +        if (x300_impl::claim_status(_wb) != x300_impl::CLAIMED_BY_US) +        { +            throw uhd::io_error("Attempted to write MB EEPROM without claim to device."); +        } +        _i2c->write_eeprom(addr, offset, buf); +    } + +    /*! +     * Read bytes from an eeprom. +     * \param addr the address +     * \param offset byte offset +     * \param num_bytes number of bytes to read +     * \return a vector of bytes +     */ +    byte_vector_t read_eeprom( +        uint16_t addr, +        uint16_t offset, +        size_t num_bytes +    ) +    { +        UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR); +        byte_vector_t bytes; +        x300_impl::claim_status_t status = x300_impl::claim_status(_wb); +        if (_compat_num >= X300_FW_SHMEM_IDENT_MIN_VERSION) +        { +            // Get MB EEPROM data from firmware memory +            if (num_bytes == 0) return bytes; + +            size_t bytes_read = 0; +            for (size_t word = offset / 4; bytes_read < num_bytes; word++) +            { +                uint32_t value = byteswap(_wb->peek32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_IDENT + word))); +                for (size_t byte = offset % 4; byte < 4 and bytes_read < num_bytes; byte++) +                { +                    bytes.push_back(uint8_t((value >> (byte * 8)) & 0xff)); +                    bytes_read++; +                } +            } +        } else { +            // Claim device before driving the I2C bus +            if (status == x300_impl::CLAIMED_BY_US or x300_impl::try_to_claim(_wb)) +            { +                bytes = _i2c->read_eeprom(addr, offset, num_bytes); +                if (status != x300_impl::CLAIMED_BY_US) +                { +                    // We didn't originally have the claim, so give it up +                    x300_impl::release(_wb); +                } +            } +        } +        return bytes; +    } + + +private: +    wb_iface::sptr _wb; +    i2c_iface::sptr _i2c; +    uint32_t _compat_num; +}; + +x300_mb_eeprom_iface::~x300_mb_eeprom_iface(void) +{ +    /* NOP */ +} + +x300_mb_eeprom_iface::sptr x300_mb_eeprom_iface::make(wb_iface::sptr wb, i2c_iface::sptr i2c) +{ +    return boost::make_shared<x300_mb_eeprom_iface_impl>(wb, i2c->eeprom16()); +} + diff --git a/host/lib/usrp/x300/x300_mb_eeprom.hpp b/host/lib/usrp/x300/x300_mb_eeprom.hpp new file mode 100644 index 000000000..0649855c6 --- /dev/null +++ b/host/lib/usrp/x300/x300_mb_eeprom.hpp @@ -0,0 +1,37 @@ +// +// Copyright 2016 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/>. +// + +#ifndef INCLUDED_X300_MB_EEPROM_HPP +#define INCLUDED_X300_MB_EEPROM_HPP + +#include <uhd/config.hpp> +#include <uhd/types/serial.hpp> +#include <boost/utility.hpp> +#include <boost/shared_ptr.hpp> +#include <uhd/types/wb_iface.hpp> + +class x300_mb_eeprom_iface : public uhd::i2c_iface +{ +public: +    typedef boost::shared_ptr<x300_mb_eeprom_iface> sptr; + +    virtual ~x300_mb_eeprom_iface(void) = 0; + +    static sptr make(uhd::wb_iface::sptr wb, uhd::i2c_iface::sptr i2c); +}; + +#endif /* INCLUDED_X300_MB_EEPROM_HPP */ diff --git a/host/lib/usrp/x300/x300_regs.hpp b/host/lib/usrp/x300/x300_regs.hpp index 6e7c47a64..d908bfb34 100644 --- a/host/lib/usrp/x300/x300_regs.hpp +++ b/host/lib/usrp/x300/x300_regs.hpp @@ -33,6 +33,9 @@ static const int BL_DATA       = 1;  #define I2C1_BASE     0xff00  #define SR_ADDR(base, offset) ((base) + (offset)*4) +//I2C1 device addresses +#define MBOARD_EEPROM_ADDR  0x50 +  static const int ZPU_SR_LEDS       = 00;  static const int ZPU_SR_SW_RST     = 01;  static const int ZPU_SR_CLOCK_CTRL = 02;  | 
