diff options
Diffstat (limited to 'fpga/usrp3/lib/rfnoc')
5 files changed, 111 insertions, 6 deletions
| diff --git a/fpga/usrp3/lib/rfnoc/xport_sv/eth_ipv4_chdr_adapter.sv b/fpga/usrp3/lib/rfnoc/xport_sv/eth_ipv4_chdr_adapter.sv index 892e0a497..355cafb8b 100644 --- a/fpga/usrp3/lib/rfnoc/xport_sv/eth_ipv4_chdr_adapter.sv +++ b/fpga/usrp3/lib/rfnoc/xport_sv/eth_ipv4_chdr_adapter.sv @@ -65,11 +65,14 @@ module eth_ipv4_chdr_adapter #(    input  logic [47:0] my_mac,    input  logic [31:0] my_ip,    input  logic [15:0] my_udp_chdr_port, +  input  logic [15:0] my_pause_set, +  input  logic [15:0] my_pause_clear,    output logic        chdr_dropped,    output logic        cpu_dropped,    // Ethernet MAC +  output logic       eth_pause_req,    AxiStreamIf.master eth_tx, // tUser = {1'b0,trailing bytes};    AxiStreamIf.slave  eth_rx, // tUser = {error,trailing bytes};    // CHDR router interface @@ -90,7 +93,7 @@ module eth_ipv4_chdr_adapter #(    localparam CPU_USER_W  = $clog2(CPU_W/8)+1;    localparam CHDR_USER_W = $clog2(CHDR_W/8);    localparam MAX_PACKET_BYTES = 2**16; -  localparam DEBUG = 1; +  localparam DEBUG = 0;    `include "eth_constants.vh" @@ -137,12 +140,15 @@ module eth_ipv4_chdr_adapter #(      .DROP_MIN_PACKET(DROP_MIN_PACKET),      .ENET_W(ENET_W)    ) eth_dispatch_i ( +    .eth_pause_req    (eth_pause_req),      .eth_rx           (eth_rx1),      .e2v              (e2v1),      .e2c              (e2c1),      .my_mac           (my_mac),      .my_ip            (my_ip),      .my_udp_chdr_port (my_udp_chdr_port), +    .my_pause_set     (my_pause_set), +    .my_pause_clear   (my_pause_clear),      .chdr_dropped     (chdr_dropped),      .cpu_dropped      (cpu_dropped)    ); diff --git a/fpga/usrp3/lib/rfnoc/xport_sv/eth_ipv4_chdr_dispatch.sv b/fpga/usrp3/lib/rfnoc/xport_sv/eth_ipv4_chdr_dispatch.sv index 578646640..17aaadc73 100644 --- a/fpga/usrp3/lib/rfnoc/xport_sv/eth_ipv4_chdr_dispatch.sv +++ b/fpga/usrp3/lib/rfnoc/xport_sv/eth_ipv4_chdr_dispatch.sv @@ -34,6 +34,9 @@  //   - my_ip            : The IPv4 address of this endpoint  //   - my_udp_chdr_port : The UDP port allocated for CHDR traffic on this endpoint  // +//   - my pause set   : number of word of fullness on CHDR_FIFO before requesting a pause +//   - my pause clear : number of word of fullness on CHDR_FIFO before clearing a pause request +//  module eth_ipv4_chdr_dispatch #(    int CPU_FIFO_SIZE    = $clog2(8*1024), @@ -46,6 +49,7 @@ module eth_ipv4_chdr_dispatch #(  )(    // AXI-Stream interfaces +  output logic        eth_pause_req,    AxiStreamIf.slave   eth_rx, // tUser={error,trailing bytes};    AxiStreamIf.master  e2v,    // tUser={1'b0,trailing bytes};    AxiStreamIf.master  e2c,    // tUser={1'b0,trailing bytes}; @@ -54,6 +58,9 @@ module eth_ipv4_chdr_dispatch #(    input  logic [47:0] my_mac,    input  logic [31:0] my_ip,    input  logic [15:0] my_udp_chdr_port, +  // Pause control +  input  logic [15:0] my_pause_set, +  input  logic [15:0] my_pause_clear,    output logic        chdr_dropped,    output logic        cpu_dropped @@ -63,15 +70,17 @@ module eth_ipv4_chdr_dispatch #(    logic [47:0] e_my_mac;    logic [31:0] e_my_ip;    logic [15:0] e_my_udp_chdr_port; +  logic [15:0] e_pause_set; +  logic [15:0] e_pause_clear;    // crossing clock boundaries.    // my_mac, my_ip,,my_udp_chdr_port must be written    // prior to traffic, or an inconsistent version will    // exist for a clock period or 2.  This would be better    // done with a full handshake. -  synchronizer #(.WIDTH(96),.STAGES(1)) +  synchronizer #(.WIDTH(96+32),.STAGES(1))      e_info_sync (.clk(eth_rx.clk),.rst(eth_rx.rst), -                 .in({my_mac,my_ip,my_udp_chdr_port}), -                 .out({e_my_mac,e_my_ip,e_my_udp_chdr_port})); +                 .in({my_mac,my_ip,my_udp_chdr_port,my_pause_set,my_pause_clear}), +                 .out({e_my_mac,e_my_ip,e_my_udp_chdr_port,e_pause_set,e_pause_clear}));    localparam ENET_USER_W = $clog2(ENET_W/8)+1; @@ -515,11 +524,72 @@ module eth_ipv4_chdr_dispatch #(    // transferring a packet. To ensure that upstream logic is not    // blocked, we instantiate at laeast one packet of buffering here.    // The actual size is set by CHDR_FIFO_SIZE. +  logic [15:0] chdr_occupied; +  logic [15:0] chdr_occupied_q; +  localparam CHDR_FIFO_WORD_SIZE = CHDR_FIFO_SIZE-$clog2(ENET_W/8);    axi4s_fifo #( -    .SIZE(CHDR_FIFO_SIZE-$clog2(ENET_W/8)) +    .SIZE(CHDR_FIFO_WORD_SIZE)    ) chdr_fifo_i ( -    .clear(1'b0),.space(),.occupied(), +    .clear(1'b0),.space(),.occupied(chdr_occupied),      .i(chdr1),.o(e2v)    ); +  // documentation requires pause requests to be set for a minimum of 16 clocks. +  // I'm providing the same gauranteed min time in the set and clear direction +  logic [3:0] pause_timer; +  typedef enum logic [1:0] { +      ST_IDLE           = 2'd0, +      ST_MIN_DELAY_SET  = 2'd1, +      ST_REQUESTING     = 2'd2, +      ST_MIN_DELAY_CLR  = 2'd3 +    } pause_state_t; +  pause_state_t pause_state = ST_IDLE; + +  always_ff @(posedge eth_rx.clk) begin : pause_req_ff +    if (eth_rx.rst) begin +      chdr_occupied_q <= 0; +      eth_pause_req   <= 1'b0; +      pause_state     <= ST_IDLE; +      pause_timer     <= 0; +    end else begin +      chdr_occupied_q <= chdr_occupied; + +      case (pause_state) + +        ST_IDLE: begin +          pause_timer <= 0; +          if (chdr_occupied_q >= e_pause_set) begin +            eth_pause_req   <= 1'b1; +            pause_state     <= ST_MIN_DELAY_SET; +            pause_timer     <= pause_timer-1; // Wrap counter to max value +          end +        end + +        ST_MIN_DELAY_SET: begin +          pause_timer     <= pause_timer-1; +          if (pause_timer == 1) begin +            pause_state     <= ST_REQUESTING; +          end +        end + +        ST_REQUESTING: begin +          pause_timer     <= 0; +          if (chdr_occupied_q <= e_pause_clear) begin +            eth_pause_req   <= 1'b0; +            pause_state     <= ST_MIN_DELAY_CLR; +            pause_timer     <= pause_timer-1; // Wrap counter to max value +          end +        end + +        ST_MIN_DELAY_CLR: begin +          pause_timer     <= pause_timer-1; +          if (pause_timer == 1) begin +            pause_state     <= ST_IDLE; +          end +        end +      endcase +    end +  end + +  endmodule // eth_ipv4_chdr_dispatch diff --git a/fpga/usrp3/lib/rfnoc/xport_sv/eth_ipv4_interface.sv b/fpga/usrp3/lib/rfnoc/xport_sv/eth_ipv4_interface.sv index 80670e029..fe6fff8c8 100644 --- a/fpga/usrp3/lib/rfnoc/xport_sv/eth_ipv4_interface.sv +++ b/fpga/usrp3/lib/rfnoc/xport_sv/eth_ipv4_interface.sv @@ -38,6 +38,7 @@ module eth_ipv4_interface #(    int          PREAMBLE_BYTES   = 6,    bit          ADD_SOF          = 1,    bit          SYNC             = 0, +  bit          PAUSE_EN         = 0,    int          ENET_W           = 64,    int          CPU_W            = 64,    int          CHDR_W           = 64 @@ -63,6 +64,7 @@ module eth_ipv4_interface #(    output logic [15:0] my_udp_chdr_port,    // Ethernet MAC +  output logic       eth_pause_req,    AxiStreamIf.master eth_tx, // tUser = {1'b0,trailing bytes};    AxiStreamIf.slave  eth_rx, // tUser = {error,trailing bytes};    // CHDR router interface @@ -77,6 +79,8 @@ module eth_ipv4_interface #(    localparam [47:0] DEFAULT_MAC_ADDR  = {8'h00, 8'h80, 8'h2f, 8'h16, 8'hc5, 8'h2f};    localparam [31:0] DEFAULT_IP_ADDR   = {8'd192, 8'd168, 8'd10, 8'd2};    localparam [31:0] DEFAULT_UDP_PORT  = 16'd49153; +  localparam [15:0] DEFAULT_PAUSE_SET   = 16'd00040; +  localparam [15:0] DEFAULT_PAUSE_CLEAR = 16'd00020;    //---------------------------------------------------------    // Registers @@ -102,6 +106,8 @@ module eth_ipv4_interface #(    logic        chdr_dropped;    logic [31:0] chdr_drop_count = 0;    logic [31:0] cpu_drop_count  = 0; +  logic [15:0] my_pause_set    = DEFAULT_PAUSE_SET; +  logic [15:0] my_pause_clear  = DEFAULT_PAUSE_CLEAR;    always_comb begin : bridge_mux      my_mac            = bridge_en ? bridge_mac_reg : mac_reg; @@ -118,6 +124,8 @@ module eth_ipv4_interface #(        bridge_mac_reg  <= DEFAULT_MAC_ADDR;        bridge_ip_reg   <= DEFAULT_IP_ADDR;        bridge_udp_port <= DEFAULT_UDP_PORT; +      my_pause_set    <= DEFAULT_PAUSE_SET; +      my_pause_clear  <= DEFAULT_PAUSE_CLEAR;      end      else begin        if (reg_wr_req) @@ -149,6 +157,14 @@ module eth_ipv4_interface #(          REG_BRIDGE_ENABLE:            bridge_en             <= reg_wr_data[0]; + +        REG_PAUSE: +          begin +            if (PAUSE_EN) begin +              my_pause_set        <= reg_wr_data[15:0]; +              my_pause_clear      <= reg_wr_data[31:16]; +            end +          end          endcase      end    end @@ -210,6 +226,14 @@ module eth_ipv4_interface #(                reg_rd_data <= cpu_drop_count;                cpu_drop_count <= 0; // clear when read              end + +          REG_PAUSE: +            begin +              if (PAUSE_EN) begin +                reg_rd_data[15:0]  <= my_pause_set; +                reg_rd_data[31:16] <= my_pause_clear; +              end +            end           default:              reg_rd_resp <= 1'b0;           endcase @@ -256,6 +280,7 @@ module eth_ipv4_interface #(      .CPU_W           (CPU_W),      .CHDR_W          (CHDR_W)    ) eth_adapter_i ( +    .eth_pause_req   (eth_pause_req),      .eth_rx          (eth_rx   ),      .eth_tx          (eth_tx   ),      .v2e             (v2e      ), @@ -266,6 +291,8 @@ module eth_ipv4_interface #(      .my_mac          (my_mac   ),      .my_ip           (my_ip    ),      .my_udp_chdr_port(my_udp_chdr_port), +    .my_pause_set    (my_pause_set), +    .my_pause_clear  (my_pause_clear),      .chdr_dropped    (e_chdr_dropped),      .cpu_dropped     (e_cpu_dropped)    ); diff --git a/fpga/usrp3/lib/rfnoc/xport_sv/eth_ipv4_internal.sv b/fpga/usrp3/lib/rfnoc/xport_sv/eth_ipv4_internal.sv index c0af2a84d..d4bc9d355 100644 --- a/fpga/usrp3/lib/rfnoc/xport_sv/eth_ipv4_internal.sv +++ b/fpga/usrp3/lib/rfnoc/xport_sv/eth_ipv4_internal.sv @@ -365,6 +365,7 @@ module eth_ipv4_internal #(      .reg_rd_addr      (reg_rd_addr),      .reg_rd_resp      (reg_rd_resp_eth_if),      .reg_rd_data      (reg_rd_data_eth_if), +    .eth_pause_req    (),      .eth_tx           (e2h_chdr),      .eth_rx           (h2e_chdr),      .e2v              (e2v_chdr), diff --git a/fpga/usrp3/lib/rfnoc/xport_sv/eth_regs.vh b/fpga/usrp3/lib/rfnoc/xport_sv/eth_regs.vh index 1deb35aee..96e9ce53f 100644 --- a/fpga/usrp3/lib/rfnoc/xport_sv/eth_regs.vh +++ b/fpga/usrp3/lib/rfnoc/xport_sv/eth_regs.vh @@ -30,3 +30,4 @@ localparam [REG_AWIDTH-1:0] REG_BRIDGE_ENABLE  = BASE + 'h1020;  localparam [REG_AWIDTH-1:0] REG_CHDR_DROPPED   = BASE + 'h1030;  localparam [REG_AWIDTH-1:0] REG_CPU_DROPPED    = BASE + 'h1034; +localparam [REG_AWIDTH-1:0] REG_PAUSE          = BASE + 'h1038; | 
