axi_dmac: Limit number of bursts on the source side

Currently the source side of the DMAC can issue requests for up to
2*FIFO_SIZE-1 bursts even though there is only room for FIFO_SIZE bursts in
the store and forward memory.

This can problematic for memory mapped buses. If the data is not read fast
enough from the DMAC back-pressure will propagate through the whole system
memory subsystem and can cause significant performance penalty or even a
deadlock halting the whole system.

To avoid this make sure that not more that than what fits into the
store-and-forward memory is requested by throttling the request ID based
on how much room is available in the memory.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
main
Lars-Peter Clausen 2018-05-29 11:40:32 +02:00 committed by Lars-Peter Clausen
parent d80175d895
commit 7d643e216a
2 changed files with 44 additions and 3 deletions

View File

@ -48,6 +48,8 @@ module axi_dmac_burst_memory #(
input [DATA_WIDTH_SRC-1:0] src_data,
input src_data_last,
output [ID_WIDTH-1:0] src_data_request_id,
input dest_clk,
input dest_reset,
@ -159,6 +161,8 @@ assign src_beat = src_mem_data_valid & src_mem_data_ready;
assign src_last_beat = src_beat & src_mem_data_last;
assign src_waddr = {src_id_reduced,src_beat_counter};
assign src_data_request_id = src_dest_id;
always @(*) begin
if (src_last_beat == 1'b1) begin
src_id_next <= inc_id(src_id);

View File

@ -251,6 +251,8 @@ wire [1:0] src_response_resp;
*/
wire [ID_WIDTH-1:0] src_request_id;
reg [ID_WIDTH-1:0] src_throttled_request_id;
wire [ID_WIDTH-1:0] src_data_request_id;
wire [ID_WIDTH-1:0] src_response_id;
wire src_valid;
@ -542,7 +544,7 @@ dmac_src_mm_axi #(
.response_resp(src_response_resp),
*/
.request_id(src_request_id),
.request_id(src_throttled_request_id),
.response_id(src_response_id),
.address_id(src_address_id),
.data_id(src_data_id),
@ -615,7 +617,7 @@ dmac_src_axi_stream #(
.req_sync_transfer_start(src_req_sync_transfer_start),
.req_xlast(src_req_xlast),
.request_id(src_request_id),
.request_id(src_throttled_request_id),
.response_id(src_response_id),
.eot(src_eot),
@ -671,7 +673,7 @@ dmac_src_fifo_inf #(
.req_last_burst_length(src_req_last_burst_length),
.req_sync_transfer_start(src_req_sync_transfer_start),
.request_id(src_request_id),
.request_id(src_throttled_request_id),
.response_id(src_response_id),
.eot(src_eot),
@ -705,6 +707,39 @@ sync_bits #(
.out(src_request_id)
);
`include "inc_id.h"
function compare_id;
input [ID_WIDTH-1:0] a;
input [ID_WIDTH-1:0] b;
begin
compare_id = a[ID_WIDTH-1] == b[ID_WIDTH-1];
if (ID_WIDTH >= 2) begin
if (a[ID_WIDTH-2] == b[ID_WIDTH-2]) begin
compare_id = 1'b1;
end
end
if (ID_WIDTH >= 3) begin
if (a[ID_WIDTH-3:0] != b[ID_WIDTH-3:0]) begin
compare_id = 1'b1;
end
end
end
endfunction
/*
* Make sure that we do not request more data than what fits into the
* store-and-forward burst memory.
*/
always @(posedge src_clk) begin
if (src_resetn == 1'b0) begin
src_throttled_request_id <= 'h00;
end else if (src_throttled_request_id != src_request_id &&
compare_id(src_throttled_request_id, src_data_request_id)) begin
src_throttled_request_id <= inc_id(src_throttled_request_id);
end
end
sync_bits #(
.NUM_OF_BITS(ID_WIDTH),
.ASYNC_CLK(ASYNC_CLK_DEST_REQ)
@ -744,6 +779,8 @@ axi_dmac_burst_memory #(
.src_data(src_fifo_data),
.src_data_last(src_fifo_last),
.src_data_request_id(src_data_request_id),
.dest_clk(dest_clk),
.dest_reset(~dest_resetn),
.dest_data_valid(dest_fifo_valid),