summaryrefslogtreecommitdiffstats
path: root/simple_gemac
diff options
context:
space:
mode:
authorMatt Ettus <matt@ettus.com>2009-09-04 22:23:27 -0700
committerMatt Ettus <matt@ettus.com>2009-09-04 22:23:27 -0700
commitc21464b1107295575afa958e34f915f7d9985c14 (patch)
treed129daeeb1af64465858aaca126ec9923742e7fb /simple_gemac
parent71babf966d8cd340eb62122a297c2cc3b1294b82 (diff)
downloaduhd-c21464b1107295575afa958e34f915f7d9985c14.tar.gz
uhd-c21464b1107295575afa958e34f915f7d9985c14.tar.bz2
uhd-c21464b1107295575afa958e34f915f7d9985c14.zip
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.
Diffstat (limited to 'simple_gemac')
-rw-r--r--simple_gemac/flow_ctrl_rx.v105
-rw-r--r--simple_gemac/simple_gemac.v6
-rw-r--r--simple_gemac/simple_gemac_wb.v20
-rw-r--r--simple_gemac/simple_gemac_wrapper.v7
4 files changed, 65 insertions, 73 deletions
diff --git a/simple_gemac/flow_ctrl_rx.v b/simple_gemac/flow_ctrl_rx.v
index 7ded9e08b..b13334d0e 100644
--- a/simple_gemac/flow_ctrl_rx.v
+++ b/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/simple_gemac/simple_gemac.v b/simple_gemac/simple_gemac.v
index 5ec2fa2ba..868a66819 100644
--- a/simple_gemac/simple_gemac.v
+++ b/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/simple_gemac/simple_gemac_wb.v b/simple_gemac/simple_gemac_wb.v
index cc2cdf7ec..6df277e3e 100644
--- a/simple_gemac/simple_gemac_wb.v
+++ b/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/simple_gemac/simple_gemac_wrapper.v b/simple_gemac/simple_gemac_wrapper.v
index de445476c..7511f3fb9 100644
--- a/simple_gemac/simple_gemac_wrapper.v
+++ b/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,