diff options
11 files changed, 145 insertions, 45 deletions
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c index 6a633c70f603..99ef1daaa4d8 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c | |||
| @@ -407,13 +407,13 @@ static void aq_ethtool_get_pauseparam(struct net_device *ndev, | |||
| 407 | struct ethtool_pauseparam *pause) | 407 | struct ethtool_pauseparam *pause) |
| 408 | { | 408 | { |
| 409 | struct aq_nic_s *aq_nic = netdev_priv(ndev); | 409 | struct aq_nic_s *aq_nic = netdev_priv(ndev); |
| 410 | u32 fc = aq_nic->aq_nic_cfg.flow_control; | ||
| 410 | 411 | ||
| 411 | pause->autoneg = 0; | 412 | pause->autoneg = 0; |
| 412 | 413 | ||
| 413 | if (aq_nic->aq_hw->aq_nic_cfg->flow_control & AQ_NIC_FC_RX) | 414 | pause->rx_pause = !!(fc & AQ_NIC_FC_RX); |
| 414 | pause->rx_pause = 1; | 415 | pause->tx_pause = !!(fc & AQ_NIC_FC_TX); |
| 415 | if (aq_nic->aq_hw->aq_nic_cfg->flow_control & AQ_NIC_FC_TX) | 416 | |
| 416 | pause->tx_pause = 1; | ||
| 417 | } | 417 | } |
| 418 | 418 | ||
| 419 | static int aq_ethtool_set_pauseparam(struct net_device *ndev, | 419 | static int aq_ethtool_set_pauseparam(struct net_device *ndev, |
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h index e8689241204e..a1e70da358ca 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h | |||
| @@ -204,6 +204,10 @@ struct aq_hw_ops { | |||
| 204 | 204 | ||
| 205 | int (*hw_get_fw_version)(struct aq_hw_s *self, u32 *fw_version); | 205 | int (*hw_get_fw_version)(struct aq_hw_s *self, u32 *fw_version); |
| 206 | 206 | ||
| 207 | int (*hw_set_offload)(struct aq_hw_s *self, | ||
| 208 | struct aq_nic_cfg_s *aq_nic_cfg); | ||
| 209 | |||
| 210 | int (*hw_set_fc)(struct aq_hw_s *self, u32 fc, u32 tc); | ||
| 207 | }; | 211 | }; |
| 208 | 212 | ||
| 209 | struct aq_fw_ops { | 213 | struct aq_fw_ops { |
| @@ -226,6 +230,8 @@ struct aq_fw_ops { | |||
| 226 | 230 | ||
| 227 | int (*update_stats)(struct aq_hw_s *self); | 231 | int (*update_stats)(struct aq_hw_s *self); |
| 228 | 232 | ||
| 233 | u32 (*get_flow_control)(struct aq_hw_s *self, u32 *fcmode); | ||
| 234 | |||
| 229 | int (*set_flow_control)(struct aq_hw_s *self); | 235 | int (*set_flow_control)(struct aq_hw_s *self); |
| 230 | 236 | ||
| 231 | int (*set_power)(struct aq_hw_s *self, unsigned int power_state, | 237 | int (*set_power)(struct aq_hw_s *self, unsigned int power_state, |
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_main.c b/drivers/net/ethernet/aquantia/atlantic/aq_main.c index e3ae29e523f0..7c07eef275eb 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_main.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_main.c | |||
| @@ -99,8 +99,11 @@ static int aq_ndev_set_features(struct net_device *ndev, | |||
| 99 | struct aq_nic_s *aq_nic = netdev_priv(ndev); | 99 | struct aq_nic_s *aq_nic = netdev_priv(ndev); |
| 100 | struct aq_nic_cfg_s *aq_cfg = aq_nic_get_cfg(aq_nic); | 100 | struct aq_nic_cfg_s *aq_cfg = aq_nic_get_cfg(aq_nic); |
| 101 | bool is_lro = false; | 101 | bool is_lro = false; |
| 102 | int err = 0; | ||
| 103 | |||
| 104 | aq_cfg->features = features; | ||
| 102 | 105 | ||
| 103 | if (aq_cfg->hw_features & NETIF_F_LRO) { | 106 | if (aq_cfg->aq_hw_caps->hw_features & NETIF_F_LRO) { |
| 104 | is_lro = features & NETIF_F_LRO; | 107 | is_lro = features & NETIF_F_LRO; |
| 105 | 108 | ||
| 106 | if (aq_cfg->is_lro != is_lro) { | 109 | if (aq_cfg->is_lro != is_lro) { |
| @@ -112,8 +115,11 @@ static int aq_ndev_set_features(struct net_device *ndev, | |||
| 112 | } | 115 | } |
| 113 | } | 116 | } |
| 114 | } | 117 | } |
| 118 | if ((aq_nic->ndev->features ^ features) & NETIF_F_RXCSUM) | ||
| 119 | err = aq_nic->aq_hw_ops->hw_set_offload(aq_nic->aq_hw, | ||
| 120 | aq_cfg); | ||
| 115 | 121 | ||
| 116 | return 0; | 122 | return err; |
| 117 | } | 123 | } |
| 118 | 124 | ||
| 119 | static int aq_ndev_set_mac_address(struct net_device *ndev, void *addr) | 125 | static int aq_ndev_set_mac_address(struct net_device *ndev, void *addr) |
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index 5fed24446687..7abdc0952425 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c | |||
| @@ -118,12 +118,13 @@ void aq_nic_cfg_start(struct aq_nic_s *self) | |||
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | cfg->link_speed_msk &= cfg->aq_hw_caps->link_speed_msk; | 120 | cfg->link_speed_msk &= cfg->aq_hw_caps->link_speed_msk; |
| 121 | cfg->hw_features = cfg->aq_hw_caps->hw_features; | 121 | cfg->features = cfg->aq_hw_caps->hw_features; |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | static int aq_nic_update_link_status(struct aq_nic_s *self) | 124 | static int aq_nic_update_link_status(struct aq_nic_s *self) |
| 125 | { | 125 | { |
| 126 | int err = self->aq_fw_ops->update_link_status(self->aq_hw); | 126 | int err = self->aq_fw_ops->update_link_status(self->aq_hw); |
| 127 | u32 fc = 0; | ||
| 127 | 128 | ||
| 128 | if (err) | 129 | if (err) |
| 129 | return err; | 130 | return err; |
| @@ -133,6 +134,15 @@ static int aq_nic_update_link_status(struct aq_nic_s *self) | |||
| 133 | AQ_CFG_DRV_NAME, self->link_status.mbps, | 134 | AQ_CFG_DRV_NAME, self->link_status.mbps, |
| 134 | self->aq_hw->aq_link_status.mbps); | 135 | self->aq_hw->aq_link_status.mbps); |
| 135 | aq_nic_update_interrupt_moderation_settings(self); | 136 | aq_nic_update_interrupt_moderation_settings(self); |
| 137 | |||
| 138 | /* Driver has to update flow control settings on RX block | ||
| 139 | * on any link event. | ||
| 140 | * We should query FW whether it negotiated FC. | ||
| 141 | */ | ||
| 142 | if (self->aq_fw_ops->get_flow_control) | ||
| 143 | self->aq_fw_ops->get_flow_control(self->aq_hw, &fc); | ||
| 144 | if (self->aq_hw_ops->hw_set_fc) | ||
| 145 | self->aq_hw_ops->hw_set_fc(self->aq_hw, fc, 0); | ||
| 136 | } | 146 | } |
| 137 | 147 | ||
| 138 | self->link_status = self->aq_hw->aq_link_status; | 148 | self->link_status = self->aq_hw->aq_link_status; |
| @@ -590,7 +600,7 @@ int aq_nic_set_multicast_list(struct aq_nic_s *self, struct net_device *ndev) | |||
| 590 | } | 600 | } |
| 591 | } | 601 | } |
| 592 | 602 | ||
| 593 | if (i > 0 && i < AQ_HW_MULTICAST_ADDRESS_MAX) { | 603 | if (i > 0 && i <= AQ_HW_MULTICAST_ADDRESS_MAX) { |
| 594 | packet_filter |= IFF_MULTICAST; | 604 | packet_filter |= IFF_MULTICAST; |
| 595 | self->mc_list.count = i; | 605 | self->mc_list.count = i; |
| 596 | self->aq_hw_ops->hw_multicast_list_set(self->aq_hw, | 606 | self->aq_hw_ops->hw_multicast_list_set(self->aq_hw, |
| @@ -772,7 +782,9 @@ void aq_nic_get_link_ksettings(struct aq_nic_s *self, | |||
| 772 | ethtool_link_ksettings_add_link_mode(cmd, advertising, | 782 | ethtool_link_ksettings_add_link_mode(cmd, advertising, |
| 773 | Pause); | 783 | Pause); |
| 774 | 784 | ||
| 775 | if (self->aq_nic_cfg.flow_control & AQ_NIC_FC_TX) | 785 | /* Asym is when either RX or TX, but not both */ |
| 786 | if (!!(self->aq_nic_cfg.flow_control & AQ_NIC_FC_TX) ^ | ||
| 787 | !!(self->aq_nic_cfg.flow_control & AQ_NIC_FC_RX)) | ||
| 776 | ethtool_link_ksettings_add_link_mode(cmd, advertising, | 788 | ethtool_link_ksettings_add_link_mode(cmd, advertising, |
| 777 | Asym_Pause); | 789 | Asym_Pause); |
| 778 | 790 | ||
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h index c1582f4e8e1b..44ec47a3d60a 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h | |||
| @@ -23,7 +23,7 @@ struct aq_vec_s; | |||
| 23 | 23 | ||
| 24 | struct aq_nic_cfg_s { | 24 | struct aq_nic_cfg_s { |
| 25 | const struct aq_hw_caps_s *aq_hw_caps; | 25 | const struct aq_hw_caps_s *aq_hw_caps; |
| 26 | u64 hw_features; | 26 | u64 features; |
| 27 | u32 rxds; /* rx ring size, descriptors # */ | 27 | u32 rxds; /* rx ring size, descriptors # */ |
| 28 | u32 txds; /* tx ring size, descriptors # */ | 28 | u32 txds; /* tx ring size, descriptors # */ |
| 29 | u32 vecs; /* vecs==allocated irqs */ | 29 | u32 vecs; /* vecs==allocated irqs */ |
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c index 3db91446cc67..74550ccc7a20 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ring.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ring.c | |||
| @@ -172,6 +172,27 @@ bool aq_ring_tx_clean(struct aq_ring_s *self) | |||
| 172 | return !!budget; | 172 | return !!budget; |
| 173 | } | 173 | } |
| 174 | 174 | ||
| 175 | static void aq_rx_checksum(struct aq_ring_s *self, | ||
| 176 | struct aq_ring_buff_s *buff, | ||
| 177 | struct sk_buff *skb) | ||
| 178 | { | ||
| 179 | if (!(self->aq_nic->ndev->features & NETIF_F_RXCSUM)) | ||
| 180 | return; | ||
| 181 | |||
| 182 | if (unlikely(buff->is_cso_err)) { | ||
| 183 | ++self->stats.rx.errors; | ||
| 184 | skb->ip_summed = CHECKSUM_NONE; | ||
| 185 | return; | ||
| 186 | } | ||
| 187 | if (buff->is_ip_cso) { | ||
| 188 | __skb_incr_checksum_unnecessary(skb); | ||
| 189 | if (buff->is_udp_cso || buff->is_tcp_cso) | ||
| 190 | __skb_incr_checksum_unnecessary(skb); | ||
| 191 | } else { | ||
| 192 | skb->ip_summed = CHECKSUM_NONE; | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 175 | #define AQ_SKB_ALIGN SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) | 196 | #define AQ_SKB_ALIGN SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) |
| 176 | int aq_ring_rx_clean(struct aq_ring_s *self, | 197 | int aq_ring_rx_clean(struct aq_ring_s *self, |
| 177 | struct napi_struct *napi, | 198 | struct napi_struct *napi, |
| @@ -267,18 +288,8 @@ int aq_ring_rx_clean(struct aq_ring_s *self, | |||
| 267 | } | 288 | } |
| 268 | 289 | ||
| 269 | skb->protocol = eth_type_trans(skb, ndev); | 290 | skb->protocol = eth_type_trans(skb, ndev); |
| 270 | if (unlikely(buff->is_cso_err)) { | 291 | |
| 271 | ++self->stats.rx.errors; | 292 | aq_rx_checksum(self, buff, skb); |
| 272 | skb->ip_summed = CHECKSUM_NONE; | ||
| 273 | } else { | ||
| 274 | if (buff->is_ip_cso) { | ||
| 275 | __skb_incr_checksum_unnecessary(skb); | ||
| 276 | if (buff->is_udp_cso || buff->is_tcp_cso) | ||
| 277 | __skb_incr_checksum_unnecessary(skb); | ||
| 278 | } else { | ||
| 279 | skb->ip_summed = CHECKSUM_NONE; | ||
| 280 | } | ||
| 281 | } | ||
| 282 | 293 | ||
| 283 | skb_set_hash(skb, buff->rss_hash, | 294 | skb_set_hash(skb, buff->rss_hash, |
| 284 | buff->is_hash_l4 ? PKT_HASH_TYPE_L4 : | 295 | buff->is_hash_l4 ? PKT_HASH_TYPE_L4 : |
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 76d25d594a0f..f02592f43fe3 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 | |||
| @@ -100,12 +100,17 @@ static int hw_atl_b0_hw_reset(struct aq_hw_s *self) | |||
| 100 | return err; | 100 | return err; |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | static int hw_atl_b0_set_fc(struct aq_hw_s *self, u32 fc, u32 tc) | ||
| 104 | { | ||
| 105 | hw_atl_rpb_rx_xoff_en_per_tc_set(self, !!(fc & AQ_NIC_FC_RX), tc); | ||
| 106 | return 0; | ||
| 107 | } | ||
| 108 | |||
| 103 | static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self) | 109 | static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self) |
| 104 | { | 110 | { |
| 105 | u32 tc = 0U; | 111 | u32 tc = 0U; |
| 106 | u32 buff_size = 0U; | 112 | u32 buff_size = 0U; |
| 107 | unsigned int i_priority = 0U; | 113 | unsigned int i_priority = 0U; |
| 108 | bool is_rx_flow_control = false; | ||
| 109 | 114 | ||
| 110 | /* TPS Descriptor rate init */ | 115 | /* TPS Descriptor rate init */ |
| 111 | hw_atl_tps_tx_pkt_shed_desc_rate_curr_time_res_set(self, 0x0U); | 116 | hw_atl_tps_tx_pkt_shed_desc_rate_curr_time_res_set(self, 0x0U); |
| @@ -138,7 +143,6 @@ static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self) | |||
| 138 | 143 | ||
| 139 | /* QoS Rx buf size per TC */ | 144 | /* QoS Rx buf size per TC */ |
| 140 | tc = 0; | 145 | tc = 0; |
| 141 | is_rx_flow_control = (AQ_NIC_FC_RX & self->aq_nic_cfg->flow_control); | ||
| 142 | buff_size = HW_ATL_B0_RXBUF_MAX; | 146 | buff_size = HW_ATL_B0_RXBUF_MAX; |
| 143 | 147 | ||
| 144 | hw_atl_rpb_rx_pkt_buff_size_per_tc_set(self, buff_size, tc); | 148 | hw_atl_rpb_rx_pkt_buff_size_per_tc_set(self, buff_size, tc); |
| @@ -150,7 +154,8 @@ static int hw_atl_b0_hw_qos_set(struct aq_hw_s *self) | |||
| 150 | (buff_size * | 154 | (buff_size * |
| 151 | (1024U / 32U) * 50U) / | 155 | (1024U / 32U) * 50U) / |
| 152 | 100U, tc); | 156 | 100U, tc); |
| 153 | hw_atl_rpb_rx_xoff_en_per_tc_set(self, is_rx_flow_control ? 1U : 0U, tc); | 157 | |
| 158 | hw_atl_b0_set_fc(self, self->aq_nic_cfg->flow_control, tc); | ||
| 154 | 159 | ||
| 155 | /* QoS 802.1p priority -> TC mapping */ | 160 | /* QoS 802.1p priority -> TC mapping */ |
| 156 | for (i_priority = 8U; i_priority--;) | 161 | for (i_priority = 8U; i_priority--;) |
| @@ -229,8 +234,10 @@ static int hw_atl_b0_hw_offload_set(struct aq_hw_s *self, | |||
| 229 | hw_atl_tpo_tcp_udp_crc_offload_en_set(self, 1); | 234 | hw_atl_tpo_tcp_udp_crc_offload_en_set(self, 1); |
| 230 | 235 | ||
| 231 | /* RX checksums offloads*/ | 236 | /* RX checksums offloads*/ |
| 232 | hw_atl_rpo_ipv4header_crc_offload_en_set(self, 1); | 237 | hw_atl_rpo_ipv4header_crc_offload_en_set(self, !!(aq_nic_cfg->features & |
| 233 | hw_atl_rpo_tcp_udp_crc_offload_en_set(self, 1); | 238 | NETIF_F_RXCSUM)); |
| 239 | hw_atl_rpo_tcp_udp_crc_offload_en_set(self, !!(aq_nic_cfg->features & | ||
| 240 | NETIF_F_RXCSUM)); | ||
| 234 | 241 | ||
| 235 | /* LSO offloads*/ | 242 | /* LSO offloads*/ |
| 236 | hw_atl_tdm_large_send_offload_en_set(self, 0xFFFFFFFFU); | 243 | hw_atl_tdm_large_send_offload_en_set(self, 0xFFFFFFFFU); |
| @@ -655,9 +662,9 @@ static int hw_atl_b0_hw_ring_rx_receive(struct aq_hw_s *self, | |||
| 655 | struct hw_atl_rxd_wb_s *rxd_wb = (struct hw_atl_rxd_wb_s *) | 662 | struct hw_atl_rxd_wb_s *rxd_wb = (struct hw_atl_rxd_wb_s *) |
| 656 | &ring->dx_ring[ring->hw_head * HW_ATL_B0_RXD_SIZE]; | 663 | &ring->dx_ring[ring->hw_head * HW_ATL_B0_RXD_SIZE]; |
| 657 | 664 | ||
| 658 | unsigned int is_err = 1U; | ||
| 659 | unsigned int is_rx_check_sum_enabled = 0U; | 665 | unsigned int is_rx_check_sum_enabled = 0U; |
| 660 | unsigned int pkt_type = 0U; | 666 | unsigned int pkt_type = 0U; |
| 667 | u8 rx_stat = 0U; | ||
| 661 | 668 | ||
| 662 | if (!(rxd_wb->status & 0x1U)) { /* RxD is not done */ | 669 | if (!(rxd_wb->status & 0x1U)) { /* RxD is not done */ |
| 663 | break; | 670 | break; |
| @@ -665,35 +672,35 @@ static int hw_atl_b0_hw_ring_rx_receive(struct aq_hw_s *self, | |||
| 665 | 672 | ||
| 666 | buff = &ring->buff_ring[ring->hw_head]; | 673 | buff = &ring->buff_ring[ring->hw_head]; |
| 667 | 674 | ||
| 668 | is_err = (0x0000003CU & rxd_wb->status); | 675 | rx_stat = (0x0000003CU & rxd_wb->status) >> 2; |
| 669 | 676 | ||
| 670 | is_rx_check_sum_enabled = (rxd_wb->type) & (0x3U << 19); | 677 | is_rx_check_sum_enabled = (rxd_wb->type) & (0x3U << 19); |
| 671 | is_err &= ~0x20U; /* exclude validity bit */ | ||
| 672 | 678 | ||
| 673 | pkt_type = 0xFFU & (rxd_wb->type >> 4); | 679 | pkt_type = 0xFFU & (rxd_wb->type >> 4); |
| 674 | 680 | ||
| 675 | if (is_rx_check_sum_enabled) { | 681 | if (is_rx_check_sum_enabled & BIT(0) && |
| 676 | if (0x0U == (pkt_type & 0x3U)) | 682 | (0x0U == (pkt_type & 0x3U))) |
| 677 | buff->is_ip_cso = (is_err & 0x08U) ? 0U : 1U; | 683 | buff->is_ip_cso = (rx_stat & BIT(1)) ? 0U : 1U; |
| 678 | 684 | ||
| 685 | if (is_rx_check_sum_enabled & BIT(1)) { | ||
| 679 | if (0x4U == (pkt_type & 0x1CU)) | 686 | if (0x4U == (pkt_type & 0x1CU)) |
| 680 | buff->is_udp_cso = buff->is_cso_err ? 0U : 1U; | 687 | buff->is_udp_cso = (rx_stat & BIT(2)) ? 0U : |
| 688 | !!(rx_stat & BIT(3)); | ||
| 681 | else if (0x0U == (pkt_type & 0x1CU)) | 689 | else if (0x0U == (pkt_type & 0x1CU)) |
| 682 | buff->is_tcp_cso = buff->is_cso_err ? 0U : 1U; | 690 | buff->is_tcp_cso = (rx_stat & BIT(2)) ? 0U : |
| 683 | 691 | !!(rx_stat & BIT(3)); | |
| 684 | /* Checksum offload workaround for small packets */ | 692 | } |
| 685 | if (rxd_wb->pkt_len <= 60) { | 693 | buff->is_cso_err = !!(rx_stat & 0x6); |
| 686 | buff->is_ip_cso = 0U; | 694 | /* Checksum offload workaround for small packets */ |
| 687 | buff->is_cso_err = 0U; | 695 | if (unlikely(rxd_wb->pkt_len <= 60)) { |
| 688 | } | 696 | buff->is_ip_cso = 0U; |
| 697 | buff->is_cso_err = 0U; | ||
| 689 | } | 698 | } |
| 690 | |||
| 691 | is_err &= ~0x18U; | ||
| 692 | 699 | ||
| 693 | dma_unmap_page(ndev, buff->pa, buff->len, DMA_FROM_DEVICE); | 700 | dma_unmap_page(ndev, buff->pa, buff->len, DMA_FROM_DEVICE); |
| 694 | 701 | ||
| 695 | if (is_err || rxd_wb->type & 0x1000U) { | 702 | if ((rx_stat & BIT(0)) || rxd_wb->type & 0x1000U) { |
| 696 | /* status error or DMA error */ | 703 | /* MAC error or DMA error */ |
| 697 | buff->is_error = 1U; | 704 | buff->is_error = 1U; |
| 698 | } else { | 705 | } else { |
| 699 | if (self->aq_nic_cfg->is_rss) { | 706 | if (self->aq_nic_cfg->is_rss) { |
| @@ -915,6 +922,12 @@ static int hw_atl_b0_hw_interrupt_moderation_set(struct aq_hw_s *self) | |||
| 915 | static int hw_atl_b0_hw_stop(struct aq_hw_s *self) | 922 | static int hw_atl_b0_hw_stop(struct aq_hw_s *self) |
| 916 | { | 923 | { |
| 917 | hw_atl_b0_hw_irq_disable(self, HW_ATL_B0_INT_MASK); | 924 | hw_atl_b0_hw_irq_disable(self, HW_ATL_B0_INT_MASK); |
| 925 | |||
| 926 | /* Invalidate Descriptor Cache to prevent writing to the cached | ||
| 927 | * descriptors and to the data pointer of those descriptors | ||
| 928 | */ | ||
| 929 | hw_atl_rdm_rx_dma_desc_cache_init_set(self, 1); | ||
| 930 | |||
| 918 | return aq_hw_err_from_flags(self); | 931 | return aq_hw_err_from_flags(self); |
| 919 | } | 932 | } |
| 920 | 933 | ||
| @@ -963,4 +976,6 @@ const struct aq_hw_ops hw_atl_ops_b0 = { | |||
| 963 | .hw_get_regs = hw_atl_utils_hw_get_regs, | 976 | .hw_get_regs = hw_atl_utils_hw_get_regs, |
| 964 | .hw_get_hw_stats = hw_atl_utils_get_hw_stats, | 977 | .hw_get_hw_stats = hw_atl_utils_get_hw_stats, |
| 965 | .hw_get_fw_version = hw_atl_utils_get_fw_version, | 978 | .hw_get_fw_version = hw_atl_utils_get_fw_version, |
| 979 | .hw_set_offload = hw_atl_b0_hw_offload_set, | ||
| 980 | .hw_set_fc = hw_atl_b0_set_fc, | ||
| 966 | }; | 981 | }; |
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c index be0a3a90dfad..5502ec5f0f69 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.c | |||
| @@ -619,6 +619,14 @@ void hw_atl_rpb_rx_flow_ctl_mode_set(struct aq_hw_s *aq_hw, u32 rx_flow_ctl_mode | |||
| 619 | HW_ATL_RPB_RX_FC_MODE_SHIFT, rx_flow_ctl_mode); | 619 | HW_ATL_RPB_RX_FC_MODE_SHIFT, rx_flow_ctl_mode); |
| 620 | } | 620 | } |
| 621 | 621 | ||
| 622 | void hw_atl_rdm_rx_dma_desc_cache_init_set(struct aq_hw_s *aq_hw, u32 init) | ||
| 623 | { | ||
| 624 | aq_hw_write_reg_bit(aq_hw, HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_ADR, | ||
| 625 | HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_MSK, | ||
| 626 | HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_SHIFT, | ||
| 627 | init); | ||
| 628 | } | ||
| 629 | |||
| 622 | void hw_atl_rpb_rx_pkt_buff_size_per_tc_set(struct aq_hw_s *aq_hw, | 630 | void hw_atl_rpb_rx_pkt_buff_size_per_tc_set(struct aq_hw_s *aq_hw, |
| 623 | u32 rx_pkt_buff_size_per_tc, u32 buffer) | 631 | u32 rx_pkt_buff_size_per_tc, u32 buffer) |
| 624 | { | 632 | { |
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h index 7056c7342afc..41f239928c15 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh.h | |||
| @@ -325,6 +325,9 @@ void hw_atl_rpb_rx_pkt_buff_size_per_tc_set(struct aq_hw_s *aq_hw, | |||
| 325 | u32 rx_pkt_buff_size_per_tc, | 325 | u32 rx_pkt_buff_size_per_tc, |
| 326 | u32 buffer); | 326 | u32 buffer); |
| 327 | 327 | ||
| 328 | /* set rdm rx dma descriptor cache init */ | ||
| 329 | void hw_atl_rdm_rx_dma_desc_cache_init_set(struct aq_hw_s *aq_hw, u32 init); | ||
| 330 | |||
| 328 | /* set rx xoff enable (per tc) */ | 331 | /* set rx xoff enable (per tc) */ |
| 329 | void hw_atl_rpb_rx_xoff_en_per_tc_set(struct aq_hw_s *aq_hw, u32 rx_xoff_en_per_tc, | 332 | void hw_atl_rpb_rx_xoff_en_per_tc_set(struct aq_hw_s *aq_hw, u32 rx_xoff_en_per_tc, |
| 330 | u32 buffer); | 333 | u32 buffer); |
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h index 716674a9b729..a715fa317b1c 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_llh_internal.h | |||
| @@ -293,6 +293,24 @@ | |||
| 293 | /* default value of bitfield desc{d}_reset */ | 293 | /* default value of bitfield desc{d}_reset */ |
| 294 | #define HW_ATL_RDM_DESCDRESET_DEFAULT 0x0 | 294 | #define HW_ATL_RDM_DESCDRESET_DEFAULT 0x0 |
| 295 | 295 | ||
| 296 | /* rdm_desc_init_i bitfield definitions | ||
| 297 | * preprocessor definitions for the bitfield rdm_desc_init_i. | ||
| 298 | * port="pif_rdm_desc_init_i" | ||
| 299 | */ | ||
| 300 | |||
| 301 | /* register address for bitfield rdm_desc_init_i */ | ||
| 302 | #define HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_ADR 0x00005a00 | ||
| 303 | /* bitmask for bitfield rdm_desc_init_i */ | ||
| 304 | #define HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_MSK 0xffffffff | ||
| 305 | /* inverted bitmask for bitfield rdm_desc_init_i */ | ||
| 306 | #define HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_MSKN 0x00000000 | ||
| 307 | /* lower bit position of bitfield rdm_desc_init_i */ | ||
| 308 | #define HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_SHIFT 0 | ||
| 309 | /* width of bitfield rdm_desc_init_i */ | ||
| 310 | #define HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_WIDTH 32 | ||
| 311 | /* default value of bitfield rdm_desc_init_i */ | ||
| 312 | #define HW_ATL_RDM_RX_DMA_DESC_CACHE_INIT_DEFAULT 0x0 | ||
| 313 | |||
| 296 | /* rx int_desc_wrb_en bitfield definitions | 314 | /* rx int_desc_wrb_en bitfield definitions |
| 297 | * preprocessor definitions for the bitfield "int_desc_wrb_en". | 315 | * preprocessor definitions for the bitfield "int_desc_wrb_en". |
| 298 | * port="pif_rdm_int_desc_wrb_en_i" | 316 | * port="pif_rdm_int_desc_wrb_en_i" |
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c index 096ca5730887..7de3220d9cab 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c | |||
| @@ -30,6 +30,8 @@ | |||
| 30 | #define HW_ATL_FW2X_MPI_STATE_ADDR 0x370 | 30 | #define HW_ATL_FW2X_MPI_STATE_ADDR 0x370 |
| 31 | #define HW_ATL_FW2X_MPI_STATE2_ADDR 0x374 | 31 | #define HW_ATL_FW2X_MPI_STATE2_ADDR 0x374 |
| 32 | 32 | ||
| 33 | #define HW_ATL_FW2X_CAP_PAUSE BIT(CAPS_HI_PAUSE) | ||
| 34 | #define HW_ATL_FW2X_CAP_ASYM_PAUSE BIT(CAPS_HI_ASYMMETRIC_PAUSE) | ||
| 33 | #define HW_ATL_FW2X_CAP_SLEEP_PROXY BIT(CAPS_HI_SLEEP_PROXY) | 35 | #define HW_ATL_FW2X_CAP_SLEEP_PROXY BIT(CAPS_HI_SLEEP_PROXY) |
| 34 | #define HW_ATL_FW2X_CAP_WOL BIT(CAPS_HI_WOL) | 36 | #define HW_ATL_FW2X_CAP_WOL BIT(CAPS_HI_WOL) |
| 35 | 37 | ||
| @@ -451,6 +453,24 @@ static int aq_fw2x_set_flow_control(struct aq_hw_s *self) | |||
| 451 | return 0; | 453 | return 0; |
| 452 | } | 454 | } |
| 453 | 455 | ||
| 456 | static u32 aq_fw2x_get_flow_control(struct aq_hw_s *self, u32 *fcmode) | ||
| 457 | { | ||
| 458 | u32 mpi_state = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR); | ||
| 459 | |||
| 460 | if (mpi_state & HW_ATL_FW2X_CAP_PAUSE) | ||
| 461 | if (mpi_state & HW_ATL_FW2X_CAP_ASYM_PAUSE) | ||
| 462 | *fcmode = AQ_NIC_FC_RX; | ||
| 463 | else | ||
| 464 | *fcmode = AQ_NIC_FC_RX | AQ_NIC_FC_TX; | ||
| 465 | else | ||
| 466 | if (mpi_state & HW_ATL_FW2X_CAP_ASYM_PAUSE) | ||
| 467 | *fcmode = AQ_NIC_FC_TX; | ||
| 468 | else | ||
| 469 | *fcmode = 0; | ||
| 470 | |||
| 471 | return 0; | ||
| 472 | } | ||
| 473 | |||
| 454 | const struct aq_fw_ops aq_fw_2x_ops = { | 474 | const struct aq_fw_ops aq_fw_2x_ops = { |
| 455 | .init = aq_fw2x_init, | 475 | .init = aq_fw2x_init, |
| 456 | .deinit = aq_fw2x_deinit, | 476 | .deinit = aq_fw2x_deinit, |
| @@ -465,4 +485,5 @@ const struct aq_fw_ops aq_fw_2x_ops = { | |||
| 465 | .set_eee_rate = aq_fw2x_set_eee_rate, | 485 | .set_eee_rate = aq_fw2x_set_eee_rate, |
| 466 | .get_eee_rate = aq_fw2x_get_eee_rate, | 486 | .get_eee_rate = aq_fw2x_get_eee_rate, |
| 467 | .set_flow_control = aq_fw2x_set_flow_control, | 487 | .set_flow_control = aq_fw2x_set_flow_control, |
| 488 | .get_flow_control = aq_fw2x_get_flow_control | ||
| 468 | }; | 489 | }; |
