Commit 8b26cf7f authored by Adrian Byszuk (CTI)'s avatar Adrian Byszuk (CTI)

PCIe: fix handling short TLP writes to DDR memory

In case of excessive TLP burst (caused by e.g. memcpy()),
insufficient FIFO handling would overflow elastic buffer by writing corrupted data.
parent ed906b1e
......@@ -215,6 +215,8 @@ architecture Behavioral of RxIn_Delay is
--old interface helper signals
signal in_packet_reg : std_logic;
signal trn_rsof_n : std_logic;
signal mwr_ready_r, cpld_ready_r : std_logic;
begin
......@@ -536,6 +538,8 @@ begin
m_axis_rx_tvalid_r1 <= m_axis_rx_tvalid;
m_axis_rx_tready_r1 <= m_axis_rx_tready_i;
m_axis_rx_tbar_hit_r1 <= m_axis_rx_tbar_hit;
mwr_ready_r <= mwr_ready;
cpld_ready_r <= cpld_ready;
end if;
end process;
......@@ -778,7 +782,8 @@ begin
end if;
when TK_Body =>
m_axis_rx_tready_i <= ((TLP_is_MWr_H4DW or TLP_is_MWr_H3DW) and mwr_ready) or (TLP_is_CplD and cpld_ready);
m_axis_rx_tready_i <= ((TLP_is_MWr_H4DW or TLP_is_MWr_H3DW) and mwr_ready and mwr_ready_r)
or (TLP_is_CplD and cpld_ready and cpld_ready_r);
--for TLP body we can't wait for rising edge because there is a chance that TLP EOF
--will hit when *_tready_i = 0 which will cause deadlock
if m_axis_rx_tlast = '1' and m_axis_rx_tvalid = '1' and m_axis_rx_tready_i = '1' then
......
......@@ -27,6 +27,7 @@ library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_ARITH.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
use IEEE.STD_LOGIC_MISC.all;
library work;
use work.abb64Package.all;
......@@ -705,12 +706,16 @@ begin
elbuf_din(C_IS_HDR_BIT) <= '0';
elbuf_din(C_DDR_HIT_BIT) <= '1';
elbuf_din(C_WB_HIT_BIT) <= '0';
--r1 in 4DW hdr case, i or r1 in 3DW hdr case
elbuf_din(C_TLAST_BIT) <= (not(mwr_has_4dw_header) and (m_axis_rx_tlast_i or m_axis_rx_tlast_r1))
or (mwr_has_4dw_header and m_axis_rx_tlast_r1);
elbuf_din(C_TKEEP_BTOP downto C_TKEEP_BBOT) <= endian_invert_tkeep(m_axis_rx_tkeep_fixed) and (tkeep_hmask & x"F");
elbuf_din(C_DBUS_WIDTH-1 downto 0) <= endian_invert_64(m_axis_rx_tdata_fixed);
elbuf_we <= not trn_rx_throttle_r;
if mwr_has_4dw_header = '1' then
elbuf_din(C_TLAST_BIT) <= m_axis_rx_tlast_r1;
elbuf_we <= not trn_rx_throttle_r;
else
elbuf_din(C_TLAST_BIT) <= (or_reduce(tkeep_hmask) and m_axis_rx_tlast_i) or m_axis_rx_tlast_r1;
elbuf_we <= (or_reduce(tkeep_hmask) and not(trn_rx_throttle))
or (not(trn_rx_throttle_r) and or_reduce(m_axis_rx_tkeep_fixed(3 downto 0)) and m_axis_rx_tlast_r1);
end if;
end if;
end case;
......@@ -800,6 +805,7 @@ begin
ddr_write:
process(user_clk)
variable first_data : std_logic;
begin
if rising_edge(user_clk) then
if user_reset = '1' then
......@@ -834,6 +840,7 @@ begin
elsif elbuf_dout(C_IS_HDR_BIT) = '1' and elbuf_dout(C_DDR_HIT_BIT) = '1' and ddr_s2mm_cmd_tready = '1' then
ddr_wr_state <= st_data;
elbuf_re_st <= '1';
first_data := '1';
end if;
when st_data =>
......@@ -846,9 +853,11 @@ begin
if (elbuf_empty = '0' and elbuf_re = '1') or elbuf_dout(C_TLAST_BIT) = '1' then
--if it's the last word in a packet fifo will be already empty, so push last word unconditionally
ddr_s2mm_tdata <= elbuf_dout(C_DBUS_WIDTH-1 downto 0);
ddr_s2mm_tvalid_i <= not(ddr_s2mm_cmd_tvalid_i); --omit 1st word after command
ddr_s2mm_tvalid_i <= not(ddr_s2mm_cmd_tvalid_i) and elbuf_re_r; --omit 1st word after command and align delay
first_data := '0';
else
ddr_s2mm_tvalid_i <= not(ddr_s2mm_tready); --keep valid to push word currently present on *_tdata
--keep valid to push word currently present on *_tdata, unless it's first word
ddr_s2mm_tvalid_i <= not(ddr_s2mm_tready) and not(first_data);
end if;
if ddr_s2mm_tready = '1' and ddr_s2mm_tvalid_i = '1' and ddr_s2mm_tlast_i = '1' then
ddr_wr_state <= st_idle;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment