diff options
Diffstat (limited to 'mpm/python/usrp_mpm/periph_manager/e320.py')
-rw-r--r-- | mpm/python/usrp_mpm/periph_manager/e320.py | 188 |
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), + } + ] |