diff options
author | Dmitry Bezrukov <dbezrukov@marvell.com> | 2020-05-22 11:19:40 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2020-05-22 14:08:28 -0700 |
commit | a83fe6b6ad6b10f6912025ae23bd5c2596a4e7f4 (patch) | |
tree | f6a62568c6f6ed691faea395159b5417b3d6ee9a /drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c | |
parent | 0aa7bc3ee4652e0790f9b42c93c769b59b9f2308 (diff) |
net: atlantic: QoS implementation: multi-TC support
This patch adds multi-TC support.
PTP is automatically disabled when the user enables more than 2 TCs,
otherwise traffic on TC2 won't quite work, because it's reserved for PTP.
Signed-off-by: Dmitry Bezrukov <dbezrukov@marvell.com>
Co-developed-by: Dmitry Bogdanov <dbogdanov@marvell.com>
Signed-off-by: Dmitry Bogdanov <dbogdanov@marvell.com>
Co-developed-by: Mark Starovoytov <mstarovoitov@marvell.com>
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_atl2/hw_atl2.c')
-rw-r--r-- | drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c | 122 |
1 files changed, 71 insertions, 51 deletions
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c index a14118550882..05c049661b2e 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2.c @@ -47,7 +47,8 @@ static int hw_atl2_act_rslvr_table_set(struct aq_hw_s *self, u8 location, NETIF_F_HW_VLAN_CTAG_RX | \ NETIF_F_HW_VLAN_CTAG_TX | \ NETIF_F_GSO_UDP_L4 | \ - NETIF_F_GSO_PARTIAL, \ + NETIF_F_GSO_PARTIAL | \ + NETIF_F_HW_TC, \ .hw_priv_flags = IFF_UNICAST_FLT, \ .flow_control = true, \ .mtu = HW_ATL2_MTU_JUMBO, \ @@ -132,7 +133,6 @@ static int hw_atl2_hw_qos_set(struct aq_hw_s *self) u32 tx_buff_size = HW_ATL2_TXBUF_MAX; u32 rx_buff_size = HW_ATL2_RXBUF_MAX; unsigned int prio = 0U; - u32 threshold = 0U; u32 tc = 0U; /* TPS Descriptor rate init */ @@ -146,34 +146,41 @@ static int hw_atl2_hw_qos_set(struct aq_hw_s *self) 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 Packet Scheduler Data TC0 */ - hw_atl2_tps_tx_pkt_shed_tc_data_max_credit_set(self, 0xFFF0, tc); - hw_atl2_tps_tx_pkt_shed_tc_data_weight_set(self, 0x640, 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_buff_size /= cfg->tcs; + rx_buff_size /= cfg->tcs; + for (tc = 0; tc < cfg->tcs; tc++) { + u32 threshold = 0U; - /* Tx buf size TC0 */ - hw_atl_tpb_tx_pkt_buff_size_per_tc_set(self, tx_buff_size, tc); + /* TX Packet Scheduler Data TC0 */ + hw_atl2_tps_tx_pkt_shed_tc_data_max_credit_set(self, 0xFFF0, + tc); + hw_atl2_tps_tx_pkt_shed_tc_data_weight_set(self, 0x640, 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); - threshold = (tx_buff_size * (1024 / 32U) * 66U) / 100U; - hw_atl_tpb_tx_buff_hi_threshold_per_tc_set(self, threshold, tc); + /* Tx buf size TC0 */ + hw_atl_tpb_tx_pkt_buff_size_per_tc_set(self, tx_buff_size, tc); - threshold = (tx_buff_size * (1024 / 32U) * 50U) / 100U; - hw_atl_tpb_tx_buff_lo_threshold_per_tc_set(self, threshold, tc); + threshold = (tx_buff_size * (1024 / 32U) * 66U) / 100U; + hw_atl_tpb_tx_buff_hi_threshold_per_tc_set(self, threshold, tc); - /* QoS Rx buf size per TC */ - hw_atl_rpb_rx_pkt_buff_size_per_tc_set(self, rx_buff_size, tc); + threshold = (tx_buff_size * (1024 / 32U) * 50U) / 100U; + hw_atl_tpb_tx_buff_lo_threshold_per_tc_set(self, threshold, tc); - threshold = (rx_buff_size * (1024U / 32U) * 66U) / 100U; - hw_atl_rpb_rx_buff_hi_threshold_per_tc_set(self, threshold, tc); + /* QoS Rx buf size per TC */ + hw_atl_rpb_rx_pkt_buff_size_per_tc_set(self, rx_buff_size, tc); - threshold = (rx_buff_size * (1024U / 32U) * 50U) / 100U; - hw_atl_rpb_rx_buff_lo_threshold_per_tc_set(self, threshold, tc); + threshold = (rx_buff_size * (1024U / 32U) * 66U) / 100U; + hw_atl_rpb_rx_buff_hi_threshold_per_tc_set(self, threshold, tc); + + threshold = (rx_buff_size * (1024U / 32U) * 50U) / 100U; + hw_atl_rpb_rx_buff_lo_threshold_per_tc_set(self, threshold, tc); + } /* QoS 802.1p priority -> TC mapping */ for (prio = 0; prio < 8; ++prio) hw_atl_rpf_rpb_user_priority_tc_map_set(self, prio, - cfg->tcs * prio / 8); + cfg->prio_tc_map[prio]); /* ATL2 Apply legacy ring to TC mapping */ hw_atl2_hw_queue_to_tc_map_set(self); @@ -184,11 +191,24 @@ static int hw_atl2_hw_qos_set(struct aq_hw_s *self) static int hw_atl2_hw_rss_set(struct aq_hw_s *self, struct aq_rss_parameters *rss_params) { - u8 *indirection_table = rss_params->indirection_table; + u8 *indirection_table = rss_params->indirection_table; + const u32 num_tcs = aq_hw_num_tcs(self); + u32 rpf_redir2_enable; + int tc; int i; - for (i = HW_ATL2_RSS_REDIRECTION_MAX; i--;) - hw_atl2_new_rpf_rss_redir_set(self, 0, i, indirection_table[i]); + rpf_redir2_enable = num_tcs > 4 ? 1 : 0; + + hw_atl2_rpf_redirection_table2_select_set(self, rpf_redir2_enable); + + for (i = HW_ATL2_RSS_REDIRECTION_MAX; i--;) { + for (tc = 0; tc != num_tcs; tc++) { + hw_atl2_new_rpf_rss_redir_set(self, tc, i, + tc * + aq_hw_q_per_tc(self) + + indirection_table[i]); + } + } return aq_hw_err_from_flags(self); } @@ -196,7 +216,7 @@ static int hw_atl2_hw_rss_set(struct aq_hw_s *self, static int hw_atl2_hw_init_tx_path(struct aq_hw_s *self) { /* Tx TC/RSS number config */ - hw_atl_tpb_tps_tx_tc_mode_set(self, 1U); + hw_atl_tpb_tps_tx_tc_mode_set(self, self->aq_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); @@ -219,13 +239,29 @@ static int hw_atl2_hw_init_tx_path(struct aq_hw_s *self) static void hw_atl2_hw_init_new_rx_filters(struct aq_hw_s *self) { struct hw_atl2_priv *priv = (struct hw_atl2_priv *)self->priv; + u8 *prio_tc_map = self->aq_nic_cfg->prio_tc_map; + u16 action; u8 index; + int i; + /* Action Resolver Table (ART) is used by RPF to decide which action + * to take with a packet based upon input tag and tag mask, where: + * - input tag is a combination of 3-bit VLan Prio (PTP) and + * 29-bit concatenation of all tags from filter block; + * - tag mask is a mask used for matching against input tag. + * The input_tag is compared with the all the Requested_tags in the + * Record table to find a match. Action field of the selected matched + * REC entry is used for further processing. If multiple entries match, + * the lowest REC entry, Action field will be selected. + */ hw_atl2_rpf_act_rslvr_section_en_set(self, 0xFFFF); hw_atl2_rpfl2_uc_flr_tag_set(self, HW_ATL2_RPF_TAG_BASE_UC, HW_ATL2_MAC_UC); hw_atl2_rpfl2_bc_flr_tag_set(self, HW_ATL2_RPF_TAG_BASE_UC); + /* FW reserves the beginning of ART, thus all driver entries must + * start from the offset specified in FW caps. + */ index = priv->art_base_index + HW_ATL2_RPF_L2_PROMISC_OFF_INDEX; hw_atl2_act_rslvr_table_set(self, index, 0, HW_ATL2_RPF_TAG_UC_MASK | @@ -238,33 +274,17 @@ static void hw_atl2_hw_init_new_rx_filters(struct aq_hw_s *self) HW_ATL2_RPF_TAG_UNTAG_MASK, HW_ATL2_ACTION_DROP); - index = priv->art_base_index + HW_ATL2_RPF_VLAN_INDEX; - hw_atl2_act_rslvr_table_set(self, index, HW_ATL2_RPF_TAG_BASE_VLAN, - HW_ATL2_RPF_TAG_VLAN_MASK, - HW_ATL2_ACTION_ASSIGN_TC(0)); + /* Configure ART to map given VLan Prio (PCP) to the TC index for + * RSS redirection table. + */ + for (i = 0; i < 8; i++) { + action = HW_ATL2_ACTION_ASSIGN_TC(prio_tc_map[i]); - index = priv->art_base_index + HW_ATL2_RPF_MAC_INDEX; - hw_atl2_act_rslvr_table_set(self, index, HW_ATL2_RPF_TAG_BASE_UC, - HW_ATL2_RPF_TAG_UC_MASK, - HW_ATL2_ACTION_ASSIGN_TC(0)); - - index = priv->art_base_index + HW_ATL2_RPF_ALLMC_INDEX; - hw_atl2_act_rslvr_table_set(self, index, HW_ATL2_RPF_TAG_BASE_ALLMC, - HW_ATL2_RPF_TAG_ALLMC_MASK, - HW_ATL2_ACTION_ASSIGN_TC(0)); - - index = priv->art_base_index + HW_ATL2_RPF_UNTAG_INDEX; - hw_atl2_act_rslvr_table_set(self, index, HW_ATL2_RPF_TAG_UNTAG_MASK, - HW_ATL2_RPF_TAG_UNTAG_MASK, - HW_ATL2_ACTION_ASSIGN_TC(0)); - - index = priv->art_base_index + HW_ATL2_RPF_VLAN_PROMISC_ON_INDEX; - hw_atl2_act_rslvr_table_set(self, index, 0, HW_ATL2_RPF_TAG_VLAN_MASK, - HW_ATL2_ACTION_DISABLE); - - index = priv->art_base_index + HW_ATL2_RPF_L2_PROMISC_ON_INDEX; - hw_atl2_act_rslvr_table_set(self, index, 0, HW_ATL2_RPF_TAG_UC_MASK, - HW_ATL2_ACTION_DISABLE); + index = priv->art_base_index + HW_ATL2_RPF_PCP_TO_TC_INDEX + i; + hw_atl2_act_rslvr_table_set(self, index, + i << HW_ATL2_RPF_TAG_PCP_OFFSET, + HW_ATL2_RPF_TAG_PCP_MASK, action); + } } static void hw_atl2_hw_new_rx_filter_vlan_promisc(struct aq_hw_s *self, @@ -327,7 +347,7 @@ static int hw_atl2_hw_init_rx_path(struct aq_hw_s *self) int i; /* Rx TC/RSS number config */ - hw_atl_rpb_rpf_rx_traf_class_mode_set(self, 1U); + hw_atl_rpb_rpf_rx_traf_class_mode_set(self, cfg->tc_mode); /* Rx flow control */ hw_atl_rpb_rx_flow_ctl_mode_set(self, 1U); |