From 9e05f0770b92f9c85f09e3629f875011e8f1ac24 Mon Sep 17 00:00:00 2001 From: Matt Ettus Date: Fri, 4 Sep 2009 22:23:27 -0700 Subject: [PATCH] Implement Eth flow control using pause frames Not fully tested, but it seems to work without frame errors, sequence number errors or ethernet overruns. Still of course will get tx underruns on a slow machine, and the transmitted signal has some issues though. --- usrp2/firmware/lib/eth_mac.c | 5 +- usrp2/firmware/lib/eth_mac_regs.h | 3 + usrp2/fpga/simple_gemac/flow_ctrl_rx.v | 105 +++++++----------- usrp2/fpga/simple_gemac/simple_gemac.v | 6 +- usrp2/fpga/simple_gemac/simple_gemac_wb.v | 20 +++- .../fpga/simple_gemac/simple_gemac_wrapper.v | 7 +- usrp2/fpga/top/u2_rev3/Makefile | 1 + 7 files changed, 73 insertions(+), 74 deletions(-) diff --git a/usrp2/firmware/lib/eth_mac.c b/usrp2/firmware/lib/eth_mac.c index becd9364..2ef1f73f 100644 --- a/usrp2/firmware/lib/eth_mac.c +++ b/usrp2/firmware/lib/eth_mac.c @@ -46,7 +46,10 @@ eth_mac_init(const u2_mac_addr_t *src) eth_mac->miimoder = 25; // divider from CPU clock (50MHz/25 = 2MHz) eth_mac_set_addr(src); - eth_mac->settings = MAC_SET_PAUSE_EN | MAC_SET_PASS_BCAST | MAC_SET_PASS_UCAST; // 0x39; + eth_mac->settings = MAC_SET_PAUSE_EN | MAC_SET_PASS_BCAST | MAC_SET_PASS_UCAST | MAC_SET_PAUSE_SEND_EN; + + eth_mac->pause_time = 38; + eth_mac->pause_thresh = 1200; // set rx flow control high and low water marks // unsigned int lwmark = (2*2048 + 64)/4; // 2 * 2048-byte frames + 1 * 64-byte pause frame diff --git a/usrp2/firmware/lib/eth_mac_regs.h b/usrp2/firmware/lib/eth_mac_regs.h index a14c0064..d680f8de 100644 --- a/usrp2/firmware/lib/eth_mac_regs.h +++ b/usrp2/firmware/lib/eth_mac_regs.h @@ -35,6 +35,8 @@ typedef struct { volatile int miicommand; volatile int miistatus; volatile int miirx_data; + volatile int pause_time; + volatile int pause_thresh; } eth_mac_regs_t; // settings register @@ -44,6 +46,7 @@ typedef struct { #define MAC_SET_PASS_BCAST (1 << 3) // Sends broadcast frames through (normally on) #define MAC_SET_PASS_MCAST (1 << 4) // Sends multicast frames that match mcast addr (normally off) #define MAC_SET_PASS_UCAST (1 << 5) // Sends unicast (normal) frames through if they hit in address filter (normally on) +#define MAC_SET_PAUSE_SEND_EN (1 << 6) // Enables sending pause frames // miicommand register #define MIIC_SCANSSTAT (1 << 0) // Scan status diff --git a/usrp2/fpga/simple_gemac/flow_ctrl_rx.v b/usrp2/fpga/simple_gemac/flow_ctrl_rx.v index 7ded9e08..b13334d0 100644 --- a/usrp2/fpga/simple_gemac/flow_ctrl_rx.v +++ b/usrp2/fpga/simple_gemac/flow_ctrl_rx.v @@ -2,84 +2,59 @@ // RX side of flow control -- when we are running out of RX space, send a PAUSE module flow_ctrl_rx - (input rst, - //host processor - input pause_frame_send_en, - input [15:0] pause_quanta_set, - input [15:0] fc_hwmark, - input [15:0] fc_lwmark, - // From MAC_rx_ctrl - input rx_clk, - input [15:0] rx_fifo_space, - // MAC_tx_ctrl - input tx_clk, - output reg xoff_gen, - output reg xon_gen, - input xoff_gen_complete, - input xon_gen_complete + (input pause_request_en, input [15:0] pause_time, input [15:0] pause_thresh, + input rx_clk, input rx_reset, input [15:0] rx_fifo_space, + input tx_clk, input tx_reset, output reg pause_req, output reg [15:0] pause_time_req ); // ****************************************************************************** // Force our TX to send a PAUSE frame because our RX is nearly full // ****************************************************************************** - reg xon_int, xoff_int; + // RX Clock Domain + reg xon, xoff; reg [21:0] countdown; - - always @(posedge rx_clk or posedge rst) - if(rst) - begin - xon_int <= 0; - xoff_int <= 0; - end - else - begin - xon_int <= 0; - xoff_int <= 0; - if(pause_frame_send_en) - if(countdown == 0) - if(rx_fifo_space < fc_lwmark) - xoff_int <= 1; - else - ; - else - if(rx_fifo_space > fc_hwmark) - xon_int <= 1; - end // else: !if(rst) - - reg xoff_int_d1, xon_int_d1; - always @(posedge rx_clk) - xon_int_d1 <= xon_int; - always @(posedge rx_clk) - xoff_int_d1 <= xoff_int; + wire [15:0] pause_low_thresh = pause_thresh; + wire [15:0] pause_hi_thresh = 16'hFFFF; + wire [21:0] pq_reduced = {pause_time,6'd0} - 1700; - always @ (posedge tx_clk or posedge rst) - if (rst) - xoff_gen <=0; - else if (xoff_gen_complete) - xoff_gen <=0; - else if (xoff_int | xoff_int_d1) - xoff_gen <=1; + always @(posedge rx_clk) + if(rx_reset) + xoff <= 0; + else + xoff <= (pause_request_en & (countdown==0) & (rx_fifo_space < pause_low_thresh)); - always @ (posedge tx_clk or posedge rst) - if (rst) - xon_gen <=0; - else if (xon_gen_complete) - xon_gen <=0; - else if (xon_int | xon_int_d1) - xon_gen <=1; - - wire [15:0] pq_reduced = pause_quanta_set - 2; + always @(posedge rx_clk) + if(rx_reset) + xon <= 0; + else + xon <= ((countdown!=0) & (rx_fifo_space > pause_hi_thresh)); - always @(posedge tx_clk or posedge rst) - if(rst) + always @(posedge rx_clk) + if(rx_reset) countdown <= 0; - else if(xoff_gen) - countdown <= {pq_reduced,6'd0}; - else if(xon_gen) + else if(xoff) + countdown <= pq_reduced; + else if(xon) countdown <= 0; else if(countdown != 0) countdown <= countdown - 1; + + // Cross clock domains + oneshot_2clk send_xon (.clk_in(rx_clk), .in(xon), .clk_out(tx_clk), .out(xon_tx)); + oneshot_2clk send_xoff (.clk_in(rx_clk), .in(xoff), .clk_out(tx_clk), .out(xoff_tx)); + + always @(posedge tx_clk) + if(xoff_tx) + pause_time_req <= pause_time; + else if(xon_tx) + pause_time_req <= 0; + + always @(posedge tx_clk) + if(tx_reset) + pause_req <= 0; + else + pause_req <= xon_tx | xoff_tx; -endmodule // flow_ctrl +endmodule // flow_ctrl_rx diff --git a/usrp2/fpga/simple_gemac/simple_gemac.v b/usrp2/fpga/simple_gemac/simple_gemac.v index 5ec2fa2b..868a6681 100644 --- a/usrp2/fpga/simple_gemac/simple_gemac.v +++ b/usrp2/fpga/simple_gemac/simple_gemac.v @@ -6,7 +6,7 @@ module simple_gemac input GMII_RX_CLK, input GMII_RX_DV, input GMII_RX_ER, input [7:0] GMII_RXD, // Flow Control Interface - input pause_req, input [15:0] pause_time, input pause_en, + input pause_req, input [15:0] pause_time_req, input pause_respect_en, // Settings input [47:0] ucast_addr, input [47:0] mcast_addr, @@ -33,7 +33,7 @@ module simple_gemac .GMII_TX_ER(GMII_TX_ER), .GMII_TXD(GMII_TXD), .tx_clk(tx_clk), .tx_data(tx_data), .tx_valid(tx_valid), .tx_error(tx_error), .tx_ack(tx_ack), .ifg(SGE_IFG), .mac_addr(ucast_addr), - .pause_req(pause_req), .pause_time(pause_time), // We request flow control + .pause_req(pause_req), .pause_time(pause_time_req), // We request flow control .pause_apply(pause_apply), .paused(paused) // We respect flow control ); @@ -50,7 +50,7 @@ module simple_gemac flow_ctrl_tx flow_ctrl_tx (.rst(rst_txclk), .tx_clk(tx_clk), - .tx_pause_en(pause_en), + .tx_pause_en(pause_respect_en), .pause_quanta(pause_quanta_rcvd), // 16 bit value .pause_quanta_val(pause_rcvd), .pause_apply(pause_apply), diff --git a/usrp2/fpga/simple_gemac/simple_gemac_wb.v b/usrp2/fpga/simple_gemac/simple_gemac_wb.v index cc2cdf7e..6df277e3 100644 --- a/usrp2/fpga/simple_gemac/simple_gemac_wb.v +++ b/usrp2/fpga/simple_gemac/simple_gemac_wb.v @@ -24,7 +24,9 @@ module simple_gemac_wb inout mdio, output mdc, output [47:0] ucast_addr, output [47:0] mcast_addr, output pass_ucast, output pass_mcast, output pass_bcast, - output pass_pause, output pass_all, output pause_en ); + output pass_pause, output pass_all, + output pause_respect_en, output pause_request_en, + output [15:0] pause_time, output [15:0] pause_thresh ); wire acc = wb_cyc & wb_stb; wire wr_acc = wb_cyc & wb_stb & wb_we; @@ -36,10 +38,10 @@ module simple_gemac_wb else wb_ack <= acc & ~wb_ack; - wire [5:0] misc_settings; - assign {pass_ucast, pass_mcast, pass_bcast, pass_pause, pass_all, pause_en} = misc_settings; + wire [6:0] misc_settings; + assign {pause_request_en, pass_ucast, pass_mcast, pass_bcast, pass_pause, pass_all, pause_respect_en} = misc_settings; - wb_reg #(.ADDR(0),.DEFAULT(6'b111001)) + wb_reg #(.ADDR(0),.DEFAULT(7'b0111001)) wb_reg_settings (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .wr_acc(wr_acc), .dat_i(wb_dat_i), .dat_o(misc_settings) ); wb_reg #(.ADDR(1),.DEFAULT(0)) @@ -131,6 +133,14 @@ module simple_gemac_wb .WCtrlDataStart(WCtrlDataStart), .RStatStart(RStatStart), .UpdateMIIRX_DATAReg(UpdateMIIRX_DATAReg) ); + wb_reg #(.ADDR(11),.DEFAULT(0)) + wb_reg_pausetime (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .wr_acc(wr_acc), + .dat_i(wb_dat_i), .dat_o(pause_time) ); + + wb_reg #(.ADDR(12),.DEFAULT(0)) + wb_reg_pausethresh (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .wr_acc(wr_acc), + .dat_i(wb_dat_i), .dat_o(pause_thresh) ); + always @(posedge wb_clk) case(wb_adr[7:2]) 0 : wb_dat_o <= misc_settings; @@ -144,6 +154,8 @@ module simple_gemac_wb 8 : wb_dat_o <= MIICOMMAND; 9 : wb_dat_o <= MIISTATUS; 10: wb_dat_o <= MIIRX_DATA; + 11: wb_dat_o <= pause_time; + 12: wb_dat_o <= pause_thresh; endcase // case (wb_adr[7:2]) endmodule // simple_gemac_wb diff --git a/usrp2/fpga/simple_gemac/simple_gemac_wrapper.v b/usrp2/fpga/simple_gemac/simple_gemac_wrapper.v index de445476..7511f3fb 100644 --- a/usrp2/fpga/simple_gemac/simple_gemac_wrapper.v +++ b/usrp2/fpga/simple_gemac/simple_gemac_wrapper.v @@ -140,7 +140,12 @@ module simple_gemac_wrapper .ll_src_rdy(tx_ll_src_rdy), .ll_dst_rdy(tx_ll_dst_rdy), .tx_data(tx_data), .tx_valid(tx_valid), .tx_error(tx_error), .tx_ack(tx_ack)); - wire [31:0] debug_tx, debug_rx; + flow_ctrl_rx flow_ctrl_rx + (.pause_request_en(pause_request_en), .pause_time(pause_time), .pause_thresh(pause_thresh), + .rx_clk(rx_clk), .rx_reset(rx_reset), .rx_fifo_space(rx_fifo_space), + .tx_clk(tx_clk), .tx_reset(tx_reset), .pause_req(pause_req), .pause_time_req(pause_time_req)); + + wire [31:0] debug_tx, debug_rx; assign debug_tx = { { tx_ll_data }, { tx_ll_sof, tx_ll_eof, tx_ll_src_rdy, tx_ll_dst_rdy, diff --git a/usrp2/fpga/top/u2_rev3/Makefile b/usrp2/fpga/top/u2_rev3/Makefile index 7847b8c7..94681f6c 100644 --- a/usrp2/fpga/top/u2_rev3/Makefile +++ b/usrp2/fpga/top/u2_rev3/Makefile @@ -90,6 +90,7 @@ simple_gemac/simple_gemac_rx.v \ simple_gemac/crc.v \ simple_gemac/delay_line.v \ simple_gemac/flow_ctrl_tx.v \ +simple_gemac/flow_ctrl_rx.v \ simple_gemac/address_filter.v \ simple_gemac/ll8_to_txmac.v \ simple_gemac/rxmac_to_ll8.v \ -- 2.47.2