diff options
author | Mark Starovoytov <mstarovoitov@marvell.com> | 2020-05-22 11:19:43 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2020-05-22 14:08:28 -0700 |
commit | 7327699f35f8e90b32c03080b5cba4e9aa95e087 (patch) | |
tree | 8e18469819df2e1181a574e9593c086980a26330 /drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c | |
parent | b9e989262a3e2e9b795361a7e7978d64851eb98f (diff) | |
download | linux-7327699f35f8e90b32c03080b5cba4e9aa95e087.tar.bz2 |
net: atlantic: QoS implementation: max_rate
This patch adds initial support for mqprio rate limiters (max_rate only).
Atlantic HW supports Rate-Shaping for time-sensitive traffic at per
Traffic Class (TC) granularity.
Target rate is defined by:
* nominal link rate (always 10G);
* rate factor (ratio between nominal rate and max allowed).
Signed-off-by: Mark Starovoytov <mstarovoitov@marvell.com>
Signed-off-by: Igor Russkikh <irusskikh@marvell.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c')
-rw-r--r-- | drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c | 58 |
1 files changed, 54 insertions, 4 deletions
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c index 775382440b47..abc86eb4f525 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c @@ -138,6 +138,8 @@ static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self) unsigned int prio = 0U; u32 tc = 0U; + hw_atl_b0_hw_init_tx_tc_rate_limit(self); + if (cfg->is_ptp) { tx_buff_size -= HW_ATL_B0_PTP_TXBUF_SIZE; rx_buff_size -= HW_ATL_B0_PTP_RXBUF_SIZE; @@ -151,7 +153,6 @@ static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self) hw_atl_tps_tx_pkt_shed_desc_vm_arb_mode_set(self, 0U); /* TPS TC credits init */ - hw_atl_tps_tx_pkt_shed_desc_tc_arb_mode_set(self, 0U); hw_atl_tps_tx_pkt_shed_data_arb_mode_set(self, 0U); tx_buff_size /= cfg->tcs; @@ -162,8 +163,6 @@ static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self) /* TX Packet Scheduler Data TC0 */ hw_atl_tps_tx_pkt_shed_tc_data_max_credit_set(self, 0xFFF, tc); hw_atl_tps_tx_pkt_shed_tc_data_weight_set(self, 0x64, tc); - hw_atl_tps_tx_pkt_shed_desc_tc_max_credit_set(self, 0x50, tc); - hw_atl_tps_tx_pkt_shed_desc_tc_weight_set(self, 0x1E, tc); /* Tx buf size TC0 */ hw_atl_tpb_tx_pkt_buff_size_per_tc_set(self, tx_buff_size, tc); @@ -320,10 +319,61 @@ int hw_atl_b0_hw_offload_set(struct aq_hw_s *self, return aq_hw_err_from_flags(self); } +int hw_atl_b0_hw_init_tx_tc_rate_limit(struct aq_hw_s *self) +{ + /* Scale factor is based on the number of bits in fractional portion */ + static const u32 scale = BIT(HW_ATL_TPS_DESC_RATE_Y_WIDTH); + static const u32 frac_msk = HW_ATL_TPS_DESC_RATE_Y_MSK >> + HW_ATL_TPS_DESC_RATE_Y_SHIFT; + struct aq_nic_cfg_s *nic_cfg = self->aq_nic_cfg; + int tc; + + hw_atl_tps_tx_pkt_shed_desc_tc_arb_mode_set(self, 0U); + hw_atl_tps_tx_desc_rate_mode_set(self, nic_cfg->is_qos ? 1U : 0U); + for (tc = 0; tc != nic_cfg->tcs; tc++) { + const u32 en = (nic_cfg->tc_max_rate[tc] != 0) ? 1U : 0U; + const u32 desc = AQ_NIC_CFG_TCVEC2RING(nic_cfg, tc, 0); + + hw_atl_tps_tx_pkt_shed_desc_tc_max_credit_set(self, 0x50, tc); + hw_atl_tps_tx_pkt_shed_desc_tc_weight_set(self, 0x1E, tc); + + hw_atl_tps_tx_desc_rate_en_set(self, desc, en); + + if (en) { + /* Nominal rate is always 10G */ + const u32 rate = 10000U * scale / + nic_cfg->tc_max_rate[tc]; + const u32 rate_int = rate >> + HW_ATL_TPS_DESC_RATE_Y_WIDTH; + const u32 rate_frac = rate & frac_msk; + + hw_atl_tps_tx_desc_rate_x_set(self, desc, rate_int); + hw_atl_tps_tx_desc_rate_y_set(self, desc, rate_frac); + } else { + /* A value of 1 indicates the queue is not + * rate controlled. + */ + hw_atl_tps_tx_desc_rate_x_set(self, desc, 1U); + hw_atl_tps_tx_desc_rate_y_set(self, desc, 0U); + } + } + for (tc = nic_cfg->tcs; tc != AQ_CFG_TCS_MAX; tc++) { + const u32 desc = AQ_NIC_CFG_TCVEC2RING(nic_cfg, tc, 0); + + hw_atl_tps_tx_desc_rate_en_set(self, desc, 0U); + hw_atl_tps_tx_desc_rate_x_set(self, desc, 1U); + hw_atl_tps_tx_desc_rate_y_set(self, desc, 0U); + } + + return aq_hw_err_from_flags(self); +} + static int hw_atl_b0_hw_init_tx_path(struct aq_hw_s *self) { + struct aq_nic_cfg_s *nic_cfg = self->aq_nic_cfg; + /* Tx TC/Queue number config */ - hw_atl_tpb_tps_tx_tc_mode_set(self, self->aq_nic_cfg->tc_mode); + hw_atl_tpb_tps_tx_tc_mode_set(self, nic_cfg->tc_mode); hw_atl_thm_lso_tcp_flag_of_first_pkt_set(self, 0x0FF6U); hw_atl_thm_lso_tcp_flag_of_middle_pkt_set(self, 0x0FF6U); |