SatCat5
switch_cfg.cc
1 // Copyright 2021-2025 The Aerospace Corporation.
3 // This file is a part of SatCat5, licensed under CERN-OHL-W v2 or later.
5 
6 #include <satcat5/log.h>
7 #include <satcat5/switch_cfg.h>
8 #include <satcat5/utils.h>
9 
10 namespace eth = satcat5::eth;
11 namespace log = satcat5::log;
12 namespace util = satcat5::util;
16 
17 // Define opcodes for REG_MACTBL_CTRL:
18 constexpr u32 MACTBL_OPCODE_MASK = 0xFF000000u;
19 constexpr u32 MACTBL_ARGVAL_MASK = 0x00FFFFFFu;
20 constexpr u32 MACTBL_IDLE = 0;
21 constexpr u32 MACTBL_READ(unsigned tbl_idx) {return (u32)(0x01000000 + tbl_idx);}
22 constexpr u32 MACTBL_WRITE(unsigned port_idx) {return (u32)(0x02000000 + port_idx);}
23 constexpr u32 MACTBL_CLEAR() {return (u32)(0x03000000);}
24 constexpr u32 MACTBL_LEARN(unsigned enable) {return (u32)(0x04000000 + enable);}
25 
26 SwitchConfig::SwitchConfig(satcat5::cfg::ConfigBus* cfg, unsigned devaddr)
27  : m_reg(cfg->get_register(devaddr, 0))
28  , m_pri_wridx(0)
29  , m_stats_filter(0)
30 {
32 }
33 
34 void SwitchConfig::log_info(const char* label) {
35  log::Log msg(log::INFO, label);
36  msg.write("\r\n Ports").write10(m_reg[REG_PORTCOUNT]);
37  msg.write("\r\n Datapath").write10(m_reg[REG_DATAPATH]);
38  msg.write("\r\n CoreClk").write10(m_reg[REG_CORECLOCK]);
39  msg.write("\r\n MAC-count").write10(m_reg[REG_MACCOUNT]);
40  msg.write("\r\n PRI-count").write10(m_reg[REG_PRIORITY]);
41 }
42 
43 // Note: Method cannot be "const" because register reads may have side-effects.
45  return m_reg[REG_PORTCOUNT];
46 }
47 
49  // Read table size, then zeroize.
50  u32 tsize = m_reg[REG_PRIORITY];
51  for (u32 a = 0 ; a < tsize ; ++a) {
52  m_reg[REG_PRIORITY] = (a << 24);
53  }
54 
55  // Next write is to table index zero.
56  m_pri_wridx = 0;
57 }
58 
59 bool SwitchConfig::priority_set(u16 etype, unsigned plen) {
60  // Sanity checks before we write:
61  u32 tsize = m_reg[REG_PRIORITY];
62  if (m_pri_wridx >= tsize) {
63  log::Log(log::WARNING, "MAC priority-table overflow.");
64  return false;
65  } else if (etype < 1536 || plen > 16) {
66  log::Log(log::WARNING, "Invalid MAC-priority entry.");
67  return false;
68  }
69 
70  // Write the next table entry.
71  u32 wcl = (u32)(16 - plen); // Wildcard length
72  u32 cmd = (m_pri_wridx << 24) | (wcl << 16) | etype;
73  m_reg[REG_PRIORITY] = cmd;
74 
75  // Success!
76  ++m_pri_wridx;
77  return true;
78 }
79 
80 void SwitchConfig::set_miss_bcast(unsigned port_idx, bool enable) {
81  u32 temp = m_reg[REG_MISS_BCAST];
82  u32 mask = (1u << port_idx);
83  util::set_mask_if(temp, mask, enable);
84  set_miss_mask(temp);
85 }
86 
88  m_reg[REG_MISS_BCAST] = mask;
89 }
90 
92  return m_reg[REG_MISS_BCAST];
93 }
94 
95 void SwitchConfig::set_promiscuous(unsigned port_idx, bool enable) {
96  u32 temp = m_reg[REG_PROMISC];
97  u32 mask = (1u << port_idx);
98  util::set_mask_if(temp, mask, enable);
99  m_reg[REG_PROMISC] = temp;
100 }
101 
103  m_reg[REG_PROMISC] = mask;
104 }
105 
107  return m_reg[REG_PROMISC];
108 }
109 
111  m_stats_filter = etype;
113 }
114 
116  // Write any value to refresh the counter register.
117  // (This also sets filter configuration for the *next* interval.)
119  // Short delay before reading the register value.
120  for (volatile unsigned a = 0 ; a < 16 ; ++a) {}
121  return m_reg[REG_PKTCOUNT];
122 }
123 
125  u32 regval = m_reg[REG_FRAMESIZE];
126  return (u16)((regval >> 0) & 0xFFFF);
127 }
128 
130  u32 regval = m_reg[REG_FRAMESIZE];
131  return (u16)((regval >> 16) & 0xFFFF);
132 }
133 
135  return m_reg + REG_LOGGING;
136 }
137 
138 s32 SwitchConfig::ptp_get_offset_rx(unsigned port_idx) {
139  return (s32)m_reg[REG_PTP_RX(port_idx)];
140 }
141 
142 s32 SwitchConfig::ptp_get_offset_tx(unsigned port_idx) {
143  return (s32)m_reg[REG_PTP_TX(port_idx)];
144 }
145 
147  return m_reg[REG_PTP_2STEP];
148 }
149 
150 void SwitchConfig::ptp_set_offset_rx(unsigned port_idx, s32 subns) {
151  m_reg[REG_PTP_RX(port_idx)] = (u32)subns;
152 }
153 
154 void SwitchConfig::ptp_set_offset_tx(unsigned port_idx, s32 subns) {
155  m_reg[REG_PTP_TX(port_idx)] = (u32)subns;
156 }
157 
158 void SwitchConfig::ptp_set_2step(unsigned port_idx, bool enable) {
159  u32 temp = m_reg[REG_PTP_2STEP];
160  u32 mask = (1u << port_idx);
161  util::set_mask_if(temp, mask, enable);
162  m_reg[REG_PTP_2STEP] = temp;
163 }
164 
165 void SwitchConfig::vlan_reset(bool lockdown) {
166  // Set default policy and port-mask.
167  u32 policy = lockdown ? eth::VTAG_RESTRICT : eth::VTAG_ADMIT_ALL;
168  u32 mask = lockdown ? eth::VLAN_CONNECT_NONE : eth::VLAN_CONNECT_ALL;
169  VlanRate rate = lockdown ? eth::VRATE_8KBPS : eth::VRATE_UNLIMITED;
170 
171  // Reset each port with default policy and VID = 1.
172  u32 pcount = m_reg[REG_PORTCOUNT];
173  for (unsigned port = 0 ; port < pcount ; ++port) {
174  VtagPolicy vtag(port, policy, eth::VTAG_DEFAULT);
175  m_reg[REG_VLAN_PORT] = vtag.value;
176  }
177 
178  // Reset every VID so it connects the designated ports.
179  // (Write base address, then repeated masks with auto-increment.)
180  m_reg[REG_VLAN_VID] = (u32)eth::VID_MIN;
181  for (u16 vid = eth::VID_MIN ; vid <= eth::VID_MAX ; ++vid)
182  m_reg[REG_VLAN_MASK] = mask;
183 
184  // If rate limiter is enabled, reset policy for each VID.
185  if (m_reg[REG_VLAN_RATE] > 0) {
186  for (u16 vid = eth::VID_MIN ; vid <= eth::VID_MAX ; ++vid)
187  vlan_set_rate(vid, rate);
188  }
189 }
190 
192  m_reg[REG_VLAN_VID] = (u32)vid;
193  return m_reg[REG_VLAN_MASK];
194 }
195 
196 void SwitchConfig::vlan_set_mask(u16 vid, u32 mask) {
197  m_reg[REG_VLAN_VID] = (u32)vid;
198  m_reg[REG_VLAN_MASK] = mask;
199 }
200 
202  m_reg[REG_VLAN_PORT] = cfg.value;
203 }
204 
205 void SwitchConfig::vlan_set_rate(u16 vid, const VlanRate& cfg) {
206  // Three consecutive writes sets the new rate-limit.
208  m_reg[REG_VLAN_RATE] = cfg.tok_max;
209  m_reg[REG_VLAN_RATE] = cfg.tok_policy | vid;
210 }
211 
212 void SwitchConfig::vlan_join(u16 vid, unsigned port) {
213  // Read original mask.
214  m_reg[REG_VLAN_VID] = (u32)vid;
215  u32 mask = m_reg[REG_VLAN_MASK];
216  // Write modified mask.
217  util::set_mask_u32(mask, 1u << port);
218  m_reg[REG_VLAN_VID] = (u32)vid;
219  m_reg[REG_VLAN_MASK] = mask;
220 }
221 
222 void SwitchConfig::vlan_leave(u16 vid, unsigned port) {
223  // Read original mask.
224  m_reg[REG_VLAN_VID] = (u32)vid;
225  u32 mask = m_reg[REG_VLAN_MASK];
226  // Write modified mask.
227  util::clr_mask_u32(mask, 1u << port);
228  m_reg[REG_VLAN_VID] = (u32)vid;
229  m_reg[REG_VLAN_MASK] = mask;
230 }
231 
233  unsigned tbl_idx,
234  unsigned& port_idx,
235  eth::MacAddr& mac_addr)
236 {
237  // Wait until other commands are finished.
238  if (!mactbl_wait_idle()) return false; // Timeout?
239 
240  // Issue command and wait for completion.
241  m_reg[REG_MACTBL_CTRL] = MACTBL_READ(tbl_idx);
242  if (!mactbl_wait_idle()) return false; // Timeout?
243 
244  // Read and parse results.
245  u32 mac_lsb = m_reg[REG_MACTBL_LSB];
246  u32 mac_msb = m_reg[REG_MACTBL_MSB];
247  u32 status = m_reg[REG_MACTBL_CTRL];
248  port_idx = (unsigned)(status & MACTBL_ARGVAL_MASK);
249  util::write_be_u16(mac_addr.addr + 0, mac_msb);
250  util::write_be_u32(mac_addr.addr + 2, mac_lsb);
251 
252  // A value of 00:00:... or FF:FF:... indicates an empty row.
253  return (mac_addr != MACADDR_NONE)
254  && (mac_addr != MACADDR_BROADCAST);
255 }
256 
258  unsigned port_idx,
259  const eth::MacAddr& mac_addr)
260 {
261  // Wait until other commands are finished.
262  if (!mactbl_wait_idle()) return false; // Timeout?
263 
264  // Setup arguments and issue command.
265  m_reg[REG_MACTBL_MSB] = util::extract_be_u16(mac_addr.addr + 0);
266  m_reg[REG_MACTBL_LSB] = util::extract_be_u32(mac_addr.addr + 2);
267  m_reg[REG_MACTBL_CTRL] = MACTBL_WRITE(port_idx);
268 
269  // Wait for completion.
270  return mactbl_wait_idle(); // Success?
271 }
272 
274  // Read table size from hardware (typ. 32-128)
275  return (unsigned)m_reg[REG_MACCOUNT];
276 }
277 
279  // Wait until other commands are finished.
280  if (!mactbl_wait_idle()) return false; // Timeout?
281 
282  // Issue command and wait for completion.
283  m_reg[REG_MACTBL_CTRL] = MACTBL_CLEAR();
284  return mactbl_wait_idle(); // Success?
285 }
286 
287 bool SwitchConfig::mactbl_learn(bool enable) {
288  // Wait until other commands are finished.
289  if (!mactbl_wait_idle()) return false; // Timeout?
290 
291  // Issue command and wait for completion.
292  m_reg[REG_MACTBL_CTRL] = MACTBL_LEARN(enable ? 1 : 0);
293  return mactbl_wait_idle(); // Success?
294 }
295 
296 void SwitchConfig::mactbl_log(const char* label) {
297  unsigned port_idx;
298  eth::MacAddr mac_addr;
299 
300  // Create a log message for each table entry.
301  unsigned table_size = mactbl_size();
302  for (unsigned tbl_idx = 0 ; tbl_idx < table_size ; ++tbl_idx) {
303  log::Log msg(log::INFO, label);
304  msg.write(": Row").write10((u32)tbl_idx);
305  if (mactbl_read(tbl_idx, port_idx, mac_addr)) {
306  msg.write(": Port").write10((u32)port_idx);
307  msg.write(", MAC").write(mac_addr);
308  } else {
309  msg.write(": Empty");
310  }
311  }
312 }
313 
315  // Poll the control register up to N times.
316  // TODO: Tie this to real-world timeout of a few microseconds.
317  for (unsigned a = 0 ; a < 100 ; ++a) {
318  u32 status = m_reg[REG_MACTBL_CTRL];
319  if ((status & MACTBL_OPCODE_MASK) == MACTBL_IDLE)
320  return true; // Done / idle
321  }
322  return false; // Timeout
323 }
Generic ConfigBus API.
Definition: cfgbus_core.h:124
Pointer-like wrapper for one or more ConfigBus registers.
Definition: cfgbus_core.h:76
Management functions for a SatCat5 Ethernet switch.
Definition: switch_cfg.h:166
void mactbl_log(const char *label)
Log the contents of the MAC-address table.
Definition: switch_cfg.cc:296
bool mactbl_write(unsigned port_idx, const satcat5::eth::MacAddr &mac_addr)
Write a new entry to the MAC-address table.
Definition: switch_cfg.cc:257
static constexpr unsigned REG_MACTBL_CTRL
MAC-table control (read-write)
Definition: switch_cfg.h:293
static constexpr unsigned REG_MACTBL_LSB
MAC-table control (read-write)
Definition: switch_cfg.h:291
static constexpr unsigned REG_VLAN_VID
VLAN connections: set VID (read-write)
Definition: switch_cfg.h:289
void vlan_reset(bool lockdown=false)
Revert all VLAN settings to default.
Definition: switch_cfg.cc:165
u32 get_miss_mask()
Identify which ports are currently in "miss-as-broadcast" mode.
Definition: switch_cfg.cc:91
bool priority_set(u16 etype, unsigned plen=16)
Designate specific EtherType range(s) as high-priority.
Definition: switch_cfg.cc:59
u16 get_frame_max()
Get the maximum allowed frame size, in bytes.
Definition: switch_cfg.cc:129
void vlan_set_mask(u16 vid, u32 mask)
Set connected port-mask for the designated VLAN.
Definition: switch_cfg.cc:196
static constexpr unsigned REG_MACCOUNT
MAC-address table size (read-only)
Definition: switch_cfg.h:283
void ptp_set_2step(unsigned port_idx, bool enable)
PTP configuration for each port.
Definition: switch_cfg.cc:158
static constexpr unsigned REG_VLAN_PORT
VLAN port configuration (write-only)
Definition: switch_cfg.h:288
void vlan_leave(u16 vid, unsigned port)
Remote a given port from the designated VLAN.
Definition: switch_cfg.cc:222
void set_miss_bcast(unsigned port_idx, bool enable)
Enable or disable "miss-as-broadcast" flag on the specified port.
Definition: switch_cfg.cc:80
static constexpr unsigned REG_FRAMESIZE
Frame size limits (read-only)
Definition: switch_cfg.h:287
bool mactbl_clear()
Clear MAC-address table contents.
Definition: switch_cfg.cc:278
void vlan_join(u16 vid, unsigned port)
Join a given port to the designated VLAN.
Definition: switch_cfg.cc:212
unsigned mactbl_size()
Read the maximum size of the MAC-address table.
Definition: switch_cfg.cc:273
void set_miss_mask(u32 mask)
Enable or disable all "miss-as-broadcast" flags at once.
Definition: switch_cfg.cc:87
static constexpr unsigned REG_CORECLOCK
Core clock frequency, in Hz (read-only)
Definition: switch_cfg.h:282
static constexpr unsigned REG_DATAPATH
Datapath width, in bits (read-only)
Definition: switch_cfg.h:281
static constexpr unsigned REG_PROMISC
Promisicuous port mask (read-write)
Definition: switch_cfg.h:284
void ptp_set_offset_tx(unsigned port_idx, s32 subns)
PTP configuration for each port.
Definition: switch_cfg.cc:154
bool mactbl_wait_idle()
Wait for MAC-table access.
Definition: switch_cfg.cc:314
static constexpr unsigned REG_PRIORITY
Packet prioritization (read-write, optional)
Definition: switch_cfg.h:285
void vlan_set_port(const VtagPolicy &cfg)
Set tag policy and other per-port settings.
Definition: switch_cfg.cc:201
static constexpr unsigned REG_MISS_BCAST
Miss-as-broadcast port mask (read-write)
Definition: switch_cfg.h:294
u32 get_promiscuous_mask()
Identify which ports are currently promiscuous.
Definition: switch_cfg.cc:106
static constexpr unsigned REG_MACTBL_MSB
MAC-table control (read-write)
Definition: switch_cfg.h:292
u32 vlan_get_mask(u16 vid)
Get connected port-mask for the designated VLAN.
Definition: switch_cfg.cc:191
u32 m_pri_wridx
Next index in priority table.
Definition: switch_cfg.h:311
static constexpr unsigned REG_PTP_TX(unsigned idx)
Tx timestamp offset for Nth port.
Definition: switch_cfg.h:304
static constexpr unsigned REG_VLAN_RATE
VLAN rate-control configuration (write-only)
Definition: switch_cfg.h:296
u32 ptp_get_2step_mask()
PTP configuration for each port.
Definition: switch_cfg.cc:146
u32 get_traffic_count()
Report matching frames since last call to get_traffic_count().
Definition: switch_cfg.cc:115
satcat5::cfg::Register m_reg
ConfigBus register space.
Definition: switch_cfg.h:310
static constexpr unsigned REG_PTP_2STEP
PTP "twoStep" mode flag (read-write)
Definition: switch_cfg.h:295
void priority_reset()
Clear all EtherType-based priority settings.
Definition: switch_cfg.cc:48
void set_traffic_filter(u16 etype=0)
Set EtherType filter for traffic reporting. (0 = Any type)
Definition: switch_cfg.cc:110
s32 ptp_get_offset_rx(unsigned port_idx)
PTP configuration for each port.
Definition: switch_cfg.cc:138
void set_promiscuous_mask(u32 mask)
Set the "promiscuous" flag for all ports at once.
Definition: switch_cfg.cc:102
u32 port_count()
Number of ports on this switch.
Definition: switch_cfg.cc:44
static constexpr unsigned REG_PTP_RX(unsigned idx)
Rx timestamp offset for Nth port.
Definition: switch_cfg.h:302
static constexpr unsigned REG_PORTCOUNT
Number of ports (read-only)
Definition: switch_cfg.h:280
void set_promiscuous(unsigned port_idx, bool enable)
Enable or disable "promiscuous" flag on the specified port index.
Definition: switch_cfg.cc:95
satcat5::cfg::Register get_log_register()
Get packet-logging register.
Definition: switch_cfg.cc:134
static constexpr unsigned REG_LOGGING
Packet logging diagnostics (read-only)
Definition: switch_cfg.h:297
bool mactbl_read(unsigned tbl_idx, unsigned &port_idx, satcat5::eth::MacAddr &mac_addr)
Read the Nth entry from the MAC-address table.
Definition: switch_cfg.cc:232
void log_info(const char *label)
Log some basic info about this switch.
Definition: switch_cfg.cc:34
static constexpr unsigned REG_VLAN_MASK
VLAN connections: set mask (read-write)
Definition: switch_cfg.h:290
void ptp_set_offset_rx(unsigned port_idx, s32 subns)
PTP configuration for each port.
Definition: switch_cfg.cc:150
s32 ptp_get_offset_tx(unsigned port_idx)
PTP configuration for each port.
Definition: switch_cfg.cc:142
u16 get_frame_min()
Get the minimum allowed frame size, in bytes.
Definition: switch_cfg.cc:124
void vlan_set_rate(u16 vid, const satcat5::eth::VlanRate &cfg)
Set the maximum aggregated throughput for a given VID.
Definition: switch_cfg.cc:205
u16 m_stats_filter
Filter stats by EtherType.
Definition: switch_cfg.h:312
bool mactbl_learn(bool enable)
Enable automatic learning of new MAC addresses?
Definition: switch_cfg.cc:287
static constexpr unsigned REG_PKTCOUNT
Packet-counting w/ filter (read-write)
Definition: switch_cfg.h:286
The Log class creates and formats one log message.
Definition: log.h:195
Log & write10(s32 val)
Print integer as a decimal value with no leading zeros.
Definition: log.cc:261
Log & write(const char *str)
Formatting methods for various data types.
Definition: log.cc:198
Diagnostic logging to UART and/or Ethernet ports.
An Ethernet MAC address (with serializable interface).
Definition: eth_header.h:29
u8 addr[6]
Byte array in network order (Index 0 = MSB)
Definition: eth_header.h:31
Data structure for configuring VLAN rate-limiter parameters.
Definition: switch_cfg.h:107
u32 tok_rate
Tokens per millisecond.
Definition: switch_cfg.h:109
u32 tok_max
Maximum accumulated tokens.
Definition: switch_cfg.h:110
u32 tok_policy
Policy and scaling.
Definition: switch_cfg.h:108
Data structure for configuring VLAN tagging policy of each port.
Definition: switch_cfg.h:68
u32 value
Packed value holds the tag policy, port number, and default VID.
Definition: switch_cfg.h:71
Configuration for a managed SatCat5 switch.
constexpr u32 VTAG_RESTRICT
Define VLAN policy modes for a given switch port.
Definition: switch_cfg.h:36
constexpr u32 VTAG_ADMIT_ALL
Define VLAN policy modes for a given switch port.
Definition: switch_cfg.h:35
constexpr u32 VLAN_CONNECT_ALL
Common port-connection masks.
Definition: switch_cfg.h:63
constexpr u32 VLAN_CONNECT_NONE
Common port-connection masks.
Definition: switch_cfg.h:64
constexpr satcat5::eth::VlanRate VRATE_UNLIMITED(VPOL_UNLIMITED, 0, 0)
Define some commonly-used rate-limiter configurations.
constexpr satcat5::eth::VlanRate VRATE_8KBPS(VPOL_STRICT, 8000ull, 4096)
Define some commonly-used rate-limiter configurations.
Miscellaneous mathematical utility functions.