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); |