Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More testing and fix Qav + refactor #98

Open
wants to merge 25 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
587556b
WIP document MAC feature set
ed-xmos Jan 21, 2025
2f67ae0
Add text about queues and shaper
ed-xmos Jan 21, 2025
f9ca840
Add helper function example to set_egress_qav_idle_slope api
ed-xmos Jan 21, 2025
9ad88b1
Add VLAN stripping docs and some correctlons
ed-xmos Jan 22, 2025
15cfb29
Tidy tables
ed-xmos Jan 22, 2025
753e638
typo
ed-xmos Jan 22, 2025
cc5e573
typo2
ed-xmos Jan 22, 2025
5fa8321
typo3
ed-xmos Jan 22, 2025
e2d4873
typo4
ed-xmos Jan 22, 2025
b0c37ed
Review feedback
ed-xmos Jan 22, 2025
2c8e8fa
More detail for standard API
ed-xmos Jan 27, 2025
3d95087
Merge commit '2442e760fce18e533277e4804eb9206789f8eb48' into feature/…
ed-xmos Jan 27, 2025
96f3b01
Add MII_CREDIT_FRACTIONAL_BITS to API
ed-xmos Jan 27, 2025
fc2d2bd
Merge commit 'ea7273fefcef44f3f9e55dc41bc110cc6c58e78c' into feature/…
ed-xmos Jan 27, 2025
83a9cca
set_macaddr is const addr
ed-xmos Jan 27, 2025
bb6df87
Merge branch 'feature/docs_enhance' into feature/qav_update
ed-xmos Jan 27, 2025
5b7a2a2
Initial move shaper to helper file
ed-xmos Jan 28, 2025
b5adfeb
Initial test WIP
ed-xmos Jan 28, 2025
6c05cf5
Update shaper_do_idle_slope so it's ASM compatible. Failing test incl…
ed-xmos Jan 28, 2025
4fc208d
Major re-work of shaper
ed-xmos Jan 29, 2025
d4b45fa
Add passing regex for idle_slope unit
ed-xmos Jan 29, 2025
72514c3
Use new shaper in rmii
ed-xmos Jan 29, 2025
040303b
fix new shaper
ed-xmos Jan 30, 2025
e0d7d00
no-limit = 0, Qav test passing
ed-xmos Jan 30, 2025
1590b22
Add clipping for no limit case to avoid overflow
ed-xmos Jan 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions lib_ethernet/api/ethernet.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
#include "doxygen.h" // Sphynx Documentation Workarounds


#define ETHERNET_ALL_INTERFACES (-1)
#define ETHERNET_MAX_PACKET_SIZE (1518) /**< MAX packet size in bytes */
#define ETHERNET_ALL_INTERFACES (-1)
#define ETHERNET_MAX_PACKET_SIZE (1518) /**< MAX packet size in bytes including src, dst, ether/tags but NOT preamble or CRC*/

#define MACADDR_NUM_BYTES (6) /**< Number of octets in MAC address */

#define MII_CREDIT_FRACTIONAL_BITS (16) /** Fractional bits for Qav credit based shaper setting */

#define MACADDR_NUM_BYTES 6

