aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/aquantia/atlantic/hw_atl
diff options
context:
space:
mode:
authorMark Starovoytov <mstarovoitov@marvell.com>2020-05-22 11:19:47 +0300
committerDavid S. Miller <davem@davemloft.net>2020-05-22 14:08:29 -0700
commit2deac71ac492a6025b163701436e0aa39435a05f (patch)
tree6eaffd56ab8aa392580a9004b2dda9f96d91ce58 /drivers/net/ethernet/aquantia/atlantic/hw_atl
parentnet: atlantic: change the order of arguments for TC weight/credit setters (diff)
downloadlinux-dev-2deac71ac492a6025b163701436e0aa39435a05f.tar.xz
linux-dev-2deac71ac492a6025b163701436e0aa39435a05f.zip
net: atlantic: QoS implementation: min_rate
This patch adds support for mqprio min_rate limiters. A2 HW supports Weighted Strict Priority (WSP) arbitration for Tx Descriptor Queue scheduling among TCs, which can be used for min_rate shaping. 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')
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.c77
-rw-r--r--drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.h2
2 files changed, 66 insertions, 13 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 2448a09ef7b9..320f3669305d 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,8 +138,6 @@ 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;
@@ -152,18 +150,11 @@ static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self)
/* TPS VM init */
hw_atl_tps_tx_pkt_shed_desc_vm_arb_mode_set(self, 0U);
- /* TPS TC credits init */
- hw_atl_tps_tx_pkt_shed_data_arb_mode_set(self, 0U);
-
tx_buff_size /= cfg->tcs;
rx_buff_size /= cfg->tcs;
for (tc = 0; tc < cfg->tcs; tc++) {
u32 threshold = 0U;
- /* TX Packet Scheduler Data TC0 */
- hw_atl_tps_tx_pkt_shed_tc_data_max_credit_set(self, tc, 0xFFF);
- hw_atl_tps_tx_pkt_shed_tc_data_weight_set(self, tc, 0x64);
-
/* Tx buf size TC0 */
hw_atl_tpb_tx_pkt_buff_size_per_tc_set(self, tx_buff_size, tc);
@@ -319,24 +310,87 @@ 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)
+static int hw_atl_b0_hw_init_tx_tc_rate_limit(struct aq_hw_s *self)
{
+ static const u32 max_weight = BIT(HW_ATL_TPS_DATA_TCTWEIGHT_WIDTH) - 1;
/* 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;
+ const u32 link_speed = self->aq_link_status.mbps;
struct aq_nic_cfg_s *nic_cfg = self->aq_nic_cfg;
+ unsigned long num_min_rated_tcs = 0;
+ u32 tc_weight[AQ_CFG_TCS_MAX];
+ u32 fixed_max_credit;
+ u8 min_rate_msk = 0;
+ u32 sum_weight = 0;
int tc;
+ /* By default max_credit is based upon MTU (in unit of 64b) */
+ fixed_max_credit = nic_cfg->aq_hw_caps->mtu / 64;
+
+ if (link_speed) {
+ min_rate_msk = nic_cfg->tc_min_rate_msk &
+ (BIT(nic_cfg->tcs) - 1);
+ num_min_rated_tcs = hweight8(min_rate_msk);
+ }
+
+ /* First, calculate weights where min_rate is specified */
+ if (num_min_rated_tcs) {
+ for (tc = 0; tc != nic_cfg->tcs; tc++) {
+ if (!nic_cfg->tc_min_rate[tc]) {
+ tc_weight[tc] = 0;
+ continue;
+ }
+
+ tc_weight[tc] = (-1L + link_speed +
+ nic_cfg->tc_min_rate[tc] *
+ max_weight) /
+ link_speed;
+ tc_weight[tc] = min(tc_weight[tc], max_weight);
+ sum_weight += tc_weight[tc];
+ }
+ }
+
+ /* WSP, if min_rate is set for at least one TC.
+ * RR otherwise.
+ */
+ hw_atl_tps_tx_pkt_shed_data_arb_mode_set(self, min_rate_msk ? 1U : 0U);
+ /* Data TC Arbiter takes precedence over Descriptor TC Arbiter,
+ * leave Descriptor TC Arbiter as RR.
+ */
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);
+ u32 weight, max_credit;
- hw_atl_tps_tx_pkt_shed_desc_tc_max_credit_set(self, tc, 0x50);
+ hw_atl_tps_tx_pkt_shed_desc_tc_max_credit_set(self, tc,
+ fixed_max_credit);
hw_atl_tps_tx_pkt_shed_desc_tc_weight_set(self, tc, 0x1E);
+ if (num_min_rated_tcs) {
+ weight = tc_weight[tc];
+
+ if (!weight && sum_weight < max_weight)
+ weight = (max_weight - sum_weight) /
+ (nic_cfg->tcs - num_min_rated_tcs);
+ else if (!weight)
+ weight = 0x64;
+
+ max_credit = max(8 * weight, fixed_max_credit);
+ } else {
+ weight = 0x64;
+ max_credit = 0xFFF;
+ }
+
+ hw_atl_tps_tx_pkt_shed_tc_data_weight_set(self, tc, weight);
+ hw_atl_tps_tx_pkt_shed_tc_data_max_credit_set(self, tc,
+ max_credit);
+
hw_atl_tps_tx_desc_rate_en_set(self, desc, en);
if (en) {
@@ -1550,6 +1604,7 @@ const struct aq_hw_ops hw_atl_ops_b0 = {
.hw_interrupt_moderation_set = hw_atl_b0_hw_interrupt_moderation_set,
.hw_rss_set = hw_atl_b0_hw_rss_set,
.hw_rss_hash_set = hw_atl_b0_hw_rss_hash_set,
+ .hw_tc_rate_limit_set = hw_atl_b0_hw_init_tx_tc_rate_limit,
.hw_get_regs = hw_atl_utils_hw_get_regs,
.hw_get_hw_stats = hw_atl_utils_get_hw_stats,
.hw_get_fw_version = hw_atl_utils_get_fw_version,
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.h
index 992ee4ed37cc..b855459272ca 100644
--- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.h
+++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0.h
@@ -62,8 +62,6 @@ int hw_atl_b0_hw_mac_addr_set(struct aq_hw_s *self, u8 *mac_addr);
int hw_atl_b0_hw_start(struct aq_hw_s *self);
-int hw_atl_b0_hw_init_tx_tc_rate_limit(struct aq_hw_s *self);
-
int hw_atl_b0_hw_irq_enable(struct aq_hw_s *self, u64 mask);
int hw_atl_b0_hw_irq_disable(struct aq_hw_s *self, u64 mask);
int hw_atl_b0_hw_irq_read(struct aq_hw_s *self, u64 *mask);