aboutsummaryrefslogtreecommitdiffstats
path: root/mpm/python/usrp_mpm/periph_manager/e320.py
diff options
context:
space:
mode:
Diffstat (limited to 'mpm/python/usrp_mpm/periph_manager/e320.py')
-rw-r--r--mpm/python/usrp_mpm/periph_manager/e320.py188
1 files changed, 120 insertions, 68 deletions
diff --git a/mpm/python/usrp_mpm/periph_manager/e320.py b/mpm/python/usrp_mpm/periph_manager/e320.py
index f76e6ac3e..04999e505 100644
--- a/mpm/python/usrp_mpm/periph_manager/e320.py
+++ b/mpm/python/usrp_mpm/periph_manager/e320.py
@@ -32,7 +32,7 @@ E320_DEFAULT_CLOCK_SOURCE = 'internal'
E320_DEFAULT_TIME_SOURCE = 'internal'
E320_DEFAULT_ENABLE_GPS = True
E320_DEFAULT_ENABLE_FPGPIO = True
-E320_FPGA_COMPAT = (3, 1)
+E320_FPGA_COMPAT = (4, 0)
E320_MONITOR_THREAD_INTERVAL = 1.0 # seconds
E320_DBOARD_SLOT_IDX = 0
@@ -42,21 +42,15 @@ E320_DBOARD_SLOT_IDX = 0
###############################################################################
class E320XportMgrUDP(XportMgrUDP):
"E320-specific UDP configuration"
- xbar_dev = "/dev/crossbar0"
iface_config = {
'sfp0': {
'label': 'misc-enet-regs',
- 'xbar': 0,
- 'xbar_port': 0,
- 'ctrl_src_addr': 0,
}
}
class E320XportMgrLiberio(XportMgrLiberio):
" E320-specific Liberio configuration "
max_chan = 6
- xbar_dev = "/dev/crossbar0"
- xbar_port = 1
###############################################################################
# Main Class
@@ -139,7 +133,6 @@ class e320(ZynqComponents, PeriphManagerBase):
self._ext_clock_freq = E320_DEFAULT_EXT_CLOCK_FREQ
self._clock_source = None
self._time_source = None
- self._available_endpoints = list(range(256))
self._gpsd = None
self.dboard = self.dboards[E320_DBOARD_SLOT_IDX]
from functools import partial
@@ -266,7 +259,6 @@ class e320(ZynqComponents, PeriphManagerBase):
self.mboard_regs_control.get_build_timestamp()
self._check_fpga_compat()
self._update_fpga_type()
- self.crossbar_base_port = self.mboard_regs_control.get_xbar_baseport()
# Init peripherals
self.enable_gps(
enable=str2bool(
@@ -274,10 +266,7 @@ class e320(ZynqComponents, PeriphManagerBase):
)
)
self.enable_fp_gpio(
- enable=args.get(
- 'enable_fp_gpio',
- E320_DEFAULT_ENABLE_FPGPIO
- )
+ enable=args.get('enable_fp_gpio', E320_DEFAULT_ENABLE_FPGPIO)
)
# Init clocking
self._init_ref_clock_and_time(args)
@@ -285,8 +274,8 @@ class e320(ZynqComponents, PeriphManagerBase):
self._init_gps_sensors()
# Init CHDR transports
self._xport_mgrs = {
- 'udp': E320XportMgrUDP(self.log.getChild('UDP'), args),
- 'liberio': E320XportMgrLiberio(self.log.getChild('liberio')),
+ 'udp': E320XportMgrUDP(self.log, args),
+ 'liberio': E320XportMgrLiberio(self.log),
}
# Spawn status monitoring thread
self.log.trace("Spawning status monitor thread...")
@@ -347,8 +336,6 @@ class e320(ZynqComponents, PeriphManagerBase):
super(e320, self).deinit()
for xport_mgr in itervalues(self._xport_mgrs):
xport_mgr.deinit()
- self.log.trace("Resetting SID pool...")
- self._available_endpoints = list(range(256))
def tear_down(self):
"""
@@ -372,61 +359,37 @@ class e320(ZynqComponents, PeriphManagerBase):
###########################################################################
# Transport API
###########################################################################
- def request_xport(
- self,
- dst_address,
- suggested_src_address,
- xport_type
- ):
- """
- See PeriphManagerBase.request_xport() for docs.
- """
- # Try suggested address first, then just pick the first available one:
- src_address = suggested_src_address
- if src_address not in self._available_endpoints:
- if not self._available_endpoints:
- raise RuntimeError(
- "Depleted pool of SID endpoints for this device!")
- else:
- src_address = self._available_endpoints[0]
- sid = SID(src_address << 16 | dst_address)
- # Note: This SID may change its source address!
- self.log.trace(
- "request_xport(dst=0x%04X, suggested_src_address=0x%04X, xport_type=%s): " \
- "operating on temporary SID: %s",
- dst_address, suggested_src_address, str(xport_type), str(sid))
- # FIXME token!
+ def get_chdr_link_types(self):
+ """
+ This will only ever return a single item (udp or liberio).
+ """
assert self.mboard_info['rpc_connection'] in ('remote', 'local')
if self.mboard_info['rpc_connection'] == 'remote':
- return self._xport_mgrs['udp'].request_xport(
- sid,
- xport_type,
- )
- elif self.mboard_info['rpc_connection'] == 'local':
- return self._xport_mgrs['liberio'].request_xport(
- sid,
- xport_type,
- )
+ return ["udp"]
+ # else:
+ return ["liberio"]
- def commit_xport(self, xport_info):
+ def get_chdr_link_options(self, xport_type):
"""
- See PeriphManagerBase.commit_xport() for docs.
+ Returns a list of dictionaries. Every dictionary contains information
+ about one way to connect to this device in order to initiate CHDR
+ traffic.
+
+ The interpretation of the return value is very highly dependant on the
+ transport type (xport_type).
+ For UDP, the every entry of the list has the following keys:
+ - ipv4 (IP Address)
+ - port (UDP port)
+ - link_rate (bps of the link, e.g. 10e9 for 10GigE)
- Reminder: All connections are incoming, i.e. "send" or "TX" means
- remote device to local device, and "receive" or "RX" means this local
- device to remote device. "Remote device" can be, for example, a UHD
- session.
+ For Liberio, every entry has the following keys:
+ - tx_dev: TX device (/dev/tx-dma*)
+ - rx_dev: RX device (/dev/rx-dma*)
"""
- ## Go, go, go
- assert self.mboard_info['rpc_connection'] in ('remote', 'local')
- sid = SID(xport_info['send_sid'])
- self._available_endpoints.remove(sid.src_ep)
- self.log.debug("Committing transport for SID %s, xport info: %s",
- str(sid), str(xport_info))
- if self.mboard_info['rpc_connection'] == 'remote':
- return self._xport_mgrs['udp'].commit_xport(sid, xport_info)
- elif self.mboard_info['rpc_connection'] == 'local':
- return self._xport_mgrs['liberio'].commit_xport(sid, xport_info)
+ if xport_type not in self._xport_mgrs:
+ self.log.warning("Can't get link options for unknown link type: `{}'.")
+ return []
+ return self._xport_mgrs[xport_type].get_chdr_link_options()
###########################################################################
# Device info
@@ -443,10 +406,43 @@ class e320(ZynqComponents, PeriphManagerBase):
*self.mboard_regs_control.get_compat_number()),
'fpga_version_hash': "{:x}.{}".format(
*self.mboard_regs_control.get_git_hash()),
- 'fpga': self.updateable_components.get('fpga', {}).get('type',""),
+ 'fpga': self.updateable_components.get('fpga', {}).get('type', ""),
})
return device_info
+ def set_device_id(self, device_id):
+ """
+ Sets the device ID for this motherboard.
+ The device ID is used to identify the RFNoC components associated with
+ this motherboard.
+ """
+ self.log.debug("Setting device ID to `{}'".format(device_id))
+ self.mboard_regs_control.set_device_id(device_id)
+
+ def get_device_id(self):
+ """
+ Gets the device ID for this motherboard.
+ The device ID is used to identify the RFNoC components associated with
+ this motherboard.
+ """
+ return self.mboard_regs_control.get_device_id()
+
+ def get_proto_ver(self):
+ """
+ Return RFNoC protocol version
+ """
+ proto_ver = self.mboard_regs_control.get_proto_ver()
+ self.log.debug("RFNoC protocol version supported by this device is {}".format(proto_ver))
+ return proto_ver
+
+ def get_chdr_width(self):
+ """
+ Return RFNoC CHDR width
+ """
+ chdr_width = self.mboard_regs_control.get_chdr_width()
+ self.log.debug("CHDR width supported by the device is {}".format(chdr_width))
+ return chdr_width
+
###########################################################################
# Clock/Time API
###########################################################################
@@ -637,7 +633,7 @@ class e320(ZynqComponents, PeriphManagerBase):
except ValueError:
self.log.warning("Error when converting temperature value")
except KeyError:
- self.log.warning("Can't read temp on thermal_zone".format(sensor))
+ self.log.warning("Can't read temp on thermal_zone {}".format(sensor))
return {
'name': sensor_name,
'type': 'REALNUM',
@@ -753,3 +749,59 @@ class e320(ZynqComponents, PeriphManagerBase):
fpga_type = self.mboard_regs_control.get_fpga_type()
self.log.debug("Updating mboard FPGA type info to {}".format(fpga_type))
self.updateable_components['fpga']['type'] = fpga_type
+
+ #######################################################################
+ # Timekeeper API
+ #######################################################################
+ def get_num_timekeepers(self):
+ """
+ Return the number of timekeepers
+ """
+ return self.mboard_regs_control.get_num_timekeepers()
+
+ def get_timekeeper_time(self, tk_idx, last_pps):
+ """
+ Get the time in ticks
+
+ Arguments:
+ tk_idx: Index of timekeeper
+ next_pps: If True, get time at last PPS. Otherwise, get time now.
+ """
+ return self.mboard_regs_control.get_timekeeper_time(tk_idx, last_pps)
+
+ def set_timekeeper_time(self, tk_idx, ticks, next_pps):
+ """
+ Set the time in ticks
+
+ Arguments:
+ tk_idx: Index of timekeeper
+ ticks: Time in ticks
+ next_pps: If True, set time at next PPS. Otherwise, set time now.
+ """
+ self.mboard_regs_control.set_timekeeper_time(tk_idx, ticks, next_pps)
+
+ def set_tick_period(self, tk_idx, period_ns):
+ """
+ Set the time per tick in nanoseconds (tick period)
+
+ Arguments:
+ tk_idx: Index of timekeeper
+ period_ns: Period in nanoseconds
+ """
+ self.mboard_regs_control.set_tick_period(tk_idx, period_ns)
+
+ def get_clocks(self):
+ """
+ Gets the RFNoC-related clocks present in the FPGA design
+ """
+ return [
+ {
+ 'name': 'radio_clk',
+ 'freq': str(self.dboard.get_master_clock_rate()),
+ 'mutable': 'true'
+ },
+ {
+ 'name': 'bus_clk',
+ 'freq': str(200e6),
+ }
+ ]