diff options
author | Igor Russkikh <igor.russkikh@aquantia.com> | 2017-10-19 11:23:58 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-10-21 07:32:24 -0400 |
commit | b82ee71a86b0ea66da79a91959d800ffb696a5cb (patch) | |
tree | 09d3b88dc813d8aae6b2d1d8ef6c9a6775693d7d /drivers/net | |
parent | 6849540adc0bcc8c648d7c11be169d2ca267fbca (diff) |
net: aquantia: Enable coalescing management via ethtool interface
Aquantia NIC allows both TX and RX interrupt throttle rate (ITR)
management, but this was used in a very limited way via predefined
values. This patch allows to setup ITR default values via module
command line arguments and via standard ethtool coalescing settings.
Signed-off-by: Pavel Belous <pavel.belous@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
9 files changed, 155 insertions, 62 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 3eab4089e91a..d5e99b468870 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c | |||
@@ -221,6 +221,69 @@ static int aq_ethtool_get_rxnfc(struct net_device *ndev, | |||
221 | return err; | 221 | return err; |
222 | } | 222 | } |
223 | 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 | |||
224 | const struct ethtool_ops aq_ethtool_ops = { | 287 | const struct ethtool_ops aq_ethtool_ops = { |
225 | .get_link = aq_ethtool_get_link, | 288 | .get_link = aq_ethtool_get_link, |
226 | .get_regs_len = aq_ethtool_get_regs_len, | 289 | .get_regs_len = aq_ethtool_get_regs_len, |
@@ -235,4 +298,6 @@ const struct ethtool_ops aq_ethtool_ops = { | |||
235 | .get_ethtool_stats = aq_ethtool_stats, | 298 | .get_ethtool_stats = aq_ethtool_stats, |
236 | .get_link_ksettings = aq_ethtool_get_link_ksettings, | 299 | .get_link_ksettings = aq_ethtool_get_link_ksettings, |
237 | .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, | ||
238 | }; | 303 | }; |
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_hw.h b/drivers/net/ethernet/aquantia/atlantic/aq_hw.h index 3a8baaef053c..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); |
diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.c b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c index 9378b4877783..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,9 +179,6 @@ 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, | ||
168 | self->aq_nic_cfg.is_interrupt_moderation); | ||
169 | |||
170 | if (self->aq_hw_ops.hw_update_stats) | 182 | if (self->aq_hw_ops.hw_update_stats) |
171 | self->aq_hw_ops.hw_update_stats(self->aq_hw); | 183 | self->aq_hw_ops.hw_update_stats(self->aq_hw); |
172 | 184 | ||
@@ -425,9 +437,8 @@ int aq_nic_start(struct aq_nic_s *self) | |||
425 | if (err < 0) | 437 | if (err < 0) |
426 | goto err_exit; | 438 | goto err_exit; |
427 | 439 | ||
428 | err = self->aq_hw_ops.hw_interrupt_moderation_set(self->aq_hw, | 440 | err = aq_nic_update_interrupt_moderation_settings(self); |
429 | self->aq_nic_cfg.is_interrupt_moderation); | 441 | if (err) |
430 | if (err < 0) | ||
431 | goto err_exit; | 442 | goto err_exit; |
432 | setup_timer(&self->service_timer, &aq_nic_service_timer_cb, | 443 | setup_timer(&self->service_timer, &aq_nic_service_timer_cb, |
433 | (unsigned long)self); | 444 | (unsigned long)self); |
@@ -649,6 +660,11 @@ err_exit: | |||
649 | return err; | 660 | return err; |
650 | } | 661 | } |
651 | 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 | |||
652 | 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) |
653 | { | 669 | { |
654 | int err = 0; | 670 | int err = 0; |
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/hw_atl/hw_atl_a0.c b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_a0.c index b0747b2486b2..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 | } |
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 6f6e70aa1047..11f7e71bf448 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,31 +788,37 @@ 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 | {0xffU, 0xffU}, /* 10Gbit */ |
@@ -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); |
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.h b/drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h index 2218bdb605a7..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 | |||
@@ -131,8 +131,6 @@ struct __packed hw_atl_s { | |||
131 | struct hw_atl_stats_s last_stats; | 131 | struct hw_atl_stats_s last_stats; |
132 | struct hw_atl_stats_s curr_stats; | 132 | struct hw_atl_stats_s curr_stats; |
133 | u64 speed; | 133 | u64 speed; |
134 | u32 itr_tx; | ||
135 | u32 itr_rx; | ||
136 | unsigned int chip_features; | 134 | unsigned int chip_features; |
137 | u32 fw_ver_actual; | 135 | u32 fw_ver_actual; |
138 | atomic_t dpc; | 136 | atomic_t dpc; |