1 //
2 // Copyright 2019 Ettus Research, a National Instruments Brand
3 //
4 // SPDX-License-Identifier: GPL-3.0-or-later
5 //
6 
7 #pragma once
8 
9 #include <uhd/rfnoc/register_iface_holder.hpp>
10 #include <uhdlib/rfnoc/chdr_ctrl_endpoint.hpp>
11 #include <chrono>
12 #include <cstdint>
13 #include <functional>
14 #include <memory>
15 #include <string>
16 #include <vector>
17 
18 namespace uhd { namespace rfnoc { namespace detail {
19 
20 /*!
21  * Class that uses a register_iface to read important configuration information from the
22  * RFNoC backend registers
23  */
24 class client_zero : public uhd::rfnoc::register_iface_holder
25 {
26 public:
27     using sptr = std::shared_ptr<client_zero>;
28 
29     static sptr make(chdr_ctrl_endpoint& chdr_ctrl_ep, sep_id_t dst_epid);
30 
31     client_zero(register_iface::sptr reg);
32 
33     //! Definition of an edge in the static router
34     struct edge_def_t
35     {
36         uint16_t src_blk_index;
37         uint8_t src_blk_port;
38         uint16_t dst_blk_index;
39         uint8_t dst_blk_port;
40     };
41 
42     //! Contents of the backend status block configuration register
43     struct block_config_info
44     {
45         uint8_t protover;
46         uint8_t num_inputs;
47         uint8_t num_outputs;
48         uint8_t ctrl_fifo_size;
49         uint8_t ctrl_max_async_msgs;
50         uint8_t data_mtu;
51     };
52 
53     //! Return the RFNoC protocol version for this motherboard
get_proto_ver()54     uint16_t get_proto_ver()
55     {
56         return _proto_ver;
57     };
58 
59     //! Return the device type
get_device_type()60     uint16_t get_device_type()
61     {
62         return _device_type;
63     };
64 
65     //! Return the number of blocks in our RFNoC graph
get_num_blocks()66     size_t get_num_blocks()
67     {
68         return _num_blocks;
69     };
70 
71     //! Return the number of stream endpoints in our RFNoC graph
get_num_stream_endpoints()72     size_t get_num_stream_endpoints()
73     {
74         return _num_stream_endpoints;
75     };
76 
77     //! Return the number of stream endpoints connected to the control crossbar
get_num_ctrl_endpoints() const78     size_t get_num_ctrl_endpoints() const
79     {
80         return _num_ctrl_endpoints;
81     };
82 
83     //! Return the number of transports available
get_num_transports()84     size_t get_num_transports()
85     {
86         return _num_transports;
87     };
88 
89     //! Return the control crossbar port of the block \p block_idx
get_ctrl_xbar_port(const size_t block_idx) const90     size_t get_ctrl_xbar_port(const size_t block_idx) const
91     {
92         return 1 + _num_ctrl_endpoints + block_idx;
93     }
94 
95     //! Return whether or not the device includes a CHDR crossbar
has_chdr_crossbar()96     bool has_chdr_crossbar()
97     {
98         return _has_chdr_crossbar;
99     };
100 
101     //! Return the number of edges in our graph (the number of static connections)
get_num_edges()102     size_t get_num_edges()
103     {
104         return _num_edges;
105     };
106 
107     //! Return a vector containing the edge definitions
get_adjacency_list()108     std::vector<edge_def_t>& get_adjacency_list()
109     {
110         return _adjacency_list;
111     };
112 
113     /*! Return the NOC ID of the block located at `portno`
114      *
115      * \throws uhd::index_error if no NOC block is connected to the port
116      */
117     uint32_t get_noc_id(uint16_t portno);
118 
119     /*! Return whether the port is actively flushing
120      *
121      * \throws uhd::index_error if no NOC block is connected to the port
122      * \return boolean status
123      */
124     bool get_flush_active(uint16_t portno);
125 
126     /*! Return whether the port is done flushing
127      *
128      * \throws uhd::index_error if no NOC block is connected to the port
129      * \return boolean status
130      */
131     bool get_flush_done(uint16_t portno);
132 
133     /*! Returns once the port is done flushing
134      *
135      * Note: this function queries the port once every millisecond
136      *
137      * \param portno Port number
138      * \param timeout time, in milliseconds, to poll before quitting
139      * \throws uhd::index_error if no NOC block is connected to the port
140      * \return boolean whether or not the flush had completed in the timeout period
141      */
142     bool poll_flush_done(uint16_t portno, std::chrono::milliseconds timeout);
143 
144     /*! Set the port's hardware flush timeout
145      *
146      * \param timeout number of cycles the device waits for the flushing to complete
147      * \param portno Port number
148      * \throws uhd::index_error if no NOC block is connected to the port
149      */
150     void set_flush_timeout(uint32_t timeout, uint16_t portno);
151 
152     /*! Send a request to flush a port
153      *
154      * \param portno Port number
155      * \throws uhd::index_error if no NOC block is connected to the port
156      */
157     void set_flush(uint16_t portno);
158 
159     /*! Go through the entire flush process for a port
160      *
161      * \param portno Port number
162      * \throws uhd::index_error if no NOC block is connected to the port
163      * \return whether or not the flush succeeded
164      */
165     bool complete_flush(uint16_t portno);
166 
167     /*! Go through the entire flush process for all ports
168      * \return whether or not the flush succeeded
169      */
170     bool complete_flush_all_blocks();
171 
172     /*! Reset a port's control logic
173      *
174      * It is recommended to flush a port calling this.
175      *
176      * \param portno Port number
177      * \throws uhd::index_error if no NOC block is connected to the port
178      */
179     void reset_ctrl(uint16_t portno);
180 
181     /*! Reset a port's CHDR logic
182      *
183      * It is recommended to flush a port calling this.
184      *
185      * \param portno Port number
186      * \throws uhd::index_error if no NOC block is connected to the port
187      */
188     void reset_chdr(uint16_t portno);
189 
190     /*! Get the port's configuration information
191      *
192      * \return Struct containing configuration information
193      */
194     block_config_info get_block_info(uint16_t portno);
195 
196     // TODO: handle callbacks?
197 
198 private:
199     uint16_t _proto_ver;
200     uint16_t _device_type;
201     uint16_t _num_blocks;
202     uint16_t _num_stream_endpoints;
203     uint16_t _num_ctrl_endpoints;
204     uint16_t _num_transports;
205     bool _has_chdr_crossbar;
206     uint16_t _num_edges;
207     std::vector<edge_def_t> _adjacency_list;
208 
209     std::vector<client_zero::edge_def_t> _get_adjacency_list();
210 
211     /* Helper function to determine if the given port number has a block connected
212      *
213      * \throws uhd::index_error if no NOC block is connected to the port
214      */
215     void _check_port_number(uint16_t portno);
216     //! Translate port number to base address for the register
217     uint32_t _get_port_base_addr(uint16_t portno);
218     //! Helper function to get the backend control flush status flags
219     uint32_t _get_flush_status_flags(uint16_t portno);
220 };
221 
222 }}} /* namespace uhd::rfnoc::detail */
223