/** Type representing the type of packet from the MAC */
typedef enum eth_packet_type_t {
Expand Down Expand Up @@ -77,7 +80,7 @@ typedef interface ethernet_cfg_if {
* \param ifnum The index of the MAC interface to set
* \param mac_address The six-octet MAC address to set
*/
void set_macaddr(size_t ifnum, uint8_t mac_address[MACADDR_NUM_BYTES]);
void set_macaddr(size_t ifnum, const uint8_t mac_address[MACADDR_NUM_BYTES]);

/** Gets the source MAC address of the Ethernet MAC
*
Expand Down
2 changes: 1 addition & 1 deletion lib_ethernet/src/mii_ethernet_mac.xc
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ static void mii_ethernet_aux(client mii_if i_mii,
memcpy(r_mac_address, mac_address, sizeof mac_address);
break;

case i_cfg[int i].set_macaddr(size_t ifnum, uint8_t r_mac_address[MACADDR_NUM_BYTES]):
case i_cfg[int i].set_macaddr(size_t ifnum, const uint8_t r_mac_address[MACADDR_NUM_BYTES]):
memcpy(mac_address, r_mac_address, sizeof r_mac_address);
break;

Expand Down
2 changes: 1 addition & 1 deletion lib_ethernet/src/mii_ethernet_rt_mac.xc
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ unsafe void mii_ethernet_server(mii_mempool_t rx_mem,
memcpy(r_mac_address, mac_address, sizeof mac_address);
break;

case i_cfg[int i].set_macaddr(size_t ifnum, uint8_t r_mac_address[MACADDR_NUM_BYTES]):
case i_cfg[int i].set_macaddr(size_t ifnum, const uint8_t r_mac_address[MACADDR_NUM_BYTES]):
memcpy(mac_address, r_mac_address, sizeof r_mac_address);
break;

Expand Down
41 changes: 13 additions & 28 deletions lib_ethernet/src/mii_master.xc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "mii_common_lld.h"
#include "string.h"
#include "check_ifg_wait.h"
#include "shaper.h"

#define QUOTEAUX(x) #x
#define QUOTE(x) QUOTEAUX(x)
Expand Down Expand Up @@ -471,9 +472,9 @@ unsafe void mii_master_tx_pins(mii_mempool_t tx_mem_lp,
out buffered port:32 p_mii_txd,
volatile ethernet_port_state_t * unsafe p_port_state)
{
int credit = 0; // No. of bits allowed to send
int credit_time;
// Need one timer to be able to read at any time for the shaper
qav_state_t qav_state = {0, 0, 0}; // Set times and credit to zero so it can tx first frame

// Need a timer to be able to read at any time for the shaper
timer credit_tmr;
// And a second timer to be enforcing the IFG gap
hwtimer_t ifg_tmr;
Expand All @@ -485,7 +486,8 @@ unsafe void mii_master_tx_pins(mii_mempool_t tx_mem_lp,
enable_shaper = 0;

if (ETHERNET_SUPPORT_HP_QUEUES && enable_shaper) {
credit_tmr :> credit_time;
credit_tmr :> qav_state.current_time;
qav_state.prev_time = qav_state.current_time;
}

ifg_tmr :> ifg_time;
Expand All @@ -500,23 +502,10 @@ unsafe void mii_master_tx_pins(mii_mempool_t tx_mem_lp,
buf = mii_get_next_buf(packets_hp);

if (enable_shaper) {
int prev_credit_time = credit_time;
credit_tmr :> credit_time;

int elapsed = credit_time - prev_credit_time;
credit += elapsed * p_port_state->qav_idle_slope; // add bit budget since last transmission to credit. ticks * bits/tick = bits

if (buf) {
if (credit < 0) {
buf = 0; // if out of credit drop this HP packet
}
}
else {
if (credit > 0)
credit = 0;
}
credit_tmr :> qav_state.current_time;
buf = shaper_do_idle_slope(buf, &qav_state, p_port_state);
}

if (!buf) {
buf = mii_get_next_buf(packets_lp);
p_ts_queue = &ts_queue;
Expand All @@ -530,19 +519,15 @@ unsafe void mii_master_tx_pins(mii_mempool_t tx_mem_lp,

unsigned time = mii_transmit_packet(tx_mem, buf, p_mii_txd, ifg_tmr, ifg_time, eof_time);

eof_time = ifg_time;
// Setup the hardware timer to enforce the IFG
eof_time = ifg_time;
ifg_time += MII_ETHERNET_IFS_AS_REF_CLOCK_COUNT;
ifg_time += (buf->length & 0x3) * 8;

// Calculate the send slope (decrement credit) if enabled and was HP
const int packet_is_high_priority = (p_ts_queue == null);
if (enable_shaper && packet_is_high_priority) {
const int preamble_bytes = 8;
const int ifg_bytes = 96/8;
const int crc_bytes = 4;
int len = buf->length + preamble_bytes + ifg_bytes + crc_bytes;
// decrease credit by no. of bits transmitted
credit = credit - (len << (MII_CREDIT_FRACTIONAL_BITS+3)); // MII_CREDIT_FRACTIONAL_BITS+3 to convert from bytes to bits
shaper_do_send_slope(buf->length, &qav_state);
}

if (mii_get_and_dec_transmit_count(buf) == 0) {
Expand All @@ -559,6 +544,6 @@ unsafe void mii_master_tx_pins(mii_mempool_t tx_mem_lp,
mii_free_current(packets_hp);
}
}
}
} // while(1)
}

2 changes: 1 addition & 1 deletion lib_ethernet/src/rgmii_buffering.xc
Original file line number Diff line number Diff line change
Expand Up @@ -747,7 +747,7 @@ void rgmii_ethernet_mac_config(server ethernet_cfg_if i_cfg[n],
memcpy(r_mac_address, mac_address, sizeof mac_address);
break;

case i_cfg[int i].set_macaddr(size_t ifnum, uint8_t r_mac_address[MACADDR_NUM_BYTES]):
case i_cfg[int i].set_macaddr(size_t ifnum, const uint8_t r_mac_address[MACADDR_NUM_BYTES]):
memcpy(mac_address, r_mac_address, sizeof r_mac_address);
break;

Expand Down
31 changes: 8 additions & 23 deletions lib_ethernet/src/rmii_master.xc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "string.h"
#include "check_ifg_wait.h"
#include "rmii_rx_pins_exit.h"
#include "shaper.h"


#define QUOTEAUX(x) #x
Expand Down Expand Up @@ -992,21 +993,22 @@ unsafe void rmii_master_tx_pins(mii_mempool_t tx_mem_lp,
// Flag for readability and faster comparison
const unsigned use_4b = (tx_port_width == 4);

int credit = 0;
int credit_time;
// Need one timer to be able to read at any time for the shaper
timer credit_tmr;
// And a second timer to be enforcing the IFG gap
hwtimer_t ifg_tmr;
unsigned ifg_time = 0;
unsigned eof_time = 0;

qav_state_t qav_state = {0, 0, 0}; // Set times and credit to zero so it can tx first frame
unsigned enable_shaper = p_port_state->qav_shaper_enabled;

if (!ETHERNET_SUPPORT_TRAFFIC_SHAPER) {
enable_shaper = 0;
}
if (ETHERNET_SUPPORT_HP_QUEUES && enable_shaper) {
credit_tmr :> credit_time;
credit_tmr :> qav_state.current_time;
qav_state.prev_time = qav_state.current_time;;
}

ifg_tmr :> ifg_time;
Expand All @@ -1021,21 +1023,8 @@ unsafe void rmii_master_tx_pins(mii_mempool_t tx_mem_lp,
}

if (enable_shaper) {
int prev_credit_time = credit_time;
credit_tmr :> credit_time;

int elapsed = credit_time - prev_credit_time;
credit += elapsed * p_port_state->qav_idle_slope;

if (buf) {
if (credit < 0) {
buf = 0;
}
} else {
if (credit > 0) {
credit = 0;
}
}
credit_tmr :> qav_state.current_time;
buf = shaper_do_idle_slope(buf, &qav_state, p_port_state);
}

if (!buf) {
Expand Down Expand Up @@ -1071,11 +1060,7 @@ unsafe void rmii_master_tx_pins(mii_mempool_t tx_mem_lp,

const int packet_is_high_priority = (p_ts_queue == null);
if (enable_shaper && packet_is_high_priority) {
const int preamble_bytes = 8;
const int ifg_bytes = 96/8;
const int crc_bytes = 4;
int len = buf->length + preamble_bytes + ifg_bytes + crc_bytes;
credit = credit - (len << (MII_CREDIT_FRACTIONAL_BITS+3));
shaper_do_send_slope(buf->length, &qav_state);
}

if (mii_get_and_dec_transmit_count(buf) == 0) {
Expand Down
3 changes: 1 addition & 2 deletions lib_ethernet/src/server_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
#include "xccompat.h"
#include "ethernet.h"

#define MII_CREDIT_FRACTIONAL_BITS 16

// Server is shared for rmii/mii so pass in enum
typedef enum phy_100mb_t {
ETH_MAC_IF_MII = 0,
Expand All @@ -21,6 +19,7 @@ typedef struct ethernet_port_state_t
ethernet_speed_t link_speed;
int qav_shaper_enabled;
int qav_idle_slope;
int64_t qav_credit_limit;
int ingress_ts_latency[NUM_ETHERNET_SPEEDS];
int egress_ts_latency[NUM_ETHERNET_SPEEDS];
} ethernet_port_state_t;
Expand Down
3 changes: 2 additions & 1 deletion lib_ethernet/src/server_state.xc
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ void init_server_port_state(ethernet_port_state_t &state, int enable_qav_shaper)
memset(&state, 0, sizeof(ethernet_port_state_t));
state.link_state = ETHERNET_LINK_DOWN;
state.qav_shaper_enabled = enable_qav_shaper;
state.qav_idle_slope = (11<<MII_CREDIT_FRACTIONAL_BITS);
state.qav_credit_limit = 0; // No credit limit
state.qav_idle_slope = (11<<MII_CREDIT_FRACTIONAL_BITS); // 11 bits per tick (more than max egress even in gbit)
}
129 changes: 129 additions & 0 deletions lib_ethernet/src/shaper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// Copyright 2025 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef __shaper_h__
#define __shaper_h__

#include <stdio.h>
#include "ethernet.h"
#include "server_state.h"
#include "mii_buffering.h"
#include "xassert.h"
#include <print.h>

#ifndef ETHERNET_SUPPORT_TRAFFIC_SHAPER_CREDIT_LIMIT
#define ETHERNET_SUPPORT_TRAFFIC_SHAPER_CREDIT_LIMIT 1
#endif

static const unsigned preamble_bytes = 8;
static const unsigned crc_bytes = 4;
static const unsigned ifg_bytes = 96 / 8;

/** Type which stores the Qav credit based shaper state */
typedef struct qav_state_t{
int prev_time; /**< Previous time in hw_timer ticks (10ns, 32b). */
int current_time; /**< Current time in hw_timer ticks (10ns, 32b). */
int credit; /**< Credit in MII_CREDIT_FRACTIONAL_BITS fractional format. */
} qav_state_t;

/** Sets the Qav idle slope in units of bits per second.
*
* \param port_state Pointer to the port state to be modified
* \param limit_bps The idle slope setting in bits per second
*
*/
void set_qav_idle_slope(ethernet_port_state_t * port_state, unsigned limit_bps);


/** Sets the Qav credit limit in units of frame size byte
*
* \param port_state Pointer to the port state to be modified
* \param limit_bytes The credit limit in units of payload size in bytes to set as a credit limit,
* not including preamble, CRC and IFG. Set to 0 for no limit (default)
*
*/
void set_qav_credit_limit(ethernet_port_state_t * port_state, int payload_limit_bytes);


/** Performs the idle slope calculation for MII and RMII MACs.
*
* Adds credits based on time since last HP packet and bit rate. If credit after calculation is above zero then
* the HP packet is allowed to be transmitted. If credit is negative then the return buffer
* is null so that it waits until credit is sufficient.
*
* The credit is optionally limited to hiCredit which is initialised by set_qav_credit_limit()
*
* \param hp_buf Pointer to packet to be transmitted
* \param qav_state Pointer to Qav state struct
* \param port_state Pointer to MAC port state
*
* \returns The hp_buf passed to it which is either maintained if credit is sufficient
* or NULL if credit is not sufficient.
*/
static inline mii_packet_t * unsafe shaper_do_idle_slope(mii_packet_t * unsafe hp_buf,
qav_state_t * unsafe qav_state,
ethernet_port_state_t * unsafe port_state){
unsafe{
uint32_t elapsed_ticks = qav_state->current_time - qav_state->prev_time;

#if ETHERNET_SUPPORT_TRAFFIC_SHAPER_CREDIT_LIMIT
int64_t credit64 = (int64_t)elapsed_ticks * (int64_t)port_state->qav_idle_slope + (int64_t)qav_state->credit;

// cast qav_credit_limit as saves a cycle
if((unsigned)port_state->qav_credit_limit){
// Apply limit
if(credit64 > port_state->qav_credit_limit)
{
// printf("limited credit: %lld limit: %lld\n", credit64, port_state->qav_credit_limit);
credit64 = port_state->qav_credit_limit;
}
} else {
// Clip to max_int to avoid overflow
const int64_t max_int = 0x7fffffff;
if(credit64 > max_int){
// printf("clip credit: %lld limit: %lld\n", credit64, port_state->qav_credit_limit);
credit64 = max_int;
}
}
qav_state->credit = (int)credit64;
#else
// This is the old code from <4.0.0
qav_state->credit += elapsed_ticks * (int)port_state->qav_idle_slope; // add bit budget since last transmission to credit. ticks * bits/tick = bits
#endif

// If valid hp buffer
if (hp_buf) {
if (qav_state->credit < 0) {
hp_buf = 0; // if out of credit drop this HP packet
}
}
else
// Buffer invalid, no HP packet so reset credit as per Annex L of Qav
{
if (qav_state->credit > 0){
qav_state->credit = 0; // HP ready to send next time
}
}

// Ensure we keep track of state (time since last packet) for next time
qav_state->prev_time = qav_state->current_time;

return hp_buf;
}
}


static inline void shaper_do_send_slope(int len_bytes, qav_state_t * unsafe qav_state){
unsafe{
// Calculate number of additional byte slots on wire over the payload
const int overhead_bytes = preamble_bytes + crc_bytes + ifg_bytes;

// decrease credit by no. of bits transmitted, scaled by MII_CREDIT_FRACTIONAL_BITS
// Note we don't need to check for overflow here as we will only be here if credit
// was previously positive (worst case 1) and len_bytes <= ETHERNET_MAX_PACKET_SIZE so
// will only decrement by roughly -(1<<29)
qav_state->credit = qav_state->credit - ((len_bytes + overhead_bytes) << (MII_CREDIT_FRACTIONAL_BITS + 3)); // MII_CREDIT_FRACTIONAL_BITS+3 to convert from bytes to bits
}
}


#endif // __shaper_h__
29 changes: 29 additions & 0 deletions lib_ethernet/src/shaper.xc
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright 2025 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include "ethernet.h"
#include "shaper.h"

void set_qav_idle_slope(ethernet_port_state_t * port_state, unsigned limit_bps)
{
// Scale for 16.16 representation
uint64_t slope = ((uint64_t)limit_bps) << MII_CREDIT_FRACTIONAL_BITS;

// Calculate bits per tick per bit in 16.16
slope = slope / XS1_TIMER_HZ;

port_state->qav_idle_slope = (unsigned)slope;
}


void set_qav_credit_limit(ethernet_port_state_t * port_state, int payload_limit_bytes)
{
int64_t max_interferring_frame_bits = (preamble_bytes + payload_limit_bytes + crc_bytes + ifg_bytes) * 8;
if(payload_limit_bytes > 0){
port_state->qav_credit_limit = max_interferring_frame_bits;
}
else
{
// No limit
port_state->qav_credit_limit = 0;
}
}
Loading