xref: /openbmc/linux/drivers/net/ethernet/aquantia/atlantic/aq_nic.c (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
175a6faf6SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2843e1396SMark Starovoytov /* Atlantic Network Driver
3843e1396SMark Starovoytov  *
4843e1396SMark Starovoytov  * Copyright (C) 2014-2019 aQuantia Corporation
5843e1396SMark Starovoytov  * Copyright (C) 2019-2020 Marvell International Ltd.
697bde5c4SDavid VomLehn  */
797bde5c4SDavid VomLehn 
897bde5c4SDavid VomLehn /* File aq_nic.c: Definition of common code for NIC. */
997bde5c4SDavid VomLehn 
1097bde5c4SDavid VomLehn #include "aq_nic.h"
1197bde5c4SDavid VomLehn #include "aq_ring.h"
1297bde5c4SDavid VomLehn #include "aq_vec.h"
1397bde5c4SDavid VomLehn #include "aq_hw.h"
1497bde5c4SDavid VomLehn #include "aq_pci_func.h"
1562c1c2e6SDmitry Bogdanov #include "aq_macsec.h"
164c83f170SIgor Russkikh #include "aq_main.h"
17dbcd6806SDmitry Bezrukov #include "aq_phy.h"
181a64f8dcSEgor Pomozov #include "aq_ptp.h"
195a1bf9efSDmitry Bezrukov #include "aq_filters.h"
2097bde5c4SDavid VomLehn 
21b82ee71aSIgor Russkikh #include <linux/moduleparam.h>
2297bde5c4SDavid VomLehn #include <linux/netdevice.h>
2397bde5c4SDavid VomLehn #include <linux/etherdevice.h>
2497bde5c4SDavid VomLehn #include <linux/timer.h>
2597bde5c4SDavid VomLehn #include <linux/cpu.h>
2697bde5c4SDavid VomLehn #include <linux/ip.h>
2797bde5c4SDavid VomLehn #include <linux/tcp.h>
2897bde5c4SDavid VomLehn #include <net/ip.h>
29a83fe6b6SDmitry Bezrukov #include <net/pkt_cls.h>
3097bde5c4SDavid VomLehn 
31b82ee71aSIgor Russkikh static unsigned int aq_itr = AQ_CFG_INTERRUPT_MODERATION_AUTO;
32b82ee71aSIgor Russkikh module_param_named(aq_itr, aq_itr, uint, 0644);
33b82ee71aSIgor Russkikh MODULE_PARM_DESC(aq_itr, "Interrupt throttling mode");
34b82ee71aSIgor Russkikh 
35b82ee71aSIgor Russkikh static unsigned int aq_itr_tx;
36b82ee71aSIgor Russkikh module_param_named(aq_itr_tx, aq_itr_tx, uint, 0644);
37b82ee71aSIgor Russkikh MODULE_PARM_DESC(aq_itr_tx, "TX interrupt throttle rate");
38b82ee71aSIgor Russkikh 
39b82ee71aSIgor Russkikh static unsigned int aq_itr_rx;
40b82ee71aSIgor Russkikh module_param_named(aq_itr_rx, aq_itr_rx, uint, 0644);
41b82ee71aSIgor Russkikh MODULE_PARM_DESC(aq_itr_rx, "RX interrupt throttle rate");
42b82ee71aSIgor Russkikh 
439f8a2203SIgor Russkikh static void aq_nic_update_ndev_stats(struct aq_nic_s *self);
449f8a2203SIgor Russkikh 
aq_nic_rss_init(struct aq_nic_s * self,unsigned int num_rss_queues)4597bde5c4SDavid VomLehn static void aq_nic_rss_init(struct aq_nic_s *self, unsigned int num_rss_queues)
4697bde5c4SDavid VomLehn {
47474fb115SDmitry Bogdanov 	static u8 rss_key[AQ_CFG_RSS_HASHKEY_SIZE] = {
4897bde5c4SDavid VomLehn 		0x1e, 0xad, 0x71, 0x87, 0x65, 0xfc, 0x26, 0x7d,
4997bde5c4SDavid VomLehn 		0x0d, 0x45, 0x67, 0x74, 0xcd, 0x06, 0x1a, 0x18,
5097bde5c4SDavid VomLehn 		0xb6, 0xc1, 0xf0, 0xc7, 0xbb, 0x18, 0xbe, 0xf8,
5197bde5c4SDavid VomLehn 		0x19, 0x13, 0x4b, 0xa9, 0xd0, 0x3e, 0xfe, 0x70,
5297bde5c4SDavid VomLehn 		0x25, 0x03, 0xab, 0x50, 0x6a, 0x8b, 0x82, 0x0c
5397bde5c4SDavid VomLehn 	};
547b0c342fSNikita Danilov 	struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg;
557b0c342fSNikita Danilov 	struct aq_rss_parameters *rss_params;
567b0c342fSNikita Danilov 	int i = 0;
577b0c342fSNikita Danilov 
587b0c342fSNikita Danilov 	rss_params = &cfg->aq_rss;
5997bde5c4SDavid VomLehn 
6097bde5c4SDavid VomLehn 	rss_params->hash_secret_key_size = sizeof(rss_key);
6197bde5c4SDavid VomLehn 	memcpy(rss_params->hash_secret_key, rss_key, sizeof(rss_key));
6297bde5c4SDavid VomLehn 	rss_params->indirection_table_size = AQ_CFG_RSS_INDIRECTION_TABLE_MAX;
6397bde5c4SDavid VomLehn 
6497bde5c4SDavid VomLehn 	for (i = rss_params->indirection_table_size; i--;)
6597bde5c4SDavid VomLehn 		rss_params->indirection_table[i] = i & (num_rss_queues - 1);
6697bde5c4SDavid VomLehn }
6797bde5c4SDavid VomLehn 
6814ef766bSMark Starovoytov /* Recalculate the number of vectors */
aq_nic_cfg_update_num_vecs(struct aq_nic_s * self)6914ef766bSMark Starovoytov static void aq_nic_cfg_update_num_vecs(struct aq_nic_s *self)
7014ef766bSMark Starovoytov {
7114ef766bSMark Starovoytov 	struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg;
7214ef766bSMark Starovoytov 
7314ef766bSMark Starovoytov 	cfg->vecs = min(cfg->aq_hw_caps->vecs, AQ_CFG_VECS_DEF);
7414ef766bSMark Starovoytov 	cfg->vecs = min(cfg->vecs, num_online_cpus());
7514ef766bSMark Starovoytov 	if (self->irqvecs > AQ_HW_SERVICE_IRQS)
7614ef766bSMark Starovoytov 		cfg->vecs = min(cfg->vecs, self->irqvecs - AQ_HW_SERVICE_IRQS);
7714ef766bSMark Starovoytov 	/* cfg->vecs should be power of 2 for RSS */
7814ef766bSMark Starovoytov 	cfg->vecs = rounddown_pow_of_two(cfg->vecs);
7914ef766bSMark Starovoytov 
8014ef766bSMark Starovoytov 	if (ATL_HW_IS_CHIP_FEATURE(self->aq_hw, ANTIGUA)) {
8114ef766bSMark Starovoytov 		if (cfg->tcs > 2)
8214ef766bSMark Starovoytov 			cfg->vecs = min(cfg->vecs, 4U);
8314ef766bSMark Starovoytov 	}
8414ef766bSMark Starovoytov 
8514ef766bSMark Starovoytov 	if (cfg->vecs <= 4)
8614ef766bSMark Starovoytov 		cfg->tc_mode = AQ_TC_MODE_8TCS;
8714ef766bSMark Starovoytov 	else
8814ef766bSMark Starovoytov 		cfg->tc_mode = AQ_TC_MODE_4TCS;
8914ef766bSMark Starovoytov 
9014ef766bSMark Starovoytov 	/*rss rings */
9114ef766bSMark Starovoytov 	cfg->num_rss_queues = min(cfg->vecs, AQ_CFG_NUM_RSS_QUEUES_DEF);
9214ef766bSMark Starovoytov 	aq_nic_rss_init(self, cfg->num_rss_queues);
9314ef766bSMark Starovoytov }
9414ef766bSMark Starovoytov 
9523ee07adSIgor Russkikh /* Checks hw_caps and 'corrects' aq_nic_cfg in runtime */
aq_nic_cfg_start(struct aq_nic_s * self)9623ee07adSIgor Russkikh void aq_nic_cfg_start(struct aq_nic_s *self)
9797bde5c4SDavid VomLehn {
9897bde5c4SDavid VomLehn 	struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg;
99a83fe6b6SDmitry Bezrukov 	int i;
10097bde5c4SDavid VomLehn 
10197bde5c4SDavid VomLehn 	cfg->tcs = AQ_CFG_TCS_DEF;
10297bde5c4SDavid VomLehn 
10397bde5c4SDavid VomLehn 	cfg->is_polling = AQ_CFG_IS_POLLING_DEF;
10497bde5c4SDavid VomLehn 
105b82ee71aSIgor Russkikh 	cfg->itr = aq_itr;
106b82ee71aSIgor Russkikh 	cfg->tx_itr = aq_itr_tx;
107b82ee71aSIgor Russkikh 	cfg->rx_itr = aq_itr_rx;
10897bde5c4SDavid VomLehn 
10946f4c29dSIgor Russkikh 	cfg->rxpageorder = AQ_CFG_RX_PAGEORDER;
11097bde5c4SDavid VomLehn 	cfg->is_rss = AQ_CFG_IS_RSS_DEF;
11197bde5c4SDavid VomLehn 	cfg->aq_rss.base_cpu_number = AQ_CFG_RSS_BASE_CPU_NUM_DEF;
1128009bb19SNikita Danilov 	cfg->fc.req = AQ_CFG_FC_MODE;
113837c6378SNikita Danilov 	cfg->wol = AQ_CFG_WOL_MODES;
11497bde5c4SDavid VomLehn 
11597bde5c4SDavid VomLehn 	cfg->mtu = AQ_CFG_MTU_DEF;
11697bde5c4SDavid VomLehn 	cfg->link_speed_msk = AQ_CFG_SPEED_MSK;
11797bde5c4SDavid VomLehn 	cfg->is_autoneg = AQ_CFG_IS_AUTONEG_DEF;
11897bde5c4SDavid VomLehn 
11997bde5c4SDavid VomLehn 	cfg->is_lro = AQ_CFG_IS_LRO_DEF;
1200aa7bc3eSDmitry Bezrukov 	cfg->is_ptp = true;
12197bde5c4SDavid VomLehn 
12297bde5c4SDavid VomLehn 	/*descriptors */
123c1af5427SAnton Mikaev 	cfg->rxds = min(cfg->aq_hw_caps->rxds_max, AQ_CFG_RXDS_DEF);
124c1af5427SAnton Mikaev 	cfg->txds = min(cfg->aq_hw_caps->txds_max, AQ_CFG_TXDS_DEF);
12597bde5c4SDavid VomLehn 
12614ef766bSMark Starovoytov 	aq_nic_cfg_update_num_vecs(self);
127a8c69ca7SDmitry Bogdanov 
12823ee07adSIgor Russkikh 	cfg->irq_type = aq_pci_func_get_irq_type(self);
12997bde5c4SDavid VomLehn 
13097bde5c4SDavid VomLehn 	if ((cfg->irq_type == AQ_HW_IRQ_LEGACY) ||
1318fcb98f4SIgor Russkikh 	    (cfg->aq_hw_caps->vecs == 1U) ||
13297bde5c4SDavid VomLehn 	    (cfg->vecs == 1U)) {
13397bde5c4SDavid VomLehn 		cfg->is_rss = 0U;
13497bde5c4SDavid VomLehn 		cfg->vecs = 1U;
13597bde5c4SDavid VomLehn 	}
13697bde5c4SDavid VomLehn 
1374c83f170SIgor Russkikh 	/* Check if we have enough vectors allocated for
1384c83f170SIgor Russkikh 	 * link status IRQ. If no - we'll know link state from
1394c83f170SIgor Russkikh 	 * slower service task.
1404c83f170SIgor Russkikh 	 */
1414c83f170SIgor Russkikh 	if (AQ_HW_SERVICE_IRQS > 0 && cfg->vecs + 1 <= self->irqvecs)
1424c83f170SIgor Russkikh 		cfg->link_irq_vec = cfg->vecs;
1434c83f170SIgor Russkikh 	else
1444c83f170SIgor Russkikh 		cfg->link_irq_vec = 0;
1454c83f170SIgor Russkikh 
1468fcb98f4SIgor Russkikh 	cfg->link_speed_msk &= cfg->aq_hw_caps->link_speed_msk;
147bbb67a44SDmitry Bogdanov 	cfg->features = cfg->aq_hw_caps->hw_features;
148d3ed7c5cSIgor Russkikh 	cfg->is_vlan_rx_strip = !!(cfg->features & NETIF_F_HW_VLAN_CTAG_RX);
149d3ed7c5cSIgor Russkikh 	cfg->is_vlan_tx_insert = !!(cfg->features & NETIF_F_HW_VLAN_CTAG_TX);
15048dd73d0SDmitry Bogdanov 	cfg->is_vlan_force_promisc = true;
151a83fe6b6SDmitry Bezrukov 
152a83fe6b6SDmitry Bezrukov 	for (i = 0; i < sizeof(cfg->prio_tc_map); i++)
153a83fe6b6SDmitry Bezrukov 		cfg->prio_tc_map[i] = cfg->tcs * i / 8;
15497bde5c4SDavid VomLehn }
15597bde5c4SDavid VomLehn 
aq_nic_update_link_status(struct aq_nic_s * self)1563aec6412SIgor Russkikh static int aq_nic_update_link_status(struct aq_nic_s *self)
1573aec6412SIgor Russkikh {
1580c58c35fSIgor Russkikh 	int err = self->aq_fw_ops->update_link_status(self->aq_hw);
15935e8e8b4SIgor Russkikh 	u32 fc = 0;
1603aec6412SIgor Russkikh 
1613aec6412SIgor Russkikh 	if (err)
1623aec6412SIgor Russkikh 		return err;
1633aec6412SIgor Russkikh 
1648009bb19SNikita Danilov 	if (self->aq_fw_ops->get_flow_control)
1658009bb19SNikita Danilov 		self->aq_fw_ops->get_flow_control(self->aq_hw, &fc);
1668009bb19SNikita Danilov 	self->aq_nic_cfg.fc.cur = fc;
1678009bb19SNikita Danilov 
168b82ee71aSIgor Russkikh 	if (self->link_status.mbps != self->aq_hw->aq_link_status.mbps) {
16958128fa0SNikita Danilov 		netdev_info(self->ndev, "%s: link change old %d new %d\n",
1703aec6412SIgor Russkikh 			    AQ_CFG_DRV_NAME, self->link_status.mbps,
1713aec6412SIgor Russkikh 			    self->aq_hw->aq_link_status.mbps);
172b82ee71aSIgor Russkikh 		aq_nic_update_interrupt_moderation_settings(self);
17335e8e8b4SIgor Russkikh 
17404a18399SEgor Pomozov 		if (self->aq_ptp) {
175910479a9SEgor Pomozov 			aq_ptp_clock_init(self);
17604a18399SEgor Pomozov 			aq_ptp_tm_offset_set(self,
17704a18399SEgor Pomozov 					     self->aq_hw->aq_link_status.mbps);
1789c477032SDmitry Bezrukov 			aq_ptp_link_change(self);
17904a18399SEgor Pomozov 		}
180910479a9SEgor Pomozov 
18135e8e8b4SIgor Russkikh 		/* Driver has to update flow control settings on RX block
18235e8e8b4SIgor Russkikh 		 * on any link event.
18335e8e8b4SIgor Russkikh 		 * We should query FW whether it negotiated FC.
18435e8e8b4SIgor Russkikh 		 */
18535e8e8b4SIgor Russkikh 		if (self->aq_hw_ops->hw_set_fc)
18635e8e8b4SIgor Russkikh 			self->aq_hw_ops->hw_set_fc(self->aq_hw, fc, 0);
187b82ee71aSIgor Russkikh 	}
1883aec6412SIgor Russkikh 
1893aec6412SIgor Russkikh 	self->link_status = self->aq_hw->aq_link_status;
1903aec6412SIgor Russkikh 	if (!netif_carrier_ok(self->ndev) && self->link_status.mbps) {
19178f5193dSIgor Russkikh 		aq_utils_obj_set(&self->flags,
1923aec6412SIgor Russkikh 				 AQ_NIC_FLAG_STARTED);
19378f5193dSIgor Russkikh 		aq_utils_obj_clear(&self->flags,
1943aec6412SIgor Russkikh 				   AQ_NIC_LINK_DOWN);
1953aec6412SIgor Russkikh 		netif_carrier_on(self->ndev);
19662c1c2e6SDmitry Bogdanov #if IS_ENABLED(CONFIG_MACSEC)
19762c1c2e6SDmitry Bogdanov 		aq_macsec_enable(self);
19862c1c2e6SDmitry Bogdanov #endif
1992deac71aSMark Starovoytov 		if (self->aq_hw_ops->hw_tc_rate_limit_set)
2002deac71aSMark Starovoytov 			self->aq_hw_ops->hw_tc_rate_limit_set(self->aq_hw);
2012deac71aSMark Starovoytov 
2023aec6412SIgor Russkikh 		netif_tx_wake_all_queues(self->ndev);
2033aec6412SIgor Russkikh 	}
2043aec6412SIgor Russkikh 	if (netif_carrier_ok(self->ndev) && !self->link_status.mbps) {
2053aec6412SIgor Russkikh 		netif_carrier_off(self->ndev);
2063aec6412SIgor Russkikh 		netif_tx_disable(self->ndev);
20778f5193dSIgor Russkikh 		aq_utils_obj_set(&self->flags, AQ_NIC_LINK_DOWN);
2083aec6412SIgor Russkikh 	}
2097b0c342fSNikita Danilov 
2103aec6412SIgor Russkikh 	return 0;
2113aec6412SIgor Russkikh }
2123aec6412SIgor Russkikh 
aq_linkstate_threaded_isr(int irq,void * private)2131d2a8a13SIgor Russkikh static irqreturn_t aq_linkstate_threaded_isr(int irq, void *private)
2141d2a8a13SIgor Russkikh {
2151d2a8a13SIgor Russkikh 	struct aq_nic_s *self = private;
2161d2a8a13SIgor Russkikh 
2171d2a8a13SIgor Russkikh 	if (!self)
2181d2a8a13SIgor Russkikh 		return IRQ_NONE;
2191d2a8a13SIgor Russkikh 
2201d2a8a13SIgor Russkikh 	aq_nic_update_link_status(self);
2211d2a8a13SIgor Russkikh 
2221d2a8a13SIgor Russkikh 	self->aq_hw_ops->hw_irq_enable(self->aq_hw,
2231d2a8a13SIgor Russkikh 				       BIT(self->aq_nic_cfg.link_irq_vec));
2247b0c342fSNikita Danilov 
2251d2a8a13SIgor Russkikh 	return IRQ_HANDLED;
2261d2a8a13SIgor Russkikh }
2271d2a8a13SIgor Russkikh 
aq_nic_service_task(struct work_struct * work)22849544935SIgor Russkikh static void aq_nic_service_task(struct work_struct *work)
22997bde5c4SDavid VomLehn {
23049544935SIgor Russkikh 	struct aq_nic_s *self = container_of(work, struct aq_nic_s,
23149544935SIgor Russkikh 					     service_task);
23249544935SIgor Russkikh 	int err;
23397bde5c4SDavid VomLehn 
23404a18399SEgor Pomozov 	aq_ptp_service_task(self);
23504a18399SEgor Pomozov 
23678f5193dSIgor Russkikh 	if (aq_utils_obj_test(&self->flags, AQ_NIC_FLAGS_IS_NOT_READY))
23749544935SIgor Russkikh 		return;
23897bde5c4SDavid VomLehn 
2393aec6412SIgor Russkikh 	err = aq_nic_update_link_status(self);
2403aec6412SIgor Russkikh 	if (err)
24149544935SIgor Russkikh 		return;
24297bde5c4SDavid VomLehn 
24362c1c2e6SDmitry Bogdanov #if IS_ENABLED(CONFIG_MACSEC)
24462c1c2e6SDmitry Bogdanov 	aq_macsec_work(self);
24562c1c2e6SDmitry Bogdanov #endif
24662c1c2e6SDmitry Bogdanov 
24749544935SIgor Russkikh 	mutex_lock(&self->fwreq_mutex);
2480c58c35fSIgor Russkikh 	if (self->aq_fw_ops->update_stats)
2490c58c35fSIgor Russkikh 		self->aq_fw_ops->update_stats(self->aq_hw);
25049544935SIgor Russkikh 	mutex_unlock(&self->fwreq_mutex);
25165e665e6SIgor Russkikh 
2529f8a2203SIgor Russkikh 	aq_nic_update_ndev_stats(self);
25349544935SIgor Russkikh }
25497bde5c4SDavid VomLehn 
aq_nic_service_timer_cb(struct timer_list * t)25549544935SIgor Russkikh static void aq_nic_service_timer_cb(struct timer_list *t)
25649544935SIgor Russkikh {
25749544935SIgor Russkikh 	struct aq_nic_s *self = from_timer(self, t, service_timer);
25849544935SIgor Russkikh 
2597b0c342fSNikita Danilov 	mod_timer(&self->service_timer,
2607b0c342fSNikita Danilov 		  jiffies + AQ_CFG_SERVICE_TIMER_INTERVAL);
26149544935SIgor Russkikh 
26249544935SIgor Russkikh 	aq_ndev_schedule_work(&self->service_task);
26397bde5c4SDavid VomLehn }
26497bde5c4SDavid VomLehn 
aq_nic_polling_timer_cb(struct timer_list * t)265e99e88a9SKees Cook static void aq_nic_polling_timer_cb(struct timer_list *t)
26697bde5c4SDavid VomLehn {
267e99e88a9SKees Cook 	struct aq_nic_s *self = from_timer(self, t, polling_timer);
26897bde5c4SDavid VomLehn 	unsigned int i = 0U;
26997bde5c4SDavid VomLehn 
2702ba5e47fSChia-Lin Kao (AceLan) 	for (i = 0U; self->aq_vecs > i; ++i)
2712ba5e47fSChia-Lin Kao (AceLan) 		aq_vec_isr(i, (void *)self->aq_vec[i]);
27297bde5c4SDavid VomLehn 
27397bde5c4SDavid VomLehn 	mod_timer(&self->polling_timer, jiffies +
27497bde5c4SDavid VomLehn 		  AQ_CFG_POLLING_TIMER_INTERVAL);
27597bde5c4SDavid VomLehn }
27697bde5c4SDavid VomLehn 
aq_nic_hw_prepare(struct aq_nic_s * self)277099d074eSMark Starovoytov static int aq_nic_hw_prepare(struct aq_nic_s *self)
278099d074eSMark Starovoytov {
279099d074eSMark Starovoytov 	int err = 0;
280099d074eSMark Starovoytov 
281099d074eSMark Starovoytov 	err = self->aq_hw_ops->hw_soft_reset(self->aq_hw);
282099d074eSMark Starovoytov 	if (err)
283099d074eSMark Starovoytov 		goto exit;
284099d074eSMark Starovoytov 
285099d074eSMark Starovoytov 	err = self->aq_hw_ops->hw_prepare(self->aq_hw, &self->aq_fw_ops);
286099d074eSMark Starovoytov 
287099d074eSMark Starovoytov exit:
288099d074eSMark Starovoytov 	return err;
289099d074eSMark Starovoytov }
290099d074eSMark Starovoytov 
aq_nic_is_valid_ether_addr(const u8 * addr)291b4de6c49SMark Starovoytov static bool aq_nic_is_valid_ether_addr(const u8 *addr)
292b4de6c49SMark Starovoytov {
293b4de6c49SMark Starovoytov 	/* Some engineering samples of Aquantia NICs are provisioned with a
294b4de6c49SMark Starovoytov 	 * partially populated MAC, which is still invalid.
295b4de6c49SMark Starovoytov 	 */
296b4de6c49SMark Starovoytov 	return !(addr[0] == 0 && addr[1] == 0 && addr[2] == 0);
297b4de6c49SMark Starovoytov }
298b4de6c49SMark Starovoytov 
aq_nic_ndev_register(struct aq_nic_s * self)29997bde5c4SDavid VomLehn int aq_nic_ndev_register(struct aq_nic_s *self)
30097bde5c4SDavid VomLehn {
301698c33d8SJakub Kicinski 	u8 addr[ETH_ALEN];
30297bde5c4SDavid VomLehn 	int err = 0;
30397bde5c4SDavid VomLehn 
30497bde5c4SDavid VomLehn 	if (!self->ndev) {
30597bde5c4SDavid VomLehn 		err = -EINVAL;
30697bde5c4SDavid VomLehn 		goto err_exit;
30797bde5c4SDavid VomLehn 	}
30823ee07adSIgor Russkikh 
309099d074eSMark Starovoytov 	err = aq_nic_hw_prepare(self);
3100c58c35fSIgor Russkikh 	if (err)
3110c58c35fSIgor Russkikh 		goto err_exit;
3120c58c35fSIgor Russkikh 
31362c1c2e6SDmitry Bogdanov #if IS_ENABLED(CONFIG_MACSEC)
31462c1c2e6SDmitry Bogdanov 	aq_macsec_init(self);
31562c1c2e6SDmitry Bogdanov #endif
31662c1c2e6SDmitry Bogdanov 
317553217c2STianhao Chai 	if (platform_get_ethdev_address(&self->pdev->dev, self->ndev) != 0) {
318553217c2STianhao Chai 		// If DT has none or an invalid one, ask device for MAC address
319f5dce08aSNikita Danilov 		mutex_lock(&self->fwreq_mutex);
320698c33d8SJakub Kicinski 		err = self->aq_fw_ops->get_mac_permanent(self->aq_hw, addr);
321f5dce08aSNikita Danilov 		mutex_unlock(&self->fwreq_mutex);
322553217c2STianhao Chai 
32323ee07adSIgor Russkikh 		if (err)
32497bde5c4SDavid VomLehn 			goto err_exit;
32597bde5c4SDavid VomLehn 
326553217c2STianhao Chai 		if (is_valid_ether_addr(addr) &&
327553217c2STianhao Chai 		    aq_nic_is_valid_ether_addr(addr)) {
328698c33d8SJakub Kicinski 			eth_hw_addr_set(self->ndev, addr);
329553217c2STianhao Chai 		} else {
330b4de6c49SMark Starovoytov 			netdev_warn(self->ndev, "MAC is invalid, will use random.");
331b4de6c49SMark Starovoytov 			eth_hw_addr_random(self->ndev);
332b4de6c49SMark Starovoytov 		}
333553217c2STianhao Chai 	}
334b4de6c49SMark Starovoytov 
33597bde5c4SDavid VomLehn #if defined(AQ_CFG_MAC_ADDR_PERMANENT)
33697bde5c4SDavid VomLehn 	{
33797bde5c4SDavid VomLehn 		static u8 mac_addr_permanent[] = AQ_CFG_MAC_ADDR_PERMANENT;
33897bde5c4SDavid VomLehn 
339f3956ebbSJakub Kicinski 		eth_hw_addr_set(self->ndev, mac_addr_permanent);
34097bde5c4SDavid VomLehn 	}
34197bde5c4SDavid VomLehn #endif
34297bde5c4SDavid VomLehn 
34323ee07adSIgor Russkikh 	for (self->aq_vecs = 0; self->aq_vecs < aq_nic_get_cfg(self)->vecs;
34423ee07adSIgor Russkikh 	     self->aq_vecs++) {
34523ee07adSIgor Russkikh 		self->aq_vec[self->aq_vecs] =
34623ee07adSIgor Russkikh 		    aq_vec_alloc(self, self->aq_vecs, aq_nic_get_cfg(self));
34723ee07adSIgor Russkikh 		if (!self->aq_vec[self->aq_vecs]) {
34823ee07adSIgor Russkikh 			err = -ENOMEM;
34923ee07adSIgor Russkikh 			goto err_exit;
35023ee07adSIgor Russkikh 		}
35123ee07adSIgor Russkikh 	}
35223ee07adSIgor Russkikh 
35397bde5c4SDavid VomLehn 	netif_carrier_off(self->ndev);
35497bde5c4SDavid VomLehn 
3553aec6412SIgor Russkikh 	netif_tx_disable(self->ndev);
35697bde5c4SDavid VomLehn 
35755629109SPavel Belous 	err = register_netdev(self->ndev);
35823ee07adSIgor Russkikh 	if (err)
35955629109SPavel Belous 		goto err_exit;
36055629109SPavel Belous 
36197bde5c4SDavid VomLehn err_exit:
36262c1c2e6SDmitry Bogdanov #if IS_ENABLED(CONFIG_MACSEC)
36362c1c2e6SDmitry Bogdanov 	if (err)
36462c1c2e6SDmitry Bogdanov 		aq_macsec_free(self);
36562c1c2e6SDmitry Bogdanov #endif
36697bde5c4SDavid VomLehn 	return err;
36797bde5c4SDavid VomLehn }
36897bde5c4SDavid VomLehn 
aq_nic_ndev_init(struct aq_nic_s * self)36923ee07adSIgor Russkikh void aq_nic_ndev_init(struct aq_nic_s *self)
37097bde5c4SDavid VomLehn {
3714cbc9f92SIgor Russkikh 	const struct aq_hw_caps_s *aq_hw_caps = self->aq_nic_cfg.aq_hw_caps;
37297bde5c4SDavid VomLehn 	struct aq_nic_cfg_s *aq_nic_cfg = &self->aq_nic_cfg;
37397bde5c4SDavid VomLehn 
37497bde5c4SDavid VomLehn 	self->ndev->hw_features |= aq_hw_caps->hw_features;
37597bde5c4SDavid VomLehn 	self->ndev->features = aq_hw_caps->hw_features;
3768c61ab7fSIgor Russkikh 	self->ndev->vlan_features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM |
377d3ed7c5cSIgor Russkikh 				     NETIF_F_RXHASH | NETIF_F_SG |
3788bd60710SIgor Russkikh 				     NETIF_F_LRO | NETIF_F_TSO | NETIF_F_TSO6;
379822cd114SIgor Russkikh 	self->ndev->gso_partial_features = NETIF_F_GSO_UDP_L4;
38097bde5c4SDavid VomLehn 	self->ndev->priv_flags = aq_hw_caps->hw_priv_flags;
3813e9a5451SIgor Russkikh 	self->ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
3823e9a5451SIgor Russkikh 
38358128fa0SNikita Danilov 	self->msg_enable = NETIF_MSG_DRV | NETIF_MSG_LINK;
38497bde5c4SDavid VomLehn 	self->ndev->mtu = aq_nic_cfg->mtu - ETH_HLEN;
3858fcb98f4SIgor Russkikh 	self->ndev->max_mtu = aq_hw_caps->mtu - ETH_FCS_LEN - ETH_HLEN;
38697bde5c4SDavid VomLehn 
387*66c0e13aSMarek Majtyka 	self->ndev->xdp_features = NETDEV_XDP_ACT_BASIC |
388*66c0e13aSMarek Majtyka 				   NETDEV_XDP_ACT_REDIRECT |
389*66c0e13aSMarek Majtyka 				   NETDEV_XDP_ACT_NDO_XMIT |
390*66c0e13aSMarek Majtyka 				   NETDEV_XDP_ACT_RX_SG |
391*66c0e13aSMarek Majtyka 				   NETDEV_XDP_ACT_NDO_XMIT_SG;
39297bde5c4SDavid VomLehn }
39397bde5c4SDavid VomLehn 
aq_nic_set_tx_ring(struct aq_nic_s * self,unsigned int idx,struct aq_ring_s * ring)39497bde5c4SDavid VomLehn void aq_nic_set_tx_ring(struct aq_nic_s *self, unsigned int idx,
39597bde5c4SDavid VomLehn 			struct aq_ring_s *ring)
39697bde5c4SDavid VomLehn {
39797bde5c4SDavid VomLehn 	self->aq_ring_tx[idx] = ring;
39897bde5c4SDavid VomLehn }
39997bde5c4SDavid VomLehn 
aq_nic_get_ndev(struct aq_nic_s * self)40097bde5c4SDavid VomLehn struct net_device *aq_nic_get_ndev(struct aq_nic_s *self)
40197bde5c4SDavid VomLehn {
40297bde5c4SDavid VomLehn 	return self->ndev;
40397bde5c4SDavid VomLehn }
40497bde5c4SDavid VomLehn 
aq_nic_init(struct aq_nic_s * self)40597bde5c4SDavid VomLehn int aq_nic_init(struct aq_nic_s *self)
40697bde5c4SDavid VomLehn {
40797bde5c4SDavid VomLehn 	struct aq_vec_s *aq_vec = NULL;
40897bde5c4SDavid VomLehn 	unsigned int i = 0U;
4097b0c342fSNikita Danilov 	int err = 0;
41097bde5c4SDavid VomLehn 
41197bde5c4SDavid VomLehn 	self->power_state = AQ_HW_POWER_STATE_D0;
412f5dce08aSNikita Danilov 	mutex_lock(&self->fwreq_mutex);
4138fcb98f4SIgor Russkikh 	err = self->aq_hw_ops->hw_reset(self->aq_hw);
414f5dce08aSNikita Danilov 	mutex_unlock(&self->fwreq_mutex);
41597bde5c4SDavid VomLehn 	if (err < 0)
41697bde5c4SDavid VomLehn 		goto err_exit;
417e193c3abSIgor Russkikh 	/* Restore default settings */
418e193c3abSIgor Russkikh 	aq_nic_set_downshift(self, self->aq_nic_cfg.downshift_counter);
41960db5e40SIgor Russkikh 	aq_nic_set_media_detect(self, self->aq_nic_cfg.is_media_detect ?
42060db5e40SIgor Russkikh 				AQ_HW_MEDIA_DETECT_CNT : 0);
42197bde5c4SDavid VomLehn 
4228fcb98f4SIgor Russkikh 	err = self->aq_hw_ops->hw_init(self->aq_hw,
42397bde5c4SDavid VomLehn 				       aq_nic_get_ndev(self)->dev_addr);
42497bde5c4SDavid VomLehn 	if (err < 0)
42597bde5c4SDavid VomLehn 		goto err_exit;
42697bde5c4SDavid VomLehn 
427e54dcf4bSIgor Russkikh 	if (ATL_HW_IS_CHIP_FEATURE(self->aq_hw, ATLANTIC) &&
428e54dcf4bSIgor Russkikh 	    self->aq_nic_cfg.aq_hw_caps->media_type == AQ_HW_MEDIA_TYPE_TP) {
429dbcd6806SDmitry Bezrukov 		self->aq_hw->phy_id = HW_ATL_PHY_ID_MAX;
430dbcd6806SDmitry Bezrukov 		err = aq_phy_init(self->aq_hw);
43123e500e8SNikita Danilov 
43223e500e8SNikita Danilov 		/* Disable the PTP on NICs where it's known to cause datapath
43323e500e8SNikita Danilov 		 * problems.
43423e500e8SNikita Danilov 		 * Ideally this should have been done by PHY provisioning, but
43523e500e8SNikita Danilov 		 * many units have been shipped with enabled PTP block already.
43623e500e8SNikita Danilov 		 */
43723e500e8SNikita Danilov 		if (self->aq_nic_cfg.aq_hw_caps->quirks & AQ_NIC_QUIRK_BAD_PTP)
43823e500e8SNikita Danilov 			if (self->aq_hw->phy_id != HW_ATL_PHY_ID_MAX)
43923e500e8SNikita Danilov 				aq_phy_disable_ptp(self->aq_hw);
440dbcd6806SDmitry Bezrukov 	}
441dbcd6806SDmitry Bezrukov 
4428ce84271SDmitry Bezrukov 	for (i = 0U; i < self->aq_vecs; i++) {
4438ce84271SDmitry Bezrukov 		aq_vec = self->aq_vec[i];
4448ce84271SDmitry Bezrukov 		err = aq_vec_ring_alloc(aq_vec, self, i,
4458ce84271SDmitry Bezrukov 					aq_nic_get_cfg(self));
4468ce84271SDmitry Bezrukov 		if (err)
4478ce84271SDmitry Bezrukov 			goto err_exit;
4488ce84271SDmitry Bezrukov 
4498fcb98f4SIgor Russkikh 		aq_vec_init(aq_vec, self->aq_hw_ops, self->aq_hw);
4508ce84271SDmitry Bezrukov 	}
45197bde5c4SDavid VomLehn 
4520aa7bc3eSDmitry Bezrukov 	if (aq_nic_get_cfg(self)->is_ptp) {
4531a64f8dcSEgor Pomozov 		err = aq_ptp_init(self, self->irqvecs - 1);
4541a64f8dcSEgor Pomozov 		if (err < 0)
4551a64f8dcSEgor Pomozov 			goto err_exit;
4561a64f8dcSEgor Pomozov 
45794ad9455SEgor Pomozov 		err = aq_ptp_ring_alloc(self);
45894ad9455SEgor Pomozov 		if (err < 0)
45994ad9455SEgor Pomozov 			goto err_exit;
46094ad9455SEgor Pomozov 
46194ad9455SEgor Pomozov 		err = aq_ptp_ring_init(self);
46294ad9455SEgor Pomozov 		if (err < 0)
46394ad9455SEgor Pomozov 			goto err_exit;
4640aa7bc3eSDmitry Bezrukov 	}
46594ad9455SEgor Pomozov 
46623ee07adSIgor Russkikh 	netif_carrier_off(self->ndev);
46723ee07adSIgor Russkikh 
46897bde5c4SDavid VomLehn err_exit:
46997bde5c4SDavid VomLehn 	return err;
47097bde5c4SDavid VomLehn }
47197bde5c4SDavid VomLehn 
aq_nic_start(struct aq_nic_s * self)47297bde5c4SDavid VomLehn int aq_nic_start(struct aq_nic_s *self)
47397bde5c4SDavid VomLehn {
47497bde5c4SDavid VomLehn 	struct aq_vec_s *aq_vec = NULL;
4758ce84271SDmitry Bezrukov 	struct aq_nic_cfg_s *cfg;
47697bde5c4SDavid VomLehn 	unsigned int i = 0U;
4777b0c342fSNikita Danilov 	int err = 0;
47897bde5c4SDavid VomLehn 
4798ce84271SDmitry Bezrukov 	cfg = aq_nic_get_cfg(self);
4808ce84271SDmitry Bezrukov 
4818fcb98f4SIgor Russkikh 	err = self->aq_hw_ops->hw_multicast_list_set(self->aq_hw,
48297bde5c4SDavid VomLehn 						     self->mc_list.ar,
48397bde5c4SDavid VomLehn 						     self->mc_list.count);
48497bde5c4SDavid VomLehn 	if (err < 0)
48597bde5c4SDavid VomLehn 		goto err_exit;
48697bde5c4SDavid VomLehn 
4878fcb98f4SIgor Russkikh 	err = self->aq_hw_ops->hw_packet_filter_set(self->aq_hw,
48897bde5c4SDavid VomLehn 						    self->packet_filter);
48997bde5c4SDavid VomLehn 	if (err < 0)
49097bde5c4SDavid VomLehn 		goto err_exit;
49197bde5c4SDavid VomLehn 
4928d3a6c37SKai-Heng Feng 	for (i = 0U; self->aq_vecs > i; ++i) {
4938d3a6c37SKai-Heng Feng 		aq_vec = self->aq_vec[i];
49497bde5c4SDavid VomLehn 		err = aq_vec_start(aq_vec);
49597bde5c4SDavid VomLehn 		if (err < 0)
49697bde5c4SDavid VomLehn 			goto err_exit;
49797bde5c4SDavid VomLehn 	}
49897bde5c4SDavid VomLehn 
49994ad9455SEgor Pomozov 	err = aq_ptp_ring_start(self);
50094ad9455SEgor Pomozov 	if (err < 0)
50194ad9455SEgor Pomozov 		goto err_exit;
50294ad9455SEgor Pomozov 
503883daa18SIgor Russkikh 	aq_nic_set_loopback(self);
504883daa18SIgor Russkikh 
5058fcb98f4SIgor Russkikh 	err = self->aq_hw_ops->hw_start(self->aq_hw);
50697bde5c4SDavid VomLehn 	if (err < 0)
50797bde5c4SDavid VomLehn 		goto err_exit;
50897bde5c4SDavid VomLehn 
509b82ee71aSIgor Russkikh 	err = aq_nic_update_interrupt_moderation_settings(self);
510b82ee71aSIgor Russkikh 	if (err)
51197bde5c4SDavid VomLehn 		goto err_exit;
51249544935SIgor Russkikh 
51349544935SIgor Russkikh 	INIT_WORK(&self->service_task, aq_nic_service_task);
51449544935SIgor Russkikh 
515e99e88a9SKees Cook 	timer_setup(&self->service_timer, aq_nic_service_timer_cb, 0);
51667758788SIgor Russkikh 	aq_nic_service_timer_cb(&self->service_timer);
51797bde5c4SDavid VomLehn 
5188ce84271SDmitry Bezrukov 	if (cfg->is_polling) {
519e99e88a9SKees Cook 		timer_setup(&self->polling_timer, aq_nic_polling_timer_cb, 0);
52097bde5c4SDavid VomLehn 		mod_timer(&self->polling_timer, jiffies +
52197bde5c4SDavid VomLehn 			  AQ_CFG_POLLING_TIMER_INTERVAL);
52297bde5c4SDavid VomLehn 	} else {
5238d3a6c37SKai-Heng Feng 		for (i = 0U; self->aq_vecs > i; ++i) {
5248d3a6c37SKai-Heng Feng 			aq_vec = self->aq_vec[i];
5254c83f170SIgor Russkikh 			err = aq_pci_func_alloc_irq(self, i, self->ndev->name,
5264c83f170SIgor Russkikh 						    aq_vec_isr, aq_vec,
52797bde5c4SDavid VomLehn 						    aq_vec_get_affinity_mask(aq_vec));
52897bde5c4SDavid VomLehn 			if (err < 0)
52997bde5c4SDavid VomLehn 				goto err_exit;
53097bde5c4SDavid VomLehn 		}
53197bde5c4SDavid VomLehn 
53204a18399SEgor Pomozov 		err = aq_ptp_irq_alloc(self);
53304a18399SEgor Pomozov 		if (err < 0)
53404a18399SEgor Pomozov 			goto err_exit;
53504a18399SEgor Pomozov 
5368ce84271SDmitry Bezrukov 		if (cfg->link_irq_vec) {
5374c83f170SIgor Russkikh 			int irqvec = pci_irq_vector(self->pdev,
5388ce84271SDmitry Bezrukov 						    cfg->link_irq_vec);
5394c83f170SIgor Russkikh 			err = request_threaded_irq(irqvec, NULL,
5404c83f170SIgor Russkikh 						   aq_linkstate_threaded_isr,
5415c47e3baSIgor Russkikh 						   IRQF_SHARED | IRQF_ONESHOT,
5424c83f170SIgor Russkikh 						   self->ndev->name, self);
5434c83f170SIgor Russkikh 			if (err < 0)
5444c83f170SIgor Russkikh 				goto err_exit;
5458ce84271SDmitry Bezrukov 			self->msix_entry_mask |= (1 << cfg->link_irq_vec);
5464c83f170SIgor Russkikh 		}
5474c83f170SIgor Russkikh 
5488fcb98f4SIgor Russkikh 		err = self->aq_hw_ops->hw_irq_enable(self->aq_hw,
54997bde5c4SDavid VomLehn 						     AQ_CFG_IRQ_MASK);
55097bde5c4SDavid VomLehn 		if (err < 0)
55197bde5c4SDavid VomLehn 			goto err_exit;
55297bde5c4SDavid VomLehn 	}
55397bde5c4SDavid VomLehn 
554a83fe6b6SDmitry Bezrukov 	err = netif_set_real_num_tx_queues(self->ndev,
555a83fe6b6SDmitry Bezrukov 					   self->aq_vecs * cfg->tcs);
55697bde5c4SDavid VomLehn 	if (err < 0)
55797bde5c4SDavid VomLehn 		goto err_exit;
55897bde5c4SDavid VomLehn 
559a83fe6b6SDmitry Bezrukov 	err = netif_set_real_num_rx_queues(self->ndev,
560a83fe6b6SDmitry Bezrukov 					   self->aq_vecs * cfg->tcs);
56197bde5c4SDavid VomLehn 	if (err < 0)
56297bde5c4SDavid VomLehn 		goto err_exit;
56397bde5c4SDavid VomLehn 
564a83fe6b6SDmitry Bezrukov 	for (i = 0; i < cfg->tcs; i++) {
565a83fe6b6SDmitry Bezrukov 		u16 offset = self->aq_vecs * i;
566a83fe6b6SDmitry Bezrukov 
567a83fe6b6SDmitry Bezrukov 		netdev_set_tc_queue(self->ndev, i, self->aq_vecs, offset);
568a83fe6b6SDmitry Bezrukov 	}
5693aec6412SIgor Russkikh 	netif_tx_start_all_queues(self->ndev);
5703aec6412SIgor Russkikh 
57197bde5c4SDavid VomLehn err_exit:
57297bde5c4SDavid VomLehn 	return err;
57397bde5c4SDavid VomLehn }
57497bde5c4SDavid VomLehn 
aq_nic_map_xdp(struct aq_nic_s * self,struct xdp_frame * xdpf,struct aq_ring_s * ring)57526efaef7STaehee Yoo static unsigned int aq_nic_map_xdp(struct aq_nic_s *self,
57626efaef7STaehee Yoo 				   struct xdp_frame *xdpf,
57726efaef7STaehee Yoo 				   struct aq_ring_s *ring)
57826efaef7STaehee Yoo {
57926efaef7STaehee Yoo 	struct device *dev = aq_nic_get_dev(self);
58026efaef7STaehee Yoo 	struct aq_ring_buff_s *first = NULL;
58126efaef7STaehee Yoo 	unsigned int dx = ring->sw_tail;
58226efaef7STaehee Yoo 	struct aq_ring_buff_s *dx_buff;
58326efaef7STaehee Yoo 	struct skb_shared_info *sinfo;
58426efaef7STaehee Yoo 	unsigned int frag_count = 0U;
58526efaef7STaehee Yoo 	unsigned int nr_frags = 0U;
58626efaef7STaehee Yoo 	unsigned int ret = 0U;
58726efaef7STaehee Yoo 	u16 total_len;
58826efaef7STaehee Yoo 
58926efaef7STaehee Yoo 	dx_buff = &ring->buff_ring[dx];
59026efaef7STaehee Yoo 	dx_buff->flags = 0U;
59126efaef7STaehee Yoo 
59226efaef7STaehee Yoo 	sinfo = xdp_get_shared_info_from_frame(xdpf);
59326efaef7STaehee Yoo 	total_len = xdpf->len;
59426efaef7STaehee Yoo 	dx_buff->len = total_len;
59526efaef7STaehee Yoo 	if (xdp_frame_has_frags(xdpf)) {
59626efaef7STaehee Yoo 		nr_frags = sinfo->nr_frags;
59726efaef7STaehee Yoo 		total_len += sinfo->xdp_frags_size;
59826efaef7STaehee Yoo 	}
59926efaef7STaehee Yoo 	dx_buff->pa = dma_map_single(dev, xdpf->data, dx_buff->len,
60026efaef7STaehee Yoo 				     DMA_TO_DEVICE);
60126efaef7STaehee Yoo 
60226efaef7STaehee Yoo 	if (unlikely(dma_mapping_error(dev, dx_buff->pa)))
60326efaef7STaehee Yoo 		goto exit;
60426efaef7STaehee Yoo 
60526efaef7STaehee Yoo 	first = dx_buff;
60626efaef7STaehee Yoo 	dx_buff->len_pkt = total_len;
60726efaef7STaehee Yoo 	dx_buff->is_sop = 1U;
60826efaef7STaehee Yoo 	dx_buff->is_mapped = 1U;
60926efaef7STaehee Yoo 	++ret;
61026efaef7STaehee Yoo 
61126efaef7STaehee Yoo 	for (; nr_frags--; ++frag_count) {
61226efaef7STaehee Yoo 		skb_frag_t *frag = &sinfo->frags[frag_count];
61326efaef7STaehee Yoo 		unsigned int frag_len = skb_frag_size(frag);
61426efaef7STaehee Yoo 		unsigned int buff_offset = 0U;
61526efaef7STaehee Yoo 		unsigned int buff_size = 0U;
61626efaef7STaehee Yoo 		dma_addr_t frag_pa;
61726efaef7STaehee Yoo 
61826efaef7STaehee Yoo 		while (frag_len) {
61926efaef7STaehee Yoo 			if (frag_len > AQ_CFG_TX_FRAME_MAX)
62026efaef7STaehee Yoo 				buff_size = AQ_CFG_TX_FRAME_MAX;
62126efaef7STaehee Yoo 			else
62226efaef7STaehee Yoo 				buff_size = frag_len;
62326efaef7STaehee Yoo 
62426efaef7STaehee Yoo 			frag_pa = skb_frag_dma_map(dev, frag, buff_offset,
62526efaef7STaehee Yoo 						   buff_size, DMA_TO_DEVICE);
62626efaef7STaehee Yoo 
62726efaef7STaehee Yoo 			if (unlikely(dma_mapping_error(dev, frag_pa)))
62826efaef7STaehee Yoo 				goto mapping_error;
62926efaef7STaehee Yoo 
63026efaef7STaehee Yoo 			dx = aq_ring_next_dx(ring, dx);
63126efaef7STaehee Yoo 			dx_buff = &ring->buff_ring[dx];
63226efaef7STaehee Yoo 
63326efaef7STaehee Yoo 			dx_buff->flags = 0U;
63426efaef7STaehee Yoo 			dx_buff->len = buff_size;
63526efaef7STaehee Yoo 			dx_buff->pa = frag_pa;
63626efaef7STaehee Yoo 			dx_buff->is_mapped = 1U;
63726efaef7STaehee Yoo 			dx_buff->eop_index = 0xffffU;
63826efaef7STaehee Yoo 
63926efaef7STaehee Yoo 			frag_len -= buff_size;
64026efaef7STaehee Yoo 			buff_offset += buff_size;
64126efaef7STaehee Yoo 
64226efaef7STaehee Yoo 			++ret;
64326efaef7STaehee Yoo 		}
64426efaef7STaehee Yoo 	}
64526efaef7STaehee Yoo 
64626efaef7STaehee Yoo 	first->eop_index = dx;
64726efaef7STaehee Yoo 	dx_buff->is_eop = 1U;
64826efaef7STaehee Yoo 	dx_buff->skb = NULL;
64926efaef7STaehee Yoo 	dx_buff->xdpf = xdpf;
65026efaef7STaehee Yoo 	goto exit;
65126efaef7STaehee Yoo 
65226efaef7STaehee Yoo mapping_error:
65326efaef7STaehee Yoo 	for (dx = ring->sw_tail;
65426efaef7STaehee Yoo 	     ret > 0;
65526efaef7STaehee Yoo 	     --ret, dx = aq_ring_next_dx(ring, dx)) {
65626efaef7STaehee Yoo 		dx_buff = &ring->buff_ring[dx];
65726efaef7STaehee Yoo 
65826efaef7STaehee Yoo 		if (!dx_buff->pa)
65926efaef7STaehee Yoo 			continue;
66026efaef7STaehee Yoo 		if (unlikely(dx_buff->is_sop))
66126efaef7STaehee Yoo 			dma_unmap_single(dev, dx_buff->pa, dx_buff->len,
66226efaef7STaehee Yoo 					 DMA_TO_DEVICE);
66326efaef7STaehee Yoo 		else
66426efaef7STaehee Yoo 			dma_unmap_page(dev, dx_buff->pa, dx_buff->len,
66526efaef7STaehee Yoo 				       DMA_TO_DEVICE);
66626efaef7STaehee Yoo 	}
66726efaef7STaehee Yoo 
66826efaef7STaehee Yoo exit:
66926efaef7STaehee Yoo 	return ret;
67026efaef7STaehee Yoo }
67126efaef7STaehee Yoo 
aq_nic_map_skb(struct aq_nic_s * self,struct sk_buff * skb,struct aq_ring_s * ring)67204a18399SEgor Pomozov unsigned int aq_nic_map_skb(struct aq_nic_s *self, struct sk_buff *skb,
673e399553dSPavel Belous 			    struct aq_ring_s *ring)
67497bde5c4SDavid VomLehn {
67597bde5c4SDavid VomLehn 	unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
6768ce84271SDmitry Bezrukov 	struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(self);
6778ce84271SDmitry Bezrukov 	struct device *dev = aq_nic_get_dev(self);
678c7545689SPavel Belous 	struct aq_ring_buff_s *first = NULL;
679822cd114SIgor Russkikh 	u8 ipver = ip_hdr(skb)->version;
6807b0c342fSNikita Danilov 	struct aq_ring_buff_s *dx_buff;
681880b3ca5SIgor Russkikh 	bool need_context_tag = false;
6827b0c342fSNikita Danilov 	unsigned int frag_count = 0U;
6837b0c342fSNikita Danilov 	unsigned int ret = 0U;
6847b0c342fSNikita Danilov 	unsigned int dx;
685822cd114SIgor Russkikh 	u8 l4proto = 0;
686822cd114SIgor Russkikh 
687822cd114SIgor Russkikh 	if (ipver == 4)
688822cd114SIgor Russkikh 		l4proto = ip_hdr(skb)->protocol;
689822cd114SIgor Russkikh 	else if (ipver == 6)
690822cd114SIgor Russkikh 		l4proto = ipv6_hdr(skb)->nexthdr;
691880b3ca5SIgor Russkikh 
6927b0c342fSNikita Danilov 	dx = ring->sw_tail;
6937b0c342fSNikita Danilov 	dx_buff = &ring->buff_ring[dx];
694880b3ca5SIgor Russkikh 	dx_buff->flags = 0U;
69597bde5c4SDavid VomLehn 
696e399553dSPavel Belous 	if (unlikely(skb_is_gso(skb))) {
697880b3ca5SIgor Russkikh 		dx_buff->mss = skb_shinfo(skb)->gso_size;
698822cd114SIgor Russkikh 		if (l4proto == IPPROTO_TCP) {
699822cd114SIgor Russkikh 			dx_buff->is_gso_tcp = 1U;
700822cd114SIgor Russkikh 			dx_buff->len_l4 = tcp_hdrlen(skb);
701822cd114SIgor Russkikh 		} else if (l4proto == IPPROTO_UDP) {
702822cd114SIgor Russkikh 			dx_buff->is_gso_udp = 1U;
703822cd114SIgor Russkikh 			dx_buff->len_l4 = sizeof(struct udphdr);
704822cd114SIgor Russkikh 			/* UDP GSO Hardware does not replace packet length. */
705822cd114SIgor Russkikh 			udp_hdr(skb)->len = htons(dx_buff->mss +
706822cd114SIgor Russkikh 						  dx_buff->len_l4);
707822cd114SIgor Russkikh 		} else {
708822cd114SIgor Russkikh 			WARN_ONCE(true, "Bad GSO mode");
709822cd114SIgor Russkikh 			goto exit;
710822cd114SIgor Russkikh 		}
711e399553dSPavel Belous 		dx_buff->len_pkt = skb->len;
712e399553dSPavel Belous 		dx_buff->len_l2 = ETH_HLEN;
713822cd114SIgor Russkikh 		dx_buff->len_l3 = skb_network_header_len(skb);
714c7545689SPavel Belous 		dx_buff->eop_index = 0xffffU;
715822cd114SIgor Russkikh 		dx_buff->is_ipv6 = (ipver == 6);
716880b3ca5SIgor Russkikh 		need_context_tag = true;
717880b3ca5SIgor Russkikh 	}
718386aff88SPavel Belous 
7198ce84271SDmitry Bezrukov 	if (cfg->is_vlan_tx_insert && skb_vlan_tag_present(skb)) {
720880b3ca5SIgor Russkikh 		dx_buff->vlan_tx_tag = skb_vlan_tag_get(skb);
721880b3ca5SIgor Russkikh 		dx_buff->len_pkt = skb->len;
722880b3ca5SIgor Russkikh 		dx_buff->is_vlan = 1U;
723880b3ca5SIgor Russkikh 		need_context_tag = true;
724880b3ca5SIgor Russkikh 	}
725880b3ca5SIgor Russkikh 
726880b3ca5SIgor Russkikh 	if (need_context_tag) {
727e399553dSPavel Belous 		dx = aq_ring_next_dx(ring, dx);
728e399553dSPavel Belous 		dx_buff = &ring->buff_ring[dx];
729880b3ca5SIgor Russkikh 		dx_buff->flags = 0U;
730e399553dSPavel Belous 		++ret;
731e399553dSPavel Belous 	}
732e399553dSPavel Belous 
733e399553dSPavel Belous 	dx_buff->len = skb_headlen(skb);
7348ce84271SDmitry Bezrukov 	dx_buff->pa = dma_map_single(dev,
735e399553dSPavel Belous 				     skb->data,
736e399553dSPavel Belous 				     dx_buff->len,
73797bde5c4SDavid VomLehn 				     DMA_TO_DEVICE);
73897bde5c4SDavid VomLehn 
7398ce84271SDmitry Bezrukov 	if (unlikely(dma_mapping_error(dev, dx_buff->pa))) {
740380ec5b9SPavel Belous 		ret = 0;
741e399553dSPavel Belous 		goto exit;
742380ec5b9SPavel Belous 	}
743e399553dSPavel Belous 
744c7545689SPavel Belous 	first = dx_buff;
745e399553dSPavel Belous 	dx_buff->len_pkt = skb->len;
746e399553dSPavel Belous 	dx_buff->is_sop = 1U;
747e399553dSPavel Belous 	dx_buff->is_mapped = 1U;
74897bde5c4SDavid VomLehn 	++ret;
74997bde5c4SDavid VomLehn 
75097bde5c4SDavid VomLehn 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
751822cd114SIgor Russkikh 		dx_buff->is_ip_cso = (htons(ETH_P_IP) == skb->protocol);
752822cd114SIgor Russkikh 		dx_buff->is_tcp_cso = (l4proto == IPPROTO_TCP);
753822cd114SIgor Russkikh 		dx_buff->is_udp_cso = (l4proto == IPPROTO_UDP);
75497bde5c4SDavid VomLehn 	}
75597bde5c4SDavid VomLehn 
75697bde5c4SDavid VomLehn 	for (; nr_frags--; ++frag_count) {
757e399553dSPavel Belous 		unsigned int frag_len = 0U;
758c7545689SPavel Belous 		unsigned int buff_offset = 0U;
759c7545689SPavel Belous 		unsigned int buff_size = 0U;
76097bde5c4SDavid VomLehn 		dma_addr_t frag_pa;
76197bde5c4SDavid VomLehn 		skb_frag_t *frag = &skb_shinfo(skb)->frags[frag_count];
76297bde5c4SDavid VomLehn 
76397bde5c4SDavid VomLehn 		frag_len = skb_frag_size(frag);
76497bde5c4SDavid VomLehn 
765c7545689SPavel Belous 		while (frag_len) {
766c7545689SPavel Belous 			if (frag_len > AQ_CFG_TX_FRAME_MAX)
767c7545689SPavel Belous 				buff_size = AQ_CFG_TX_FRAME_MAX;
768c7545689SPavel Belous 			else
769c7545689SPavel Belous 				buff_size = frag_len;
770c7545689SPavel Belous 
7718ce84271SDmitry Bezrukov 			frag_pa = skb_frag_dma_map(dev,
772c7545689SPavel Belous 						   frag,
773c7545689SPavel Belous 						   buff_offset,
774c7545689SPavel Belous 						   buff_size,
775c7545689SPavel Belous 						   DMA_TO_DEVICE);
776c7545689SPavel Belous 
7778ce84271SDmitry Bezrukov 			if (unlikely(dma_mapping_error(dev,
778c7545689SPavel Belous 						       frag_pa)))
779e399553dSPavel Belous 				goto mapping_error;
780e399553dSPavel Belous 
781e399553dSPavel Belous 			dx = aq_ring_next_dx(ring, dx);
782e399553dSPavel Belous 			dx_buff = &ring->buff_ring[dx];
783e399553dSPavel Belous 
784e399553dSPavel Belous 			dx_buff->flags = 0U;
785c7545689SPavel Belous 			dx_buff->len = buff_size;
786e399553dSPavel Belous 			dx_buff->pa = frag_pa;
787e399553dSPavel Belous 			dx_buff->is_mapped = 1U;
788c7545689SPavel Belous 			dx_buff->eop_index = 0xffffU;
78997bde5c4SDavid VomLehn 
790c7545689SPavel Belous 			frag_len -= buff_size;
791c7545689SPavel Belous 			buff_offset += buff_size;
792c7545689SPavel Belous 
79397bde5c4SDavid VomLehn 			++ret;
79497bde5c4SDavid VomLehn 		}
79597bde5c4SDavid VomLehn 	}
79697bde5c4SDavid VomLehn 
797c7545689SPavel Belous 	first->eop_index = dx;
798e399553dSPavel Belous 	dx_buff->is_eop = 1U;
799e399553dSPavel Belous 	dx_buff->skb = skb;
80026efaef7STaehee Yoo 	dx_buff->xdpf = NULL;
801e399553dSPavel Belous 	goto exit;
802e399553dSPavel Belous 
803e399553dSPavel Belous mapping_error:
804e399553dSPavel Belous 	for (dx = ring->sw_tail;
805e399553dSPavel Belous 	     ret > 0;
806e399553dSPavel Belous 	     --ret, dx = aq_ring_next_dx(ring, dx)) {
807e399553dSPavel Belous 		dx_buff = &ring->buff_ring[dx];
808e399553dSPavel Belous 
809822cd114SIgor Russkikh 		if (!(dx_buff->is_gso_tcp || dx_buff->is_gso_udp) &&
810822cd114SIgor Russkikh 		    !dx_buff->is_vlan && dx_buff->pa) {
811e399553dSPavel Belous 			if (unlikely(dx_buff->is_sop)) {
8128ce84271SDmitry Bezrukov 				dma_unmap_single(dev,
813e399553dSPavel Belous 						 dx_buff->pa,
814e399553dSPavel Belous 						 dx_buff->len,
815e399553dSPavel Belous 						 DMA_TO_DEVICE);
816e399553dSPavel Belous 			} else {
8178ce84271SDmitry Bezrukov 				dma_unmap_page(dev,
818e399553dSPavel Belous 					       dx_buff->pa,
819e399553dSPavel Belous 					       dx_buff->len,
820e399553dSPavel Belous 					       DMA_TO_DEVICE);
821e399553dSPavel Belous 			}
822e399553dSPavel Belous 		}
82397bde5c4SDavid VomLehn 	}
82497bde5c4SDavid VomLehn 
825e399553dSPavel Belous exit:
82697bde5c4SDavid VomLehn 	return ret;
82797bde5c4SDavid VomLehn }
82897bde5c4SDavid VomLehn 
aq_nic_xmit_xdpf(struct aq_nic_s * aq_nic,struct aq_ring_s * tx_ring,struct xdp_frame * xdpf)82926efaef7STaehee Yoo int aq_nic_xmit_xdpf(struct aq_nic_s *aq_nic, struct aq_ring_s *tx_ring,
83026efaef7STaehee Yoo 		     struct xdp_frame *xdpf)
83126efaef7STaehee Yoo {
83226efaef7STaehee Yoo 	u16 queue_index = AQ_NIC_RING2QMAP(aq_nic, tx_ring->idx);
83326efaef7STaehee Yoo 	struct net_device *ndev = aq_nic_get_ndev(aq_nic);
83426efaef7STaehee Yoo 	struct skb_shared_info *sinfo;
83526efaef7STaehee Yoo 	int cpu = smp_processor_id();
83626efaef7STaehee Yoo 	int err = NETDEV_TX_BUSY;
83726efaef7STaehee Yoo 	struct netdev_queue *nq;
83826efaef7STaehee Yoo 	unsigned int frags = 1;
83926efaef7STaehee Yoo 
84026efaef7STaehee Yoo 	if (xdp_frame_has_frags(xdpf)) {
84126efaef7STaehee Yoo 		sinfo = xdp_get_shared_info_from_frame(xdpf);
84226efaef7STaehee Yoo 		frags += sinfo->nr_frags;
84326efaef7STaehee Yoo 	}
84426efaef7STaehee Yoo 
84526efaef7STaehee Yoo 	if (frags > AQ_CFG_SKB_FRAGS_MAX)
84626efaef7STaehee Yoo 		return err;
84726efaef7STaehee Yoo 
84826efaef7STaehee Yoo 	nq = netdev_get_tx_queue(ndev, tx_ring->idx);
84926efaef7STaehee Yoo 	__netif_tx_lock(nq, cpu);
85026efaef7STaehee Yoo 
85126efaef7STaehee Yoo 	aq_ring_update_queue_state(tx_ring);
85226efaef7STaehee Yoo 
85326efaef7STaehee Yoo 	/* Above status update may stop the queue. Check this. */
85426efaef7STaehee Yoo 	if (__netif_subqueue_stopped(aq_nic_get_ndev(aq_nic), queue_index))
85526efaef7STaehee Yoo 		goto out;
85626efaef7STaehee Yoo 
85726efaef7STaehee Yoo 	frags = aq_nic_map_xdp(aq_nic, xdpf, tx_ring);
85826efaef7STaehee Yoo 	if (likely(frags))
85926efaef7STaehee Yoo 		err = aq_nic->aq_hw_ops->hw_ring_tx_xmit(aq_nic->aq_hw, tx_ring,
86026efaef7STaehee Yoo 							 frags);
86126efaef7STaehee Yoo out:
86226efaef7STaehee Yoo 	__netif_tx_unlock(nq);
86326efaef7STaehee Yoo 
86426efaef7STaehee Yoo 	return err;
86526efaef7STaehee Yoo }
86626efaef7STaehee Yoo 
aq_nic_xmit(struct aq_nic_s * self,struct sk_buff * skb)86797bde5c4SDavid VomLehn int aq_nic_xmit(struct aq_nic_s *self, struct sk_buff *skb)
86897bde5c4SDavid VomLehn {
869b9e98926SMark Starovoytov 	struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(self);
870b9e98926SMark Starovoytov 	unsigned int vec = skb->queue_mapping % cfg->vecs;
871b9e98926SMark Starovoytov 	unsigned int tc = skb->queue_mapping / cfg->vecs;
87297bde5c4SDavid VomLehn 	struct aq_ring_s *ring = NULL;
87397bde5c4SDavid VomLehn 	unsigned int frags = 0U;
874b350d7b8SPavel Belous 	int err = NETDEV_TX_OK;
87597bde5c4SDavid VomLehn 
87697bde5c4SDavid VomLehn 	frags = skb_shinfo(skb)->nr_frags + 1;
87797bde5c4SDavid VomLehn 
878b9e98926SMark Starovoytov 	ring = self->aq_ring_tx[AQ_NIC_CFG_TCVEC2RING(cfg, tc, vec)];
87997bde5c4SDavid VomLehn 
88097bde5c4SDavid VomLehn 	if (frags > AQ_CFG_SKB_FRAGS_MAX) {
88197bde5c4SDavid VomLehn 		dev_kfree_skb_any(skb);
88297bde5c4SDavid VomLehn 		goto err_exit;
88397bde5c4SDavid VomLehn 	}
88497bde5c4SDavid VomLehn 
8853aec6412SIgor Russkikh 	aq_ring_update_queue_state(ring);
88697bde5c4SDavid VomLehn 
887b9e98926SMark Starovoytov 	if (cfg->priv_flags & BIT(AQ_HW_LOOPBACK_DMA_NET)) {
888ea4b4d7fSIgor Russkikh 		err = NETDEV_TX_BUSY;
889ea4b4d7fSIgor Russkikh 		goto err_exit;
890ea4b4d7fSIgor Russkikh 	}
891ea4b4d7fSIgor Russkikh 
8923aec6412SIgor Russkikh 	/* Above status update may stop the queue. Check this. */
893a83fe6b6SDmitry Bezrukov 	if (__netif_subqueue_stopped(self->ndev,
894a83fe6b6SDmitry Bezrukov 				     AQ_NIC_RING2QMAP(self, ring->idx))) {
89597bde5c4SDavid VomLehn 		err = NETDEV_TX_BUSY;
89697bde5c4SDavid VomLehn 		goto err_exit;
89797bde5c4SDavid VomLehn 	}
89897bde5c4SDavid VomLehn 
899e399553dSPavel Belous 	frags = aq_nic_map_skb(self, skb, ring);
90097bde5c4SDavid VomLehn 
901e399553dSPavel Belous 	if (likely(frags)) {
9028fcb98f4SIgor Russkikh 		err = self->aq_hw_ops->hw_ring_tx_xmit(self->aq_hw,
90323ee07adSIgor Russkikh 						       ring, frags);
904e399553dSPavel Belous 	} else {
905e399553dSPavel Belous 		err = NETDEV_TX_BUSY;
906e399553dSPavel Belous 	}
907e399553dSPavel Belous 
90897bde5c4SDavid VomLehn err_exit:
90997bde5c4SDavid VomLehn 	return err;
91097bde5c4SDavid VomLehn }
91197bde5c4SDavid VomLehn 
aq_nic_update_interrupt_moderation_settings(struct aq_nic_s * self)912b82ee71aSIgor Russkikh int aq_nic_update_interrupt_moderation_settings(struct aq_nic_s *self)
913b82ee71aSIgor Russkikh {
9148fcb98f4SIgor Russkikh 	return self->aq_hw_ops->hw_interrupt_moderation_set(self->aq_hw);
915b82ee71aSIgor Russkikh }
916b82ee71aSIgor Russkikh 
aq_nic_set_packet_filter(struct aq_nic_s * self,unsigned int flags)91797bde5c4SDavid VomLehn int aq_nic_set_packet_filter(struct aq_nic_s *self, unsigned int flags)
91897bde5c4SDavid VomLehn {
91997bde5c4SDavid VomLehn 	int err = 0;
92097bde5c4SDavid VomLehn 
9218fcb98f4SIgor Russkikh 	err = self->aq_hw_ops->hw_packet_filter_set(self->aq_hw, flags);
92297bde5c4SDavid VomLehn 	if (err < 0)
92397bde5c4SDavid VomLehn 		goto err_exit;
92497bde5c4SDavid VomLehn 
92597bde5c4SDavid VomLehn 	self->packet_filter = flags;
92697bde5c4SDavid VomLehn 
92797bde5c4SDavid VomLehn err_exit:
92897bde5c4SDavid VomLehn 	return err;
92997bde5c4SDavid VomLehn }
93097bde5c4SDavid VomLehn 
aq_nic_set_multicast_list(struct aq_nic_s * self,struct net_device * ndev)93197bde5c4SDavid VomLehn int aq_nic_set_multicast_list(struct aq_nic_s *self, struct net_device *ndev)
93297bde5c4SDavid VomLehn {
9339f051db5SDmitry Bogdanov 	const struct aq_hw_ops *hw_ops = self->aq_hw_ops;
9349f051db5SDmitry Bogdanov 	struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg;
9359f051db5SDmitry Bogdanov 	unsigned int packet_filter = ndev->flags;
93697bde5c4SDavid VomLehn 	struct netdev_hw_addr *ha = NULL;
93797bde5c4SDavid VomLehn 	unsigned int i = 0U;
9389f051db5SDmitry Bogdanov 	int err = 0;
93997bde5c4SDavid VomLehn 
94094b3b542SIgor Russkikh 	self->mc_list.count = 0;
94194b3b542SIgor Russkikh 	if (netdev_uc_count(ndev) > AQ_HW_MULTICAST_ADDRESS_MAX) {
94294b3b542SIgor Russkikh 		packet_filter |= IFF_PROMISC;
94394b3b542SIgor Russkikh 	} else {
94494b3b542SIgor Russkikh 		netdev_for_each_uc_addr(ha, ndev) {
94597bde5c4SDavid VomLehn 			ether_addr_copy(self->mc_list.ar[i++], ha->addr);
94697bde5c4SDavid VomLehn 		}
94794b3b542SIgor Russkikh 	}
94897bde5c4SDavid VomLehn 
9499f051db5SDmitry Bogdanov 	cfg->is_mc_list_enabled = !!(packet_filter & IFF_MULTICAST);
9509f051db5SDmitry Bogdanov 	if (cfg->is_mc_list_enabled) {
95194b3b542SIgor Russkikh 		if (i + netdev_mc_count(ndev) > AQ_HW_MULTICAST_ADDRESS_MAX) {
95294b3b542SIgor Russkikh 			packet_filter |= IFF_ALLMULTI;
953b21f502fSIgor Russkikh 		} else {
95494b3b542SIgor Russkikh 			netdev_for_each_mc_addr(ha, ndev) {
9559f051db5SDmitry Bogdanov 				ether_addr_copy(self->mc_list.ar[i++],
9569f051db5SDmitry Bogdanov 						ha->addr);
9579f051db5SDmitry Bogdanov 			}
95894b3b542SIgor Russkikh 		}
95994b3b542SIgor Russkikh 	}
96094b3b542SIgor Russkikh 
961bfaa9f85SIgor Russkikh 	if (i > 0 && i <= AQ_HW_MULTICAST_ADDRESS_MAX) {
96294b3b542SIgor Russkikh 		self->mc_list.count = i;
9639f051db5SDmitry Bogdanov 		err = hw_ops->hw_multicast_list_set(self->aq_hw,
96497bde5c4SDavid VomLehn 						    self->mc_list.ar,
96597bde5c4SDavid VomLehn 						    self->mc_list.count);
9663d00cf2fSChenwandun 		if (err < 0)
9673d00cf2fSChenwandun 			return err;
96897bde5c4SDavid VomLehn 	}
9697b0c342fSNikita Danilov 
97094b3b542SIgor Russkikh 	return aq_nic_set_packet_filter(self, packet_filter);
971b21f502fSIgor Russkikh }
97297bde5c4SDavid VomLehn 
aq_nic_set_mtu(struct aq_nic_s * self,int new_mtu)97397bde5c4SDavid VomLehn int aq_nic_set_mtu(struct aq_nic_s *self, int new_mtu)
97497bde5c4SDavid VomLehn {
97597bde5c4SDavid VomLehn 	self->aq_nic_cfg.mtu = new_mtu;
97697bde5c4SDavid VomLehn 
977d85fc17bSIgor Russkikh 	return 0;
97897bde5c4SDavid VomLehn }
97997bde5c4SDavid VomLehn 
aq_nic_set_mac(struct aq_nic_s * self,struct net_device * ndev)98097bde5c4SDavid VomLehn int aq_nic_set_mac(struct aq_nic_s *self, struct net_device *ndev)
98197bde5c4SDavid VomLehn {
9828fcb98f4SIgor Russkikh 	return self->aq_hw_ops->hw_set_mac_address(self->aq_hw, ndev->dev_addr);
98397bde5c4SDavid VomLehn }
98497bde5c4SDavid VomLehn 
aq_nic_get_link_speed(struct aq_nic_s * self)98597bde5c4SDavid VomLehn unsigned int aq_nic_get_link_speed(struct aq_nic_s *self)
98697bde5c4SDavid VomLehn {
98797bde5c4SDavid VomLehn 	return self->link_status.mbps;
98897bde5c4SDavid VomLehn }
98997bde5c4SDavid VomLehn 
aq_nic_get_regs(struct aq_nic_s * self,struct ethtool_regs * regs,void * p)99097bde5c4SDavid VomLehn int aq_nic_get_regs(struct aq_nic_s *self, struct ethtool_regs *regs, void *p)
99197bde5c4SDavid VomLehn {
99297bde5c4SDavid VomLehn 	u32 *regs_buff = p;
99397bde5c4SDavid VomLehn 	int err = 0;
99497bde5c4SDavid VomLehn 
995d0f23741SMark Starovoytov 	if (unlikely(!self->aq_hw_ops->hw_get_regs))
996d0f23741SMark Starovoytov 		return -EOPNOTSUPP;
997d0f23741SMark Starovoytov 
99897bde5c4SDavid VomLehn 	regs->version = 1;
99997bde5c4SDavid VomLehn 
10008fcb98f4SIgor Russkikh 	err = self->aq_hw_ops->hw_get_regs(self->aq_hw,
10018fcb98f4SIgor Russkikh 					   self->aq_nic_cfg.aq_hw_caps,
10028fcb98f4SIgor Russkikh 					   regs_buff);
100397bde5c4SDavid VomLehn 	if (err < 0)
100497bde5c4SDavid VomLehn 		goto err_exit;
100597bde5c4SDavid VomLehn 
100697bde5c4SDavid VomLehn err_exit:
100797bde5c4SDavid VomLehn 	return err;
100897bde5c4SDavid VomLehn }
100997bde5c4SDavid VomLehn 
aq_nic_get_regs_count(struct aq_nic_s * self)101097bde5c4SDavid VomLehn int aq_nic_get_regs_count(struct aq_nic_s *self)
101197bde5c4SDavid VomLehn {
1012d0f23741SMark Starovoytov 	if (unlikely(!self->aq_hw_ops->hw_get_regs))
1013d0f23741SMark Starovoytov 		return 0;
1014d0f23741SMark Starovoytov 
10158fcb98f4SIgor Russkikh 	return self->aq_nic_cfg.aq_hw_caps->mac_regs_count;
101697bde5c4SDavid VomLehn }
101797bde5c4SDavid VomLehn 
aq_nic_get_stats(struct aq_nic_s * self,u64 * data)1018aec0f1aaSDmitry Bogdanov u64 *aq_nic_get_stats(struct aq_nic_s *self, u64 *data)
101997bde5c4SDavid VomLehn {
1020190f3438SDmitry Bogdanov 	struct aq_stats_s *stats;
10217b0c342fSNikita Danilov 	unsigned int count = 0U;
10227b0c342fSNikita Danilov 	unsigned int i = 0U;
10234272ba8bSMark Starovoytov 	unsigned int tc;
1024190f3438SDmitry Bogdanov 
1025190f3438SDmitry Bogdanov 	if (self->aq_fw_ops->update_stats) {
1026190f3438SDmitry Bogdanov 		mutex_lock(&self->fwreq_mutex);
1027190f3438SDmitry Bogdanov 		self->aq_fw_ops->update_stats(self->aq_hw);
1028190f3438SDmitry Bogdanov 		mutex_unlock(&self->fwreq_mutex);
1029190f3438SDmitry Bogdanov 	}
1030190f3438SDmitry Bogdanov 	stats = self->aq_hw_ops->hw_get_hw_stats(self->aq_hw);
103197bde5c4SDavid VomLehn 
1032be08d839SIgor Russkikh 	if (!stats)
103397bde5c4SDavid VomLehn 		goto err_exit;
103497bde5c4SDavid VomLehn 
1035be08d839SIgor Russkikh 	data[i] = stats->uprc + stats->mprc + stats->bprc;
1036be08d839SIgor Russkikh 	data[++i] = stats->uprc;
1037be08d839SIgor Russkikh 	data[++i] = stats->mprc;
1038be08d839SIgor Russkikh 	data[++i] = stats->bprc;
1039be08d839SIgor Russkikh 	data[++i] = stats->erpt;
1040be08d839SIgor Russkikh 	data[++i] = stats->uptc + stats->mptc + stats->bptc;
1041be08d839SIgor Russkikh 	data[++i] = stats->uptc;
1042be08d839SIgor Russkikh 	data[++i] = stats->mptc;
1043be08d839SIgor Russkikh 	data[++i] = stats->bptc;
1044be08d839SIgor Russkikh 	data[++i] = stats->ubrc;
1045be08d839SIgor Russkikh 	data[++i] = stats->ubtc;
1046be08d839SIgor Russkikh 	data[++i] = stats->mbrc;
1047be08d839SIgor Russkikh 	data[++i] = stats->mbtc;
1048be08d839SIgor Russkikh 	data[++i] = stats->bbrc;
1049be08d839SIgor Russkikh 	data[++i] = stats->bbtc;
10502087ced0SDmitry Bogdanov 	if (stats->brc)
10512087ced0SDmitry Bogdanov 		data[++i] = stats->brc;
10522087ced0SDmitry Bogdanov 	else
1053be08d839SIgor Russkikh 		data[++i] = stats->ubrc + stats->mbrc + stats->bbrc;
10542087ced0SDmitry Bogdanov 	if (stats->btc)
10552087ced0SDmitry Bogdanov 		data[++i] = stats->btc;
10562087ced0SDmitry Bogdanov 	else
1057be08d839SIgor Russkikh 		data[++i] = stats->ubtc + stats->mbtc + stats->bbtc;
1058be08d839SIgor Russkikh 	data[++i] = stats->dma_pkt_rc;
1059be08d839SIgor Russkikh 	data[++i] = stats->dma_pkt_tc;
1060be08d839SIgor Russkikh 	data[++i] = stats->dma_oct_rc;
1061be08d839SIgor Russkikh 	data[++i] = stats->dma_oct_tc;
1062be08d839SIgor Russkikh 	data[++i] = stats->dpc;
1063be08d839SIgor Russkikh 
1064be08d839SIgor Russkikh 	i++;
1065be08d839SIgor Russkikh 
1066be08d839SIgor Russkikh 	data += i;
106797bde5c4SDavid VomLehn 
10684272ba8bSMark Starovoytov 	for (tc = 0U; tc < self->aq_nic_cfg.tcs; tc++) {
10692ba5e47fSChia-Lin Kao (AceLan) 		for (i = 0U; self->aq_vecs > i; ++i) {
10702ba5e47fSChia-Lin Kao (AceLan) 			if (!self->aq_vec[i])
10712ba5e47fSChia-Lin Kao (AceLan) 				break;
107297bde5c4SDavid VomLehn 			data += count;
10732ba5e47fSChia-Lin Kao (AceLan) 			count = aq_vec_get_sw_stats(self->aq_vec[i], tc, data);
10744272ba8bSMark Starovoytov 		}
107597bde5c4SDavid VomLehn 	}
107697bde5c4SDavid VomLehn 
1077aec0f1aaSDmitry Bogdanov 	data += count;
1078aec0f1aaSDmitry Bogdanov 
1079b772112cSMark Starovoytov err_exit:
1080aec0f1aaSDmitry Bogdanov 	return data;
108197bde5c4SDavid VomLehn }
108297bde5c4SDavid VomLehn 
aq_nic_update_ndev_stats(struct aq_nic_s * self)10839f8a2203SIgor Russkikh static void aq_nic_update_ndev_stats(struct aq_nic_s *self)
10849f8a2203SIgor Russkikh {
10858fcb98f4SIgor Russkikh 	struct aq_stats_s *stats = self->aq_hw_ops->hw_get_hw_stats(self->aq_hw);
10867b0c342fSNikita Danilov 	struct net_device *ndev = self->ndev;
10879f8a2203SIgor Russkikh 
1088f55d477bSDmitry Bogdanov 	ndev->stats.rx_packets = stats->dma_pkt_rc;
1089f55d477bSDmitry Bogdanov 	ndev->stats.rx_bytes = stats->dma_oct_rc;
10909f8a2203SIgor Russkikh 	ndev->stats.rx_errors = stats->erpr;
1091f55d477bSDmitry Bogdanov 	ndev->stats.rx_dropped = stats->dpc;
1092f55d477bSDmitry Bogdanov 	ndev->stats.tx_packets = stats->dma_pkt_tc;
1093f55d477bSDmitry Bogdanov 	ndev->stats.tx_bytes = stats->dma_oct_tc;
10949f8a2203SIgor Russkikh 	ndev->stats.tx_errors = stats->erpt;
109545cc1c7aSIgor Russkikh 	ndev->stats.multicast = stats->mprc;
10969f8a2203SIgor Russkikh }
10979f8a2203SIgor Russkikh 
aq_nic_get_link_ksettings(struct aq_nic_s * self,struct ethtool_link_ksettings * cmd)1098f8244ab5SPhilippe Reynes void aq_nic_get_link_ksettings(struct aq_nic_s *self,
1099f8244ab5SPhilippe Reynes 			       struct ethtool_link_ksettings *cmd)
110097bde5c4SDavid VomLehn {
11012b53b04dSDmitry Bogdanov 	u32 lp_link_speed_msk;
11022b53b04dSDmitry Bogdanov 
1103854ab38cSIgor Russkikh 	if (self->aq_nic_cfg.aq_hw_caps->media_type == AQ_HW_MEDIA_TYPE_FIBRE)
1104854ab38cSIgor Russkikh 		cmd->base.port = PORT_FIBRE;
1105854ab38cSIgor Russkikh 	else
1106f8244ab5SPhilippe Reynes 		cmd->base.port = PORT_TP;
1107071a0204SIgor Russkikh 
1108071a0204SIgor Russkikh 	cmd->base.duplex = DUPLEX_UNKNOWN;
1109071a0204SIgor Russkikh 	if (self->link_status.mbps)
1110071a0204SIgor Russkikh 		cmd->base.duplex = self->link_status.full_duplex ?
1111071a0204SIgor Russkikh 				   DUPLEX_FULL : DUPLEX_HALF;
1112f8244ab5SPhilippe Reynes 	cmd->base.autoneg = self->aq_nic_cfg.is_autoneg;
111397bde5c4SDavid VomLehn 
11148f9000a5SPavel Belous 	ethtool_link_ksettings_zero_link_mode(cmd, supported);
1115f8244ab5SPhilippe Reynes 
11168fcb98f4SIgor Russkikh 	if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_10G)
11178f9000a5SPavel Belous 		ethtool_link_ksettings_add_link_mode(cmd, supported,
11188f9000a5SPavel Belous 						     10000baseT_Full);
111997bde5c4SDavid VomLehn 
11208fcb98f4SIgor Russkikh 	if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_5G)
11218f9000a5SPavel Belous 		ethtool_link_ksettings_add_link_mode(cmd, supported,
11228f9000a5SPavel Belous 						     5000baseT_Full);
112397bde5c4SDavid VomLehn 
1124843e1396SMark Starovoytov 	if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_2G5)
11258f9000a5SPavel Belous 		ethtool_link_ksettings_add_link_mode(cmd, supported,
11268f9000a5SPavel Belous 						     2500baseT_Full);
1127f8244ab5SPhilippe Reynes 
11288fcb98f4SIgor Russkikh 	if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_1G)
11298f9000a5SPavel Belous 		ethtool_link_ksettings_add_link_mode(cmd, supported,
11308f9000a5SPavel Belous 						     1000baseT_Full);
11318f9000a5SPavel Belous 
1132071a0204SIgor Russkikh 	if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_1G_HALF)
1133071a0204SIgor Russkikh 		ethtool_link_ksettings_add_link_mode(cmd, supported,
1134071a0204SIgor Russkikh 						     1000baseT_Half);
1135071a0204SIgor Russkikh 
11368fcb98f4SIgor Russkikh 	if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_100M)
11378f9000a5SPavel Belous 		ethtool_link_ksettings_add_link_mode(cmd, supported,
11388f9000a5SPavel Belous 						     100baseT_Full);
11398f9000a5SPavel Belous 
1140071a0204SIgor Russkikh 	if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_100M_HALF)
1141071a0204SIgor Russkikh 		ethtool_link_ksettings_add_link_mode(cmd, supported,
1142071a0204SIgor Russkikh 						     100baseT_Half);
1143071a0204SIgor Russkikh 
11443d464aadSIgor Russkikh 	if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_10M)
11453d464aadSIgor Russkikh 		ethtool_link_ksettings_add_link_mode(cmd, supported,
11463d464aadSIgor Russkikh 						     10baseT_Full);
11473d464aadSIgor Russkikh 
1148071a0204SIgor Russkikh 	if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_10M_HALF)
1149071a0204SIgor Russkikh 		ethtool_link_ksettings_add_link_mode(cmd, supported,
1150071a0204SIgor Russkikh 						     10baseT_Half);
1151071a0204SIgor Russkikh 
11528009bb19SNikita Danilov 	if (self->aq_nic_cfg.aq_hw_caps->flow_control) {
11538f9000a5SPavel Belous 		ethtool_link_ksettings_add_link_mode(cmd, supported,
11548f9000a5SPavel Belous 						     Pause);
11558009bb19SNikita Danilov 		ethtool_link_ksettings_add_link_mode(cmd, supported,
11568009bb19SNikita Danilov 						     Asym_Pause);
11578009bb19SNikita Danilov 	}
11588f9000a5SPavel Belous 
11598f9000a5SPavel Belous 	ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg);
1160854ab38cSIgor Russkikh 
1161854ab38cSIgor Russkikh 	if (self->aq_nic_cfg.aq_hw_caps->media_type == AQ_HW_MEDIA_TYPE_FIBRE)
1162854ab38cSIgor Russkikh 		ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
1163854ab38cSIgor Russkikh 	else
11648f9000a5SPavel Belous 		ethtool_link_ksettings_add_link_mode(cmd, supported, TP);
11658f9000a5SPavel Belous 
11668f9000a5SPavel Belous 	ethtool_link_ksettings_zero_link_mode(cmd, advertising);
11678f9000a5SPavel Belous 
11688f9000a5SPavel Belous 	if (self->aq_nic_cfg.is_autoneg)
11698f9000a5SPavel Belous 		ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg);
11708f9000a5SPavel Belous 
11718f9000a5SPavel Belous 	if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_10G)
11728f9000a5SPavel Belous 		ethtool_link_ksettings_add_link_mode(cmd, advertising,
11738f9000a5SPavel Belous 						     10000baseT_Full);
11748f9000a5SPavel Belous 
11758f9000a5SPavel Belous 	if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_5G)
11768f9000a5SPavel Belous 		ethtool_link_ksettings_add_link_mode(cmd, advertising,
11778f9000a5SPavel Belous 						     5000baseT_Full);
11788f9000a5SPavel Belous 
1179843e1396SMark Starovoytov 	if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_2G5)
11808f9000a5SPavel Belous 		ethtool_link_ksettings_add_link_mode(cmd, advertising,
11818f9000a5SPavel Belous 						     2500baseT_Full);
11828f9000a5SPavel Belous 
11838f9000a5SPavel Belous 	if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_1G)
11848f9000a5SPavel Belous 		ethtool_link_ksettings_add_link_mode(cmd, advertising,
11858f9000a5SPavel Belous 						     1000baseT_Full);
11868f9000a5SPavel Belous 
1187071a0204SIgor Russkikh 	if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_1G_HALF)
1188071a0204SIgor Russkikh 		ethtool_link_ksettings_add_link_mode(cmd, advertising,
1189071a0204SIgor Russkikh 						     1000baseT_Half);
1190071a0204SIgor Russkikh 
11918f9000a5SPavel Belous 	if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_100M)
11928f9000a5SPavel Belous 		ethtool_link_ksettings_add_link_mode(cmd, advertising,
11938f9000a5SPavel Belous 						     100baseT_Full);
11948f9000a5SPavel Belous 
1195071a0204SIgor Russkikh 	if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_100M_HALF)
1196071a0204SIgor Russkikh 		ethtool_link_ksettings_add_link_mode(cmd, advertising,
1197071a0204SIgor Russkikh 						     100baseT_Half);
1198071a0204SIgor Russkikh 
11993d464aadSIgor Russkikh 	if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_10M)
12003d464aadSIgor Russkikh 		ethtool_link_ksettings_add_link_mode(cmd, advertising,
12013d464aadSIgor Russkikh 						     10baseT_Full);
12023d464aadSIgor Russkikh 
1203071a0204SIgor Russkikh 	if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_10M_HALF)
1204071a0204SIgor Russkikh 		ethtool_link_ksettings_add_link_mode(cmd, advertising,
1205071a0204SIgor Russkikh 						     10baseT_Half);
1206071a0204SIgor Russkikh 
12078009bb19SNikita Danilov 	if (self->aq_nic_cfg.fc.cur & AQ_NIC_FC_RX)
12088f9000a5SPavel Belous 		ethtool_link_ksettings_add_link_mode(cmd, advertising,
12098f9000a5SPavel Belous 						     Pause);
12108f9000a5SPavel Belous 
121135e8e8b4SIgor Russkikh 	/* Asym is when either RX or TX, but not both */
12128009bb19SNikita Danilov 	if (!!(self->aq_nic_cfg.fc.cur & AQ_NIC_FC_TX) ^
12138009bb19SNikita Danilov 	    !!(self->aq_nic_cfg.fc.cur & AQ_NIC_FC_RX))
1214288551deSIgor Russkikh 		ethtool_link_ksettings_add_link_mode(cmd, advertising,
1215288551deSIgor Russkikh 						     Asym_Pause);
1216288551deSIgor Russkikh 
1217854ab38cSIgor Russkikh 	if (self->aq_nic_cfg.aq_hw_caps->media_type == AQ_HW_MEDIA_TYPE_FIBRE)
1218854ab38cSIgor Russkikh 		ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE);
1219854ab38cSIgor Russkikh 	else
12208f9000a5SPavel Belous 		ethtool_link_ksettings_add_link_mode(cmd, advertising, TP);
12212b53b04dSDmitry Bogdanov 
12222b53b04dSDmitry Bogdanov 	ethtool_link_ksettings_zero_link_mode(cmd, lp_advertising);
12232b53b04dSDmitry Bogdanov 	lp_link_speed_msk = self->aq_hw->aq_link_status.lp_link_speed_msk;
12242b53b04dSDmitry Bogdanov 
12252b53b04dSDmitry Bogdanov 	if (lp_link_speed_msk & AQ_NIC_RATE_10G)
12262b53b04dSDmitry Bogdanov 		ethtool_link_ksettings_add_link_mode(cmd, lp_advertising,
12272b53b04dSDmitry Bogdanov 						     10000baseT_Full);
12282b53b04dSDmitry Bogdanov 
12292b53b04dSDmitry Bogdanov 	if (lp_link_speed_msk & AQ_NIC_RATE_5G)
12302b53b04dSDmitry Bogdanov 		ethtool_link_ksettings_add_link_mode(cmd, lp_advertising,
12312b53b04dSDmitry Bogdanov 						     5000baseT_Full);
12322b53b04dSDmitry Bogdanov 
12332b53b04dSDmitry Bogdanov 	if (lp_link_speed_msk & AQ_NIC_RATE_2G5)
12342b53b04dSDmitry Bogdanov 		ethtool_link_ksettings_add_link_mode(cmd, lp_advertising,
12352b53b04dSDmitry Bogdanov 						     2500baseT_Full);
12362b53b04dSDmitry Bogdanov 
12372b53b04dSDmitry Bogdanov 	if (lp_link_speed_msk & AQ_NIC_RATE_1G)
12382b53b04dSDmitry Bogdanov 		ethtool_link_ksettings_add_link_mode(cmd, lp_advertising,
12392b53b04dSDmitry Bogdanov 						     1000baseT_Full);
12402b53b04dSDmitry Bogdanov 
12412b53b04dSDmitry Bogdanov 	if (lp_link_speed_msk & AQ_NIC_RATE_1G_HALF)
12422b53b04dSDmitry Bogdanov 		ethtool_link_ksettings_add_link_mode(cmd, lp_advertising,
12432b53b04dSDmitry Bogdanov 						     1000baseT_Half);
12442b53b04dSDmitry Bogdanov 
12452b53b04dSDmitry Bogdanov 	if (lp_link_speed_msk & AQ_NIC_RATE_100M)
12462b53b04dSDmitry Bogdanov 		ethtool_link_ksettings_add_link_mode(cmd, lp_advertising,
12472b53b04dSDmitry Bogdanov 						     100baseT_Full);
12482b53b04dSDmitry Bogdanov 
12492b53b04dSDmitry Bogdanov 	if (lp_link_speed_msk & AQ_NIC_RATE_100M_HALF)
12502b53b04dSDmitry Bogdanov 		ethtool_link_ksettings_add_link_mode(cmd, lp_advertising,
12512b53b04dSDmitry Bogdanov 						     100baseT_Half);
12522b53b04dSDmitry Bogdanov 
12532b53b04dSDmitry Bogdanov 	if (lp_link_speed_msk & AQ_NIC_RATE_10M)
12542b53b04dSDmitry Bogdanov 		ethtool_link_ksettings_add_link_mode(cmd, lp_advertising,
12552b53b04dSDmitry Bogdanov 						     10baseT_Full);
12562b53b04dSDmitry Bogdanov 
12572b53b04dSDmitry Bogdanov 	if (lp_link_speed_msk & AQ_NIC_RATE_10M_HALF)
12582b53b04dSDmitry Bogdanov 		ethtool_link_ksettings_add_link_mode(cmd, lp_advertising,
12592b53b04dSDmitry Bogdanov 						     10baseT_Half);
12602b53b04dSDmitry Bogdanov 
12612b53b04dSDmitry Bogdanov 	if (self->aq_hw->aq_link_status.lp_flow_control & AQ_NIC_FC_RX)
12622b53b04dSDmitry Bogdanov 		ethtool_link_ksettings_add_link_mode(cmd, lp_advertising,
12632b53b04dSDmitry Bogdanov 						     Pause);
12642b53b04dSDmitry Bogdanov 	if (!!(self->aq_hw->aq_link_status.lp_flow_control & AQ_NIC_FC_TX) ^
12652b53b04dSDmitry Bogdanov 	    !!(self->aq_hw->aq_link_status.lp_flow_control & AQ_NIC_FC_RX))
12662b53b04dSDmitry Bogdanov 		ethtool_link_ksettings_add_link_mode(cmd, lp_advertising,
12672b53b04dSDmitry Bogdanov 						     Asym_Pause);
126897bde5c4SDavid VomLehn }
126997bde5c4SDavid VomLehn 
aq_nic_set_link_ksettings(struct aq_nic_s * self,const struct ethtool_link_ksettings * cmd)1270f8244ab5SPhilippe Reynes int aq_nic_set_link_ksettings(struct aq_nic_s *self,
1271f8244ab5SPhilippe Reynes 			      const struct ethtool_link_ksettings *cmd)
127297bde5c4SDavid VomLehn {
1273071a0204SIgor Russkikh 	int fduplex = (cmd->base.duplex == DUPLEX_FULL);
1274071a0204SIgor Russkikh 	u32 speed = cmd->base.speed;
127597bde5c4SDavid VomLehn 	u32 rate = 0U;
127697bde5c4SDavid VomLehn 	int err = 0;
127797bde5c4SDavid VomLehn 
1278071a0204SIgor Russkikh 	if (!fduplex && speed > SPEED_1000) {
1279071a0204SIgor Russkikh 		err = -EINVAL;
1280071a0204SIgor Russkikh 		goto err_exit;
1281071a0204SIgor Russkikh 	}
1282071a0204SIgor Russkikh 
1283f8244ab5SPhilippe Reynes 	if (cmd->base.autoneg == AUTONEG_ENABLE) {
12848fcb98f4SIgor Russkikh 		rate = self->aq_nic_cfg.aq_hw_caps->link_speed_msk;
128597bde5c4SDavid VomLehn 		self->aq_nic_cfg.is_autoneg = true;
128697bde5c4SDavid VomLehn 	} else {
128797bde5c4SDavid VomLehn 		switch (speed) {
12883d464aadSIgor Russkikh 		case SPEED_10:
1289071a0204SIgor Russkikh 			rate = fduplex ? AQ_NIC_RATE_10M : AQ_NIC_RATE_10M_HALF;
12903d464aadSIgor Russkikh 			break;
12913d464aadSIgor Russkikh 
129297bde5c4SDavid VomLehn 		case SPEED_100:
1293071a0204SIgor Russkikh 			rate = fduplex ? AQ_NIC_RATE_100M
1294071a0204SIgor Russkikh 				       : AQ_NIC_RATE_100M_HALF;
129597bde5c4SDavid VomLehn 			break;
129697bde5c4SDavid VomLehn 
129797bde5c4SDavid VomLehn 		case SPEED_1000:
1298071a0204SIgor Russkikh 			rate = fduplex ? AQ_NIC_RATE_1G : AQ_NIC_RATE_1G_HALF;
129997bde5c4SDavid VomLehn 			break;
130097bde5c4SDavid VomLehn 
130197bde5c4SDavid VomLehn 		case SPEED_2500:
1302843e1396SMark Starovoytov 			rate = AQ_NIC_RATE_2G5;
130397bde5c4SDavid VomLehn 			break;
130497bde5c4SDavid VomLehn 
130597bde5c4SDavid VomLehn 		case SPEED_5000:
130697bde5c4SDavid VomLehn 			rate = AQ_NIC_RATE_5G;
130797bde5c4SDavid VomLehn 			break;
130897bde5c4SDavid VomLehn 
130997bde5c4SDavid VomLehn 		case SPEED_10000:
131097bde5c4SDavid VomLehn 			rate = AQ_NIC_RATE_10G;
131197bde5c4SDavid VomLehn 			break;
131297bde5c4SDavid VomLehn 
131397bde5c4SDavid VomLehn 		default:
131497bde5c4SDavid VomLehn 			err = -1;
131597bde5c4SDavid VomLehn 			goto err_exit;
131697bde5c4SDavid VomLehn 		}
13178fcb98f4SIgor Russkikh 		if (!(self->aq_nic_cfg.aq_hw_caps->link_speed_msk & rate)) {
131897bde5c4SDavid VomLehn 			err = -1;
131997bde5c4SDavid VomLehn 			goto err_exit;
132097bde5c4SDavid VomLehn 		}
132197bde5c4SDavid VomLehn 
132297bde5c4SDavid VomLehn 		self->aq_nic_cfg.is_autoneg = false;
132397bde5c4SDavid VomLehn 	}
132497bde5c4SDavid VomLehn 
1325f5dce08aSNikita Danilov 	mutex_lock(&self->fwreq_mutex);
13260c58c35fSIgor Russkikh 	err = self->aq_fw_ops->set_link_speed(self->aq_hw, rate);
1327f5dce08aSNikita Danilov 	mutex_unlock(&self->fwreq_mutex);
132897bde5c4SDavid VomLehn 	if (err < 0)
132997bde5c4SDavid VomLehn 		goto err_exit;
133097bde5c4SDavid VomLehn 
133197bde5c4SDavid VomLehn 	self->aq_nic_cfg.link_speed_msk = rate;
133297bde5c4SDavid VomLehn 
133397bde5c4SDavid VomLehn err_exit:
133497bde5c4SDavid VomLehn 	return err;
133597bde5c4SDavid VomLehn }
133697bde5c4SDavid VomLehn 
aq_nic_get_cfg(struct aq_nic_s * self)133797bde5c4SDavid VomLehn struct aq_nic_cfg_s *aq_nic_get_cfg(struct aq_nic_s *self)
133897bde5c4SDavid VomLehn {
133997bde5c4SDavid VomLehn 	return &self->aq_nic_cfg;
134097bde5c4SDavid VomLehn }
134197bde5c4SDavid VomLehn 
aq_nic_get_fw_version(struct aq_nic_s * self)134297bde5c4SDavid VomLehn u32 aq_nic_get_fw_version(struct aq_nic_s *self)
134397bde5c4SDavid VomLehn {
134436e90a52SNikita Danilov 	return self->aq_hw_ops->hw_get_fw_version(self->aq_hw);
134597bde5c4SDavid VomLehn }
134697bde5c4SDavid VomLehn 
aq_nic_set_loopback(struct aq_nic_s * self)1347ea4b4d7fSIgor Russkikh int aq_nic_set_loopback(struct aq_nic_s *self)
1348ea4b4d7fSIgor Russkikh {
1349ea4b4d7fSIgor Russkikh 	struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg;
1350ea4b4d7fSIgor Russkikh 
1351ea4b4d7fSIgor Russkikh 	if (!self->aq_hw_ops->hw_set_loopback ||
1352ea4b4d7fSIgor Russkikh 	    !self->aq_fw_ops->set_phyloopback)
1353e35df218SMark Starovoytov 		return -EOPNOTSUPP;
1354ea4b4d7fSIgor Russkikh 
1355ea4b4d7fSIgor Russkikh 	mutex_lock(&self->fwreq_mutex);
1356ea4b4d7fSIgor Russkikh 	self->aq_hw_ops->hw_set_loopback(self->aq_hw,
1357ea4b4d7fSIgor Russkikh 					 AQ_HW_LOOPBACK_DMA_SYS,
1358ea4b4d7fSIgor Russkikh 					 !!(cfg->priv_flags &
1359ea4b4d7fSIgor Russkikh 					    BIT(AQ_HW_LOOPBACK_DMA_SYS)));
1360ea4b4d7fSIgor Russkikh 
1361ea4b4d7fSIgor Russkikh 	self->aq_hw_ops->hw_set_loopback(self->aq_hw,
1362ea4b4d7fSIgor Russkikh 					 AQ_HW_LOOPBACK_PKT_SYS,
1363ea4b4d7fSIgor Russkikh 					 !!(cfg->priv_flags &
1364ea4b4d7fSIgor Russkikh 					    BIT(AQ_HW_LOOPBACK_PKT_SYS)));
1365ea4b4d7fSIgor Russkikh 
1366ea4b4d7fSIgor Russkikh 	self->aq_hw_ops->hw_set_loopback(self->aq_hw,
1367ea4b4d7fSIgor Russkikh 					 AQ_HW_LOOPBACK_DMA_NET,
1368ea4b4d7fSIgor Russkikh 					 !!(cfg->priv_flags &
1369ea4b4d7fSIgor Russkikh 					    BIT(AQ_HW_LOOPBACK_DMA_NET)));
1370ea4b4d7fSIgor Russkikh 
1371ea4b4d7fSIgor Russkikh 	self->aq_fw_ops->set_phyloopback(self->aq_hw,
1372ea4b4d7fSIgor Russkikh 					 AQ_HW_LOOPBACK_PHYINT_SYS,
1373ea4b4d7fSIgor Russkikh 					 !!(cfg->priv_flags &
1374ea4b4d7fSIgor Russkikh 					    BIT(AQ_HW_LOOPBACK_PHYINT_SYS)));
1375ea4b4d7fSIgor Russkikh 
1376ea4b4d7fSIgor Russkikh 	self->aq_fw_ops->set_phyloopback(self->aq_hw,
1377ea4b4d7fSIgor Russkikh 					 AQ_HW_LOOPBACK_PHYEXT_SYS,
1378ea4b4d7fSIgor Russkikh 					 !!(cfg->priv_flags &
1379ea4b4d7fSIgor Russkikh 					    BIT(AQ_HW_LOOPBACK_PHYEXT_SYS)));
1380ea4b4d7fSIgor Russkikh 	mutex_unlock(&self->fwreq_mutex);
1381ea4b4d7fSIgor Russkikh 
1382ea4b4d7fSIgor Russkikh 	return 0;
1383ea4b4d7fSIgor Russkikh }
1384ea4b4d7fSIgor Russkikh 
aq_nic_stop(struct aq_nic_s * self)138597bde5c4SDavid VomLehn int aq_nic_stop(struct aq_nic_s *self)
138697bde5c4SDavid VomLehn {
138797bde5c4SDavid VomLehn 	unsigned int i = 0U;
138897bde5c4SDavid VomLehn 
13893aec6412SIgor Russkikh 	netif_tx_disable(self->ndev);
139093d87b8fSIgor Russkikh 	netif_carrier_off(self->ndev);
139197bde5c4SDavid VomLehn 
139297bde5c4SDavid VomLehn 	del_timer_sync(&self->service_timer);
139349544935SIgor Russkikh 	cancel_work_sync(&self->service_task);
139497bde5c4SDavid VomLehn 
13958fcb98f4SIgor Russkikh 	self->aq_hw_ops->hw_irq_disable(self->aq_hw, AQ_CFG_IRQ_MASK);
139697bde5c4SDavid VomLehn 
139797bde5c4SDavid VomLehn 	if (self->aq_nic_cfg.is_polling)
139897bde5c4SDavid VomLehn 		del_timer_sync(&self->polling_timer);
139997bde5c4SDavid VomLehn 	else
140023ee07adSIgor Russkikh 		aq_pci_func_free_irqs(self);
140197bde5c4SDavid VomLehn 
140204a18399SEgor Pomozov 	aq_ptp_irq_free(self);
140304a18399SEgor Pomozov 
14042ba5e47fSChia-Lin Kao (AceLan) 	for (i = 0U; self->aq_vecs > i; ++i)
14052ba5e47fSChia-Lin Kao (AceLan) 		aq_vec_stop(self->aq_vec[i]);
140697bde5c4SDavid VomLehn 
140794ad9455SEgor Pomozov 	aq_ptp_ring_stop(self);
140894ad9455SEgor Pomozov 
14098fcb98f4SIgor Russkikh 	return self->aq_hw_ops->hw_stop(self->aq_hw);
141097bde5c4SDavid VomLehn }
141197bde5c4SDavid VomLehn 
aq_nic_set_power(struct aq_nic_s * self)1412837c6378SNikita Danilov void aq_nic_set_power(struct aq_nic_s *self)
1413837c6378SNikita Danilov {
1414837c6378SNikita Danilov 	if (self->power_state != AQ_HW_POWER_STATE_D0 ||
1415837c6378SNikita Danilov 	    self->aq_hw->aq_nic_cfg->wol)
1416837c6378SNikita Danilov 		if (likely(self->aq_fw_ops->set_power)) {
1417837c6378SNikita Danilov 			mutex_lock(&self->fwreq_mutex);
1418837c6378SNikita Danilov 			self->aq_fw_ops->set_power(self->aq_hw,
1419837c6378SNikita Danilov 						   self->power_state,
1420837c6378SNikita Danilov 						   self->ndev->dev_addr);
1421837c6378SNikita Danilov 			mutex_unlock(&self->fwreq_mutex);
1422837c6378SNikita Danilov 		}
1423837c6378SNikita Danilov }
1424837c6378SNikita Danilov 
aq_nic_deinit(struct aq_nic_s * self,bool link_down)1425837c6378SNikita Danilov void aq_nic_deinit(struct aq_nic_s *self, bool link_down)
142697bde5c4SDavid VomLehn {
142797bde5c4SDavid VomLehn 	struct aq_vec_s *aq_vec = NULL;
142897bde5c4SDavid VomLehn 	unsigned int i = 0U;
142997bde5c4SDavid VomLehn 
143097bde5c4SDavid VomLehn 	if (!self)
143197bde5c4SDavid VomLehn 		goto err_exit;
143297bde5c4SDavid VomLehn 
14338ce84271SDmitry Bezrukov 	for (i = 0U; i < self->aq_vecs; i++) {
14348ce84271SDmitry Bezrukov 		aq_vec = self->aq_vec[i];
143597bde5c4SDavid VomLehn 		aq_vec_deinit(aq_vec);
14368ce84271SDmitry Bezrukov 		aq_vec_ring_free(aq_vec);
14378ce84271SDmitry Bezrukov 	}
143897bde5c4SDavid VomLehn 
14391a64f8dcSEgor Pomozov 	aq_ptp_unregister(self);
144094ad9455SEgor Pomozov 	aq_ptp_ring_deinit(self);
144194ad9455SEgor Pomozov 	aq_ptp_ring_free(self);
14421a64f8dcSEgor Pomozov 	aq_ptp_free(self);
14431a64f8dcSEgor Pomozov 
1444837c6378SNikita Danilov 	if (likely(self->aq_fw_ops->deinit) && link_down) {
1445f5dce08aSNikita Danilov 		mutex_lock(&self->fwreq_mutex);
1446a0da96c0SYana Esina 		self->aq_fw_ops->deinit(self->aq_hw);
1447f5dce08aSNikita Danilov 		mutex_unlock(&self->fwreq_mutex);
1448f5dce08aSNikita Danilov 	}
1449a0da96c0SYana Esina 
145097bde5c4SDavid VomLehn err_exit:;
145197bde5c4SDavid VomLehn }
145297bde5c4SDavid VomLehn 
aq_nic_free_vectors(struct aq_nic_s * self)145323ee07adSIgor Russkikh void aq_nic_free_vectors(struct aq_nic_s *self)
145497bde5c4SDavid VomLehn {
145597bde5c4SDavid VomLehn 	unsigned int i = 0U;
145697bde5c4SDavid VomLehn 
145797bde5c4SDavid VomLehn 	if (!self)
145897bde5c4SDavid VomLehn 		goto err_exit;
145997bde5c4SDavid VomLehn 
146008b5cf08SIgor Russkikh 	for (i = ARRAY_SIZE(self->aq_vec); i--;) {
14613013c498SPavel Belous 		if (self->aq_vec[i]) {
146297bde5c4SDavid VomLehn 			aq_vec_free(self->aq_vec[i]);
14633013c498SPavel Belous 			self->aq_vec[i] = NULL;
14643013c498SPavel Belous 		}
146597bde5c4SDavid VomLehn 	}
146697bde5c4SDavid VomLehn 
146797bde5c4SDavid VomLehn err_exit:;
146897bde5c4SDavid VomLehn }
146997bde5c4SDavid VomLehn 
aq_nic_realloc_vectors(struct aq_nic_s * self)147014ef766bSMark Starovoytov int aq_nic_realloc_vectors(struct aq_nic_s *self)
147114ef766bSMark Starovoytov {
147214ef766bSMark Starovoytov 	struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(self);
147314ef766bSMark Starovoytov 
147414ef766bSMark Starovoytov 	aq_nic_free_vectors(self);
147514ef766bSMark Starovoytov 
147614ef766bSMark Starovoytov 	for (self->aq_vecs = 0; self->aq_vecs < cfg->vecs; self->aq_vecs++) {
147714ef766bSMark Starovoytov 		self->aq_vec[self->aq_vecs] = aq_vec_alloc(self, self->aq_vecs,
147814ef766bSMark Starovoytov 							   cfg);
147914ef766bSMark Starovoytov 		if (unlikely(!self->aq_vec[self->aq_vecs]))
148014ef766bSMark Starovoytov 			return -ENOMEM;
148114ef766bSMark Starovoytov 	}
148214ef766bSMark Starovoytov 
148314ef766bSMark Starovoytov 	return 0;
148414ef766bSMark Starovoytov }
148514ef766bSMark Starovoytov 
aq_nic_shutdown(struct aq_nic_s * self)148690869ddfSIgor Russkikh void aq_nic_shutdown(struct aq_nic_s *self)
148790869ddfSIgor Russkikh {
148890869ddfSIgor Russkikh 	int err = 0;
148990869ddfSIgor Russkikh 
149090869ddfSIgor Russkikh 	if (!self->ndev)
149190869ddfSIgor Russkikh 		return;
149290869ddfSIgor Russkikh 
149390869ddfSIgor Russkikh 	rtnl_lock();
149490869ddfSIgor Russkikh 
149590869ddfSIgor Russkikh 	netif_device_detach(self->ndev);
149690869ddfSIgor Russkikh 
14979a11aff2SIgor Russkikh 	if (netif_running(self->ndev)) {
149890869ddfSIgor Russkikh 		err = aq_nic_stop(self);
149990869ddfSIgor Russkikh 		if (err < 0)
150090869ddfSIgor Russkikh 			goto err_exit;
15019a11aff2SIgor Russkikh 	}
1502837c6378SNikita Danilov 	aq_nic_deinit(self, !self->aq_hw->aq_nic_cfg->wol);
1503837c6378SNikita Danilov 	aq_nic_set_power(self);
150490869ddfSIgor Russkikh 
150590869ddfSIgor Russkikh err_exit:
150690869ddfSIgor Russkikh 	rtnl_unlock();
150790869ddfSIgor Russkikh }
15085a1bf9efSDmitry Bezrukov 
aq_nic_reserve_filter(struct aq_nic_s * self,enum aq_rx_filter_type type)15095a1bf9efSDmitry Bezrukov u8 aq_nic_reserve_filter(struct aq_nic_s *self, enum aq_rx_filter_type type)
15105a1bf9efSDmitry Bezrukov {
15115a1bf9efSDmitry Bezrukov 	u8 location = 0xFF;
15125a1bf9efSDmitry Bezrukov 	u32 fltr_cnt;
15135a1bf9efSDmitry Bezrukov 	u32 n_bit;
15145a1bf9efSDmitry Bezrukov 
15155a1bf9efSDmitry Bezrukov 	switch (type) {
15165a1bf9efSDmitry Bezrukov 	case aq_rx_filter_ethertype:
15175a1bf9efSDmitry Bezrukov 		location = AQ_RX_LAST_LOC_FETHERT - AQ_RX_FIRST_LOC_FETHERT -
15185a1bf9efSDmitry Bezrukov 			   self->aq_hw_rx_fltrs.fet_reserved_count;
15195a1bf9efSDmitry Bezrukov 		self->aq_hw_rx_fltrs.fet_reserved_count++;
15205a1bf9efSDmitry Bezrukov 		break;
15215a1bf9efSDmitry Bezrukov 	case aq_rx_filter_l3l4:
15225a1bf9efSDmitry Bezrukov 		fltr_cnt = AQ_RX_LAST_LOC_FL3L4 - AQ_RX_FIRST_LOC_FL3L4;
15235a1bf9efSDmitry Bezrukov 		n_bit = fltr_cnt - self->aq_hw_rx_fltrs.fl3l4.reserved_count;
15245a1bf9efSDmitry Bezrukov 
15255a1bf9efSDmitry Bezrukov 		self->aq_hw_rx_fltrs.fl3l4.active_ipv4 |= BIT(n_bit);
15265a1bf9efSDmitry Bezrukov 		self->aq_hw_rx_fltrs.fl3l4.reserved_count++;
15275a1bf9efSDmitry Bezrukov 		location = n_bit;
15285a1bf9efSDmitry Bezrukov 		break;
15295a1bf9efSDmitry Bezrukov 	default:
15305a1bf9efSDmitry Bezrukov 		break;
15315a1bf9efSDmitry Bezrukov 	}
15325a1bf9efSDmitry Bezrukov 
15335a1bf9efSDmitry Bezrukov 	return location;
15345a1bf9efSDmitry Bezrukov }
15355a1bf9efSDmitry Bezrukov 
aq_nic_release_filter(struct aq_nic_s * self,enum aq_rx_filter_type type,u32 location)15365a1bf9efSDmitry Bezrukov void aq_nic_release_filter(struct aq_nic_s *self, enum aq_rx_filter_type type,
15375a1bf9efSDmitry Bezrukov 			   u32 location)
15385a1bf9efSDmitry Bezrukov {
15395a1bf9efSDmitry Bezrukov 	switch (type) {
15405a1bf9efSDmitry Bezrukov 	case aq_rx_filter_ethertype:
15415a1bf9efSDmitry Bezrukov 		self->aq_hw_rx_fltrs.fet_reserved_count--;
15425a1bf9efSDmitry Bezrukov 		break;
15435a1bf9efSDmitry Bezrukov 	case aq_rx_filter_l3l4:
15445a1bf9efSDmitry Bezrukov 		self->aq_hw_rx_fltrs.fl3l4.reserved_count--;
15455a1bf9efSDmitry Bezrukov 		self->aq_hw_rx_fltrs.fl3l4.active_ipv4 &= ~BIT(location);
15465a1bf9efSDmitry Bezrukov 		break;
15475a1bf9efSDmitry Bezrukov 	default:
15485a1bf9efSDmitry Bezrukov 		break;
15495a1bf9efSDmitry Bezrukov 	}
15505a1bf9efSDmitry Bezrukov }
1551a83fe6b6SDmitry Bezrukov 
aq_nic_set_downshift(struct aq_nic_s * self,int val)1552e193c3abSIgor Russkikh int aq_nic_set_downshift(struct aq_nic_s *self, int val)
1553e193c3abSIgor Russkikh {
1554e193c3abSIgor Russkikh 	int err = 0;
1555e193c3abSIgor Russkikh 	struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg;
1556e193c3abSIgor Russkikh 
1557e193c3abSIgor Russkikh 	if (!self->aq_fw_ops->set_downshift)
1558e193c3abSIgor Russkikh 		return -EOPNOTSUPP;
1559e193c3abSIgor Russkikh 
1560e193c3abSIgor Russkikh 	if (val > 15) {
1561e193c3abSIgor Russkikh 		netdev_err(self->ndev, "downshift counter should be <= 15\n");
1562e193c3abSIgor Russkikh 		return -EINVAL;
1563e193c3abSIgor Russkikh 	}
1564e193c3abSIgor Russkikh 	cfg->downshift_counter = val;
1565e193c3abSIgor Russkikh 
1566e193c3abSIgor Russkikh 	mutex_lock(&self->fwreq_mutex);
1567e193c3abSIgor Russkikh 	err = self->aq_fw_ops->set_downshift(self->aq_hw, cfg->downshift_counter);
1568e193c3abSIgor Russkikh 	mutex_unlock(&self->fwreq_mutex);
1569e193c3abSIgor Russkikh 
1570e193c3abSIgor Russkikh 	return err;
1571e193c3abSIgor Russkikh }
1572e193c3abSIgor Russkikh 
aq_nic_set_media_detect(struct aq_nic_s * self,int val)157360db5e40SIgor Russkikh int aq_nic_set_media_detect(struct aq_nic_s *self, int val)
157460db5e40SIgor Russkikh {
157560db5e40SIgor Russkikh 	struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg;
157660db5e40SIgor Russkikh 	int err = 0;
157760db5e40SIgor Russkikh 
157860db5e40SIgor Russkikh 	if (!self->aq_fw_ops->set_media_detect)
157960db5e40SIgor Russkikh 		return -EOPNOTSUPP;
158060db5e40SIgor Russkikh 
158160db5e40SIgor Russkikh 	if (val > 0 && val != AQ_HW_MEDIA_DETECT_CNT) {
158260db5e40SIgor Russkikh 		netdev_err(self->ndev, "EDPD on this device could have only fixed value of %d\n",
158360db5e40SIgor Russkikh 			   AQ_HW_MEDIA_DETECT_CNT);
158460db5e40SIgor Russkikh 		return -EINVAL;
158560db5e40SIgor Russkikh 	}
158660db5e40SIgor Russkikh 
158760db5e40SIgor Russkikh 	mutex_lock(&self->fwreq_mutex);
158860db5e40SIgor Russkikh 	err = self->aq_fw_ops->set_media_detect(self->aq_hw, !!val);
158960db5e40SIgor Russkikh 	mutex_unlock(&self->fwreq_mutex);
159060db5e40SIgor Russkikh 
159160db5e40SIgor Russkikh 	/* msecs plays no role - configuration is always fixed in PHY */
159260db5e40SIgor Russkikh 	if (!err)
159360db5e40SIgor Russkikh 		cfg->is_media_detect = !!val;
159460db5e40SIgor Russkikh 
159560db5e40SIgor Russkikh 	return err;
159660db5e40SIgor Russkikh }
159760db5e40SIgor Russkikh 
aq_nic_setup_tc_mqprio(struct aq_nic_s * self,u32 tcs,u8 * prio_tc_map)1598a83fe6b6SDmitry Bezrukov int aq_nic_setup_tc_mqprio(struct aq_nic_s *self, u32 tcs, u8 *prio_tc_map)
1599a83fe6b6SDmitry Bezrukov {
1600a83fe6b6SDmitry Bezrukov 	struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg;
160114ef766bSMark Starovoytov 	const unsigned int prev_vecs = cfg->vecs;
1602a83fe6b6SDmitry Bezrukov 	bool ndev_running;
1603a83fe6b6SDmitry Bezrukov 	int err = 0;
1604a83fe6b6SDmitry Bezrukov 	int i;
1605a83fe6b6SDmitry Bezrukov 
1606a83fe6b6SDmitry Bezrukov 	/* if already the same configuration or
1607a83fe6b6SDmitry Bezrukov 	 * disable request (tcs is 0) and we already is disabled
1608a83fe6b6SDmitry Bezrukov 	 */
1609a83fe6b6SDmitry Bezrukov 	if (tcs == cfg->tcs || (tcs == 0 && !cfg->is_qos))
1610a83fe6b6SDmitry Bezrukov 		return 0;
1611a83fe6b6SDmitry Bezrukov 
1612a83fe6b6SDmitry Bezrukov 	ndev_running = netif_running(self->ndev);
1613a83fe6b6SDmitry Bezrukov 	if (ndev_running)
1614a83fe6b6SDmitry Bezrukov 		dev_close(self->ndev);
1615a83fe6b6SDmitry Bezrukov 
1616a83fe6b6SDmitry Bezrukov 	cfg->tcs = tcs;
1617a83fe6b6SDmitry Bezrukov 	if (cfg->tcs == 0)
1618a83fe6b6SDmitry Bezrukov 		cfg->tcs = 1;
1619a83fe6b6SDmitry Bezrukov 	if (prio_tc_map)
1620a83fe6b6SDmitry Bezrukov 		memcpy(cfg->prio_tc_map, prio_tc_map, sizeof(cfg->prio_tc_map));
1621a83fe6b6SDmitry Bezrukov 	else
1622a83fe6b6SDmitry Bezrukov 		for (i = 0; i < sizeof(cfg->prio_tc_map); i++)
1623a83fe6b6SDmitry Bezrukov 			cfg->prio_tc_map[i] = cfg->tcs * i / 8;
1624a83fe6b6SDmitry Bezrukov 
16253ec94da9SKaixu Xia 	cfg->is_qos = !!tcs;
1626a83fe6b6SDmitry Bezrukov 	cfg->is_ptp = (cfg->tcs <= AQ_HW_PTP_TC);
1627a83fe6b6SDmitry Bezrukov 	if (!cfg->is_ptp)
1628a83fe6b6SDmitry Bezrukov 		netdev_warn(self->ndev, "%s\n",
1629a83fe6b6SDmitry Bezrukov 			    "PTP is auto disabled due to requested TC count.");
1630a83fe6b6SDmitry Bezrukov 
1631a83fe6b6SDmitry Bezrukov 	netdev_set_num_tc(self->ndev, cfg->tcs);
1632a83fe6b6SDmitry Bezrukov 
163314ef766bSMark Starovoytov 	/* Changing the number of TCs might change the number of vectors */
163414ef766bSMark Starovoytov 	aq_nic_cfg_update_num_vecs(self);
163514ef766bSMark Starovoytov 	if (prev_vecs != cfg->vecs) {
163614ef766bSMark Starovoytov 		err = aq_nic_realloc_vectors(self);
163714ef766bSMark Starovoytov 		if (err)
163814ef766bSMark Starovoytov 			goto err_exit;
163914ef766bSMark Starovoytov 	}
164014ef766bSMark Starovoytov 
1641a83fe6b6SDmitry Bezrukov 	if (ndev_running)
1642a83fe6b6SDmitry Bezrukov 		err = dev_open(self->ndev, NULL);
1643a83fe6b6SDmitry Bezrukov 
164414ef766bSMark Starovoytov err_exit:
1645a83fe6b6SDmitry Bezrukov 	return err;
1646a83fe6b6SDmitry Bezrukov }
16477327699fSMark Starovoytov 
aq_nic_setup_tc_max_rate(struct aq_nic_s * self,const unsigned int tc,const u32 max_rate)16487327699fSMark Starovoytov int aq_nic_setup_tc_max_rate(struct aq_nic_s *self, const unsigned int tc,
16497327699fSMark Starovoytov 			     const u32 max_rate)
16507327699fSMark Starovoytov {
16517327699fSMark Starovoytov 	struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg;
16527327699fSMark Starovoytov 
16537327699fSMark Starovoytov 	if (tc >= AQ_CFG_TCS_MAX)
16547327699fSMark Starovoytov 		return -EINVAL;
16557327699fSMark Starovoytov 
16567327699fSMark Starovoytov 	if (max_rate && max_rate < 10) {
16577327699fSMark Starovoytov 		netdev_warn(self->ndev,
16587327699fSMark Starovoytov 			"Setting %s to the minimum usable value of %dMbps.\n",
16597327699fSMark Starovoytov 			"max rate", 10);
16607327699fSMark Starovoytov 		cfg->tc_max_rate[tc] = 10;
16617327699fSMark Starovoytov 	} else {
16627327699fSMark Starovoytov 		cfg->tc_max_rate[tc] = max_rate;
16637327699fSMark Starovoytov 	}
16647327699fSMark Starovoytov 
16657327699fSMark Starovoytov 	return 0;
16667327699fSMark Starovoytov }
16672deac71aSMark Starovoytov 
aq_nic_setup_tc_min_rate(struct aq_nic_s * self,const unsigned int tc,const u32 min_rate)16682deac71aSMark Starovoytov int aq_nic_setup_tc_min_rate(struct aq_nic_s *self, const unsigned int tc,
16692deac71aSMark Starovoytov 			     const u32 min_rate)
16702deac71aSMark Starovoytov {
16712deac71aSMark Starovoytov 	struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg;
16722deac71aSMark Starovoytov 
16732deac71aSMark Starovoytov 	if (tc >= AQ_CFG_TCS_MAX)
16742deac71aSMark Starovoytov 		return -EINVAL;
16752deac71aSMark Starovoytov 
16762deac71aSMark Starovoytov 	if (min_rate)
16772deac71aSMark Starovoytov 		set_bit(tc, &cfg->tc_min_rate_msk);
16782deac71aSMark Starovoytov 	else
16792deac71aSMark Starovoytov 		clear_bit(tc, &cfg->tc_min_rate_msk);
16802deac71aSMark Starovoytov 
16812deac71aSMark Starovoytov 	if (min_rate && min_rate < 20) {
16822deac71aSMark Starovoytov 		netdev_warn(self->ndev,
16832deac71aSMark Starovoytov 			"Setting %s to the minimum usable value of %dMbps.\n",
16842deac71aSMark Starovoytov 			"min rate", 20);
16852deac71aSMark Starovoytov 		cfg->tc_min_rate[tc] = 20;
16862deac71aSMark Starovoytov 	} else {
16872deac71aSMark Starovoytov 		cfg->tc_min_rate[tc] = min_rate;
16882deac71aSMark Starovoytov 	}
16892deac71aSMark Starovoytov 
16902deac71aSMark Starovoytov 	return 0;
16912deac71aSMark Starovoytov }
1692