diff options
12 files changed, 284 insertions, 146 deletions
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h index 0fdaaa643073..57e796870595 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_cfg.h | |||
| @@ -22,8 +22,12 @@ | |||
| 22 | 22 | ||
| 23 | #define AQ_CFG_FORCE_LEGACY_INT 0U | 23 | #define AQ_CFG_FORCE_LEGACY_INT 0U |
| 24 | 24 | ||
| 25 | #define AQ_CFG_IS_INTERRUPT_MODERATION_DEF 1U | 25 | #define AQ_CFG_INTERRUPT_MODERATION_OFF 0 |
| 26 | #define AQ_CFG_INTERRUPT_MODERATION_RATE_DEF 0xFFFFU | 26 | #define AQ_CFG_INTERRUPT_MODERATION_ON 1 |
| 27 | #define AQ_CFG_INTERRUPT_MODERATION_AUTO 0xFFFFU | ||
| 28 | |||
| 29 | #define AQ_CFG_INTERRUPT_MODERATION_USEC_MAX (0x1FF * 2) | ||
| 30 | |||
| 27 | #define AQ_CFG_IRQ_MASK 0x1FFU | 31 | #define AQ_CFG_IRQ_MASK 0x1FFU |
| 28 | 32 | ||
| 29 | #define AQ_CFG_VECS_MAX 8U | 33 | #define AQ_CFG_VECS_MAX 8U |
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c index a761e91471df..d5e99b468870 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c | |||
| @@ -56,10 +56,6 @@ aq_ethtool_set_link_ksettings(struct net_device *ndev, | |||
| 56 | return aq_nic_set_link_ksettings(aq_nic, cmd); | 56 | return aq_nic_set_link_ksettings(aq_nic, cmd); |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | /* there "5U" is number of queue[#] stats lines (InPackets+...+InErrors) */ | ||
| 60 | static const unsigned int aq_ethtool_stat_queue_lines = 5U; | ||
| 61 | static const unsigned int aq_ethtool_stat_queue_chars = | ||
| 62 | 5U * ETH_GSTRING_LEN; | ||
| 63 | static const char aq_ethtool_stat_names[][ETH_GSTRING_LEN] = { | 59 | static const char aq_ethtool_stat_names[][ETH_GSTRING_LEN] = { |
| 64 | "InPackets", | 60 | "InPackets", |
| 65 | "InUCast", | 61 | "InUCast", |
| @@ -83,56 +79,26 @@ static const char aq_ethtool_stat_names[][ETH_GSTRING_LEN] = { | |||
| 83 | "InOctetsDma", | 79 | "InOctetsDma", |
| 84 | "OutOctetsDma", | 80 | "OutOctetsDma", |
| 85 | "InDroppedDma", | 81 | "InDroppedDma", |
| 86 | "Queue[0] InPackets", | 82 | }; |
| 87 | "Queue[0] OutPackets", | 83 | |
| 88 | "Queue[0] InJumboPackets", | 84 | static const char aq_ethtool_queue_stat_names[][ETH_GSTRING_LEN] = { |
| 89 | "Queue[0] InLroPackets", | 85 | "Queue[%d] InPackets", |
| 90 | "Queue[0] InErrors", | 86 | "Queue[%d] OutPackets", |
| 91 | "Queue[1] InPackets", | 87 | "Queue[%d] Restarts", |
| 92 | "Queue[1] OutPackets", | 88 | "Queue[%d] InJumboPackets", |
| 93 | "Queue[1] InJumboPackets", | 89 | "Queue[%d] InLroPackets", |
| 94 | "Queue[1] InLroPackets", | 90 | "Queue[%d] InErrors", |
| 95 | "Queue[1] InErrors", | ||
| 96 | "Queue[2] InPackets", | ||
| 97 | "Queue[2] OutPackets", | ||
| 98 | "Queue[2] InJumboPackets", | ||
| 99 | "Queue[2] InLroPackets", | ||
| 100 | "Queue[2] InErrors", | ||
| 101 | "Queue[3] InPackets", | ||
| 102 | "Queue[3] OutPackets", | ||
| 103 | "Queue[3] InJumboPackets", | ||
| 104 | "Queue[3] InLroPackets", | ||
| 105 | "Queue[3] InErrors", | ||
| 106 | "Queue[4] InPackets", | ||
| 107 | "Queue[4] OutPackets", | ||
| 108 | "Queue[4] InJumboPackets", | ||
| 109 | "Queue[4] InLroPackets", | ||
| 110 | "Queue[4] InErrors", | ||
| 111 | "Queue[5] InPackets", | ||
| 112 | "Queue[5] OutPackets", | ||
| 113 | "Queue[5] InJumboPackets", | ||
| 114 | "Queue[5] InLroPackets", | ||
| 115 | "Queue[5] InErrors", | ||
| 116 | "Queue[6] InPackets", | ||
| 117 | "Queue[6] OutPackets", | ||
| 118 | "Queue[6] InJumboPackets", | ||
| 119 | "Queue[6] InLroPackets", | ||
| 120 | "Queue[6] InErrors", | ||
| 121 | "Queue[7] InPackets", | ||
| 122 | "Queue[7] OutPackets", | ||
| 123 | "Queue[7] InJumboPackets", | ||
| 124 | "Queue[7] InLroPackets", | ||
| 125 | "Queue[7] InErrors", | ||
| 126 | }; | 91 | }; |
| 127 | 92 | ||
| 128 | static void aq_ethtool_stats(struct net_device *ndev, | 93 | static void aq_ethtool_stats(struct net_device *ndev, |
| 129 | struct ethtool_stats *stats, u64 *data) | 94 | struct ethtool_stats *stats, u64 *data) |
| 130 | { | 95 | { |
| 131 | struct aq_nic_s *aq_nic = netdev_priv(ndev); | 96 | struct aq_nic_s *aq_nic = netdev_priv(ndev); |
| 97 | struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); | ||
| 132 | 98 | ||
| 133 | /* ASSERT: Need add lines to aq_ethtool_stat_names if AQ_CFG_VECS_MAX > 8 */ | 99 | memset(data, 0, (ARRAY_SIZE(aq_ethtool_stat_names) + |
| 134 | BUILD_BUG_ON(AQ_CFG_VECS_MAX > 8); | 100 | ARRAY_SIZE(aq_ethtool_queue_stat_names) * |
| 135 | memset(data, 0, ARRAY_SIZE(aq_ethtool_stat_names) * sizeof(u64)); | 101 | cfg->vecs) * sizeof(u64)); |
| 136 | aq_nic_get_stats(aq_nic, data); | 102 | aq_nic_get_stats(aq_nic, data); |
| 137 | } | 103 | } |
| 138 | 104 | ||
| @@ -154,8 +120,8 @@ static void aq_ethtool_get_drvinfo(struct net_device *ndev, | |||
| 154 | 120 | ||
| 155 | strlcpy(drvinfo->bus_info, pdev ? pci_name(pdev) : "", | 121 | strlcpy(drvinfo->bus_info, pdev ? pci_name(pdev) : "", |
| 156 | sizeof(drvinfo->bus_info)); | 122 | sizeof(drvinfo->bus_info)); |
| 157 | drvinfo->n_stats = ARRAY_SIZE(aq_ethtool_stat_names) - | 123 | drvinfo->n_stats = ARRAY_SIZE(aq_ethtool_stat_names) + |
| 158 | (AQ_CFG_VECS_MAX - cfg->vecs) * aq_ethtool_stat_queue_lines; | 124 | cfg->vecs * ARRAY_SIZE(aq_ethtool_queue_stat_names); |
| 159 | drvinfo->testinfo_len = 0; | 125 | drvinfo->testinfo_len = 0; |
| 160 | drvinfo->regdump_len = regs_count; | 126 | drvinfo->regdump_len = regs_count; |
| 161 | drvinfo->eedump_len = 0; | 127 | drvinfo->eedump_len = 0; |
| @@ -164,14 +130,25 @@ static void aq_ethtool_get_drvinfo(struct net_device *ndev, | |||
| 164 | static void aq_ethtool_get_strings(struct net_device *ndev, | 130 | static void aq_ethtool_get_strings(struct net_device *ndev, |
| 165 | u32 stringset, u8 *data) | 131 | u32 stringset, u8 *data) |
| 166 | { | 132 | { |
| 133 | int i, si; | ||
| 167 | struct aq_nic_s *aq_nic = netdev_priv(ndev); | 134 | struct aq_nic_s *aq_nic = netdev_priv(ndev); |
| 168 | struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); | 135 | struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); |
| 169 | 136 | u8 *p = data; | |
| 170 | if (stringset == ETH_SS_STATS) | 137 | |
| 171 | memcpy(data, *aq_ethtool_stat_names, | 138 | if (stringset == ETH_SS_STATS) { |
| 172 | sizeof(aq_ethtool_stat_names) - | 139 | memcpy(p, *aq_ethtool_stat_names, |
| 173 | (AQ_CFG_VECS_MAX - cfg->vecs) * | 140 | sizeof(aq_ethtool_stat_names)); |
| 174 | aq_ethtool_stat_queue_chars); | 141 | p = p + sizeof(aq_ethtool_stat_names); |
| 142 | for (i = 0; i < cfg->vecs; i++) { | ||
| 143 | for (si = 0; | ||
| 144 | si < ARRAY_SIZE(aq_ethtool_queue_stat_names); | ||
| 145 | si++) { | ||
| 146 | snprintf(p, ETH_GSTRING_LEN, | ||
| 147 | aq_ethtool_queue_stat_names[si], i); | ||
| 148 | p += ETH_GSTRING_LEN; | ||
| 149 | } | ||
| 150 | } | ||
| 151 | } | ||
| 175 | } | 152 | } |
| 176 | 153 | ||
| 177 | static int aq_ethtool_get_sset_count(struct net_device *ndev, int stringset) | 154 | static int aq_ethtool_get_sset_count(struct net_device *ndev, int stringset) |
| @@ -182,9 +159,8 @@ static int aq_ethtool_get_sset_count(struct net_device *ndev, int stringset) | |||
| 182 | 159 | ||
| 183 | switch (stringset) { | 160 | switch (stringset) { |
| 184 | case ETH_SS_STATS: | 161 | case ETH_SS_STATS: |
| 185 | ret = ARRAY_SIZE(aq_ethtool_stat_names) - | 162 | ret = ARRAY_SIZE(aq_ethtool_stat_names) + |
| 186 | (AQ_CFG_VECS_MAX - cfg->vecs) * | 163 | cfg->vecs * ARRAY_SIZE(aq_ethtool_queue_stat_names); |
| 187 | aq_ethtool_stat_queue_lines; | ||
| 188 | break; | 164 | break; |
| 189 | default: | 165 | default: |
| 190 | ret = -EOPNOTSUPP; | 166 | ret = -EOPNOTSUPP; |
| @@ -245,6 +221,69 @@ static int aq_ethtool_get_rxnfc(struct net_device *ndev, | |||
| 245 | return err; | 221 | return err; |
| 246 | } | 222 | } |
| 247 | 223 | ||
| 224 | int aq_ethtool_get_coalesce(struct net_device *ndev, | ||
| 225 | struct ethtool_coalesce *coal) | ||
| 226 | { | ||
| 227 | struct aq_nic_s *aq_nic = netdev_priv(ndev); | ||
| 228 | struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); | ||
| 229 | |||
| 230 | if (cfg->itr == AQ_CFG_INTERRUPT_MODERATION_ON || | ||
| 231 | cfg->itr == AQ_CFG_INTERRUPT_MODERATION_AUTO) { | ||
| 232 | coal->rx_coalesce_usecs = cfg->rx_itr; | ||
| 233 | coal->tx_coalesce_usecs = cfg->tx_itr; | ||
| 234 | coal->rx_max_coalesced_frames = 0; | ||
| 235 | coal->tx_max_coalesced_frames = 0; | ||
| 236 | } else { | ||
| 237 | coal->rx_coalesce_usecs = 0; | ||
| 238 | coal->tx_coalesce_usecs = 0; | ||
| 239 | coal->rx_max_coalesced_frames = 1; | ||
| 240 | coal->tx_max_coalesced_frames = 1; | ||
| 241 | } | ||
| 242 | return 0; | ||
| 243 | } | ||
| 244 | |||
| 245 | int aq_ethtool_set_coalesce(struct net_device *ndev, | ||
| 246 | struct ethtool_coalesce *coal) | ||
| 247 | { | ||
| 248 | struct aq_nic_s *aq_nic = netdev_priv(ndev); | ||
| 249 | struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(aq_nic); | ||
| 250 | |||
| 251 | /* This is not yet supported | ||
| 252 | */ | ||
| 253 | if (coal->use_adaptive_rx_coalesce || coal->use_adaptive_tx_coalesce) | ||
| 254 | return -EOPNOTSUPP; | ||
| 255 | |||
| 256 | /* Atlantic only supports timing based coalescing | ||
| 257 | */ | ||
| 258 | if (coal->rx_max_coalesced_frames > 1 || | ||
| 259 | coal->rx_coalesce_usecs_irq || | ||
| 260 | coal->rx_max_coalesced_frames_irq) | ||
| 261 | return -EOPNOTSUPP; | ||
| 262 | |||
| 263 | if (coal->tx_max_coalesced_frames > 1 || | ||
| 264 | coal->tx_coalesce_usecs_irq || | ||
| 265 | coal->tx_max_coalesced_frames_irq) | ||
| 266 | return -EOPNOTSUPP; | ||
| 267 | |||
| 268 | /* We do not support frame counting. Check this | ||
| 269 | */ | ||
| 270 | if (!(coal->rx_max_coalesced_frames == !coal->rx_coalesce_usecs)) | ||
| 271 | return -EOPNOTSUPP; | ||
| 272 | if (!(coal->tx_max_coalesced_frames == !coal->tx_coalesce_usecs)) | ||
| 273 | return -EOPNOTSUPP; | ||
| 274 | |||
| 275 | if (coal->rx_coalesce_usecs > AQ_CFG_INTERRUPT_MODERATION_USEC_MAX || | ||
| 276 | coal->tx_coalesce_usecs > AQ_CFG_INTERRUPT_MODERATION_USEC_MAX) | ||
| 277 | return -EINVAL; | ||
| 278 | |||
| 279 | cfg->itr = AQ_CFG_INTERRUPT_MODERATION_ON; | ||
| 280 | |||
| 281 | cfg->rx_itr = coal->rx_coalesce_usecs; | ||
| 282 | cfg->tx_itr = coal->tx_coalesce_usecs; | ||
| 283 | |||
| 284 | return aq_nic_update_interrupt_moderation_settings(aq_nic); | ||
| 285 | } | ||
| 286 | |||
| 248 | const struct ethtool_ops aq_ethtool_ops = { | 287 | const struct ethtool_ops aq_ethtool_ops = { |
| 249 | .get_link = aq_ethtool_get_link, | 288 | .get_link = aq_ethtool_get_link, |
| 250 | .get_regs_len = aq_ethtool_get_regs_len, | 289 | .get_regs_len = aq_ethtool_get_regs_len, |
| @@ -259,4 +298,6 @@ const struct ethtool_ops aq_ethtool_ops = { | |||
| 259 | .get_ethtool_stats = aq_ethtool_stats, | 298 | .get_ethtool_stats = aq_ethtool_stats, |
| 260 | .get_link_ksettings = aq_ethtool_get_link_ksettings, | 299 | .get_link_ksettings = aq_ethtool_get_link_ksettings, |
| 261 | .set_link_ksettings = aq_ethtool_set_link_ksettings, | 300 | .set_link_ksettings = aq_ethtool_set_link_ksettings, |
| 301 | .get_coalesce = aq_ethtool_get_coalesce, | ||
| 302 | .set_coalesce = aq_ethtool_set_coalesce, | ||
| 262 | }; | 303 | }; |
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h index bf9b3f020e10..0207927dc8a6 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h | |||
| @@ -151,8 +151,7 @@ struct aq_hw_ops { | |||
| 151 | [ETH_ALEN], | 151 | [ETH_ALEN], |
| 152 | u32 count); | 152 | u32 count); |
| 153 | 153 | ||
| 154 | int (*hw_interrupt_moderation_set)(struct aq_hw_s *self, | 154 | int (*hw_interrupt_moderation_set)(struct aq_hw_s *self); |
| 155 | bool itr_enabled); | ||
| 156 | 155 | ||
| 157 | int (*hw_rss_set)(struct aq_hw_s *self, | 156 | int (*hw_rss_set)(struct aq_hw_s *self, |
| 158 | struct aq_rss_parameters *rss_params); | 157 | struct aq_rss_parameters *rss_params); |
| @@ -163,6 +162,8 @@ struct aq_hw_ops { | |||
| 163 | int (*hw_get_regs)(struct aq_hw_s *self, | 162 | int (*hw_get_regs)(struct aq_hw_s *self, |
| 164 | struct aq_hw_caps_s *aq_hw_caps, u32 *regs_buff); | 163 | struct aq_hw_caps_s *aq_hw_caps, u32 *regs_buff); |
| 165 | 164 | ||
| 165 | int (*hw_update_stats)(struct aq_hw_s *self); | ||
| 166 | |||
| 166 | int (*hw_get_hw_stats)(struct aq_hw_s *self, u64 *data, | 167 | int (*hw_get_hw_stats)(struct aq_hw_s *self, u64 *data, |
| 167 | unsigned int *p_count); | 168 | unsigned int *p_count); |
| 168 | 169 | ||
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index 0a5bb4114eb4..483e97691eea 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include "aq_pci_func.h" | 16 | #include "aq_pci_func.h" |
| 17 | #include "aq_nic_internal.h" | 17 | #include "aq_nic_internal.h" |
| 18 | 18 | ||
| 19 | #include <linux/moduleparam.h> | ||
| 19 | #include <linux/netdevice.h> | 20 | #include <linux/netdevice.h> |
| 20 | #include <linux/etherdevice.h> | 21 | #include <linux/etherdevice.h> |
| 21 | #include <linux/timer.h> | 22 | #include <linux/timer.h> |
| @@ -24,6 +25,18 @@ | |||
| 24 | #include <linux/tcp.h> | 25 | #include <linux/tcp.h> |
| 25 | #include <net/ip.h> | 26 | #include <net/ip.h> |
| 26 | 27 | ||
| 28 | static unsigned int aq_itr = AQ_CFG_INTERRUPT_MODERATION_AUTO; | ||
| 29 | module_param_named(aq_itr, aq_itr, uint, 0644); | ||
| 30 | MODULE_PARM_DESC(aq_itr, "Interrupt throttling mode"); | ||
| 31 | |||
| 32 | static unsigned int aq_itr_tx; | ||
| 33 | module_param_named(aq_itr_tx, aq_itr_tx, uint, 0644); | ||
| 34 | MODULE_PARM_DESC(aq_itr_tx, "TX interrupt throttle rate"); | ||
| 35 | |||
| 36 | static unsigned int aq_itr_rx; | ||
| 37 | module_param_named(aq_itr_rx, aq_itr_rx, uint, 0644); | ||
| 38 | MODULE_PARM_DESC(aq_itr_rx, "RX interrupt throttle rate"); | ||
| 39 | |||
| 27 | static void aq_nic_rss_init(struct aq_nic_s *self, unsigned int num_rss_queues) | 40 | static void aq_nic_rss_init(struct aq_nic_s *self, unsigned int num_rss_queues) |
| 28 | { | 41 | { |
| 29 | struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg; | 42 | struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg; |
| @@ -61,9 +74,9 @@ static void aq_nic_cfg_init_defaults(struct aq_nic_s *self) | |||
| 61 | 74 | ||
| 62 | cfg->is_polling = AQ_CFG_IS_POLLING_DEF; | 75 | cfg->is_polling = AQ_CFG_IS_POLLING_DEF; |
| 63 | 76 | ||
| 64 | cfg->is_interrupt_moderation = AQ_CFG_IS_INTERRUPT_MODERATION_DEF; | 77 | cfg->itr = aq_itr; |
| 65 | cfg->itr = cfg->is_interrupt_moderation ? | 78 | cfg->tx_itr = aq_itr_tx; |
| 66 | AQ_CFG_INTERRUPT_MODERATION_RATE_DEF : 0U; | 79 | cfg->rx_itr = aq_itr_rx; |
| 67 | 80 | ||
| 68 | cfg->is_rss = AQ_CFG_IS_RSS_DEF; | 81 | cfg->is_rss = AQ_CFG_IS_RSS_DEF; |
| 69 | cfg->num_rss_queues = AQ_CFG_NUM_RSS_QUEUES_DEF; | 82 | cfg->num_rss_queues = AQ_CFG_NUM_RSS_QUEUES_DEF; |
| @@ -126,10 +139,12 @@ static int aq_nic_update_link_status(struct aq_nic_s *self) | |||
| 126 | if (err) | 139 | if (err) |
| 127 | return err; | 140 | return err; |
| 128 | 141 | ||
| 129 | if (self->link_status.mbps != self->aq_hw->aq_link_status.mbps) | 142 | if (self->link_status.mbps != self->aq_hw->aq_link_status.mbps) { |
| 130 | pr_info("%s: link change old %d new %d\n", | 143 | pr_info("%s: link change old %d new %d\n", |
| 131 | AQ_CFG_DRV_NAME, self->link_status.mbps, | 144 | AQ_CFG_DRV_NAME, self->link_status.mbps, |
| 132 | self->aq_hw->aq_link_status.mbps); | 145 | self->aq_hw->aq_link_status.mbps); |
| 146 | aq_nic_update_interrupt_moderation_settings(self); | ||
| 147 | } | ||
| 133 | 148 | ||
| 134 | self->link_status = self->aq_hw->aq_link_status; | 149 | self->link_status = self->aq_hw->aq_link_status; |
| 135 | if (!netif_carrier_ok(self->ndev) && self->link_status.mbps) { | 150 | if (!netif_carrier_ok(self->ndev) && self->link_status.mbps) { |
| @@ -164,8 +179,8 @@ static void aq_nic_service_timer_cb(unsigned long param) | |||
| 164 | if (err) | 179 | if (err) |
| 165 | goto err_exit; | 180 | goto err_exit; |
| 166 | 181 | ||
| 167 | self->aq_hw_ops.hw_interrupt_moderation_set(self->aq_hw, | 182 | if (self->aq_hw_ops.hw_update_stats) |
| 168 | self->aq_nic_cfg.is_interrupt_moderation); | 183 | self->aq_hw_ops.hw_update_stats(self->aq_hw); |
| 169 | 184 | ||
| 170 | memset(&stats_rx, 0U, sizeof(struct aq_ring_stats_rx_s)); | 185 | memset(&stats_rx, 0U, sizeof(struct aq_ring_stats_rx_s)); |
| 171 | memset(&stats_tx, 0U, sizeof(struct aq_ring_stats_tx_s)); | 186 | memset(&stats_tx, 0U, sizeof(struct aq_ring_stats_tx_s)); |
| @@ -334,6 +349,7 @@ struct aq_nic_s *aq_nic_alloc_hot(struct net_device *ndev) | |||
| 334 | } | 349 | } |
| 335 | if (netif_running(ndev)) | 350 | if (netif_running(ndev)) |
| 336 | netif_tx_disable(ndev); | 351 | netif_tx_disable(ndev); |
| 352 | netif_carrier_off(self->ndev); | ||
| 337 | 353 | ||
| 338 | for (self->aq_vecs = 0; self->aq_vecs < self->aq_nic_cfg.vecs; | 354 | for (self->aq_vecs = 0; self->aq_vecs < self->aq_nic_cfg.vecs; |
| 339 | self->aq_vecs++) { | 355 | self->aq_vecs++) { |
| @@ -421,9 +437,8 @@ int aq_nic_start(struct aq_nic_s *self) | |||
| 421 | if (err < 0) | 437 | if (err < 0) |
| 422 | goto err_exit; | 438 | goto err_exit; |
| 423 | 439 | ||
| 424 | err = self->aq_hw_ops.hw_interrupt_moderation_set(self->aq_hw, | 440 | err = aq_nic_update_interrupt_moderation_settings(self); |
| 425 | self->aq_nic_cfg.is_interrupt_moderation); | 441 | if (err) |
| 426 | if (err < 0) | ||
| 427 | goto err_exit; | 442 | goto err_exit; |
| 428 | setup_timer(&self->service_timer, &aq_nic_service_timer_cb, | 443 | setup_timer(&self->service_timer, &aq_nic_service_timer_cb, |
| 429 | (unsigned long)self); | 444 | (unsigned long)self); |
| @@ -645,6 +660,11 @@ err_exit: | |||
| 645 | return err; | 660 | return err; |
| 646 | } | 661 | } |
| 647 | 662 | ||
| 663 | int aq_nic_update_interrupt_moderation_settings(struct aq_nic_s *self) | ||
| 664 | { | ||
| 665 | return self->aq_hw_ops.hw_interrupt_moderation_set(self->aq_hw); | ||
| 666 | } | ||
| 667 | |||
| 648 | int aq_nic_set_packet_filter(struct aq_nic_s *self, unsigned int flags) | 668 | int aq_nic_set_packet_filter(struct aq_nic_s *self, unsigned int flags) |
| 649 | { | 669 | { |
| 650 | int err = 0; | 670 | int err = 0; |
| @@ -899,6 +919,7 @@ int aq_nic_stop(struct aq_nic_s *self) | |||
| 899 | unsigned int i = 0U; | 919 | unsigned int i = 0U; |
| 900 | 920 | ||
| 901 | netif_tx_disable(self->ndev); | 921 | netif_tx_disable(self->ndev); |
| 922 | netif_carrier_off(self->ndev); | ||
| 902 | 923 | ||
| 903 | del_timer_sync(&self->service_timer); | 924 | del_timer_sync(&self->service_timer); |
| 904 | 925 | ||
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h index 0ddd556ff901..4309983acdd6 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h | |||
| @@ -40,6 +40,8 @@ struct aq_nic_cfg_s { | |||
| 40 | u32 vecs; /* vecs==allocated irqs */ | 40 | u32 vecs; /* vecs==allocated irqs */ |
| 41 | u32 irq_type; | 41 | u32 irq_type; |
| 42 | u32 itr; | 42 | u32 itr; |
| 43 | u16 rx_itr; | ||
| 44 | u16 tx_itr; | ||
| 43 | u32 num_rss_queues; | 45 | u32 num_rss_queues; |
| 44 | u32 mtu; | 46 | u32 mtu; |
| 45 | u32 ucp_0x364; | 47 | u32 ucp_0x364; |
| @@ -49,7 +51,6 @@ struct aq_nic_cfg_s { | |||
| 49 | u16 is_mc_list_enabled; | 51 | u16 is_mc_list_enabled; |
| 50 | u16 mc_list_count; | 52 | u16 mc_list_count; |
| 51 | bool is_autoneg; | 53 | bool is_autoneg; |
| 52 | bool is_interrupt_moderation; | ||
| 53 | bool is_polling; | 54 | bool is_polling; |
| 54 | bool is_rss; | 55 | bool is_rss; |
| 55 | bool is_lro; | 56 | bool is_lro; |
| @@ -104,5 +105,6 @@ int aq_nic_set_link_ksettings(struct aq_nic_s *self, | |||
| 104 | struct aq_nic_cfg_s *aq_nic_get_cfg(struct aq_nic_s *self); | 105 | struct aq_nic_cfg_s *aq_nic_get_cfg(struct aq_nic_s *self); |
| 105 | u32 aq_nic_get_fw_version(struct aq_nic_s *self); | 106 | u32 aq_nic_get_fw_version(struct aq_nic_s *self); |
| 106 | int aq_nic_change_pm_state(struct aq_nic_s *self, pm_message_t *pm_msg); | 107 | int aq_nic_change_pm_state(struct aq_nic_s *self, pm_message_t *pm_msg); |
| 108 | int aq_nic_update_interrupt_moderation_settings(struct aq_nic_s *self); | ||
| 107 | 109 | ||
| 108 | #endif /* AQ_NIC_H */ | 110 | #endif /* AQ_NIC_H */ |
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c index 4c6c882c6a1c..cadaa646c89f 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c | |||
| @@ -85,6 +85,7 @@ int aq_pci_func_init(struct aq_pci_func_s *self) | |||
| 85 | int err = 0; | 85 | int err = 0; |
| 86 | unsigned int bar = 0U; | 86 | unsigned int bar = 0U; |
| 87 | unsigned int port = 0U; | 87 | unsigned int port = 0U; |
| 88 | unsigned int numvecs = 0U; | ||
| 88 | 89 | ||
| 89 | err = pci_enable_device(self->pdev); | 90 | err = pci_enable_device(self->pdev); |
| 90 | if (err < 0) | 91 | if (err < 0) |
| @@ -142,10 +143,12 @@ int aq_pci_func_init(struct aq_pci_func_s *self) | |||
| 142 | } | 143 | } |
| 143 | } | 144 | } |
| 144 | 145 | ||
| 145 | /*enable interrupts */ | 146 | numvecs = min((u8)AQ_CFG_VECS_DEF, self->aq_hw_caps.msix_irqs); |
| 147 | numvecs = min(numvecs, num_online_cpus()); | ||
| 148 | |||
| 149 | /* enable interrupts */ | ||
| 146 | #if !AQ_CFG_FORCE_LEGACY_INT | 150 | #if !AQ_CFG_FORCE_LEGACY_INT |
| 147 | err = pci_alloc_irq_vectors(self->pdev, self->aq_hw_caps.msix_irqs, | 151 | err = pci_alloc_irq_vectors(self->pdev, numvecs, numvecs, PCI_IRQ_MSIX); |
| 148 | self->aq_hw_caps.msix_irqs, PCI_IRQ_MSIX); | ||
| 149 | 152 | ||
| 150 | if (err < 0) { | 153 | if (err < 0) { |
| 151 | err = pci_alloc_irq_vectors(self->pdev, 1, 1, | 154 | err = pci_alloc_irq_vectors(self->pdev, 1, 1, |
| @@ -153,7 +156,7 @@ int aq_pci_func_init(struct aq_pci_func_s *self) | |||
| 153 | if (err < 0) | 156 | if (err < 0) |
| 154 | goto err_exit; | 157 | goto err_exit; |
| 155 | } | 158 | } |
| 156 | #endif | 159 | #endif /* AQ_CFG_FORCE_LEGACY_INT */ |
| 157 | 160 | ||
| 158 | /* net device init */ | 161 | /* net device init */ |
| 159 | for (port = 0; port < self->ports; ++port) { | 162 | for (port = 0; port < self->ports; ++port) { |
| @@ -265,6 +268,9 @@ void aq_pci_func_free(struct aq_pci_func_s *self) | |||
| 265 | aq_nic_ndev_free(self->port[port]); | 268 | aq_nic_ndev_free(self->port[port]); |
| 266 | } | 269 | } |
| 267 | 270 | ||
| 271 | if (self->mmio) | ||
| 272 | iounmap(self->mmio); | ||
| 273 | |||
| 268 | kfree(self); | 274 | kfree(self); |
| 269 | 275 | ||
| 270 | err_exit:; | 276 | err_exit:; |
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_vec.c b/drivers/net/ethernet/aquantia/atlantic/aq_vec.c index 305ff8ffac2c..5fecc9a099ef 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_vec.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_vec.c | |||
| @@ -373,8 +373,11 @@ int aq_vec_get_sw_stats(struct aq_vec_s *self, u64 *data, unsigned int *p_count) | |||
| 373 | memset(&stats_tx, 0U, sizeof(struct aq_ring_stats_tx_s)); | 373 | memset(&stats_tx, 0U, sizeof(struct aq_ring_stats_tx_s)); |
| 374 | aq_vec_add_stats(self, &stats_rx, &stats_tx); | 374 | aq_vec_add_stats(self, &stats_rx, &stats_tx); |
| 375 | 375 | ||
| 376 | /* This data should mimic aq_ethtool_queue_stat_names structure | ||
| 377 | */ | ||
| 376 | data[count] += stats_rx.packets; | 378 | data[count] += stats_rx.packets; |
| 377 | data[++count] += stats_tx.packets; | 379 | data[++count] += stats_tx.packets; |
| 380 | data[++count] += stats_tx.queue_restarts; | ||
| 378 | data[++count] += stats_rx.jumbo_packets; | 381 | data[++count] += stats_rx.jumbo_packets; |
| 379 | data[++count] += stats_rx.lro_packets; | 382 | data[++count] += stats_rx.lro_packets; |
| 380 | data[++count] += stats_rx.errors; | 383 | data[++count] += stats_rx.errors; |
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c index c5a02df7a48b..07b3c49a16a4 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c | |||
| @@ -765,24 +765,23 @@ err_exit: | |||
| 765 | return err; | 765 | return err; |
| 766 | } | 766 | } |
| 767 | 767 | ||
| 768 | static int hw_atl_a0_hw_interrupt_moderation_set(struct aq_hw_s *self, | 768 | static int hw_atl_a0_hw_interrupt_moderation_set(struct aq_hw_s *self) |
| 769 | bool itr_enabled) | ||
| 770 | { | 769 | { |
| 771 | unsigned int i = 0U; | 770 | unsigned int i = 0U; |
| 771 | u32 itr_rx; | ||
| 772 | 772 | ||
| 773 | if (itr_enabled && self->aq_nic_cfg->itr) { | 773 | if (self->aq_nic_cfg->itr) { |
| 774 | if (self->aq_nic_cfg->itr != 0xFFFFU) { | 774 | if (self->aq_nic_cfg->itr != AQ_CFG_INTERRUPT_MODERATION_AUTO) { |
| 775 | u32 itr_ = (self->aq_nic_cfg->itr >> 1); | 775 | u32 itr_ = (self->aq_nic_cfg->itr >> 1); |
| 776 | 776 | ||
| 777 | itr_ = min(AQ_CFG_IRQ_MASK, itr_); | 777 | itr_ = min(AQ_CFG_IRQ_MASK, itr_); |
| 778 | 778 | ||
| 779 | PHAL_ATLANTIC_A0->itr_rx = 0x80000000U | | 779 | itr_rx = 0x80000000U | (itr_ << 0x10); |
| 780 | (itr_ << 0x10); | ||
| 781 | } else { | 780 | } else { |
| 782 | u32 n = 0xFFFFU & aq_hw_read_reg(self, 0x00002A00U); | 781 | u32 n = 0xFFFFU & aq_hw_read_reg(self, 0x00002A00U); |
| 783 | 782 | ||
| 784 | if (n < self->aq_link_status.mbps) { | 783 | if (n < self->aq_link_status.mbps) { |
| 785 | PHAL_ATLANTIC_A0->itr_rx = 0U; | 784 | itr_rx = 0U; |
| 786 | } else { | 785 | } else { |
| 787 | static unsigned int hw_timers_tbl_[] = { | 786 | static unsigned int hw_timers_tbl_[] = { |
| 788 | 0x01CU, /* 10Gbit */ | 787 | 0x01CU, /* 10Gbit */ |
| @@ -797,8 +796,7 @@ static int hw_atl_a0_hw_interrupt_moderation_set(struct aq_hw_s *self, | |||
| 797 | hw_atl_utils_mbps_2_speed_index( | 796 | hw_atl_utils_mbps_2_speed_index( |
| 798 | self->aq_link_status.mbps); | 797 | self->aq_link_status.mbps); |
| 799 | 798 | ||
| 800 | PHAL_ATLANTIC_A0->itr_rx = | 799 | itr_rx = 0x80000000U | |
| 801 | 0x80000000U | | ||
| 802 | (hw_timers_tbl_[speed_index] << 0x10U); | 800 | (hw_timers_tbl_[speed_index] << 0x10U); |
| 803 | } | 801 | } |
| 804 | 802 | ||
| @@ -806,11 +804,11 @@ static int hw_atl_a0_hw_interrupt_moderation_set(struct aq_hw_s *self, | |||
| 806 | aq_hw_write_reg(self, 0x00002A00U, 0x8D000000U); | 804 | aq_hw_write_reg(self, 0x00002A00U, 0x8D000000U); |
| 807 | } | 805 | } |
| 808 | } else { | 806 | } else { |
| 809 | PHAL_ATLANTIC_A0->itr_rx = 0U; | 807 | itr_rx = 0U; |
| 810 | } | 808 | } |
| 811 | 809 | ||
| 812 | for (i = HW_ATL_A0_RINGS_MAX; i--;) | 810 | for (i = HW_ATL_A0_RINGS_MAX; i--;) |
| 813 | reg_irq_thr_set(self, PHAL_ATLANTIC_A0->itr_rx, i); | 811 | reg_irq_thr_set(self, itr_rx, i); |
| 814 | 812 | ||
| 815 | return aq_hw_err_from_flags(self); | 813 | return aq_hw_err_from_flags(self); |
| 816 | } | 814 | } |
| @@ -885,6 +883,7 @@ static struct aq_hw_ops hw_atl_ops_ = { | |||
| 885 | .hw_rss_set = hw_atl_a0_hw_rss_set, | 883 | .hw_rss_set = hw_atl_a0_hw_rss_set, |
| 886 | .hw_rss_hash_set = hw_atl_a0_hw_rss_hash_set, | 884 | .hw_rss_hash_set = hw_atl_a0_hw_rss_hash_set, |
| 887 | .hw_get_regs = hw_atl_utils_hw_get_regs, | 885 | .hw_get_regs = hw_atl_utils_hw_get_regs, |
| 886 | .hw_update_stats = hw_atl_utils_update_stats, | ||
| 888 | .hw_get_hw_stats = hw_atl_utils_get_hw_stats, | 887 | .hw_get_hw_stats = hw_atl_utils_get_hw_stats, |
| 889 | .hw_get_fw_version = hw_atl_utils_get_fw_version, | 888 | .hw_get_fw_version = hw_atl_utils_get_fw_version, |
| 890 | }; | 889 | }; |
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 21784cc39dab..ec68c20efcbd 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 | |||
| @@ -788,39 +788,45 @@ err_exit: | |||
| 788 | return err; | 788 | return err; |
| 789 | } | 789 | } |
| 790 | 790 | ||
| 791 | static int hw_atl_b0_hw_interrupt_moderation_set(struct aq_hw_s *self, | 791 | static int hw_atl_b0_hw_interrupt_moderation_set(struct aq_hw_s *self) |
| 792 | bool itr_enabled) | ||
| 793 | { | 792 | { |
| 794 | unsigned int i = 0U; | 793 | unsigned int i = 0U; |
| 794 | u32 itr_tx = 2U; | ||
| 795 | u32 itr_rx = 2U; | ||
| 795 | 796 | ||
| 796 | if (itr_enabled && self->aq_nic_cfg->itr) { | 797 | switch (self->aq_nic_cfg->itr) { |
| 798 | case AQ_CFG_INTERRUPT_MODERATION_ON: | ||
| 799 | case AQ_CFG_INTERRUPT_MODERATION_AUTO: | ||
| 797 | tdm_tx_desc_wr_wb_irq_en_set(self, 0U); | 800 | tdm_tx_desc_wr_wb_irq_en_set(self, 0U); |
| 798 | tdm_tdm_intr_moder_en_set(self, 1U); | 801 | tdm_tdm_intr_moder_en_set(self, 1U); |
| 799 | rdm_rx_desc_wr_wb_irq_en_set(self, 0U); | 802 | rdm_rx_desc_wr_wb_irq_en_set(self, 0U); |
| 800 | rdm_rdm_intr_moder_en_set(self, 1U); | 803 | rdm_rdm_intr_moder_en_set(self, 1U); |
| 801 | 804 | ||
| 802 | PHAL_ATLANTIC_B0->itr_tx = 2U; | 805 | if (self->aq_nic_cfg->itr == AQ_CFG_INTERRUPT_MODERATION_ON) { |
| 803 | PHAL_ATLANTIC_B0->itr_rx = 2U; | 806 | /* HW timers are in 2us units */ |
| 807 | int tx_max_timer = self->aq_nic_cfg->tx_itr / 2; | ||
| 808 | int tx_min_timer = tx_max_timer / 2; | ||
| 804 | 809 | ||
| 805 | if (self->aq_nic_cfg->itr != 0xFFFFU) { | 810 | int rx_max_timer = self->aq_nic_cfg->rx_itr / 2; |
| 806 | unsigned int max_timer = self->aq_nic_cfg->itr / 2U; | 811 | int rx_min_timer = rx_max_timer / 2; |
| 807 | unsigned int min_timer = self->aq_nic_cfg->itr / 32U; | ||
| 808 | 812 | ||
| 809 | max_timer = min(0x1FFU, max_timer); | 813 | tx_max_timer = min(HW_ATL_INTR_MODER_MAX, tx_max_timer); |
| 810 | min_timer = min(0xFFU, min_timer); | 814 | tx_min_timer = min(HW_ATL_INTR_MODER_MIN, tx_min_timer); |
| 815 | rx_max_timer = min(HW_ATL_INTR_MODER_MAX, rx_max_timer); | ||
| 816 | rx_min_timer = min(HW_ATL_INTR_MODER_MIN, rx_min_timer); | ||
| 811 | 817 | ||
| 812 | PHAL_ATLANTIC_B0->itr_tx |= min_timer << 0x8U; | 818 | itr_tx |= tx_min_timer << 0x8U; |
| 813 | PHAL_ATLANTIC_B0->itr_tx |= max_timer << 0x10U; | 819 | itr_tx |= tx_max_timer << 0x10U; |
| 814 | PHAL_ATLANTIC_B0->itr_rx |= min_timer << 0x8U; | 820 | itr_rx |= rx_min_timer << 0x8U; |
| 815 | PHAL_ATLANTIC_B0->itr_rx |= max_timer << 0x10U; | 821 | itr_rx |= rx_max_timer << 0x10U; |
| 816 | } else { | 822 | } else { |
| 817 | static unsigned int hw_atl_b0_timers_table_tx_[][2] = { | 823 | static unsigned int hw_atl_b0_timers_table_tx_[][2] = { |
| 818 | {0xffU, 0xffU}, /* 10Gbit */ | 824 | {0xfU, 0xffU}, /* 10Gbit */ |
| 819 | {0xffU, 0x1ffU}, /* 5Gbit */ | 825 | {0xfU, 0x1ffU}, /* 5Gbit */ |
| 820 | {0xffU, 0x1ffU}, /* 5Gbit 5GS */ | 826 | {0xfU, 0x1ffU}, /* 5Gbit 5GS */ |
| 821 | {0xffU, 0x1ffU}, /* 2.5Gbit */ | 827 | {0xfU, 0x1ffU}, /* 2.5Gbit */ |
| 822 | {0xffU, 0x1ffU}, /* 1Gbit */ | 828 | {0xfU, 0x1ffU}, /* 1Gbit */ |
| 823 | {0xffU, 0x1ffU}, /* 100Mbit */ | 829 | {0xfU, 0x1ffU}, /* 100Mbit */ |
| 824 | }; | 830 | }; |
| 825 | 831 | ||
| 826 | static unsigned int hw_atl_b0_timers_table_rx_[][2] = { | 832 | static unsigned int hw_atl_b0_timers_table_rx_[][2] = { |
| @@ -836,34 +842,36 @@ static int hw_atl_b0_hw_interrupt_moderation_set(struct aq_hw_s *self, | |||
| 836 | hw_atl_utils_mbps_2_speed_index( | 842 | hw_atl_utils_mbps_2_speed_index( |
| 837 | self->aq_link_status.mbps); | 843 | self->aq_link_status.mbps); |
| 838 | 844 | ||
| 839 | PHAL_ATLANTIC_B0->itr_tx |= | 845 | /* Update user visible ITR settings */ |
| 840 | hw_atl_b0_timers_table_tx_[speed_index] | 846 | self->aq_nic_cfg->tx_itr = hw_atl_b0_timers_table_tx_ |
| 841 | [0] << 0x8U; /* set min timer value */ | 847 | [speed_index][1] * 2; |
| 842 | PHAL_ATLANTIC_B0->itr_tx |= | 848 | self->aq_nic_cfg->rx_itr = hw_atl_b0_timers_table_rx_ |
| 843 | hw_atl_b0_timers_table_tx_[speed_index] | 849 | [speed_index][1] * 2; |
| 844 | [1] << 0x10U; /* set max timer value */ | 850 | |
| 845 | 851 | itr_tx |= hw_atl_b0_timers_table_tx_ | |
| 846 | PHAL_ATLANTIC_B0->itr_rx |= | 852 | [speed_index][0] << 0x8U; |
| 847 | hw_atl_b0_timers_table_rx_[speed_index] | 853 | itr_tx |= hw_atl_b0_timers_table_tx_ |
| 848 | [0] << 0x8U; /* set min timer value */ | 854 | [speed_index][1] << 0x10U; |
| 849 | PHAL_ATLANTIC_B0->itr_rx |= | 855 | |
| 850 | hw_atl_b0_timers_table_rx_[speed_index] | 856 | itr_rx |= hw_atl_b0_timers_table_rx_ |
| 851 | [1] << 0x10U; /* set max timer value */ | 857 | [speed_index][0] << 0x8U; |
| 858 | itr_rx |= hw_atl_b0_timers_table_rx_ | ||
| 859 | [speed_index][1] << 0x10U; | ||
| 852 | } | 860 | } |
| 853 | } else { | 861 | break; |
| 862 | case AQ_CFG_INTERRUPT_MODERATION_OFF: | ||
| 854 | tdm_tx_desc_wr_wb_irq_en_set(self, 1U); | 863 | tdm_tx_desc_wr_wb_irq_en_set(self, 1U); |
| 855 | tdm_tdm_intr_moder_en_set(self, 0U); | 864 | tdm_tdm_intr_moder_en_set(self, 0U); |
| 856 | rdm_rx_desc_wr_wb_irq_en_set(self, 1U); | 865 | rdm_rx_desc_wr_wb_irq_en_set(self, 1U); |
| 857 | rdm_rdm_intr_moder_en_set(self, 0U); | 866 | rdm_rdm_intr_moder_en_set(self, 0U); |
| 858 | PHAL_ATLANTIC_B0->itr_tx = 0U; | 867 | itr_tx = 0U; |
| 859 | PHAL_ATLANTIC_B0->itr_rx = 0U; | 868 | itr_rx = 0U; |
| 869 | break; | ||
| 860 | } | 870 | } |
| 861 | 871 | ||
| 862 | for (i = HW_ATL_B0_RINGS_MAX; i--;) { | 872 | for (i = HW_ATL_B0_RINGS_MAX; i--;) { |
| 863 | reg_tx_intr_moder_ctrl_set(self, | 873 | reg_tx_intr_moder_ctrl_set(self, itr_tx, i); |
| 864 | PHAL_ATLANTIC_B0->itr_tx, i); | 874 | reg_rx_intr_moder_ctrl_set(self, itr_rx, i); |
| 865 | reg_rx_intr_moder_ctrl_set(self, | ||
| 866 | PHAL_ATLANTIC_B0->itr_rx, i); | ||
| 867 | } | 875 | } |
| 868 | 876 | ||
| 869 | return aq_hw_err_from_flags(self); | 877 | return aq_hw_err_from_flags(self); |
| @@ -939,6 +947,7 @@ static struct aq_hw_ops hw_atl_ops_ = { | |||
| 939 | .hw_rss_set = hw_atl_b0_hw_rss_set, | 947 | .hw_rss_set = hw_atl_b0_hw_rss_set, |
| 940 | .hw_rss_hash_set = hw_atl_b0_hw_rss_hash_set, | 948 | .hw_rss_hash_set = hw_atl_b0_hw_rss_hash_set, |
| 941 | .hw_get_regs = hw_atl_utils_hw_get_regs, | 949 | .hw_get_regs = hw_atl_utils_hw_get_regs, |
| 950 | .hw_update_stats = hw_atl_utils_update_stats, | ||
| 942 | .hw_get_hw_stats = hw_atl_utils_get_hw_stats, | 951 | .hw_get_hw_stats = hw_atl_utils_get_hw_stats, |
| 943 | .hw_get_fw_version = hw_atl_utils_get_fw_version, | 952 | .hw_get_fw_version = hw_atl_utils_get_fw_version, |
| 944 | }; | 953 | }; |
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h index fcf89e25a773..9aa2c6edfca2 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_b0_internal.h | |||
| @@ -139,6 +139,9 @@ | |||
| 139 | 139 | ||
| 140 | #define HW_ATL_B0_FW_VER_EXPECTED 0x01050006U | 140 | #define HW_ATL_B0_FW_VER_EXPECTED 0x01050006U |
| 141 | 141 | ||
| 142 | #define HW_ATL_INTR_MODER_MAX 0x1FF | ||
| 143 | #define HW_ATL_INTR_MODER_MIN 0xFF | ||
| 144 | |||
| 142 | /* Hardware tx descriptor */ | 145 | /* Hardware tx descriptor */ |
| 143 | struct __packed hw_atl_txd_s { | 146 | struct __packed hw_atl_txd_s { |
| 144 | u64 buf_addr; | 147 | u64 buf_addr; |
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c index bf734b32e44b..1fe016fc4bc7 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c | |||
| @@ -255,6 +255,15 @@ err_exit: | |||
| 255 | return err; | 255 | return err; |
| 256 | } | 256 | } |
| 257 | 257 | ||
| 258 | int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self, | ||
| 259 | struct hw_aq_atl_utils_mbox_header *pmbox) | ||
| 260 | { | ||
| 261 | return hw_atl_utils_fw_downld_dwords(self, | ||
| 262 | PHAL_ATLANTIC->mbox_addr, | ||
| 263 | (u32 *)(void *)pmbox, | ||
| 264 | sizeof(*pmbox) / sizeof(u32)); | ||
| 265 | } | ||
| 266 | |||
| 258 | void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self, | 267 | void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self, |
| 259 | struct hw_aq_atl_utils_mbox *pmbox) | 268 | struct hw_aq_atl_utils_mbox *pmbox) |
| 260 | { | 269 | { |
| @@ -267,9 +276,6 @@ void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self, | |||
| 267 | if (err < 0) | 276 | if (err < 0) |
| 268 | goto err_exit; | 277 | goto err_exit; |
| 269 | 278 | ||
| 270 | if (pmbox != &PHAL_ATLANTIC->mbox) | ||
| 271 | memcpy(pmbox, &PHAL_ATLANTIC->mbox, sizeof(*pmbox)); | ||
| 272 | |||
| 273 | if (IS_CHIP_FEATURE(REVISION_A0)) { | 279 | if (IS_CHIP_FEATURE(REVISION_A0)) { |
| 274 | unsigned int mtu = self->aq_nic_cfg ? | 280 | unsigned int mtu = self->aq_nic_cfg ? |
| 275 | self->aq_nic_cfg->mtu : 1514U; | 281 | self->aq_nic_cfg->mtu : 1514U; |
| @@ -299,17 +305,17 @@ void hw_atl_utils_mpi_set(struct aq_hw_s *self, | |||
| 299 | { | 305 | { |
| 300 | int err = 0; | 306 | int err = 0; |
| 301 | u32 transaction_id = 0; | 307 | u32 transaction_id = 0; |
| 308 | struct hw_aq_atl_utils_mbox_header mbox; | ||
| 302 | 309 | ||
| 303 | if (state == MPI_RESET) { | 310 | if (state == MPI_RESET) { |
| 304 | hw_atl_utils_mpi_read_stats(self, &PHAL_ATLANTIC->mbox); | 311 | hw_atl_utils_mpi_read_mbox(self, &mbox); |
| 305 | 312 | ||
| 306 | transaction_id = PHAL_ATLANTIC->mbox.transaction_id; | 313 | transaction_id = mbox.transaction_id; |
| 307 | 314 | ||
| 308 | AQ_HW_WAIT_FOR(transaction_id != | 315 | AQ_HW_WAIT_FOR(transaction_id != |
| 309 | (hw_atl_utils_mpi_read_stats | 316 | (hw_atl_utils_mpi_read_mbox(self, &mbox), |
| 310 | (self, &PHAL_ATLANTIC->mbox), | 317 | mbox.transaction_id), |
| 311 | PHAL_ATLANTIC->mbox.transaction_id), | 318 | 1000U, 100U); |
| 312 | 1000U, 100U); | ||
| 313 | if (err < 0) | 319 | if (err < 0) |
| 314 | goto err_exit; | 320 | goto err_exit; |
| 315 | } | 321 | } |
| @@ -492,16 +498,51 @@ int hw_atl_utils_hw_set_power(struct aq_hw_s *self, | |||
| 492 | return 0; | 498 | return 0; |
| 493 | } | 499 | } |
| 494 | 500 | ||
| 501 | int hw_atl_utils_update_stats(struct aq_hw_s *self) | ||
| 502 | { | ||
| 503 | struct hw_atl_s *hw_self = PHAL_ATLANTIC; | ||
| 504 | struct hw_aq_atl_utils_mbox mbox; | ||
| 505 | |||
| 506 | if (!self->aq_link_status.mbps) | ||
| 507 | return 0; | ||
| 508 | |||
| 509 | hw_atl_utils_mpi_read_stats(self, &mbox); | ||
| 510 | |||
| 511 | #define AQ_SDELTA(_N_) (hw_self->curr_stats._N_ += \ | ||
| 512 | mbox.stats._N_ - hw_self->last_stats._N_) | ||
| 513 | |||
| 514 | AQ_SDELTA(uprc); | ||
| 515 | AQ_SDELTA(mprc); | ||
| 516 | AQ_SDELTA(bprc); | ||
| 517 | AQ_SDELTA(erpt); | ||
| 518 | |||
| 519 | AQ_SDELTA(uptc); | ||
| 520 | AQ_SDELTA(mptc); | ||
| 521 | AQ_SDELTA(bptc); | ||
| 522 | AQ_SDELTA(erpr); | ||
| 523 | |||
| 524 | AQ_SDELTA(ubrc); | ||
| 525 | AQ_SDELTA(ubtc); | ||
| 526 | AQ_SDELTA(mbrc); | ||
| 527 | AQ_SDELTA(mbtc); | ||
| 528 | AQ_SDELTA(bbrc); | ||
| 529 | AQ_SDELTA(bbtc); | ||
| 530 | AQ_SDELTA(dpc); | ||
| 531 | |||
| 532 | #undef AQ_SDELTA | ||
| 533 | |||
| 534 | memcpy(&hw_self->last_stats, &mbox.stats, sizeof(mbox.stats)); | ||
| 535 | |||
| 536 | return 0; | ||
| 537 | } | ||
| 538 | |||
| 495 | int hw_atl_utils_get_hw_stats(struct aq_hw_s *self, | 539 | int hw_atl_utils_get_hw_stats(struct aq_hw_s *self, |
| 496 | u64 *data, unsigned int *p_count) | 540 | u64 *data, unsigned int *p_count) |
| 497 | { | 541 | { |
| 498 | struct hw_atl_stats_s *stats = NULL; | 542 | struct hw_atl_s *hw_self = PHAL_ATLANTIC; |
| 543 | struct hw_atl_stats_s *stats = &hw_self->curr_stats; | ||
| 499 | int i = 0; | 544 | int i = 0; |
| 500 | 545 | ||
| 501 | hw_atl_utils_mpi_read_stats(self, &PHAL_ATLANTIC->mbox); | ||
| 502 | |||
| 503 | stats = &PHAL_ATLANTIC->mbox.stats; | ||
| 504 | |||
| 505 | data[i] = stats->uprc + stats->mprc + stats->bprc; | 546 | data[i] = stats->uprc + stats->mprc + stats->bprc; |
| 506 | data[++i] = stats->uprc; | 547 | data[++i] = stats->uprc; |
| 507 | data[++i] = stats->mprc; | 548 | data[++i] = stats->mprc; |
diff --git a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h index e0360a6b2202..c99cc690e425 100644 --- a/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h +++ b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h | |||
| @@ -115,19 +115,22 @@ struct __packed hw_aq_atl_utils_fw_rpc { | |||
| 115 | }; | 115 | }; |
| 116 | }; | 116 | }; |
| 117 | 117 | ||
| 118 | struct __packed hw_aq_atl_utils_mbox { | 118 | struct __packed hw_aq_atl_utils_mbox_header { |
| 119 | u32 version; | 119 | u32 version; |
| 120 | u32 transaction_id; | 120 | u32 transaction_id; |
| 121 | int error; | 121 | u32 error; |
| 122 | }; | ||
| 123 | |||
| 124 | struct __packed hw_aq_atl_utils_mbox { | ||
| 125 | struct hw_aq_atl_utils_mbox_header header; | ||
| 122 | struct hw_atl_stats_s stats; | 126 | struct hw_atl_stats_s stats; |
| 123 | }; | 127 | }; |
| 124 | 128 | ||
| 125 | struct __packed hw_atl_s { | 129 | struct __packed hw_atl_s { |
| 126 | struct aq_hw_s base; | 130 | struct aq_hw_s base; |
| 127 | struct hw_aq_atl_utils_mbox mbox; | 131 | struct hw_atl_stats_s last_stats; |
| 132 | struct hw_atl_stats_s curr_stats; | ||
| 128 | u64 speed; | 133 | u64 speed; |
| 129 | u32 itr_tx; | ||
| 130 | u32 itr_rx; | ||
| 131 | unsigned int chip_features; | 134 | unsigned int chip_features; |
| 132 | u32 fw_ver_actual; | 135 | u32 fw_ver_actual; |
| 133 | atomic_t dpc; | 136 | atomic_t dpc; |
| @@ -170,6 +173,9 @@ enum hal_atl_utils_fw_state_e { | |||
| 170 | 173 | ||
| 171 | void hw_atl_utils_hw_chip_features_init(struct aq_hw_s *self, u32 *p); | 174 | void hw_atl_utils_hw_chip_features_init(struct aq_hw_s *self, u32 *p); |
| 172 | 175 | ||
| 176 | int hw_atl_utils_mpi_read_mbox(struct aq_hw_s *self, | ||
| 177 | struct hw_aq_atl_utils_mbox_header *pmbox); | ||
| 178 | |||
| 173 | void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self, | 179 | void hw_atl_utils_mpi_read_stats(struct aq_hw_s *self, |
| 174 | struct hw_aq_atl_utils_mbox *pmbox); | 180 | struct hw_aq_atl_utils_mbox *pmbox); |
| 175 | 181 | ||
| @@ -199,6 +205,8 @@ int hw_atl_utils_hw_deinit(struct aq_hw_s *self); | |||
| 199 | 205 | ||
| 200 | int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version); | 206 | int hw_atl_utils_get_fw_version(struct aq_hw_s *self, u32 *fw_version); |
| 201 | 207 | ||
| 208 | int hw_atl_utils_update_stats(struct aq_hw_s *self); | ||
| 209 | |||
| 202 | int hw_atl_utils_get_hw_stats(struct aq_hw_s *self, | 210 | int hw_atl_utils_get_hw_stats(struct aq_hw_s *self, |
| 203 | u64 *data, | 211 | u64 *data, |
| 204 | unsigned int *p_count); | 212 | unsigned int *p_count); |
