Commit e88934c2 authored by Maciej Lipinski's avatar Maciej Lipinski

TRU: adding quick block BPDU handling (blocks a port on reception of special…

TRU: adding quick block BPDU handling (blocks a port on reception of special frame) and cleaning a bit with hardare generation/reception of frames
parent b8b5c673
...@@ -88,9 +88,11 @@ architecture rtl of tru_port is ...@@ -88,9 +88,11 @@ architecture rtl of tru_port is
signal s_zeros : std_logic_vector(g_num_ports - 1 downto 0); signal s_zeros : std_logic_vector(g_num_ports - 1 downto 0);
signal s_patternRep : std_logic_vector(g_pattern_width-1 downto 0); signal s_patternRep : std_logic_vector(g_pattern_width-1 downto 0);
signal s_patternAdd : std_logic_vector(g_pattern_width-1 downto 0); signal s_patternAdd : std_logic_vector(g_pattern_width-1 downto 0);
signal s_patternSub : std_logic_vector(g_pattern_width-1 downto 0);
signal s_patternRep_d0 : std_logic_vector(g_pattern_width-1 downto 0); signal s_patternRep_d0 : std_logic_vector(g_pattern_width-1 downto 0);
signal s_patternAdd_d0 : std_logic_vector(g_pattern_width-1 downto 0); signal s_patternAdd_d0 : std_logic_vector(g_pattern_width-1 downto 0);
signal s_patternSub_d0 : std_logic_vector(g_pattern_width-1 downto 0);
signal s_resp_masks : t_resp_masks; signal s_resp_masks : t_resp_masks;
signal s_self_mask : std_logic_vector(g_num_ports - 1 downto 0); signal s_self_mask : std_logic_vector(g_num_ports - 1 downto 0);
signal s_port_mask : std_logic_vector(g_num_ports - 1 downto 0); signal s_port_mask : std_logic_vector(g_num_ports - 1 downto 0);
...@@ -147,7 +149,26 @@ begin --rtl ...@@ -147,7 +149,26 @@ begin --rtl
config_i => config_i, config_i => config_i,
pattern_o => s_patternAdd pattern_o => s_patternAdd
); );
-- generating pattern to be used in substraction matches
SUB_PATTERN: tru_sub_vlan_pattern
generic map(
g_num_ports => g_num_ports,
g_patternID_width => g_patternID_width,
g_pattern_width => g_pattern_width
)
port map(
clk_i => clk_i,
rst_n_i => rst_n_i,
portID_i => s_portID_vec,
patternID_i => config_i.mcr_pattern_mode_sub,
tru_req_i => tru_req_i,
endpoints_i => endpoints_i,
config_i => config_i,
pattern_o => s_patternSub
);
-- tracking changes of port configuration due to i.e. link down events (change of port status) -- tracking changes of port configuration due to i.e. link down events (change of port status)
-- and reacting appropriately (e.g.: sending HW-generated frames) -- and reacting appropriately (e.g.: sending HW-generated frames)
RT_RECONFIG: tru_reconfig_rt_port_handler RT_RECONFIG: tru_reconfig_rt_port_handler
...@@ -176,6 +197,7 @@ begin --rtl ...@@ -176,6 +197,7 @@ begin --rtl
s_self_mask <= (others =>'0'); s_self_mask <= (others =>'0');
s_patternRep_d0 <= (others =>'0'); s_patternRep_d0 <= (others =>'0');
s_patternAdd_d0 <= (others =>'0'); s_patternAdd_d0 <= (others =>'0');
s_patternSub_d0 <= (others =>'0');
s_valid_d0 <= '0'; s_valid_d0 <= '0';
s_valid_d1 <= '0'; s_valid_d1 <= '0';
s_reqMask_d0 <= (others =>'0'); s_reqMask_d0 <= (others =>'0');
...@@ -187,6 +209,7 @@ begin --rtl ...@@ -187,6 +209,7 @@ begin --rtl
-- First stage (remembering/registering input signals) -- First stage (remembering/registering input signals)
s_patternRep_d0 <= s_patternRep; s_patternRep_d0 <= s_patternRep;
s_patternAdd_d0 <= s_patternAdd; s_patternAdd_d0 <= s_patternAdd;
s_patternSub_d0 <= s_patternSub;
s_self_mask <= tru_req_i.reqMask(g_num_ports-1 downto 0); s_self_mask <= tru_req_i.reqMask(g_num_ports-1 downto 0);
s_valid_d0 <= tru_req_i.valid; s_valid_d0 <= tru_req_i.valid;
s_reqMask_d0 <= tru_req_i.reqMask(g_num_ports-1 downto 0); s_reqMask_d0 <= tru_req_i.reqMask(g_num_ports-1 downto 0);
...@@ -232,6 +255,7 @@ begin --rtl ...@@ -232,6 +255,7 @@ begin --rtl
s_resp_masks <= f_gen_mask_with_patterns(tru_tab_entry_i, s_resp_masks <= f_gen_mask_with_patterns(tru_tab_entry_i,
s_patternRep_d0, s_patternRep_d0,
s_patternAdd_d0, s_patternAdd_d0,
s_patternSub_d0,
g_tru_subentry_num); g_tru_subentry_num);
-- just to make the code a bit less messy -- just to make the code a bit less messy
s_ingress_mask <= s_resp_masks.ingress(g_num_ports-1 downto 0); s_ingress_mask <= s_resp_masks.ingress(g_num_ports-1 downto 0);
......
...@@ -93,8 +93,9 @@ architecture rtl of tru_sub_vlan_pattern is ...@@ -93,8 +93,9 @@ architecture rtl of tru_sub_vlan_pattern is
constant c_p_default : std_logic_vector(g_patternID_width-1 downto 0) :=x"0"; -- default constant c_p_default : std_logic_vector(g_patternID_width-1 downto 0) :=x"0"; -- default
constant c_p_port_down : std_logic_vector(g_patternID_width-1 downto 0) :=x"1"; -- port down constant c_p_port_down : std_logic_vector(g_patternID_width-1 downto 0) :=x"1"; -- port down
constant c_p_quick_fwd : std_logic_vector(g_patternID_width-1 downto 0) :=x"2"; -- quick forward received frames constant c_p_quick_fwd : std_logic_vector(g_patternID_width-1 downto 0) :=x"2"; -- quick forward received frames
constant c_p_aggr_gr_id : std_logic_vector(g_patternID_width-1 downto 0) :=x"3"; -- aggregation group id constant c_p_quick_blk : std_logic_vector(g_patternID_width-1 downto 0) :=x"3"; -- quick block received frames
constant c_p_rx_port : std_logic_vector(g_patternID_width-1 downto 0) :=x"4"; -- received port constant c_p_aggr_gr_id : std_logic_vector(g_patternID_width-1 downto 0) :=x"4"; -- aggregation group id
constant c_p_rx_port : std_logic_vector(g_patternID_width-1 downto 0) :=x"5"; -- received port
signal rxFrameNumber : integer range 0 to endpoints_i.rxFrameMaskReg'length-1; signal rxFrameNumber : integer range 0 to endpoints_i.rxFrameMaskReg'length-1;
...@@ -111,8 +112,9 @@ begin --rtl ...@@ -111,8 +112,9 @@ begin --rtl
(others=>'0') when (patternID_i = c_p_default) else -- 0: defaut (others=>'0') when (patternID_i = c_p_default) else -- 0: defaut
f_pattern_port_down (endpoints_i,g_pattern_width) when (patternID_i = c_p_port_down) else -- 1: eRSTP f_pattern_port_down (endpoints_i,g_pattern_width) when (patternID_i = c_p_port_down) else -- 1: eRSTP
f_pattern_quick_fwd (endpoints_i,config_i,g_pattern_width) when (patternID_i = c_p_quick_fwd) else -- 2: eRSTP: f_pattern_quick_fwd (endpoints_i,config_i,g_pattern_width) when (patternID_i = c_p_quick_fwd) else -- 2: eRSTP:
f_pattern_aggr_gr_id(endpoints_i,tru_req_i, portID_i,config_i,g_pattern_width,g_num_ports) when (patternID_i = c_p_aggr_gr_id) else -- 3: eLACP: f_pattern_quick_blk (endpoints_i,config_i,g_pattern_width) when (patternID_i = c_p_quick_blk) else -- 3: eRSTP:
f_pattern_rx_port (tru_req_i, g_pattern_width) when (patternID_i = c_p_rx_port) else -- 4: eLACP f_pattern_aggr_gr_id(endpoints_i,tru_req_i, portID_i,config_i,g_pattern_width,g_num_ports) when (patternID_i = c_p_aggr_gr_id) else -- 4: eLACP:
f_pattern_rx_port (tru_req_i, g_pattern_width) when (patternID_i = c_p_rx_port) else -- 5: eLACP
(others=>'0'); (others=>'0');
end rtl; end rtl;
...@@ -191,6 +191,9 @@ begin --rtl ...@@ -191,6 +191,9 @@ begin --rtl
s_ep_zero.pauseSend <= '0'; s_ep_zero.pauseSend <= '0';
s_ep_zero.pauseTime <= (others => '0'); s_ep_zero.pauseTime <= (others => '0');
s_ep_zero.outQueueBlockMask <= (others => '0'); s_ep_zero.outQueueBlockMask <= (others => '0');
s_ep_zero.outQueueBlockReq <= '0';
s_ep_zero.hwframe_fwd <= '0';
s_ep_zero.hwframe_blk <= '0';
-- this FSM tries to switch forwarding from port A to port B without loosing frames on a -- this FSM tries to switch forwarding from port A to port B without loosing frames on a
-- defined priority. It waits for marker broadcasted from the topology root. -- defined priority. It waits for marker broadcasted from the topology root.
...@@ -218,14 +221,11 @@ begin --rtl ...@@ -218,14 +221,11 @@ begin --rtl
s_statTransFinished <= '0'; s_statTransFinished <= '0';
tru_tab_bank_o <= '0'; tru_tab_bank_o <= '0';
s_ep_ctr_A.pauseSend <= '0'; s_ep_ctr_A <= s_ep_zero;
s_ep_ctr_A.pauseTime <= (others => '0'); s_ep_ctr_B <= s_ep_zero;
s_ep_ctr_B.pauseSend <= '0'; s_sw_ctrl.blockTime <= (others => '0');
s_ep_ctr_B.pauseTime <= (others => '0'); s_sw_ctrl.blockReq <= '0';
s_sw_ctrl.blockTime <= (others => '0');
s_sw_ctrl.blockReq <= '0';
else else
...@@ -260,7 +260,7 @@ begin --rtl ...@@ -260,7 +260,7 @@ begin --rtl
-- send HW-generated paus -- send HW-generated paus
s_ep_ctr_B.pauseSend <= '1'; s_ep_ctr_B.pauseSend <= '1';
s_ep_ctr_B.pauseTime <= config_i.tcr_trans_pause_time; -- s_ep_ctr_B.pauseTime <= config_i.tcr_trans_pause_time;
-- block output queues (TODO: to be revised) -- block output queues (TODO: to be revised)
s_sw_ctrl.blockReq <= '1'; s_sw_ctrl.blockReq <= '1';
...@@ -277,7 +277,10 @@ begin --rtl ...@@ -277,7 +277,10 @@ begin --rtl
s_tru_trans_state <= S_WAIT_WITH_TRANS; s_tru_trans_state <= S_WAIT_WITH_TRANS;
-- stop pause -- stop pause
s_sw_ctrl.blockReq <= '1'; s_sw_ctrl.blockReq <= '1';
s_sw_ctrl.blockTime <= (others => '0'); s_sw_ctrl.blockTime <= (others => '0');
-- send Quick Forward/Block frames
s_ep_ctr_A.hwframe_blk <= '1';
s_ep_ctr_B.hwframe_fwd <= '1';
-- until marker frame on port A is not detected, count rx frames of a defined priority -- until marker frame on port A is not detected, count rx frames of a defined priority
else else
if(s_port_B_rtu_srobe = '1') then if(s_port_B_rtu_srobe = '1') then
...@@ -288,6 +291,9 @@ begin --rtl ...@@ -288,6 +291,9 @@ begin --rtl
when S_WAIT_WITH_TRANS => -- wait until the same number of frames is rx-ed on both ports when S_WAIT_WITH_TRANS => -- wait until the same number of frames is rx-ed on both ports
--==================================================================================== --====================================================================================
s_sw_ctrl.blockReq <= '0'; s_sw_ctrl.blockReq <= '0';
s_ep_ctr_A.hwframe_blk <= '0';
s_ep_ctr_B.hwframe_fwd <= '0';
-- as soon as the number of frames received on port A equals the number of frames -- as soon as the number of frames received on port A equals the number of frames
-- received on port B, transition -- received on port B, transition
-- "+ 1" => we change before the next packet - the things is that the strobe -- "+ 1" => we change before the next packet - the things is that the strobe
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
--------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------
-- File : tru_wbgen2_pkg.vhd -- File : tru_wbgen2_pkg.vhd
-- Author : auto-generated by wbgen2 from tru_wishbone_slave.wb -- Author : auto-generated by wbgen2 from tru_wishbone_slave.wb
-- Created : Tue Mar 5 10:18:59 2013 -- Created : Wed Mar 13 18:49:56 2013
-- Standard : VHDL'87 -- Standard : VHDL'87
--------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------
-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE tru_wishbone_slave.wb -- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE tru_wishbone_slave.wb
...@@ -51,6 +51,7 @@ package tru_wbgen2_pkg is ...@@ -51,6 +51,7 @@ package tru_wbgen2_pkg is
gcr_rx_frame_reset_o : std_logic_vector(23 downto 0); gcr_rx_frame_reset_o : std_logic_vector(23 downto 0);
mcr_pattern_mode_rep_o : std_logic_vector(3 downto 0); mcr_pattern_mode_rep_o : std_logic_vector(3 downto 0);
mcr_pattern_mode_add_o : std_logic_vector(3 downto 0); mcr_pattern_mode_add_o : std_logic_vector(3 downto 0);
mcr_pattern_mode_sub_o : std_logic_vector(3 downto 0);
lacr_agg_df_hp_id_o : std_logic_vector(3 downto 0); lacr_agg_df_hp_id_o : std_logic_vector(3 downto 0);
lacr_agg_df_br_id_o : std_logic_vector(3 downto 0); lacr_agg_df_br_id_o : std_logic_vector(3 downto 0);
lacr_agg_df_un_id_o : std_logic_vector(3 downto 0); lacr_agg_df_un_id_o : std_logic_vector(3 downto 0);
...@@ -71,6 +72,12 @@ package tru_wbgen2_pkg is ...@@ -71,6 +72,12 @@ package tru_wbgen2_pkg is
rtrcr_rtr_mode_o : std_logic_vector(3 downto 0); rtrcr_rtr_mode_o : std_logic_vector(3 downto 0);
rtrcr_rtr_rx_o : std_logic_vector(3 downto 0); rtrcr_rtr_rx_o : std_logic_vector(3 downto 0);
rtrcr_rtr_tx_o : std_logic_vector(3 downto 0); rtrcr_rtr_tx_o : std_logic_vector(3 downto 0);
hwfc_rx_fwd_id_o : std_logic_vector(3 downto 0);
hwfc_rx_blk_id_o : std_logic_vector(3 downto 0);
hwfc_tx_fwd_id_o : std_logic_vector(3 downto 0);
hwfc_tx_blk_id_o : std_logic_vector(3 downto 0);
hwfc_tx_fwd_ub_o : std_logic_vector(7 downto 0);
hwfc_tx_blk_ub_o : std_logic_vector(7 downto 0);
ttr0_fid_o : std_logic_vector(7 downto 0); ttr0_fid_o : std_logic_vector(7 downto 0);
ttr0_sub_fid_o : std_logic_vector(7 downto 0); ttr0_sub_fid_o : std_logic_vector(7 downto 0);
ttr0_update_o : std_logic; ttr0_update_o : std_logic;
...@@ -94,6 +101,7 @@ package tru_wbgen2_pkg is ...@@ -94,6 +101,7 @@ package tru_wbgen2_pkg is
gcr_rx_frame_reset_o => (others => '0'), gcr_rx_frame_reset_o => (others => '0'),
mcr_pattern_mode_rep_o => (others => '0'), mcr_pattern_mode_rep_o => (others => '0'),
mcr_pattern_mode_add_o => (others => '0'), mcr_pattern_mode_add_o => (others => '0'),
mcr_pattern_mode_sub_o => (others => '0'),
lacr_agg_df_hp_id_o => (others => '0'), lacr_agg_df_hp_id_o => (others => '0'),
lacr_agg_df_br_id_o => (others => '0'), lacr_agg_df_br_id_o => (others => '0'),
lacr_agg_df_un_id_o => (others => '0'), lacr_agg_df_un_id_o => (others => '0'),
...@@ -114,6 +122,12 @@ package tru_wbgen2_pkg is ...@@ -114,6 +122,12 @@ package tru_wbgen2_pkg is
rtrcr_rtr_mode_o => (others => '0'), rtrcr_rtr_mode_o => (others => '0'),
rtrcr_rtr_rx_o => (others => '0'), rtrcr_rtr_rx_o => (others => '0'),
rtrcr_rtr_tx_o => (others => '0'), rtrcr_rtr_tx_o => (others => '0'),
hwfc_rx_fwd_id_o => (others => '0'),
hwfc_rx_blk_id_o => (others => '0'),
hwfc_tx_fwd_id_o => (others => '0'),
hwfc_tx_blk_id_o => (others => '0'),
hwfc_tx_fwd_ub_o => (others => '0'),
hwfc_tx_blk_ub_o => (others => '0'),
ttr0_fid_o => (others => '0'), ttr0_fid_o => (others => '0'),
ttr0_sub_fid_o => (others => '0'), ttr0_sub_fid_o => (others => '0'),
ttr0_update_o => '0', ttr0_update_o => '0',
......
This diff is collapsed.
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
--------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------
-- File : tru_wishbone_slave.vhd -- File : tru_wishbone_slave.vhd
-- Author : auto-generated by wbgen2 from tru_wishbone_slave.wb -- Author : auto-generated by wbgen2 from tru_wishbone_slave.wb
-- Created : Tue Mar 5 10:18:59 2013 -- Created : Wed Mar 13 18:49:56 2013
-- Standard : VHDL'87 -- Standard : VHDL'87
--------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------
-- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE tru_wishbone_slave.wb -- THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE tru_wishbone_slave.wb
...@@ -42,6 +42,7 @@ signal tru_gcr_tru_bank_int : std_logic ; ...@@ -42,6 +42,7 @@ signal tru_gcr_tru_bank_int : std_logic ;
signal tru_gcr_rx_frame_reset_int : std_logic_vector(23 downto 0); signal tru_gcr_rx_frame_reset_int : std_logic_vector(23 downto 0);
signal tru_mcr_pattern_mode_rep_int : std_logic_vector(3 downto 0); signal tru_mcr_pattern_mode_rep_int : std_logic_vector(3 downto 0);
signal tru_mcr_pattern_mode_add_int : std_logic_vector(3 downto 0); signal tru_mcr_pattern_mode_add_int : std_logic_vector(3 downto 0);
signal tru_mcr_pattern_mode_sub_int : std_logic_vector(3 downto 0);
signal tru_lacr_agg_df_hp_id_int : std_logic_vector(3 downto 0); signal tru_lacr_agg_df_hp_id_int : std_logic_vector(3 downto 0);
signal tru_lacr_agg_df_br_id_int : std_logic_vector(3 downto 0); signal tru_lacr_agg_df_br_id_int : std_logic_vector(3 downto 0);
signal tru_lacr_agg_df_un_id_int : std_logic_vector(3 downto 0); signal tru_lacr_agg_df_un_id_int : std_logic_vector(3 downto 0);
...@@ -62,6 +63,12 @@ signal tru_rtrcr_rtr_reset_int : std_logic ; ...@@ -62,6 +63,12 @@ signal tru_rtrcr_rtr_reset_int : std_logic ;
signal tru_rtrcr_rtr_mode_int : std_logic_vector(3 downto 0); signal tru_rtrcr_rtr_mode_int : std_logic_vector(3 downto 0);
signal tru_rtrcr_rtr_rx_int : std_logic_vector(3 downto 0); signal tru_rtrcr_rtr_rx_int : std_logic_vector(3 downto 0);
signal tru_rtrcr_rtr_tx_int : std_logic_vector(3 downto 0); signal tru_rtrcr_rtr_tx_int : std_logic_vector(3 downto 0);
signal tru_hwfc_rx_fwd_id_int : std_logic_vector(3 downto 0);
signal tru_hwfc_rx_blk_id_int : std_logic_vector(3 downto 0);
signal tru_hwfc_tx_fwd_id_int : std_logic_vector(3 downto 0);
signal tru_hwfc_tx_blk_id_int : std_logic_vector(3 downto 0);
signal tru_hwfc_tx_fwd_ub_int : std_logic_vector(7 downto 0);
signal tru_hwfc_tx_blk_ub_int : std_logic_vector(7 downto 0);
signal tru_ttr0_fid_int : std_logic_vector(7 downto 0); signal tru_ttr0_fid_int : std_logic_vector(7 downto 0);
signal tru_ttr0_sub_fid_int : std_logic_vector(7 downto 0); signal tru_ttr0_sub_fid_int : std_logic_vector(7 downto 0);
signal tru_ttr0_update_dly0 : std_logic ; signal tru_ttr0_update_dly0 : std_logic ;
...@@ -114,6 +121,7 @@ begin ...@@ -114,6 +121,7 @@ begin
tru_gcr_rx_frame_reset_int <= "000000000000000000000000"; tru_gcr_rx_frame_reset_int <= "000000000000000000000000";
tru_mcr_pattern_mode_rep_int <= "0000"; tru_mcr_pattern_mode_rep_int <= "0000";
tru_mcr_pattern_mode_add_int <= "0000"; tru_mcr_pattern_mode_add_int <= "0000";
tru_mcr_pattern_mode_sub_int <= "0000";
tru_lacr_agg_df_hp_id_int <= "0000"; tru_lacr_agg_df_hp_id_int <= "0000";
tru_lacr_agg_df_br_id_int <= "0000"; tru_lacr_agg_df_br_id_int <= "0000";
tru_lacr_agg_df_un_id_int <= "0000"; tru_lacr_agg_df_un_id_int <= "0000";
...@@ -134,6 +142,12 @@ begin ...@@ -134,6 +142,12 @@ begin
tru_rtrcr_rtr_mode_int <= "0000"; tru_rtrcr_rtr_mode_int <= "0000";
tru_rtrcr_rtr_rx_int <= "0000"; tru_rtrcr_rtr_rx_int <= "0000";
tru_rtrcr_rtr_tx_int <= "0000"; tru_rtrcr_rtr_tx_int <= "0000";
tru_hwfc_rx_fwd_id_int <= "0000";
tru_hwfc_rx_blk_id_int <= "0000";
tru_hwfc_tx_fwd_id_int <= "0000";
tru_hwfc_tx_blk_id_int <= "0000";
tru_hwfc_tx_fwd_ub_int <= "00000000";
tru_hwfc_tx_blk_ub_int <= "00000000";
tru_ttr0_fid_int <= "00000000"; tru_ttr0_fid_int <= "00000000";
tru_ttr0_sub_fid_int <= "00000000"; tru_ttr0_sub_fid_int <= "00000000";
tru_ttr0_update_int <= '0'; tru_ttr0_update_int <= '0';
...@@ -212,9 +226,11 @@ begin ...@@ -212,9 +226,11 @@ begin
if (wb_we_i = '1') then if (wb_we_i = '1') then
tru_mcr_pattern_mode_rep_int <= wrdata_reg(3 downto 0); tru_mcr_pattern_mode_rep_int <= wrdata_reg(3 downto 0);
tru_mcr_pattern_mode_add_int <= wrdata_reg(11 downto 8); tru_mcr_pattern_mode_add_int <= wrdata_reg(11 downto 8);
tru_mcr_pattern_mode_sub_int <= wrdata_reg(19 downto 16);
else else
rddata_reg(3 downto 0) <= tru_mcr_pattern_mode_rep_int; rddata_reg(3 downto 0) <= tru_mcr_pattern_mode_rep_int;
rddata_reg(11 downto 8) <= tru_mcr_pattern_mode_add_int; rddata_reg(11 downto 8) <= tru_mcr_pattern_mode_add_int;
rddata_reg(19 downto 16) <= tru_mcr_pattern_mode_sub_int;
rddata_reg(4) <= 'X'; rddata_reg(4) <= 'X';
rddata_reg(5) <= 'X'; rddata_reg(5) <= 'X';
rddata_reg(6) <= 'X'; rddata_reg(6) <= 'X';
...@@ -223,10 +239,6 @@ begin ...@@ -223,10 +239,6 @@ begin
rddata_reg(13) <= 'X'; rddata_reg(13) <= 'X';
rddata_reg(14) <= 'X'; rddata_reg(14) <= 'X';
rddata_reg(15) <= 'X'; rddata_reg(15) <= 'X';
rddata_reg(16) <= 'X';
rddata_reg(17) <= 'X';
rddata_reg(18) <= 'X';
rddata_reg(19) <= 'X';
rddata_reg(20) <= 'X'; rddata_reg(20) <= 'X';
rddata_reg(21) <= 'X'; rddata_reg(21) <= 'X';
rddata_reg(22) <= 'X'; rddata_reg(22) <= 'X';
...@@ -436,6 +448,24 @@ begin ...@@ -436,6 +448,24 @@ begin
ack_sreg(0) <= '1'; ack_sreg(0) <= '1';
ack_in_progress <= '1'; ack_in_progress <= '1';
when "01010" => when "01010" =>
if (wb_we_i = '1') then
tru_hwfc_rx_fwd_id_int <= wrdata_reg(3 downto 0);
tru_hwfc_rx_blk_id_int <= wrdata_reg(7 downto 4);
tru_hwfc_tx_fwd_id_int <= wrdata_reg(11 downto 8);
tru_hwfc_tx_blk_id_int <= wrdata_reg(15 downto 12);
tru_hwfc_tx_fwd_ub_int <= wrdata_reg(23 downto 16);
tru_hwfc_tx_blk_ub_int <= wrdata_reg(31 downto 24);
else
rddata_reg(3 downto 0) <= tru_hwfc_rx_fwd_id_int;
rddata_reg(7 downto 4) <= tru_hwfc_rx_blk_id_int;
rddata_reg(11 downto 8) <= tru_hwfc_tx_fwd_id_int;
rddata_reg(15 downto 12) <= tru_hwfc_tx_blk_id_int;
rddata_reg(23 downto 16) <= tru_hwfc_tx_fwd_ub_int;
rddata_reg(31 downto 24) <= tru_hwfc_tx_blk_ub_int;
end if;
ack_sreg(0) <= '1';
ack_in_progress <= '1';
when "01011" =>
if (wb_we_i = '1') then if (wb_we_i = '1') then
tru_ttr0_fid_int <= wrdata_reg(7 downto 0); tru_ttr0_fid_int <= wrdata_reg(7 downto 0);
tru_ttr0_sub_fid_int <= wrdata_reg(15 downto 8); tru_ttr0_sub_fid_int <= wrdata_reg(15 downto 8);
...@@ -463,7 +493,7 @@ begin ...@@ -463,7 +493,7 @@ begin
end if; end if;
ack_sreg(2) <= '1'; ack_sreg(2) <= '1';
ack_in_progress <= '1'; ack_in_progress <= '1';
when "01011" => when "01100" =>
if (wb_we_i = '1') then if (wb_we_i = '1') then
tru_ttr1_ports_ingress_int <= wrdata_reg(31 downto 0); tru_ttr1_ports_ingress_int <= wrdata_reg(31 downto 0);
else else
...@@ -471,7 +501,7 @@ begin ...@@ -471,7 +501,7 @@ begin
end if; end if;
ack_sreg(0) <= '1'; ack_sreg(0) <= '1';
ack_in_progress <= '1'; ack_in_progress <= '1';
when "01100" => when "01101" =>
if (wb_we_i = '1') then if (wb_we_i = '1') then
tru_ttr2_ports_egress_int <= wrdata_reg(31 downto 0); tru_ttr2_ports_egress_int <= wrdata_reg(31 downto 0);
else else
...@@ -479,7 +509,7 @@ begin ...@@ -479,7 +509,7 @@ begin
end if; end if;
ack_sreg(0) <= '1'; ack_sreg(0) <= '1';
ack_in_progress <= '1'; ack_in_progress <= '1';
when "01101" => when "01110" =>
if (wb_we_i = '1') then if (wb_we_i = '1') then
tru_ttr3_ports_mask_int <= wrdata_reg(31 downto 0); tru_ttr3_ports_mask_int <= wrdata_reg(31 downto 0);
else else
...@@ -487,7 +517,7 @@ begin ...@@ -487,7 +517,7 @@ begin
end if; end if;
ack_sreg(0) <= '1'; ack_sreg(0) <= '1';
ack_in_progress <= '1'; ack_in_progress <= '1';
when "01110" => when "01111" =>
if (wb_we_i = '1') then if (wb_we_i = '1') then
tru_ttr4_patrn_match_int <= wrdata_reg(31 downto 0); tru_ttr4_patrn_match_int <= wrdata_reg(31 downto 0);
else else
...@@ -495,7 +525,7 @@ begin ...@@ -495,7 +525,7 @@ begin
end if; end if;
ack_sreg(0) <= '1'; ack_sreg(0) <= '1';
ack_in_progress <= '1'; ack_in_progress <= '1';
when "01111" => when "10000" =>
if (wb_we_i = '1') then if (wb_we_i = '1') then
tru_ttr5_patrn_mask_int <= wrdata_reg(31 downto 0); tru_ttr5_patrn_mask_int <= wrdata_reg(31 downto 0);
else else
...@@ -503,7 +533,7 @@ begin ...@@ -503,7 +533,7 @@ begin
end if; end if;
ack_sreg(0) <= '1'; ack_sreg(0) <= '1';
ack_in_progress <= '1'; ack_in_progress <= '1';
when "10000" => when "10001" =>
if (wb_we_i = '1') then if (wb_we_i = '1') then
tru_dps_pid_int <= wrdata_reg(7 downto 0); tru_dps_pid_int <= wrdata_reg(7 downto 0);
else else
...@@ -535,7 +565,7 @@ begin ...@@ -535,7 +565,7 @@ begin
end if; end if;
ack_sreg(0) <= '1'; ack_sreg(0) <= '1';
ack_in_progress <= '1'; ack_in_progress <= '1';
when "10001" => when "10010" =>
if (wb_we_i = '1') then if (wb_we_i = '1') then
tru_pidr_inject_int <= wrdata_reg(0); tru_pidr_inject_int <= wrdata_reg(0);
rddata_reg(0) <= 'X'; rddata_reg(0) <= 'X';
...@@ -561,7 +591,7 @@ begin ...@@ -561,7 +591,7 @@ begin
end if; end if;
ack_sreg(2) <= '1'; ack_sreg(2) <= '1';
ack_in_progress <= '1'; ack_in_progress <= '1';
when "10010" => when "10011" =>
if (wb_we_i = '1') then if (wb_we_i = '1') then
tru_pfdr_clr_int <= wrdata_reg(0); tru_pfdr_clr_int <= wrdata_reg(0);
rddata_reg(0) <= 'X'; rddata_reg(0) <= 'X';
...@@ -579,7 +609,7 @@ begin ...@@ -579,7 +609,7 @@ begin
end if; end if;
ack_sreg(2) <= '1'; ack_sreg(2) <= '1';
ack_in_progress <= '1'; ack_in_progress <= '1';
when "10011" => when "10100" =>
if (wb_we_i = '1') then if (wb_we_i = '1') then
else else
rddata_reg(31 downto 0) <= regs_i.ptrdr_ging_mask_i; rddata_reg(31 downto 0) <= regs_i.ptrdr_ging_mask_i;
...@@ -623,6 +653,8 @@ begin ...@@ -623,6 +653,8 @@ begin
regs_o.mcr_pattern_mode_rep_o <= tru_mcr_pattern_mode_rep_int; regs_o.mcr_pattern_mode_rep_o <= tru_mcr_pattern_mode_rep_int;
-- Addition Pattern Mode -- Addition Pattern Mode
regs_o.mcr_pattern_mode_add_o <= tru_mcr_pattern_mode_add_int; regs_o.mcr_pattern_mode_add_o <= tru_mcr_pattern_mode_add_int;
-- Substraction Pattern Mode
regs_o.mcr_pattern_mode_sub_o <= tru_mcr_pattern_mode_sub_int;
-- HP traffic Distribution Function ID -- HP traffic Distribution Function ID
regs_o.lacr_agg_df_hp_id_o <= tru_lacr_agg_df_hp_id_int; regs_o.lacr_agg_df_hp_id_o <= tru_lacr_agg_df_hp_id_int;
-- Broadcast Distribution Function ID -- Broadcast Distribution Function ID
...@@ -665,6 +697,18 @@ begin ...@@ -665,6 +697,18 @@ begin
regs_o.rtrcr_rtr_rx_o <= tru_rtrcr_rtr_rx_int; regs_o.rtrcr_rtr_rx_o <= tru_rtrcr_rtr_rx_int;
-- RTR Tx Frame ID -- RTR Tx Frame ID
regs_o.rtrcr_rtr_tx_o <= tru_rtrcr_rtr_tx_int; regs_o.rtrcr_rtr_tx_o <= tru_rtrcr_rtr_tx_int;
-- HW Frame Rx Forward ID
regs_o.hwfc_rx_fwd_id_o <= tru_hwfc_rx_fwd_id_int;
-- HW Frame Rx Block ID
regs_o.hwfc_rx_blk_id_o <= tru_hwfc_rx_blk_id_int;
-- HW Frame Tx Forward ID
regs_o.hwfc_tx_fwd_id_o <= tru_hwfc_tx_fwd_id_int;
-- HW Frame Tx Block ID
regs_o.hwfc_tx_blk_id_o <= tru_hwfc_tx_blk_id_int;
-- HW Frame Tx Forward User Byte
regs_o.hwfc_tx_fwd_ub_o <= tru_hwfc_tx_fwd_ub_int;
-- HW Frame Tx Block User Byte
regs_o.hwfc_tx_blk_ub_o <= tru_hwfc_tx_blk_ub_int;
-- Filtering Database ID -- Filtering Database ID
regs_o.ttr0_fid_o <= tru_ttr0_fid_int; regs_o.ttr0_fid_o <= tru_ttr0_fid_int;
-- ID withing Filtering Database Entry -- ID withing Filtering Database Entry
......
...@@ -118,6 +118,16 @@ peripheral { ...@@ -118,6 +118,16 @@ peripheral {
access_bus = READ_WRITE; access_bus = READ_WRITE;
access_dev = READ_ONLY; access_dev = READ_ONLY;
}; };
field {
name = "Substraction Pattern Mode";
prefix = "PATTERN_MODE_SUB";
description = "Selected Pattern Mode for port config substraction";
size = 4;
align= 8;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
}; };
reg { reg {
...@@ -489,6 +499,71 @@ peripheral { ...@@ -489,6 +499,71 @@ peripheral {
}; };
}; };
reg {
name = "HW-frame gen/det config";
description = "Controls HW generation/detection of frames";
prefix = "HWFC";
field {
name = "HW Frame Rx Forward ID";
prefix = "RX_FWD_ID";
description = " ID (bit number of the rxFrameMask) of the signal from the endpoint which \
is programmed to indicate reception of Quick Forward Request BPDUe";
size = 4;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "HW Frame Rx Block ID";
prefix = "RX_BLK_ID";
description = " ID (bit number of the rxFrameMask) of the signal from the endpoint which \
is programmed to indicate reception of Quick Block Request BPDUe";
size = 4;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "HW Frame Tx Forward ID";
prefix = "TX_FWD_ID";
description = " ID (bit number of the txFrameMask) of the HW-sent frame by endpoint\
(Quick Forward Request BPDUe)";
size = 4;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "HW Frame Tx Block ID";
prefix = "TX_BLK_ID";
description = " ID (bit number of the txFrameMask) of the HW-sent frame by endpoint\
(Quick Block Request BPDUe)";
size = 4;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "HW Frame Tx Forward User Byte";
prefix = "TX_FWD_UB";
description = " LOW byte of the 16-bit User Defined Value inserted into tnjected Template";
size = 8;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
field {
name = "HW Frame Tx Block User Byte";
prefix = "TX_BLK_UB";
description = " LOW byte of the 16-bit User Defined Value inserted into tnjected Template";
size = 8;
type = SLV;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
};
reg { reg {
name = "TRU Table Register 0"; name = "TRU Table Register 0";
prefix = "TTR0"; prefix = "TTR0";
......
This diff is collapsed.
...@@ -167,6 +167,9 @@ architecture rtl of xwrsw_tru is ...@@ -167,6 +167,9 @@ architecture rtl of xwrsw_tru is
signal s_req_s_prio : std_logic; signal s_req_s_prio : std_logic;
signal s_tru_ena : std_logic; signal s_tru_ena : std_logic;
signal s_swc_ctrl : t_trans2sw; signal s_swc_ctrl : t_trans2sw;
signal s_inject_sel : t_inject_sel_array(g_num_ports-1 downto 0);
signal s_ep : t_tru2ep_array(g_num_ports-1 downto 0);
signal s_inject_ready_d : std_logic_vector(g_num_ports-1 downto 0);
begin --rtl begin --rtl
U_T_PORT: tru_port U_T_PORT: tru_port
...@@ -268,60 +271,98 @@ begin --rtl ...@@ -268,60 +271,98 @@ begin --rtl
s_endpoints.rxFrameMaskReg(i) <= f_rxFrameMaskRegInv(s_endpoint_array,i,g_num_ports); s_endpoints.rxFrameMaskReg(i) <= f_rxFrameMaskRegInv(s_endpoint_array,i,g_num_ports);
end generate G_FRAME_MASK; end generate G_FRAME_MASK;
CTRL_PINJECT: process(clk_i, rst_n_i) -- this is not really optimal for resources... shit CTRL_PINJECT: process(clk_i, rst_n_i) -- this is not really optimal for resources... shit
begin begin
if rising_edge(clk_i) then if rising_edge(clk_i) then
if(rst_n_i = '0') then if(rst_n_i = '0') then
CLEAR: for i in 0 to g_num_ports-1 loop CLEAR: for i in 0 to g_num_ports-1 loop
s_pinject_ctr(i).inject_packet_sel <= (others=>'0'); s_inject_sel(i).dbg <= '0';
s_pinject_ctr(i).inject_user_value <= (others=>'0'); s_inject_sel(i).fwd <= '0';
s_inject_sel(i).blk <= '0';
s_inject_sel(i).pause <= '0';
s_inject_ready_d(i) <= '0';
end loop; end loop;
else else
-- below we register the info from different modules about hw-injection of frames.
-- This is needed as one injection can be done at a time and many injection request
-- can (theoretically) happen at the same time.
-- We remember each request and hw-inject framess with the following priority:
-- 1) dbg msg - from WB
-- 2) quick forward - from R-T Re-config module or transition (if a request is
-- is made when other is being handled ... we don't care, since
-- the effect is achieved with the handled one
-- 3) quick block - from transition
-- 4) pause - from transition (it can be delayed since we count the received
-- frames after we requested the PAUSE -- this is to accommodate
-- the delay between requesting the PAUSE frame and the pause
-- stopping the traffic
-- The stored values of s_inject_sel are used to select the values of
-- *inject_packet_sel* and *inject_user_value* to be fed into the module
REMEMBER: for i in 0 to g_num_ports-1 loop REMEMBER: for i in 0 to g_num_ports-1 loop
if(ep_i(i).inject_ready = '1') then if(s_pidr_inject(i) ='1' and s_inject_sel(i).dbg = '0') then
if(s_pidr_inject(i) ='1') then s_inject_sel(i).dbg <= '1';
s_pinject_ctr(i).inject_packet_sel <= s_regs_fromwb.pidr_psel_o; elsif(s_inject_ready_d(i) = '0' and ep_i(i).inject_ready = '1' and -- finished injection
s_pinject_ctr(i).inject_user_value <= s_regs_fromwb.pidr_uval_o; s_inject_sel(i).dbg = '1') then
elsif(s_tx_rt_reconf_FRM(i) ='1') then s_inject_sel(i).dbg <= '0';
s_pinject_ctr(i).inject_packet_sel <= s_config.rtrcr_rtr_rx(2 downto 0); end if;
s_pinject_ctr(i).inject_user_value <= x"babe"; -- TODO - config
elsif(s_trans_ep_ctr(i).pauseSend = '1') then if((s_tx_rt_reconf_FRM(i) ='1' or s_trans_ep_ctr(i).hwframe_fwd = '1') and s_inject_sel(i).fwd = '0') then -- quick forward
s_pinject_ctr(i).inject_packet_sel <= "000"; s_inject_sel(i).fwd <= '1';
s_pinject_ctr(i).inject_user_value <= s_trans_ep_ctr(i).pauseTime; elsif(s_inject_ready_d(i) = '0' and ep_i(i).inject_ready = '1' and -- finished injection
end if; s_inject_sel(i).dbg = '0' and s_inject_sel(i).fwd = '1') then
s_inject_sel(i).fwd <= '0';
end if; end if;
if(s_trans_ep_ctr(i).hwframe_blk ='1' and s_inject_sel(i).blk = '0') then -- quick block
s_inject_sel(i).blk <='1';
elsif(s_inject_ready_d(i) = '0' and ep_i(i).inject_ready = '1' and -- finished injection
s_inject_sel(i).dbg = '0' and s_inject_sel(i).fwd = '0' and s_inject_sel(i).blk ='1') then
s_inject_sel(i).blk <='0';
end if;
if(s_trans_ep_ctr(i).pauseSend = '1' and s_inject_sel(i).pause ='0') then
s_inject_sel(i).pause <='1';
elsif(s_inject_ready_d(i) = '0' and ep_i(i).inject_ready = '1' and -- finished injection
s_inject_sel(i).dbg = '0' and s_inject_sel(i).fwd = '0' and s_inject_sel(i).blk = '0' and
s_inject_sel(i).pause = '1') then
s_inject_sel(i).pause <='0';
end if;
s_inject_ready_d(i) <= ep_i(i).inject_ready; -- detect end of injection
end loop; end loop;
end if; end if;
end if; end if;
end process; end process;
-- the proper mux to feed into injection control of Endpoints
G_EP_O: for i in 0 to g_num_ports-1 generate G_EP_O: for i in 0 to g_num_ports-1 generate
ep_o(i).inject_req <= '1' when (s_pidr_inject(i) = '1') else s_ep(i).inject_packet_sel <= s_regs_fromwb.pidr_psel_o when (s_inject_sel(i).dbg ='1') else
'1' when (s_tx_rt_reconf_FRM(i) = '1') else s_config.hwframe_tx_fwd(2 downto 0) when (s_inject_sel(i).fwd ='1') else
'1' when (s_trans_ep_ctr(i).pauseSend = '1') else s_config.hwframe_tx_blk(2 downto 0) when (s_inject_sel(i).blk ='1') else
'0'; "000" when (s_inject_sel(i).pause ='1') else
"000";
----------- this is not really optimal for resources... shit s_ep(i).inject_user_value <= s_regs_fromwb.pidr_uval_o when (s_inject_sel(i).dbg ='1') else
ep_o(i).inject_packet_sel <= s_pinject_ctr(i).inject_packet_sel; x"00" & s_regs_fromwb.hwfc_tx_fwd_ub_o when (s_inject_sel(i).fwd ='1') else
ep_o(i).inject_user_value <= s_pinject_ctr(i).inject_user_value; x"00" & s_regs_fromwb.hwfc_tx_blk_ub_o when (s_inject_sel(i).blk ='1') else
s_regs_fromwb.tcpbr_trans_pause_time_o when (s_inject_sel(i).pause ='1') else
x"0000";
-- ep_o(i).inject_packet_sel <= s_regs_fromwb.pidr_psel_o when s_pidr_inject(i) ='1' else s_ep(i).inject_req <= '1' when (s_inject_sel(i).dbg = '1' and ep_i(i).inject_ready = '1' and s_inject_ready_d(i) = '1') else
-- s_config.rtrcr_rtr_rx(2 downto 0) when s_tx_rt_reconf_FRM(i) ='1' else '1' when (s_inject_sel(i).fwd = '1' and ep_i(i).inject_ready = '1' and s_inject_ready_d(i) = '1') else
-- "000"; '1' when (s_inject_sel(i).blk = '1' and ep_i(i).inject_ready = '1' and s_inject_ready_d(i) = '1') else
-- ep_o(i).inject_user_value <= s_regs_fromwb.pidr_uval_o when s_pidr_inject(i) ='1' else '1' when (s_inject_sel(i).pause = '1' and ep_i(i).inject_ready = '1' and s_inject_ready_d(i) = '1') else
-- x"babe" when s_tx_rt_reconf_FRM(i) ='1' else '0';
-- s_trans_ep_ctr(i).pauseTime;
ep_o(i).inject_packet_sel <= s_ep(i).inject_packet_sel ;
-- ep_o(i).tx_pck <= '1' when (s_tx_rt_reconf_FRM(i) ='1') else '0'; ep_o(i).inject_user_value <= s_ep(i).inject_user_value;
-- G_TX_O: for j in 0 to g_pclass_number-1 generate ep_o(i).inject_req <= s_ep(i).inject_req ;
-- ep_o(i).tx_pck_class(j) <= s_tx_rt_reconf_FRM(i)
-- when (j = to_integer(unsigned(s_config.rtrcr_rtr_rx))) else '0';
-- end generate G_TX_O;
ep_o(i).fc_pause_req <= '0'; --s_trans_ep_ctr(i).pauseSend; ep_o(i).fc_pause_req <= '0'; --s_trans_ep_ctr(i).pauseSend;
ep_o(i).fc_pause_delay <= (others => '0'); --s_trans_ep_ctr(i).pauseTime; ep_o(i).fc_pause_delay <= (others => '0'); --s_trans_ep_ctr(i).pauseTime;
ep_o(i).outQueueBlockMask <= s_trans_ep_ctr(i).outQueueBlockMask;
end generate G_EP_O; end generate G_EP_O;
G_TRU_TAB: for i in 0 to g_tru_subentry_num-1 generate G_TRU_TAB: for i in 0 to g_tru_subentry_num-1 generate
...@@ -408,6 +449,7 @@ begin --rtl ...@@ -408,6 +449,7 @@ begin --rtl
s_config.gcr_rx_frame_reset <= s_regs_fromwb.gcr_rx_frame_reset_o ; s_config.gcr_rx_frame_reset <= s_regs_fromwb.gcr_rx_frame_reset_o ;
s_config.mcr_pattern_mode_rep <= s_regs_fromwb.mcr_pattern_mode_rep_o ; s_config.mcr_pattern_mode_rep <= s_regs_fromwb.mcr_pattern_mode_rep_o ;
s_config.mcr_pattern_mode_add <= s_regs_fromwb.mcr_pattern_mode_add_o ; s_config.mcr_pattern_mode_add <= s_regs_fromwb.mcr_pattern_mode_add_o ;
s_config.mcr_pattern_mode_sub <= s_regs_fromwb.mcr_pattern_mode_sub_o ;
s_config.lacr_agg_df_hp_id <= s_regs_fromwb.lacr_agg_df_hp_id_o ; s_config.lacr_agg_df_hp_id <= s_regs_fromwb.lacr_agg_df_hp_id_o ;
s_config.lacr_agg_df_br_id <= s_regs_fromwb.lacr_agg_df_br_id_o ; s_config.lacr_agg_df_br_id <= s_regs_fromwb.lacr_agg_df_br_id_o ;
s_config.lacr_agg_df_un_id <= s_regs_fromwb.lacr_agg_df_un_id_o ; s_config.lacr_agg_df_un_id <= s_regs_fromwb.lacr_agg_df_un_id_o ;
...@@ -437,6 +479,11 @@ begin --rtl ...@@ -437,6 +479,11 @@ begin --rtl
s_config.rtrcr_rtr_rx <= s_regs_fromwb.rtrcr_rtr_rx_o ; s_config.rtrcr_rtr_rx <= s_regs_fromwb.rtrcr_rtr_rx_o ;
s_config.rtrcr_rtr_tx <= s_regs_fromwb.rtrcr_rtr_tx_o ; s_config.rtrcr_rtr_tx <= s_regs_fromwb.rtrcr_rtr_tx_o ;
s_config.hwframe_rx_fwd <= s_regs_fromwb.hwfc_rx_fwd_id_o ;
s_config.hwframe_tx_fwd <= s_regs_fromwb.hwfc_tx_fwd_id_o ;
s_config.hwframe_rx_blk <= s_regs_fromwb.hwfc_rx_blk_id_o ;
s_config.hwframe_tx_blk <= s_regs_fromwb.hwfc_tx_blk_id_o ;
s_tru_tab_wr_index <= to_integer(unsigned(s_regs_fromwb.ttr0_sub_fid_o)); s_tru_tab_wr_index <= to_integer(unsigned(s_regs_fromwb.ttr0_sub_fid_o));
s_tru_wr_addr <= (not s_tru_tab_bank) & s_regs_fromwb.ttr0_fid_o; s_tru_wr_addr <= (not s_tru_tab_bank) & s_regs_fromwb.ttr0_fid_o;
s_tru_wr_data <= s_regs_fromwb.ttr0_patrn_mode_o & s_tru_wr_data <= s_regs_fromwb.ttr0_patrn_mode_o &
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
`define TRU_MCR_PATTERN_MODE_REP 32'h0000000f `define TRU_MCR_PATTERN_MODE_REP 32'h0000000f
`define TRU_MCR_PATTERN_MODE_ADD_OFFSET 8 `define TRU_MCR_PATTERN_MODE_ADD_OFFSET 8
`define TRU_MCR_PATTERN_MODE_ADD 32'h00000f00 `define TRU_MCR_PATTERN_MODE_ADD 32'h00000f00
`define TRU_MCR_PATTERN_MODE_SUB_OFFSET 16
`define TRU_MCR_PATTERN_MODE_SUB 32'h000f0000
`define ADDR_TRU_LACR 7'h10 `define ADDR_TRU_LACR 7'h10
`define TRU_LACR_AGG_DF_HP_ID_OFFSET 0 `define TRU_LACR_AGG_DF_HP_ID_OFFSET 0
`define TRU_LACR_AGG_DF_HP_ID 32'h0000000f `define TRU_LACR_AGG_DF_HP_ID 32'h0000000f
...@@ -68,7 +70,20 @@ ...@@ -68,7 +70,20 @@
`define TRU_RTRCR_RTR_RX 32'h000f0000 `define TRU_RTRCR_RTR_RX 32'h000f0000
`define TRU_RTRCR_RTR_TX_OFFSET 24 `define TRU_RTRCR_RTR_TX_OFFSET 24
`define TRU_RTRCR_RTR_TX 32'h0f000000 `define TRU_RTRCR_RTR_TX 32'h0f000000
`define ADDR_TRU_TTR0 7'h28 `define ADDR_TRU_HWFC 7'h28
`define TRU_HWFC_RX_FWD_ID_OFFSET 0
`define TRU_HWFC_RX_FWD_ID 32'h0000000f
`define TRU_HWFC_RX_BLK_ID_OFFSET 4
`define TRU_HWFC_RX_BLK_ID 32'h000000f0
`define TRU_HWFC_TX_FWD_ID_OFFSET 8
`define TRU_HWFC_TX_FWD_ID 32'h00000f00
`define TRU_HWFC_TX_BLK_ID_OFFSET 12
`define TRU_HWFC_TX_BLK_ID 32'h0000f000
`define TRU_HWFC_TX_FWD_UB_OFFSET 16
`define TRU_HWFC_TX_FWD_UB 32'h00ff0000
`define TRU_HWFC_TX_BLK_UB_OFFSET 24
`define TRU_HWFC_TX_BLK_UB 32'hff000000
`define ADDR_TRU_TTR0 7'h2c
`define TRU_TTR0_FID_OFFSET 0 `define TRU_TTR0_FID_OFFSET 0
`define TRU_TTR0_FID 32'h000000ff `define TRU_TTR0_FID 32'h000000ff
`define TRU_TTR0_SUB_FID_OFFSET 8 `define TRU_TTR0_SUB_FID_OFFSET 8
...@@ -79,25 +94,25 @@ ...@@ -79,25 +94,25 @@
`define TRU_TTR0_MASK_VALID 32'h00020000 `define TRU_TTR0_MASK_VALID 32'h00020000
`define TRU_TTR0_PATRN_MODE_OFFSET 24 `define TRU_TTR0_PATRN_MODE_OFFSET 24
`define TRU_TTR0_PATRN_MODE 32'h0f000000 `define TRU_TTR0_PATRN_MODE 32'h0f000000
`define ADDR_TRU_TTR1 7'h2c `define ADDR_TRU_TTR1 7'h30
`define TRU_TTR1_PORTS_INGRESS_OFFSET 0 `define TRU_TTR1_PORTS_INGRESS_OFFSET 0
`define TRU_TTR1_PORTS_INGRESS 32'hffffffff `define TRU_TTR1_PORTS_INGRESS 32'hffffffff
`define ADDR_TRU_TTR2 7'h30 `define ADDR_TRU_TTR2 7'h34
`define TRU_TTR2_PORTS_EGRESS_OFFSET 0 `define TRU_TTR2_PORTS_EGRESS_OFFSET 0
`define TRU_TTR2_PORTS_EGRESS 32'hffffffff `define TRU_TTR2_PORTS_EGRESS 32'hffffffff
`define ADDR_TRU_TTR3 7'h34 `define ADDR_TRU_TTR3 7'h38
`define TRU_TTR3_PORTS_MASK_OFFSET 0 `define TRU_TTR3_PORTS_MASK_OFFSET 0
`define TRU_TTR3_PORTS_MASK 32'hffffffff `define TRU_TTR3_PORTS_MASK 32'hffffffff
`define ADDR_TRU_TTR4 7'h38 `define ADDR_TRU_TTR4 7'h3c
`define TRU_TTR4_PATRN_MATCH_OFFSET 0 `define TRU_TTR4_PATRN_MATCH_OFFSET 0
`define TRU_TTR4_PATRN_MATCH 32'hffffffff `define TRU_TTR4_PATRN_MATCH 32'hffffffff
`define ADDR_TRU_TTR5 7'h3c `define ADDR_TRU_TTR5 7'h40
`define TRU_TTR5_PATRN_MASK_OFFSET 0 `define TRU_TTR5_PATRN_MASK_OFFSET 0
`define TRU_TTR5_PATRN_MASK 32'hffffffff `define TRU_TTR5_PATRN_MASK 32'hffffffff
`define ADDR_TRU_DPS 7'h40 `define ADDR_TRU_DPS 7'h44
`define TRU_DPS_PID_OFFSET 0 `define TRU_DPS_PID_OFFSET 0
`define TRU_DPS_PID 32'h000000ff `define TRU_DPS_PID 32'h000000ff
`define ADDR_TRU_PIDR 7'h44 `define ADDR_TRU_PIDR 7'h48
`define TRU_PIDR_INJECT_OFFSET 0 `define TRU_PIDR_INJECT_OFFSET 0
`define TRU_PIDR_INJECT 32'h00000001 `define TRU_PIDR_INJECT 32'h00000001
`define TRU_PIDR_PSEL_OFFSET 1 `define TRU_PIDR_PSEL_OFFSET 1
...@@ -106,13 +121,13 @@ ...@@ -106,13 +121,13 @@
`define TRU_PIDR_UVAL 32'h00ffff00 `define TRU_PIDR_UVAL 32'h00ffff00
`define TRU_PIDR_IREADY_OFFSET 24 `define TRU_PIDR_IREADY_OFFSET 24
`define TRU_PIDR_IREADY 32'h01000000 `define TRU_PIDR_IREADY 32'h01000000
`define ADDR_TRU_PFDR 7'h48 `define ADDR_TRU_PFDR 7'h4c
`define TRU_PFDR_CLR_OFFSET 0 `define TRU_PFDR_CLR_OFFSET 0
`define TRU_PFDR_CLR 32'h00000001 `define TRU_PFDR_CLR 32'h00000001
`define TRU_PFDR_CLASS_OFFSET 8 `define TRU_PFDR_CLASS_OFFSET 8
`define TRU_PFDR_CLASS 32'h0000ff00 `define TRU_PFDR_CLASS 32'h0000ff00
`define TRU_PFDR_CNT_OFFSET 16 `define TRU_PFDR_CNT_OFFSET 16
`define TRU_PFDR_CNT 32'hffff0000 `define TRU_PFDR_CNT 32'hffff0000
`define ADDR_TRU_PTRDR 7'h4c `define ADDR_TRU_PTRDR 7'h50
`define TRU_PTRDR_GING_MASK_OFFSET 0 `define TRU_PTRDR_GING_MASK_OFFSET 0
`define TRU_PTRDR_GING_MASK 32'hffffffff `define TRU_PTRDR_GING_MASK 32'hffffffff
...@@ -141,9 +141,12 @@ class CSimDrv_WR_TRU; ...@@ -141,9 +141,12 @@ class CSimDrv_WR_TRU;
end end
endtask; endtask;
task pattern_config(int replacement, int addition); task pattern_config(int replacement, int addition, int subtraction);
m_acc.write(m_base +`ADDR_TRU_MCR, replacement << `TRU_MCR_PATTERN_MODE_REP_OFFSET | m_acc.write(m_base +`ADDR_TRU_MCR,
addition << `TRU_MCR_PATTERN_MODE_ADD_OFFSET); (subtraction << `TRU_MCR_PATTERN_MODE_SUB_OFFSET) & `TRU_MCR_PATTERN_MODE_SUB |
(addition << `TRU_MCR_PATTERN_MODE_ADD_OFFSET) & `TRU_MCR_PATTERN_MODE_ADD |
(replacement << `TRU_MCR_PATTERN_MODE_REP_OFFSET) & `TRU_MCR_PATTERN_MODE_REP);
if(m_dbg) if(m_dbg)
begin begin
$display("TRU: Real Time transition source of patterns config:"); $display("TRU: Real Time transition source of patterns config:");
...@@ -256,6 +259,27 @@ class CSimDrv_WR_TRU; ...@@ -256,6 +259,27 @@ class CSimDrv_WR_TRU;
end end
endtask; endtask;
task hw_frame_config(int tx_fwd_id, int rx_fwd_id, int tx_blk_id, int rx_blk_id);
uint64_t tmp;
m_acc.write(m_base +`ADDR_TRU_HWFC,
('h96 << `TRU_HWFC_TX_BLK_UB_OFFSET) & `TRU_HWFC_TX_BLK_UB |
('h69 << `TRU_HWFC_TX_FWD_UB_OFFSET) & `TRU_HWFC_TX_FWD_UB |
(tx_blk_id << `TRU_HWFC_TX_BLK_ID_OFFSET) & `TRU_HWFC_TX_BLK_ID |
(tx_fwd_id << `TRU_HWFC_TX_FWD_ID_OFFSET) & `TRU_HWFC_TX_FWD_ID |
(rx_blk_id << `TRU_HWFC_RX_BLK_ID_OFFSET) & `TRU_HWFC_RX_BLK_ID |
(rx_fwd_id << `TRU_HWFC_RX_FWD_ID_OFFSET) & `TRU_HWFC_RX_FWD_ID );
if(m_dbg)
begin
$display("TRU: HW-generated/detected frame config]:");
$display("\tFrame forward: tx_fwd_id = %2d, rx_fwd_id = %2d tx_fwd_ub = x%2x",
tx_fwd_id, rx_fwd_id, 'h69);
$display("\tFrame block : tx_blk_id = %2d, rx_blk_id = %2d tx_blk_ub = x%2x",
tx_blk_id, rx_blk_id, 'h96);
end
endtask;
task lacp_config(int df_hp_id, int df_br_id, int df_un_id); task lacp_config(int df_hp_id, int df_br_id, int df_un_id);
uint64_t tmp; uint64_t tmp;
tmp = (`TRU_LACR_AGG_DF_HP_ID & (df_hp_id << `TRU_LACR_AGG_DF_HP_ID_OFFSET)) | tmp = (`TRU_LACR_AGG_DF_HP_ID & (df_hp_id << `TRU_LACR_AGG_DF_HP_ID_OFFSET)) |
......
...@@ -632,7 +632,7 @@ module main; ...@@ -632,7 +632,7 @@ module main;
* detecting different classes of incoming packets using pFilter * detecting different classes of incoming packets using pFilter
* *
**/ **/
///* /*
initial begin initial begin
portUnderTest = 18'b000000000000010001; portUnderTest = 18'b000000000000010001;
g_tru_enable = 0; g_tru_enable = 0;
...@@ -675,7 +675,7 @@ module main; ...@@ -675,7 +675,7 @@ module main;
mc.logic2(27, 1, PFilterMicrocode::AND, 5); mc.logic2(27, 1, PFilterMicrocode::AND, 5);
end end
//*/ */
/** *************************** test scenario 21 ********************** **/ /** *************************** test scenario 21 ********************** **/
/** *************************** (IMPORTANT) ********************** **/ /** *************************** (IMPORTANT) ********************** **/
/* /*
...@@ -1139,7 +1139,7 @@ module main; ...@@ -1139,7 +1139,7 @@ module main;
* testing switch over with HW-frame generation * testing switch over with HW-frame generation
* *
**/ **/
/* /*
initial begin initial begin
portUnderTest = 18'b000000000000000111; portUnderTest = 18'b000000000000000111;
g_tru_enable = 1; g_tru_enable = 1;
...@@ -1159,6 +1159,35 @@ module main; ...@@ -1159,6 +1159,35 @@ module main;
// g_injection_templates_programmed = 1; // g_injection_templates_programmed = 1;
end end
*/ */
/** *************************** test scenario 37 ************************************* **/
/*
* quick forward/block massage detection and action
*
**/
///*
initial begin
portUnderTest = 18'b000000000000000000;
g_tru_enable = 1;
g_transition_scenario= 3;
g_active_port = 0;
g_backup_port = 1;
tru_config_opt = 6;
g_pfilter_enabled = 1;
g_injection_templates_programmed = 1;
mc.nop();
mc.cmp(0, 'h0180, 'hffff, PFilterMicrocode::MOV, 1);
mc.cmp(1, 'hc200, 'hffff, PFilterMicrocode::AND, 1);
mc.cmp(2, 'h0000, 'hffff, PFilterMicrocode::AND, 1);
mc.nop();
mc.nop();
mc.nop();
mc.cmp(6, 'h2607, 'hffff, PFilterMicrocode::AND, 1);
mc.logic2(25, 1, PFilterMicrocode::MOV, 0);
mc.logic2(26, 1, PFilterMicrocode::MOV, 0);
end
//*/
////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////
...@@ -1587,8 +1616,9 @@ module main; ...@@ -1587,8 +1616,9 @@ module main;
task automatic init_tru(input CSimDrv_WR_TRU tru_drv); task automatic init_tru(input CSimDrv_WR_TRU tru_drv);
$display(">>>>>>>>>>>>>>>>>>> TRU initialization <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"); $display(">>>>>>>>>>>>>>>>>>> TRU initialization <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
tru_drv.pattern_config(1 /*replacement*/, 0 /*addition*/); tru_drv.pattern_config(1 /*replacement*/, 0 /*addition*/, 0 /*subtraction*/);
tru_drv.lacp_config(lacp_df_hp_id,lacp_df_br_id,lacp_df_un_id); tru_drv.lacp_config(lacp_df_hp_id,lacp_df_br_id,lacp_df_un_id);
tru_drv.hw_frame_config(1/*tx_fwd_id*/, 1/*rx_fwd_id*/, 1/*tx_blk_id*/, 2 /*rx_blk_id*/);
// tru_drv.rt_reconf_config(4 /*tx_frame_id*/, 4/*rx_frame_id*/, 1 /*mode*/); // tru_drv.rt_reconf_config(4 /*tx_frame_id*/, 4/*rx_frame_id*/, 1 /*mode*/);
// tru_drv.rt_reconf_enable(); // tru_drv.rt_reconf_enable();
...@@ -1692,7 +1722,7 @@ module main; ...@@ -1692,7 +1722,7 @@ module main;
32'b1001_0000_1111_0000 /*ports_mask */, 32'b0000_0000_0000_0000 /* ports_egress */,32'b1001_0000_1111_0000 /* ports_ingress */); 32'b1001_0000_1111_0000 /*ports_mask */, 32'b0000_0000_0000_0000 /* ports_egress */,32'b1001_0000_1111_0000 /* ports_ingress */);
tru_drv.pattern_config(3 /*replacement*/, 4 /*addition*/); // 3-> source is pclass tru_drv.pattern_config(4 /*replacement*/, 5 /*addition*/, 0 /*subtraction*/); // 3-> source is pclass
end end
else if(tru_config_opt == 3) else if(tru_config_opt == 3)
begin begin
...@@ -1723,6 +1753,28 @@ module main; ...@@ -1723,6 +1753,28 @@ module main;
32'b00000011 /*pattern_mask*/, 32'b00000001 /* pattern_match*/,'h0 /* mode */, 32'b00000011 /*pattern_mask*/, 32'b00000001 /* pattern_match*/,'h0 /* mode */,
32'b00000011 /*ports_mask */, 32'b00000010 /* ports_egress */,32'b00000010 /* ports_ingress */); 32'b00000011 /*ports_mask */, 32'b00000010 /* ports_egress */,32'b00000010 /* ports_ingress */);
end end
else if(tru_config_opt == 6)
begin
tru_drv.pattern_config(1 /*replacement*/, 2 /*addition*/, 3 /*subtraction*/);
// basic config
tru_drv.write_tru_tab( 1 /* valid */, 0 /* entry_addr */, 0 /* subentry_addr*/,
32'h00000 /*pattern_mask*/, 32'h00000 /* pattern_match*/, 'h0 /* mode */,
32'h3FFFF /*ports_mask */, 32'b111000000010100001 /* ports_egress */,32'b111000000010100001 /* ports_ingress */);
// backup if link down
tru_drv.write_tru_tab( 1 /* valid */, 0 /* entry_addr */, 1 /* subentry_addr*/,
32'b00000011 /*pattern_mask*/, 32'b00000001 /* pattern_match*/,'h0 /* mode */,
32'b00000011 /*ports_mask */, 32'b00000010 /* ports_egress */,32'b00000010 /* ports_ingress */);
// quick forward
tru_drv.write_tru_tab( 1 /* valid */, 0 /* entry_addr */, 2 /* subentry_addr*/,
32'b00000010 /*pattern_mask*/, 32'b00000010 /* pattern_match*/,'h2 /* mode */,
32'b00000010 /*ports_mask */, 32'b00000010 /* ports_egress */,32'b00000010 /* ports_ingress */);
// quick block
tru_drv.write_tru_tab( 1 /* valid */, 0 /* entry_addr */, 3 /* subentry_addr*/,
32'b00000001 /*pattern_mask*/, 32'b00000001 /* pattern_match*/,'h3 /* mode */,
32'b00000001 /*ports_mask */, 32'b00000001 /* ports_egress */,32'b00000001 /* ports_ingress */);
end
else // default config == 0 else // default config == 0
begin begin
tru_drv.write_tru_tab( 1 /* valid */, 0 /* entry_addr */, 0 /* subentry_addr*/, tru_drv.write_tru_tab( 1 /* valid */, 0 /* entry_addr */, 0 /* subentry_addr*/,
...@@ -1756,8 +1808,15 @@ module main; ...@@ -1756,8 +1808,15 @@ module main;
if(tru_config_opt == 4 || tru_config_opt == 5) if(tru_config_opt == 4 || tru_config_opt == 5)
begin begin
tru_drv.rt_reconf_config(1 /*tx_frame_id*/, 1/*rx_frame_id*/, 1 /*mode*/); tru_drv.rt_reconf_config(1 /*tx_frame_id*/, 1/*rx_frame_id*/, 1 /*mode*/);
tru_drv.hw_frame_config(1/*tx_fwd_id*/, 1/*rx_fwd_id*/, 1/*tx_blk_id*/, 2 /*rx_blk_id*/);
tru_drv.rt_reconf_enable(); tru_drv.rt_reconf_enable();
end end
if(tru_config_opt == 6)
begin
tru_drv.rt_reconf_config(1 /*tx_frame_id*/, 1/*rx_frame_id*/, 1 /*mode*/);
tru_drv.hw_frame_config(1/*tx_fwd_id*/, 1/*rx_fwd_id*/, 1/*tx_blk_id*/, 2 /*rx_blk_id*/);
tru_drv.rt_reconf_enable();
end
tru_drv.tru_swap_bank(); tru_drv.tru_swap_bank();
...@@ -2285,7 +2344,6 @@ module main; ...@@ -2285,7 +2344,6 @@ module main;
wait_cycles(10); wait_cycles(10);
tru.ep_debug_inject_packet(3,'h4321,0); tru.ep_debug_inject_packet(3,'h4321,0);
wait_cycles(10); wait_cycles(10);
end end
...@@ -2299,6 +2357,70 @@ module main; ...@@ -2299,6 +2357,70 @@ module main;
tx_special_pck(ports[3].send,PAUSE /*opt*/,14/*pause time*/); tx_special_pck(ports[3].send,PAUSE /*opt*/,14/*pause time*/);
end end
if(g_transition_scenario == 3)
begin
// send normal stuff
fork
begin
tx_test(seed /* seed */,
5 /* n_tries */,
0 /* is_q */,
0 /* unvid */,
ports[0].send /* src */,
ports[7].recv /* sink */,
0 /* srcPort */ ,
7 /* dstPort */,
4 /*option=4 */);
end
begin
tx_test(seed /* seed */,
5 /* n_tries */,
0 /* is_q */,
0 /* unvid */,
ports[1].send /* src */,
ports[5].recv /* sink */,
0 /* srcPort */ ,
5 /* dstPort */,
4 /*option=4 */);
end
join
fork
begin
$display(">>>>>>>>>>>>>>>>>>>>>>>>>>>>> CLOSE / OPEN port 0<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
tx_special_pck(ports[0].send,BPDU_0 /*opt*/);
end
begin
$display(">>>>>>>>>>>>>>>>>>>>>>>>>>>>> CLOSE / OPEN port 1<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
tx_special_pck(ports[1].send,BPDU_0 /*opt*/);
end
join
fork
begin
tx_test(seed /* seed */,
5 /* n_tries */,
0 /* is_q */,
0 /* unvid */,
ports[0].send /* src */,
ports[7].recv /* sink */,
0 /* srcPort */ ,
7 /* dstPort */,
4 /*option=4 */);
end
begin
tx_test(seed /* seed */,
5 /* n_tries */,
0 /* is_q */,
0 /* unvid */,
ports[1].send /* src */,
ports[5].recv /* sink */,
0 /* srcPort */ ,
5 /* dstPort */,
4 /*option=4 */);
end
join
end
end end
join_none; // join_none; //
......
...@@ -590,9 +590,9 @@ begin ...@@ -590,9 +590,9 @@ begin
pfilter_pclass_o => ep2tru(i).pfilter_pclass, pfilter_pclass_o => ep2tru(i).pfilter_pclass,
pfilter_drop_o => ep2tru(i).pfilter_drop, pfilter_drop_o => ep2tru(i).pfilter_drop,
pfilter_done_o => ep2tru(i).pfilter_done, pfilter_done_o => ep2tru(i).pfilter_done,
fc_tx_pause_req_i => tru2ep(i).fc_pause_req, fc_tx_pause_req_i => tru2ep(i).fc_pause_req, -- we don't use it, use inject instead
fc_tx_pause_delay_i => tru2ep(i).fc_pause_delay, fc_tx_pause_delay_i => tru2ep(i).fc_pause_delay, -- we don't use it, use inject instead
fc_tx_pause_ready_o => ep2tru(i).fc_pause_ready, fc_tx_pause_ready_o => ep2tru(i).fc_pause_ready, -- we don't use it, use inject instead
inject_req_i => tru2ep(i).inject_req, inject_req_i => tru2ep(i).inject_req,
inject_ready_o => ep2tru(i).inject_ready, inject_ready_o => ep2tru(i).inject_ready,
inject_packet_sel_i => tru2ep(i).inject_packet_sel, inject_packet_sel_i => tru2ep(i).inject_packet_sel,
......
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