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