18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* Atlantic Network Driver 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2014-2019 aQuantia Corporation 58c2ecf20Sopenharmony_ci * Copyright (C) 2019-2020 Marvell International Ltd. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci/* File aq_nic.c: Definition of common code for NIC. */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "aq_nic.h" 118c2ecf20Sopenharmony_ci#include "aq_ring.h" 128c2ecf20Sopenharmony_ci#include "aq_vec.h" 138c2ecf20Sopenharmony_ci#include "aq_hw.h" 148c2ecf20Sopenharmony_ci#include "aq_pci_func.h" 158c2ecf20Sopenharmony_ci#include "aq_macsec.h" 168c2ecf20Sopenharmony_ci#include "aq_main.h" 178c2ecf20Sopenharmony_ci#include "aq_phy.h" 188c2ecf20Sopenharmony_ci#include "aq_ptp.h" 198c2ecf20Sopenharmony_ci#include "aq_filters.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 228c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 238c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 248c2ecf20Sopenharmony_ci#include <linux/timer.h> 258c2ecf20Sopenharmony_ci#include <linux/cpu.h> 268c2ecf20Sopenharmony_ci#include <linux/ip.h> 278c2ecf20Sopenharmony_ci#include <linux/tcp.h> 288c2ecf20Sopenharmony_ci#include <net/ip.h> 298c2ecf20Sopenharmony_ci#include <net/pkt_cls.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic unsigned int aq_itr = AQ_CFG_INTERRUPT_MODERATION_AUTO; 328c2ecf20Sopenharmony_cimodule_param_named(aq_itr, aq_itr, uint, 0644); 338c2ecf20Sopenharmony_ciMODULE_PARM_DESC(aq_itr, "Interrupt throttling mode"); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic unsigned int aq_itr_tx; 368c2ecf20Sopenharmony_cimodule_param_named(aq_itr_tx, aq_itr_tx, uint, 0644); 378c2ecf20Sopenharmony_ciMODULE_PARM_DESC(aq_itr_tx, "TX interrupt throttle rate"); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic unsigned int aq_itr_rx; 408c2ecf20Sopenharmony_cimodule_param_named(aq_itr_rx, aq_itr_rx, uint, 0644); 418c2ecf20Sopenharmony_ciMODULE_PARM_DESC(aq_itr_rx, "RX interrupt throttle rate"); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic void aq_nic_update_ndev_stats(struct aq_nic_s *self); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic void aq_nic_rss_init(struct aq_nic_s *self, unsigned int num_rss_queues) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci static u8 rss_key[AQ_CFG_RSS_HASHKEY_SIZE] = { 488c2ecf20Sopenharmony_ci 0x1e, 0xad, 0x71, 0x87, 0x65, 0xfc, 0x26, 0x7d, 498c2ecf20Sopenharmony_ci 0x0d, 0x45, 0x67, 0x74, 0xcd, 0x06, 0x1a, 0x18, 508c2ecf20Sopenharmony_ci 0xb6, 0xc1, 0xf0, 0xc7, 0xbb, 0x18, 0xbe, 0xf8, 518c2ecf20Sopenharmony_ci 0x19, 0x13, 0x4b, 0xa9, 0xd0, 0x3e, 0xfe, 0x70, 528c2ecf20Sopenharmony_ci 0x25, 0x03, 0xab, 0x50, 0x6a, 0x8b, 0x82, 0x0c 538c2ecf20Sopenharmony_ci }; 548c2ecf20Sopenharmony_ci struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg; 558c2ecf20Sopenharmony_ci struct aq_rss_parameters *rss_params; 568c2ecf20Sopenharmony_ci int i = 0; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci rss_params = &cfg->aq_rss; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci rss_params->hash_secret_key_size = sizeof(rss_key); 618c2ecf20Sopenharmony_ci memcpy(rss_params->hash_secret_key, rss_key, sizeof(rss_key)); 628c2ecf20Sopenharmony_ci rss_params->indirection_table_size = AQ_CFG_RSS_INDIRECTION_TABLE_MAX; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci for (i = rss_params->indirection_table_size; i--;) 658c2ecf20Sopenharmony_ci rss_params->indirection_table[i] = i & (num_rss_queues - 1); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* Recalculate the number of vectors */ 698c2ecf20Sopenharmony_cistatic void aq_nic_cfg_update_num_vecs(struct aq_nic_s *self) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci cfg->vecs = min(cfg->aq_hw_caps->vecs, AQ_CFG_VECS_DEF); 748c2ecf20Sopenharmony_ci cfg->vecs = min(cfg->vecs, num_online_cpus()); 758c2ecf20Sopenharmony_ci if (self->irqvecs > AQ_HW_SERVICE_IRQS) 768c2ecf20Sopenharmony_ci cfg->vecs = min(cfg->vecs, self->irqvecs - AQ_HW_SERVICE_IRQS); 778c2ecf20Sopenharmony_ci /* cfg->vecs should be power of 2 for RSS */ 788c2ecf20Sopenharmony_ci cfg->vecs = rounddown_pow_of_two(cfg->vecs); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (ATL_HW_IS_CHIP_FEATURE(self->aq_hw, ANTIGUA)) { 818c2ecf20Sopenharmony_ci if (cfg->tcs > 2) 828c2ecf20Sopenharmony_ci cfg->vecs = min(cfg->vecs, 4U); 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (cfg->vecs <= 4) 868c2ecf20Sopenharmony_ci cfg->tc_mode = AQ_TC_MODE_8TCS; 878c2ecf20Sopenharmony_ci else 888c2ecf20Sopenharmony_ci cfg->tc_mode = AQ_TC_MODE_4TCS; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci /*rss rings */ 918c2ecf20Sopenharmony_ci cfg->num_rss_queues = min(cfg->vecs, AQ_CFG_NUM_RSS_QUEUES_DEF); 928c2ecf20Sopenharmony_ci aq_nic_rss_init(self, cfg->num_rss_queues); 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci/* Checks hw_caps and 'corrects' aq_nic_cfg in runtime */ 968c2ecf20Sopenharmony_civoid aq_nic_cfg_start(struct aq_nic_s *self) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg; 998c2ecf20Sopenharmony_ci int i; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci cfg->tcs = AQ_CFG_TCS_DEF; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci cfg->is_polling = AQ_CFG_IS_POLLING_DEF; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci cfg->itr = aq_itr; 1068c2ecf20Sopenharmony_ci cfg->tx_itr = aq_itr_tx; 1078c2ecf20Sopenharmony_ci cfg->rx_itr = aq_itr_rx; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci cfg->rxpageorder = AQ_CFG_RX_PAGEORDER; 1108c2ecf20Sopenharmony_ci cfg->is_rss = AQ_CFG_IS_RSS_DEF; 1118c2ecf20Sopenharmony_ci cfg->aq_rss.base_cpu_number = AQ_CFG_RSS_BASE_CPU_NUM_DEF; 1128c2ecf20Sopenharmony_ci cfg->fc.req = AQ_CFG_FC_MODE; 1138c2ecf20Sopenharmony_ci cfg->wol = AQ_CFG_WOL_MODES; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci cfg->mtu = AQ_CFG_MTU_DEF; 1168c2ecf20Sopenharmony_ci cfg->link_speed_msk = AQ_CFG_SPEED_MSK; 1178c2ecf20Sopenharmony_ci cfg->is_autoneg = AQ_CFG_IS_AUTONEG_DEF; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci cfg->is_lro = AQ_CFG_IS_LRO_DEF; 1208c2ecf20Sopenharmony_ci cfg->is_ptp = true; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci /*descriptors */ 1238c2ecf20Sopenharmony_ci cfg->rxds = min(cfg->aq_hw_caps->rxds_max, AQ_CFG_RXDS_DEF); 1248c2ecf20Sopenharmony_ci cfg->txds = min(cfg->aq_hw_caps->txds_max, AQ_CFG_TXDS_DEF); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci aq_nic_cfg_update_num_vecs(self); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci cfg->irq_type = aq_pci_func_get_irq_type(self); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if ((cfg->irq_type == AQ_HW_IRQ_LEGACY) || 1318c2ecf20Sopenharmony_ci (cfg->aq_hw_caps->vecs == 1U) || 1328c2ecf20Sopenharmony_ci (cfg->vecs == 1U)) { 1338c2ecf20Sopenharmony_ci cfg->is_rss = 0U; 1348c2ecf20Sopenharmony_ci cfg->vecs = 1U; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* Check if we have enough vectors allocated for 1388c2ecf20Sopenharmony_ci * link status IRQ. If no - we'll know link state from 1398c2ecf20Sopenharmony_ci * slower service task. 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_ci if (AQ_HW_SERVICE_IRQS > 0 && cfg->vecs + 1 <= self->irqvecs) 1428c2ecf20Sopenharmony_ci cfg->link_irq_vec = cfg->vecs; 1438c2ecf20Sopenharmony_ci else 1448c2ecf20Sopenharmony_ci cfg->link_irq_vec = 0; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci cfg->link_speed_msk &= cfg->aq_hw_caps->link_speed_msk; 1478c2ecf20Sopenharmony_ci cfg->features = cfg->aq_hw_caps->hw_features; 1488c2ecf20Sopenharmony_ci cfg->is_vlan_rx_strip = !!(cfg->features & NETIF_F_HW_VLAN_CTAG_RX); 1498c2ecf20Sopenharmony_ci cfg->is_vlan_tx_insert = !!(cfg->features & NETIF_F_HW_VLAN_CTAG_TX); 1508c2ecf20Sopenharmony_ci cfg->is_vlan_force_promisc = true; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(cfg->prio_tc_map); i++) 1538c2ecf20Sopenharmony_ci cfg->prio_tc_map[i] = cfg->tcs * i / 8; 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic int aq_nic_update_link_status(struct aq_nic_s *self) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci int err = self->aq_fw_ops->update_link_status(self->aq_hw); 1598c2ecf20Sopenharmony_ci u32 fc = 0; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (err) 1628c2ecf20Sopenharmony_ci return err; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (self->aq_fw_ops->get_flow_control) 1658c2ecf20Sopenharmony_ci self->aq_fw_ops->get_flow_control(self->aq_hw, &fc); 1668c2ecf20Sopenharmony_ci self->aq_nic_cfg.fc.cur = fc; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci if (self->link_status.mbps != self->aq_hw->aq_link_status.mbps) { 1698c2ecf20Sopenharmony_ci netdev_info(self->ndev, "%s: link change old %d new %d\n", 1708c2ecf20Sopenharmony_ci AQ_CFG_DRV_NAME, self->link_status.mbps, 1718c2ecf20Sopenharmony_ci self->aq_hw->aq_link_status.mbps); 1728c2ecf20Sopenharmony_ci aq_nic_update_interrupt_moderation_settings(self); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (self->aq_ptp) { 1758c2ecf20Sopenharmony_ci aq_ptp_clock_init(self); 1768c2ecf20Sopenharmony_ci aq_ptp_tm_offset_set(self, 1778c2ecf20Sopenharmony_ci self->aq_hw->aq_link_status.mbps); 1788c2ecf20Sopenharmony_ci aq_ptp_link_change(self); 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci /* Driver has to update flow control settings on RX block 1828c2ecf20Sopenharmony_ci * on any link event. 1838c2ecf20Sopenharmony_ci * We should query FW whether it negotiated FC. 1848c2ecf20Sopenharmony_ci */ 1858c2ecf20Sopenharmony_ci if (self->aq_hw_ops->hw_set_fc) 1868c2ecf20Sopenharmony_ci self->aq_hw_ops->hw_set_fc(self->aq_hw, fc, 0); 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci self->link_status = self->aq_hw->aq_link_status; 1908c2ecf20Sopenharmony_ci if (!netif_carrier_ok(self->ndev) && self->link_status.mbps) { 1918c2ecf20Sopenharmony_ci aq_utils_obj_set(&self->flags, 1928c2ecf20Sopenharmony_ci AQ_NIC_FLAG_STARTED); 1938c2ecf20Sopenharmony_ci aq_utils_obj_clear(&self->flags, 1948c2ecf20Sopenharmony_ci AQ_NIC_LINK_DOWN); 1958c2ecf20Sopenharmony_ci netif_carrier_on(self->ndev); 1968c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_MACSEC) 1978c2ecf20Sopenharmony_ci aq_macsec_enable(self); 1988c2ecf20Sopenharmony_ci#endif 1998c2ecf20Sopenharmony_ci if (self->aq_hw_ops->hw_tc_rate_limit_set) 2008c2ecf20Sopenharmony_ci self->aq_hw_ops->hw_tc_rate_limit_set(self->aq_hw); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci netif_tx_wake_all_queues(self->ndev); 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci if (netif_carrier_ok(self->ndev) && !self->link_status.mbps) { 2058c2ecf20Sopenharmony_ci netif_carrier_off(self->ndev); 2068c2ecf20Sopenharmony_ci netif_tx_disable(self->ndev); 2078c2ecf20Sopenharmony_ci aq_utils_obj_set(&self->flags, AQ_NIC_LINK_DOWN); 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci return 0; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistatic irqreturn_t aq_linkstate_threaded_isr(int irq, void *private) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci struct aq_nic_s *self = private; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (!self) 2188c2ecf20Sopenharmony_ci return IRQ_NONE; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci aq_nic_update_link_status(self); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci self->aq_hw_ops->hw_irq_enable(self->aq_hw, 2238c2ecf20Sopenharmony_ci BIT(self->aq_nic_cfg.link_irq_vec)); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic void aq_nic_service_task(struct work_struct *work) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci struct aq_nic_s *self = container_of(work, struct aq_nic_s, 2318c2ecf20Sopenharmony_ci service_task); 2328c2ecf20Sopenharmony_ci int err; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci aq_ptp_service_task(self); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci if (aq_utils_obj_test(&self->flags, AQ_NIC_FLAGS_IS_NOT_READY)) 2378c2ecf20Sopenharmony_ci return; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci err = aq_nic_update_link_status(self); 2408c2ecf20Sopenharmony_ci if (err) 2418c2ecf20Sopenharmony_ci return; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_MACSEC) 2448c2ecf20Sopenharmony_ci aq_macsec_work(self); 2458c2ecf20Sopenharmony_ci#endif 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci mutex_lock(&self->fwreq_mutex); 2488c2ecf20Sopenharmony_ci if (self->aq_fw_ops->update_stats) 2498c2ecf20Sopenharmony_ci self->aq_fw_ops->update_stats(self->aq_hw); 2508c2ecf20Sopenharmony_ci mutex_unlock(&self->fwreq_mutex); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci aq_nic_update_ndev_stats(self); 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic void aq_nic_service_timer_cb(struct timer_list *t) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci struct aq_nic_s *self = from_timer(self, t, service_timer); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci mod_timer(&self->service_timer, 2608c2ecf20Sopenharmony_ci jiffies + AQ_CFG_SERVICE_TIMER_INTERVAL); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci aq_ndev_schedule_work(&self->service_task); 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic void aq_nic_polling_timer_cb(struct timer_list *t) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci struct aq_nic_s *self = from_timer(self, t, polling_timer); 2688c2ecf20Sopenharmony_ci unsigned int i = 0U; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci for (i = 0U; self->aq_vecs > i; ++i) 2718c2ecf20Sopenharmony_ci aq_vec_isr(i, (void *)self->aq_vec[i]); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci mod_timer(&self->polling_timer, jiffies + 2748c2ecf20Sopenharmony_ci AQ_CFG_POLLING_TIMER_INTERVAL); 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic int aq_nic_hw_prepare(struct aq_nic_s *self) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci int err = 0; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci err = self->aq_hw_ops->hw_soft_reset(self->aq_hw); 2828c2ecf20Sopenharmony_ci if (err) 2838c2ecf20Sopenharmony_ci goto exit; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci err = self->aq_hw_ops->hw_prepare(self->aq_hw, &self->aq_fw_ops); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ciexit: 2888c2ecf20Sopenharmony_ci return err; 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic bool aq_nic_is_valid_ether_addr(const u8 *addr) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci /* Some engineering samples of Aquantia NICs are provisioned with a 2948c2ecf20Sopenharmony_ci * partially populated MAC, which is still invalid. 2958c2ecf20Sopenharmony_ci */ 2968c2ecf20Sopenharmony_ci return !(addr[0] == 0 && addr[1] == 0 && addr[2] == 0); 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ciint aq_nic_ndev_register(struct aq_nic_s *self) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci int err = 0; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci if (!self->ndev) { 3048c2ecf20Sopenharmony_ci err = -EINVAL; 3058c2ecf20Sopenharmony_ci goto err_exit; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci err = aq_nic_hw_prepare(self); 3098c2ecf20Sopenharmony_ci if (err) 3108c2ecf20Sopenharmony_ci goto err_exit; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_MACSEC) 3138c2ecf20Sopenharmony_ci aq_macsec_init(self); 3148c2ecf20Sopenharmony_ci#endif 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci mutex_lock(&self->fwreq_mutex); 3178c2ecf20Sopenharmony_ci err = self->aq_fw_ops->get_mac_permanent(self->aq_hw, 3188c2ecf20Sopenharmony_ci self->ndev->dev_addr); 3198c2ecf20Sopenharmony_ci mutex_unlock(&self->fwreq_mutex); 3208c2ecf20Sopenharmony_ci if (err) 3218c2ecf20Sopenharmony_ci goto err_exit; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(self->ndev->dev_addr) || 3248c2ecf20Sopenharmony_ci !aq_nic_is_valid_ether_addr(self->ndev->dev_addr)) { 3258c2ecf20Sopenharmony_ci netdev_warn(self->ndev, "MAC is invalid, will use random."); 3268c2ecf20Sopenharmony_ci eth_hw_addr_random(self->ndev); 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci#if defined(AQ_CFG_MAC_ADDR_PERMANENT) 3308c2ecf20Sopenharmony_ci { 3318c2ecf20Sopenharmony_ci static u8 mac_addr_permanent[] = AQ_CFG_MAC_ADDR_PERMANENT; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci ether_addr_copy(self->ndev->dev_addr, mac_addr_permanent); 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci#endif 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci for (self->aq_vecs = 0; self->aq_vecs < aq_nic_get_cfg(self)->vecs; 3388c2ecf20Sopenharmony_ci self->aq_vecs++) { 3398c2ecf20Sopenharmony_ci self->aq_vec[self->aq_vecs] = 3408c2ecf20Sopenharmony_ci aq_vec_alloc(self, self->aq_vecs, aq_nic_get_cfg(self)); 3418c2ecf20Sopenharmony_ci if (!self->aq_vec[self->aq_vecs]) { 3428c2ecf20Sopenharmony_ci err = -ENOMEM; 3438c2ecf20Sopenharmony_ci goto err_exit; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci netif_carrier_off(self->ndev); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci netif_tx_disable(self->ndev); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci err = register_netdev(self->ndev); 3528c2ecf20Sopenharmony_ci if (err) 3538c2ecf20Sopenharmony_ci goto err_exit; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cierr_exit: 3568c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_MACSEC) 3578c2ecf20Sopenharmony_ci if (err) 3588c2ecf20Sopenharmony_ci aq_macsec_free(self); 3598c2ecf20Sopenharmony_ci#endif 3608c2ecf20Sopenharmony_ci return err; 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_civoid aq_nic_ndev_init(struct aq_nic_s *self) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci const struct aq_hw_caps_s *aq_hw_caps = self->aq_nic_cfg.aq_hw_caps; 3668c2ecf20Sopenharmony_ci struct aq_nic_cfg_s *aq_nic_cfg = &self->aq_nic_cfg; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci self->ndev->hw_features |= aq_hw_caps->hw_features; 3698c2ecf20Sopenharmony_ci self->ndev->features = aq_hw_caps->hw_features; 3708c2ecf20Sopenharmony_ci self->ndev->vlan_features |= NETIF_F_HW_CSUM | NETIF_F_RXCSUM | 3718c2ecf20Sopenharmony_ci NETIF_F_RXHASH | NETIF_F_SG | 3728c2ecf20Sopenharmony_ci NETIF_F_LRO | NETIF_F_TSO | NETIF_F_TSO6; 3738c2ecf20Sopenharmony_ci self->ndev->gso_partial_features = NETIF_F_GSO_UDP_L4; 3748c2ecf20Sopenharmony_ci self->ndev->priv_flags = aq_hw_caps->hw_priv_flags; 3758c2ecf20Sopenharmony_ci self->ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci self->msg_enable = NETIF_MSG_DRV | NETIF_MSG_LINK; 3788c2ecf20Sopenharmony_ci self->ndev->mtu = aq_nic_cfg->mtu - ETH_HLEN; 3798c2ecf20Sopenharmony_ci self->ndev->max_mtu = aq_hw_caps->mtu - ETH_FCS_LEN - ETH_HLEN; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_civoid aq_nic_set_tx_ring(struct aq_nic_s *self, unsigned int idx, 3848c2ecf20Sopenharmony_ci struct aq_ring_s *ring) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci self->aq_ring_tx[idx] = ring; 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistruct net_device *aq_nic_get_ndev(struct aq_nic_s *self) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci return self->ndev; 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ciint aq_nic_init(struct aq_nic_s *self) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci struct aq_vec_s *aq_vec = NULL; 3978c2ecf20Sopenharmony_ci unsigned int i = 0U; 3988c2ecf20Sopenharmony_ci int err = 0; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci self->power_state = AQ_HW_POWER_STATE_D0; 4018c2ecf20Sopenharmony_ci mutex_lock(&self->fwreq_mutex); 4028c2ecf20Sopenharmony_ci err = self->aq_hw_ops->hw_reset(self->aq_hw); 4038c2ecf20Sopenharmony_ci mutex_unlock(&self->fwreq_mutex); 4048c2ecf20Sopenharmony_ci if (err < 0) 4058c2ecf20Sopenharmony_ci goto err_exit; 4068c2ecf20Sopenharmony_ci /* Restore default settings */ 4078c2ecf20Sopenharmony_ci aq_nic_set_downshift(self, self->aq_nic_cfg.downshift_counter); 4088c2ecf20Sopenharmony_ci aq_nic_set_media_detect(self, self->aq_nic_cfg.is_media_detect ? 4098c2ecf20Sopenharmony_ci AQ_HW_MEDIA_DETECT_CNT : 0); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci err = self->aq_hw_ops->hw_init(self->aq_hw, 4128c2ecf20Sopenharmony_ci aq_nic_get_ndev(self)->dev_addr); 4138c2ecf20Sopenharmony_ci if (err < 0) 4148c2ecf20Sopenharmony_ci goto err_exit; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (ATL_HW_IS_CHIP_FEATURE(self->aq_hw, ATLANTIC) && 4178c2ecf20Sopenharmony_ci self->aq_nic_cfg.aq_hw_caps->media_type == AQ_HW_MEDIA_TYPE_TP) { 4188c2ecf20Sopenharmony_ci self->aq_hw->phy_id = HW_ATL_PHY_ID_MAX; 4198c2ecf20Sopenharmony_ci err = aq_phy_init(self->aq_hw); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci /* Disable the PTP on NICs where it's known to cause datapath 4228c2ecf20Sopenharmony_ci * problems. 4238c2ecf20Sopenharmony_ci * Ideally this should have been done by PHY provisioning, but 4248c2ecf20Sopenharmony_ci * many units have been shipped with enabled PTP block already. 4258c2ecf20Sopenharmony_ci */ 4268c2ecf20Sopenharmony_ci if (self->aq_nic_cfg.aq_hw_caps->quirks & AQ_NIC_QUIRK_BAD_PTP) 4278c2ecf20Sopenharmony_ci if (self->aq_hw->phy_id != HW_ATL_PHY_ID_MAX) 4288c2ecf20Sopenharmony_ci aq_phy_disable_ptp(self->aq_hw); 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci for (i = 0U; i < self->aq_vecs; i++) { 4328c2ecf20Sopenharmony_ci aq_vec = self->aq_vec[i]; 4338c2ecf20Sopenharmony_ci err = aq_vec_ring_alloc(aq_vec, self, i, 4348c2ecf20Sopenharmony_ci aq_nic_get_cfg(self)); 4358c2ecf20Sopenharmony_ci if (err) 4368c2ecf20Sopenharmony_ci goto err_exit; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci aq_vec_init(aq_vec, self->aq_hw_ops, self->aq_hw); 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci if (aq_nic_get_cfg(self)->is_ptp) { 4428c2ecf20Sopenharmony_ci err = aq_ptp_init(self, self->irqvecs - 1); 4438c2ecf20Sopenharmony_ci if (err < 0) 4448c2ecf20Sopenharmony_ci goto err_exit; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci err = aq_ptp_ring_alloc(self); 4478c2ecf20Sopenharmony_ci if (err < 0) 4488c2ecf20Sopenharmony_ci goto err_exit; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci err = aq_ptp_ring_init(self); 4518c2ecf20Sopenharmony_ci if (err < 0) 4528c2ecf20Sopenharmony_ci goto err_exit; 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci netif_carrier_off(self->ndev); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_cierr_exit: 4588c2ecf20Sopenharmony_ci return err; 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ciint aq_nic_start(struct aq_nic_s *self) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci struct aq_vec_s *aq_vec = NULL; 4648c2ecf20Sopenharmony_ci struct aq_nic_cfg_s *cfg; 4658c2ecf20Sopenharmony_ci unsigned int i = 0U; 4668c2ecf20Sopenharmony_ci int err = 0; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci cfg = aq_nic_get_cfg(self); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci err = self->aq_hw_ops->hw_multicast_list_set(self->aq_hw, 4718c2ecf20Sopenharmony_ci self->mc_list.ar, 4728c2ecf20Sopenharmony_ci self->mc_list.count); 4738c2ecf20Sopenharmony_ci if (err < 0) 4748c2ecf20Sopenharmony_ci goto err_exit; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci err = self->aq_hw_ops->hw_packet_filter_set(self->aq_hw, 4778c2ecf20Sopenharmony_ci self->packet_filter); 4788c2ecf20Sopenharmony_ci if (err < 0) 4798c2ecf20Sopenharmony_ci goto err_exit; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci for (i = 0U; self->aq_vecs > i; ++i) { 4828c2ecf20Sopenharmony_ci aq_vec = self->aq_vec[i]; 4838c2ecf20Sopenharmony_ci err = aq_vec_start(aq_vec); 4848c2ecf20Sopenharmony_ci if (err < 0) 4858c2ecf20Sopenharmony_ci goto err_exit; 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci err = aq_ptp_ring_start(self); 4898c2ecf20Sopenharmony_ci if (err < 0) 4908c2ecf20Sopenharmony_ci goto err_exit; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci aq_nic_set_loopback(self); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci err = self->aq_hw_ops->hw_start(self->aq_hw); 4958c2ecf20Sopenharmony_ci if (err < 0) 4968c2ecf20Sopenharmony_ci goto err_exit; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci err = aq_nic_update_interrupt_moderation_settings(self); 4998c2ecf20Sopenharmony_ci if (err) 5008c2ecf20Sopenharmony_ci goto err_exit; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci INIT_WORK(&self->service_task, aq_nic_service_task); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci timer_setup(&self->service_timer, aq_nic_service_timer_cb, 0); 5058c2ecf20Sopenharmony_ci aq_nic_service_timer_cb(&self->service_timer); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (cfg->is_polling) { 5088c2ecf20Sopenharmony_ci timer_setup(&self->polling_timer, aq_nic_polling_timer_cb, 0); 5098c2ecf20Sopenharmony_ci mod_timer(&self->polling_timer, jiffies + 5108c2ecf20Sopenharmony_ci AQ_CFG_POLLING_TIMER_INTERVAL); 5118c2ecf20Sopenharmony_ci } else { 5128c2ecf20Sopenharmony_ci for (i = 0U; self->aq_vecs > i; ++i) { 5138c2ecf20Sopenharmony_ci aq_vec = self->aq_vec[i]; 5148c2ecf20Sopenharmony_ci err = aq_pci_func_alloc_irq(self, i, self->ndev->name, 5158c2ecf20Sopenharmony_ci aq_vec_isr, aq_vec, 5168c2ecf20Sopenharmony_ci aq_vec_get_affinity_mask(aq_vec)); 5178c2ecf20Sopenharmony_ci if (err < 0) 5188c2ecf20Sopenharmony_ci goto err_exit; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci err = aq_ptp_irq_alloc(self); 5228c2ecf20Sopenharmony_ci if (err < 0) 5238c2ecf20Sopenharmony_ci goto err_exit; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci if (cfg->link_irq_vec) { 5268c2ecf20Sopenharmony_ci int irqvec = pci_irq_vector(self->pdev, 5278c2ecf20Sopenharmony_ci cfg->link_irq_vec); 5288c2ecf20Sopenharmony_ci err = request_threaded_irq(irqvec, NULL, 5298c2ecf20Sopenharmony_ci aq_linkstate_threaded_isr, 5308c2ecf20Sopenharmony_ci IRQF_SHARED | IRQF_ONESHOT, 5318c2ecf20Sopenharmony_ci self->ndev->name, self); 5328c2ecf20Sopenharmony_ci if (err < 0) 5338c2ecf20Sopenharmony_ci goto err_exit; 5348c2ecf20Sopenharmony_ci self->msix_entry_mask |= (1 << cfg->link_irq_vec); 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci err = self->aq_hw_ops->hw_irq_enable(self->aq_hw, 5388c2ecf20Sopenharmony_ci AQ_CFG_IRQ_MASK); 5398c2ecf20Sopenharmony_ci if (err < 0) 5408c2ecf20Sopenharmony_ci goto err_exit; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci err = netif_set_real_num_tx_queues(self->ndev, 5448c2ecf20Sopenharmony_ci self->aq_vecs * cfg->tcs); 5458c2ecf20Sopenharmony_ci if (err < 0) 5468c2ecf20Sopenharmony_ci goto err_exit; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci err = netif_set_real_num_rx_queues(self->ndev, 5498c2ecf20Sopenharmony_ci self->aq_vecs * cfg->tcs); 5508c2ecf20Sopenharmony_ci if (err < 0) 5518c2ecf20Sopenharmony_ci goto err_exit; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci for (i = 0; i < cfg->tcs; i++) { 5548c2ecf20Sopenharmony_ci u16 offset = self->aq_vecs * i; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci netdev_set_tc_queue(self->ndev, i, self->aq_vecs, offset); 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci netif_tx_start_all_queues(self->ndev); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cierr_exit: 5618c2ecf20Sopenharmony_ci return err; 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ciunsigned int aq_nic_map_skb(struct aq_nic_s *self, struct sk_buff *skb, 5658c2ecf20Sopenharmony_ci struct aq_ring_s *ring) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci unsigned int nr_frags = skb_shinfo(skb)->nr_frags; 5688c2ecf20Sopenharmony_ci struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(self); 5698c2ecf20Sopenharmony_ci struct device *dev = aq_nic_get_dev(self); 5708c2ecf20Sopenharmony_ci struct aq_ring_buff_s *first = NULL; 5718c2ecf20Sopenharmony_ci u8 ipver = ip_hdr(skb)->version; 5728c2ecf20Sopenharmony_ci struct aq_ring_buff_s *dx_buff; 5738c2ecf20Sopenharmony_ci bool need_context_tag = false; 5748c2ecf20Sopenharmony_ci unsigned int frag_count = 0U; 5758c2ecf20Sopenharmony_ci unsigned int ret = 0U; 5768c2ecf20Sopenharmony_ci unsigned int dx; 5778c2ecf20Sopenharmony_ci u8 l4proto = 0; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (ipver == 4) 5808c2ecf20Sopenharmony_ci l4proto = ip_hdr(skb)->protocol; 5818c2ecf20Sopenharmony_ci else if (ipver == 6) 5828c2ecf20Sopenharmony_ci l4proto = ipv6_hdr(skb)->nexthdr; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci dx = ring->sw_tail; 5858c2ecf20Sopenharmony_ci dx_buff = &ring->buff_ring[dx]; 5868c2ecf20Sopenharmony_ci dx_buff->flags = 0U; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if (unlikely(skb_is_gso(skb))) { 5898c2ecf20Sopenharmony_ci dx_buff->mss = skb_shinfo(skb)->gso_size; 5908c2ecf20Sopenharmony_ci if (l4proto == IPPROTO_TCP) { 5918c2ecf20Sopenharmony_ci dx_buff->is_gso_tcp = 1U; 5928c2ecf20Sopenharmony_ci dx_buff->len_l4 = tcp_hdrlen(skb); 5938c2ecf20Sopenharmony_ci } else if (l4proto == IPPROTO_UDP) { 5948c2ecf20Sopenharmony_ci dx_buff->is_gso_udp = 1U; 5958c2ecf20Sopenharmony_ci dx_buff->len_l4 = sizeof(struct udphdr); 5968c2ecf20Sopenharmony_ci /* UDP GSO Hardware does not replace packet length. */ 5978c2ecf20Sopenharmony_ci udp_hdr(skb)->len = htons(dx_buff->mss + 5988c2ecf20Sopenharmony_ci dx_buff->len_l4); 5998c2ecf20Sopenharmony_ci } else { 6008c2ecf20Sopenharmony_ci WARN_ONCE(true, "Bad GSO mode"); 6018c2ecf20Sopenharmony_ci goto exit; 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci dx_buff->len_pkt = skb->len; 6048c2ecf20Sopenharmony_ci dx_buff->len_l2 = ETH_HLEN; 6058c2ecf20Sopenharmony_ci dx_buff->len_l3 = skb_network_header_len(skb); 6068c2ecf20Sopenharmony_ci dx_buff->eop_index = 0xffffU; 6078c2ecf20Sopenharmony_ci dx_buff->is_ipv6 = (ipver == 6); 6088c2ecf20Sopenharmony_ci need_context_tag = true; 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci if (cfg->is_vlan_tx_insert && skb_vlan_tag_present(skb)) { 6128c2ecf20Sopenharmony_ci dx_buff->vlan_tx_tag = skb_vlan_tag_get(skb); 6138c2ecf20Sopenharmony_ci dx_buff->len_pkt = skb->len; 6148c2ecf20Sopenharmony_ci dx_buff->is_vlan = 1U; 6158c2ecf20Sopenharmony_ci need_context_tag = true; 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci if (need_context_tag) { 6198c2ecf20Sopenharmony_ci dx = aq_ring_next_dx(ring, dx); 6208c2ecf20Sopenharmony_ci dx_buff = &ring->buff_ring[dx]; 6218c2ecf20Sopenharmony_ci dx_buff->flags = 0U; 6228c2ecf20Sopenharmony_ci ++ret; 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci dx_buff->len = skb_headlen(skb); 6268c2ecf20Sopenharmony_ci dx_buff->pa = dma_map_single(dev, 6278c2ecf20Sopenharmony_ci skb->data, 6288c2ecf20Sopenharmony_ci dx_buff->len, 6298c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(dev, dx_buff->pa))) { 6328c2ecf20Sopenharmony_ci ret = 0; 6338c2ecf20Sopenharmony_ci goto exit; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci first = dx_buff; 6378c2ecf20Sopenharmony_ci dx_buff->len_pkt = skb->len; 6388c2ecf20Sopenharmony_ci dx_buff->is_sop = 1U; 6398c2ecf20Sopenharmony_ci dx_buff->is_mapped = 1U; 6408c2ecf20Sopenharmony_ci ++ret; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (skb->ip_summed == CHECKSUM_PARTIAL) { 6438c2ecf20Sopenharmony_ci dx_buff->is_ip_cso = (htons(ETH_P_IP) == skb->protocol); 6448c2ecf20Sopenharmony_ci dx_buff->is_tcp_cso = (l4proto == IPPROTO_TCP); 6458c2ecf20Sopenharmony_ci dx_buff->is_udp_cso = (l4proto == IPPROTO_UDP); 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci for (; nr_frags--; ++frag_count) { 6498c2ecf20Sopenharmony_ci unsigned int frag_len = 0U; 6508c2ecf20Sopenharmony_ci unsigned int buff_offset = 0U; 6518c2ecf20Sopenharmony_ci unsigned int buff_size = 0U; 6528c2ecf20Sopenharmony_ci dma_addr_t frag_pa; 6538c2ecf20Sopenharmony_ci skb_frag_t *frag = &skb_shinfo(skb)->frags[frag_count]; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci frag_len = skb_frag_size(frag); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci while (frag_len) { 6588c2ecf20Sopenharmony_ci if (frag_len > AQ_CFG_TX_FRAME_MAX) 6598c2ecf20Sopenharmony_ci buff_size = AQ_CFG_TX_FRAME_MAX; 6608c2ecf20Sopenharmony_ci else 6618c2ecf20Sopenharmony_ci buff_size = frag_len; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci frag_pa = skb_frag_dma_map(dev, 6648c2ecf20Sopenharmony_ci frag, 6658c2ecf20Sopenharmony_ci buff_offset, 6668c2ecf20Sopenharmony_ci buff_size, 6678c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(dev, 6708c2ecf20Sopenharmony_ci frag_pa))) 6718c2ecf20Sopenharmony_ci goto mapping_error; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci dx = aq_ring_next_dx(ring, dx); 6748c2ecf20Sopenharmony_ci dx_buff = &ring->buff_ring[dx]; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci dx_buff->flags = 0U; 6778c2ecf20Sopenharmony_ci dx_buff->len = buff_size; 6788c2ecf20Sopenharmony_ci dx_buff->pa = frag_pa; 6798c2ecf20Sopenharmony_ci dx_buff->is_mapped = 1U; 6808c2ecf20Sopenharmony_ci dx_buff->eop_index = 0xffffU; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci frag_len -= buff_size; 6838c2ecf20Sopenharmony_ci buff_offset += buff_size; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci ++ret; 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci first->eop_index = dx; 6908c2ecf20Sopenharmony_ci dx_buff->is_eop = 1U; 6918c2ecf20Sopenharmony_ci dx_buff->skb = skb; 6928c2ecf20Sopenharmony_ci goto exit; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_cimapping_error: 6958c2ecf20Sopenharmony_ci for (dx = ring->sw_tail; 6968c2ecf20Sopenharmony_ci ret > 0; 6978c2ecf20Sopenharmony_ci --ret, dx = aq_ring_next_dx(ring, dx)) { 6988c2ecf20Sopenharmony_ci dx_buff = &ring->buff_ring[dx]; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if (!(dx_buff->is_gso_tcp || dx_buff->is_gso_udp) && 7018c2ecf20Sopenharmony_ci !dx_buff->is_vlan && dx_buff->pa) { 7028c2ecf20Sopenharmony_ci if (unlikely(dx_buff->is_sop)) { 7038c2ecf20Sopenharmony_ci dma_unmap_single(dev, 7048c2ecf20Sopenharmony_ci dx_buff->pa, 7058c2ecf20Sopenharmony_ci dx_buff->len, 7068c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 7078c2ecf20Sopenharmony_ci } else { 7088c2ecf20Sopenharmony_ci dma_unmap_page(dev, 7098c2ecf20Sopenharmony_ci dx_buff->pa, 7108c2ecf20Sopenharmony_ci dx_buff->len, 7118c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci } 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ciexit: 7178c2ecf20Sopenharmony_ci return ret; 7188c2ecf20Sopenharmony_ci} 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ciint aq_nic_xmit(struct aq_nic_s *self, struct sk_buff *skb) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(self); 7238c2ecf20Sopenharmony_ci unsigned int vec = skb->queue_mapping % cfg->vecs; 7248c2ecf20Sopenharmony_ci unsigned int tc = skb->queue_mapping / cfg->vecs; 7258c2ecf20Sopenharmony_ci struct aq_ring_s *ring = NULL; 7268c2ecf20Sopenharmony_ci unsigned int frags = 0U; 7278c2ecf20Sopenharmony_ci int err = NETDEV_TX_OK; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci frags = skb_shinfo(skb)->nr_frags + 1; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci ring = self->aq_ring_tx[AQ_NIC_CFG_TCVEC2RING(cfg, tc, vec)]; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci if (frags > AQ_CFG_SKB_FRAGS_MAX) { 7348c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 7358c2ecf20Sopenharmony_ci goto err_exit; 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci aq_ring_update_queue_state(ring); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci if (cfg->priv_flags & BIT(AQ_HW_LOOPBACK_DMA_NET)) { 7418c2ecf20Sopenharmony_ci err = NETDEV_TX_BUSY; 7428c2ecf20Sopenharmony_ci goto err_exit; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci /* Above status update may stop the queue. Check this. */ 7468c2ecf20Sopenharmony_ci if (__netif_subqueue_stopped(self->ndev, 7478c2ecf20Sopenharmony_ci AQ_NIC_RING2QMAP(self, ring->idx))) { 7488c2ecf20Sopenharmony_ci err = NETDEV_TX_BUSY; 7498c2ecf20Sopenharmony_ci goto err_exit; 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci frags = aq_nic_map_skb(self, skb, ring); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci if (likely(frags)) { 7558c2ecf20Sopenharmony_ci err = self->aq_hw_ops->hw_ring_tx_xmit(self->aq_hw, 7568c2ecf20Sopenharmony_ci ring, frags); 7578c2ecf20Sopenharmony_ci } else { 7588c2ecf20Sopenharmony_ci err = NETDEV_TX_BUSY; 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_cierr_exit: 7628c2ecf20Sopenharmony_ci return err; 7638c2ecf20Sopenharmony_ci} 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ciint aq_nic_update_interrupt_moderation_settings(struct aq_nic_s *self) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci return self->aq_hw_ops->hw_interrupt_moderation_set(self->aq_hw); 7688c2ecf20Sopenharmony_ci} 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ciint aq_nic_set_packet_filter(struct aq_nic_s *self, unsigned int flags) 7718c2ecf20Sopenharmony_ci{ 7728c2ecf20Sopenharmony_ci int err = 0; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci err = self->aq_hw_ops->hw_packet_filter_set(self->aq_hw, flags); 7758c2ecf20Sopenharmony_ci if (err < 0) 7768c2ecf20Sopenharmony_ci goto err_exit; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci self->packet_filter = flags; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_cierr_exit: 7818c2ecf20Sopenharmony_ci return err; 7828c2ecf20Sopenharmony_ci} 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ciint aq_nic_set_multicast_list(struct aq_nic_s *self, struct net_device *ndev) 7858c2ecf20Sopenharmony_ci{ 7868c2ecf20Sopenharmony_ci const struct aq_hw_ops *hw_ops = self->aq_hw_ops; 7878c2ecf20Sopenharmony_ci struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg; 7888c2ecf20Sopenharmony_ci unsigned int packet_filter = ndev->flags; 7898c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha = NULL; 7908c2ecf20Sopenharmony_ci unsigned int i = 0U; 7918c2ecf20Sopenharmony_ci int err = 0; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci self->mc_list.count = 0; 7948c2ecf20Sopenharmony_ci if (netdev_uc_count(ndev) > AQ_HW_MULTICAST_ADDRESS_MAX) { 7958c2ecf20Sopenharmony_ci packet_filter |= IFF_PROMISC; 7968c2ecf20Sopenharmony_ci } else { 7978c2ecf20Sopenharmony_ci netdev_for_each_uc_addr(ha, ndev) { 7988c2ecf20Sopenharmony_ci ether_addr_copy(self->mc_list.ar[i++], ha->addr); 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci } 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci cfg->is_mc_list_enabled = !!(packet_filter & IFF_MULTICAST); 8038c2ecf20Sopenharmony_ci if (cfg->is_mc_list_enabled) { 8048c2ecf20Sopenharmony_ci if (i + netdev_mc_count(ndev) > AQ_HW_MULTICAST_ADDRESS_MAX) { 8058c2ecf20Sopenharmony_ci packet_filter |= IFF_ALLMULTI; 8068c2ecf20Sopenharmony_ci } else { 8078c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, ndev) { 8088c2ecf20Sopenharmony_ci ether_addr_copy(self->mc_list.ar[i++], 8098c2ecf20Sopenharmony_ci ha->addr); 8108c2ecf20Sopenharmony_ci } 8118c2ecf20Sopenharmony_ci } 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci if (i > 0 && i <= AQ_HW_MULTICAST_ADDRESS_MAX) { 8158c2ecf20Sopenharmony_ci self->mc_list.count = i; 8168c2ecf20Sopenharmony_ci err = hw_ops->hw_multicast_list_set(self->aq_hw, 8178c2ecf20Sopenharmony_ci self->mc_list.ar, 8188c2ecf20Sopenharmony_ci self->mc_list.count); 8198c2ecf20Sopenharmony_ci if (err < 0) 8208c2ecf20Sopenharmony_ci return err; 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci return aq_nic_set_packet_filter(self, packet_filter); 8248c2ecf20Sopenharmony_ci} 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ciint aq_nic_set_mtu(struct aq_nic_s *self, int new_mtu) 8278c2ecf20Sopenharmony_ci{ 8288c2ecf20Sopenharmony_ci self->aq_nic_cfg.mtu = new_mtu; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci return 0; 8318c2ecf20Sopenharmony_ci} 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ciint aq_nic_set_mac(struct aq_nic_s *self, struct net_device *ndev) 8348c2ecf20Sopenharmony_ci{ 8358c2ecf20Sopenharmony_ci return self->aq_hw_ops->hw_set_mac_address(self->aq_hw, ndev->dev_addr); 8368c2ecf20Sopenharmony_ci} 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ciunsigned int aq_nic_get_link_speed(struct aq_nic_s *self) 8398c2ecf20Sopenharmony_ci{ 8408c2ecf20Sopenharmony_ci return self->link_status.mbps; 8418c2ecf20Sopenharmony_ci} 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ciint aq_nic_get_regs(struct aq_nic_s *self, struct ethtool_regs *regs, void *p) 8448c2ecf20Sopenharmony_ci{ 8458c2ecf20Sopenharmony_ci u32 *regs_buff = p; 8468c2ecf20Sopenharmony_ci int err = 0; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci if (unlikely(!self->aq_hw_ops->hw_get_regs)) 8498c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci regs->version = 1; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci err = self->aq_hw_ops->hw_get_regs(self->aq_hw, 8548c2ecf20Sopenharmony_ci self->aq_nic_cfg.aq_hw_caps, 8558c2ecf20Sopenharmony_ci regs_buff); 8568c2ecf20Sopenharmony_ci if (err < 0) 8578c2ecf20Sopenharmony_ci goto err_exit; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_cierr_exit: 8608c2ecf20Sopenharmony_ci return err; 8618c2ecf20Sopenharmony_ci} 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ciint aq_nic_get_regs_count(struct aq_nic_s *self) 8648c2ecf20Sopenharmony_ci{ 8658c2ecf20Sopenharmony_ci if (unlikely(!self->aq_hw_ops->hw_get_regs)) 8668c2ecf20Sopenharmony_ci return 0; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci return self->aq_nic_cfg.aq_hw_caps->mac_regs_count; 8698c2ecf20Sopenharmony_ci} 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ciu64 *aq_nic_get_stats(struct aq_nic_s *self, u64 *data) 8728c2ecf20Sopenharmony_ci{ 8738c2ecf20Sopenharmony_ci struct aq_stats_s *stats; 8748c2ecf20Sopenharmony_ci unsigned int count = 0U; 8758c2ecf20Sopenharmony_ci unsigned int i = 0U; 8768c2ecf20Sopenharmony_ci unsigned int tc; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci if (self->aq_fw_ops->update_stats) { 8798c2ecf20Sopenharmony_ci mutex_lock(&self->fwreq_mutex); 8808c2ecf20Sopenharmony_ci self->aq_fw_ops->update_stats(self->aq_hw); 8818c2ecf20Sopenharmony_ci mutex_unlock(&self->fwreq_mutex); 8828c2ecf20Sopenharmony_ci } 8838c2ecf20Sopenharmony_ci stats = self->aq_hw_ops->hw_get_hw_stats(self->aq_hw); 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci if (!stats) 8868c2ecf20Sopenharmony_ci goto err_exit; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci data[i] = stats->uprc + stats->mprc + stats->bprc; 8898c2ecf20Sopenharmony_ci data[++i] = stats->uprc; 8908c2ecf20Sopenharmony_ci data[++i] = stats->mprc; 8918c2ecf20Sopenharmony_ci data[++i] = stats->bprc; 8928c2ecf20Sopenharmony_ci data[++i] = stats->erpt; 8938c2ecf20Sopenharmony_ci data[++i] = stats->uptc + stats->mptc + stats->bptc; 8948c2ecf20Sopenharmony_ci data[++i] = stats->uptc; 8958c2ecf20Sopenharmony_ci data[++i] = stats->mptc; 8968c2ecf20Sopenharmony_ci data[++i] = stats->bptc; 8978c2ecf20Sopenharmony_ci data[++i] = stats->ubrc; 8988c2ecf20Sopenharmony_ci data[++i] = stats->ubtc; 8998c2ecf20Sopenharmony_ci data[++i] = stats->mbrc; 9008c2ecf20Sopenharmony_ci data[++i] = stats->mbtc; 9018c2ecf20Sopenharmony_ci data[++i] = stats->bbrc; 9028c2ecf20Sopenharmony_ci data[++i] = stats->bbtc; 9038c2ecf20Sopenharmony_ci if (stats->brc) 9048c2ecf20Sopenharmony_ci data[++i] = stats->brc; 9058c2ecf20Sopenharmony_ci else 9068c2ecf20Sopenharmony_ci data[++i] = stats->ubrc + stats->mbrc + stats->bbrc; 9078c2ecf20Sopenharmony_ci if (stats->btc) 9088c2ecf20Sopenharmony_ci data[++i] = stats->btc; 9098c2ecf20Sopenharmony_ci else 9108c2ecf20Sopenharmony_ci data[++i] = stats->ubtc + stats->mbtc + stats->bbtc; 9118c2ecf20Sopenharmony_ci data[++i] = stats->dma_pkt_rc; 9128c2ecf20Sopenharmony_ci data[++i] = stats->dma_pkt_tc; 9138c2ecf20Sopenharmony_ci data[++i] = stats->dma_oct_rc; 9148c2ecf20Sopenharmony_ci data[++i] = stats->dma_oct_tc; 9158c2ecf20Sopenharmony_ci data[++i] = stats->dpc; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci i++; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci data += i; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci for (tc = 0U; tc < self->aq_nic_cfg.tcs; tc++) { 9228c2ecf20Sopenharmony_ci for (i = 0U; self->aq_vecs > i; ++i) { 9238c2ecf20Sopenharmony_ci if (!self->aq_vec[i]) 9248c2ecf20Sopenharmony_ci break; 9258c2ecf20Sopenharmony_ci data += count; 9268c2ecf20Sopenharmony_ci count = aq_vec_get_sw_stats(self->aq_vec[i], tc, data); 9278c2ecf20Sopenharmony_ci } 9288c2ecf20Sopenharmony_ci } 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci data += count; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_cierr_exit: 9338c2ecf20Sopenharmony_ci return data; 9348c2ecf20Sopenharmony_ci} 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_cistatic void aq_nic_update_ndev_stats(struct aq_nic_s *self) 9378c2ecf20Sopenharmony_ci{ 9388c2ecf20Sopenharmony_ci struct aq_stats_s *stats = self->aq_hw_ops->hw_get_hw_stats(self->aq_hw); 9398c2ecf20Sopenharmony_ci struct net_device *ndev = self->ndev; 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci ndev->stats.rx_packets = stats->dma_pkt_rc; 9428c2ecf20Sopenharmony_ci ndev->stats.rx_bytes = stats->dma_oct_rc; 9438c2ecf20Sopenharmony_ci ndev->stats.rx_errors = stats->erpr; 9448c2ecf20Sopenharmony_ci ndev->stats.rx_dropped = stats->dpc; 9458c2ecf20Sopenharmony_ci ndev->stats.tx_packets = stats->dma_pkt_tc; 9468c2ecf20Sopenharmony_ci ndev->stats.tx_bytes = stats->dma_oct_tc; 9478c2ecf20Sopenharmony_ci ndev->stats.tx_errors = stats->erpt; 9488c2ecf20Sopenharmony_ci ndev->stats.multicast = stats->mprc; 9498c2ecf20Sopenharmony_ci} 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_civoid aq_nic_get_link_ksettings(struct aq_nic_s *self, 9528c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *cmd) 9538c2ecf20Sopenharmony_ci{ 9548c2ecf20Sopenharmony_ci u32 lp_link_speed_msk; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci if (self->aq_nic_cfg.aq_hw_caps->media_type == AQ_HW_MEDIA_TYPE_FIBRE) 9578c2ecf20Sopenharmony_ci cmd->base.port = PORT_FIBRE; 9588c2ecf20Sopenharmony_ci else 9598c2ecf20Sopenharmony_ci cmd->base.port = PORT_TP; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci cmd->base.duplex = DUPLEX_UNKNOWN; 9628c2ecf20Sopenharmony_ci if (self->link_status.mbps) 9638c2ecf20Sopenharmony_ci cmd->base.duplex = self->link_status.full_duplex ? 9648c2ecf20Sopenharmony_ci DUPLEX_FULL : DUPLEX_HALF; 9658c2ecf20Sopenharmony_ci cmd->base.autoneg = self->aq_nic_cfg.is_autoneg; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(cmd, supported); 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_10G) 9708c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 9718c2ecf20Sopenharmony_ci 10000baseT_Full); 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_5G) 9748c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 9758c2ecf20Sopenharmony_ci 5000baseT_Full); 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_2G5) 9788c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 9798c2ecf20Sopenharmony_ci 2500baseT_Full); 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_1G) 9828c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 9838c2ecf20Sopenharmony_ci 1000baseT_Full); 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_1G_HALF) 9868c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 9878c2ecf20Sopenharmony_ci 1000baseT_Half); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_100M) 9908c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 9918c2ecf20Sopenharmony_ci 100baseT_Full); 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_100M_HALF) 9948c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 9958c2ecf20Sopenharmony_ci 100baseT_Half); 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_10M) 9988c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 9998c2ecf20Sopenharmony_ci 10baseT_Full); 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci if (self->aq_nic_cfg.aq_hw_caps->link_speed_msk & AQ_NIC_RATE_10M_HALF) 10028c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 10038c2ecf20Sopenharmony_ci 10baseT_Half); 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci if (self->aq_nic_cfg.aq_hw_caps->flow_control) { 10068c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 10078c2ecf20Sopenharmony_ci Pause); 10088c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 10098c2ecf20Sopenharmony_ci Asym_Pause); 10108c2ecf20Sopenharmony_ci } 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci if (self->aq_nic_cfg.aq_hw_caps->media_type == AQ_HW_MEDIA_TYPE_FIBRE) 10158c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE); 10168c2ecf20Sopenharmony_ci else 10178c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, TP); 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(cmd, advertising); 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci if (self->aq_nic_cfg.is_autoneg) 10228c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg); 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_10G) 10258c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 10268c2ecf20Sopenharmony_ci 10000baseT_Full); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_5G) 10298c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 10308c2ecf20Sopenharmony_ci 5000baseT_Full); 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_2G5) 10338c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 10348c2ecf20Sopenharmony_ci 2500baseT_Full); 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_1G) 10378c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 10388c2ecf20Sopenharmony_ci 1000baseT_Full); 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_1G_HALF) 10418c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 10428c2ecf20Sopenharmony_ci 1000baseT_Half); 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_100M) 10458c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 10468c2ecf20Sopenharmony_ci 100baseT_Full); 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_100M_HALF) 10498c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 10508c2ecf20Sopenharmony_ci 100baseT_Half); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_10M) 10538c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 10548c2ecf20Sopenharmony_ci 10baseT_Full); 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci if (self->aq_nic_cfg.link_speed_msk & AQ_NIC_RATE_10M_HALF) 10578c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 10588c2ecf20Sopenharmony_ci 10baseT_Half); 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci if (self->aq_nic_cfg.fc.cur & AQ_NIC_FC_RX) 10618c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 10628c2ecf20Sopenharmony_ci Pause); 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci /* Asym is when either RX or TX, but not both */ 10658c2ecf20Sopenharmony_ci if (!!(self->aq_nic_cfg.fc.cur & AQ_NIC_FC_TX) ^ 10668c2ecf20Sopenharmony_ci !!(self->aq_nic_cfg.fc.cur & AQ_NIC_FC_RX)) 10678c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 10688c2ecf20Sopenharmony_ci Asym_Pause); 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci if (self->aq_nic_cfg.aq_hw_caps->media_type == AQ_HW_MEDIA_TYPE_FIBRE) 10718c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE); 10728c2ecf20Sopenharmony_ci else 10738c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, TP); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(cmd, lp_advertising); 10768c2ecf20Sopenharmony_ci lp_link_speed_msk = self->aq_hw->aq_link_status.lp_link_speed_msk; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci if (lp_link_speed_msk & AQ_NIC_RATE_10G) 10798c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, lp_advertising, 10808c2ecf20Sopenharmony_ci 10000baseT_Full); 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci if (lp_link_speed_msk & AQ_NIC_RATE_5G) 10838c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, lp_advertising, 10848c2ecf20Sopenharmony_ci 5000baseT_Full); 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci if (lp_link_speed_msk & AQ_NIC_RATE_2G5) 10878c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, lp_advertising, 10888c2ecf20Sopenharmony_ci 2500baseT_Full); 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci if (lp_link_speed_msk & AQ_NIC_RATE_1G) 10918c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, lp_advertising, 10928c2ecf20Sopenharmony_ci 1000baseT_Full); 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci if (lp_link_speed_msk & AQ_NIC_RATE_1G_HALF) 10958c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, lp_advertising, 10968c2ecf20Sopenharmony_ci 1000baseT_Half); 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci if (lp_link_speed_msk & AQ_NIC_RATE_100M) 10998c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, lp_advertising, 11008c2ecf20Sopenharmony_ci 100baseT_Full); 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci if (lp_link_speed_msk & AQ_NIC_RATE_100M_HALF) 11038c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, lp_advertising, 11048c2ecf20Sopenharmony_ci 100baseT_Half); 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci if (lp_link_speed_msk & AQ_NIC_RATE_10M) 11078c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, lp_advertising, 11088c2ecf20Sopenharmony_ci 10baseT_Full); 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci if (lp_link_speed_msk & AQ_NIC_RATE_10M_HALF) 11118c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, lp_advertising, 11128c2ecf20Sopenharmony_ci 10baseT_Half); 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci if (self->aq_hw->aq_link_status.lp_flow_control & AQ_NIC_FC_RX) 11158c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, lp_advertising, 11168c2ecf20Sopenharmony_ci Pause); 11178c2ecf20Sopenharmony_ci if (!!(self->aq_hw->aq_link_status.lp_flow_control & AQ_NIC_FC_TX) ^ 11188c2ecf20Sopenharmony_ci !!(self->aq_hw->aq_link_status.lp_flow_control & AQ_NIC_FC_RX)) 11198c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, lp_advertising, 11208c2ecf20Sopenharmony_ci Asym_Pause); 11218c2ecf20Sopenharmony_ci} 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ciint aq_nic_set_link_ksettings(struct aq_nic_s *self, 11248c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 11258c2ecf20Sopenharmony_ci{ 11268c2ecf20Sopenharmony_ci int fduplex = (cmd->base.duplex == DUPLEX_FULL); 11278c2ecf20Sopenharmony_ci u32 speed = cmd->base.speed; 11288c2ecf20Sopenharmony_ci u32 rate = 0U; 11298c2ecf20Sopenharmony_ci int err = 0; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci if (!fduplex && speed > SPEED_1000) { 11328c2ecf20Sopenharmony_ci err = -EINVAL; 11338c2ecf20Sopenharmony_ci goto err_exit; 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci if (cmd->base.autoneg == AUTONEG_ENABLE) { 11378c2ecf20Sopenharmony_ci rate = self->aq_nic_cfg.aq_hw_caps->link_speed_msk; 11388c2ecf20Sopenharmony_ci self->aq_nic_cfg.is_autoneg = true; 11398c2ecf20Sopenharmony_ci } else { 11408c2ecf20Sopenharmony_ci switch (speed) { 11418c2ecf20Sopenharmony_ci case SPEED_10: 11428c2ecf20Sopenharmony_ci rate = fduplex ? AQ_NIC_RATE_10M : AQ_NIC_RATE_10M_HALF; 11438c2ecf20Sopenharmony_ci break; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci case SPEED_100: 11468c2ecf20Sopenharmony_ci rate = fduplex ? AQ_NIC_RATE_100M 11478c2ecf20Sopenharmony_ci : AQ_NIC_RATE_100M_HALF; 11488c2ecf20Sopenharmony_ci break; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci case SPEED_1000: 11518c2ecf20Sopenharmony_ci rate = fduplex ? AQ_NIC_RATE_1G : AQ_NIC_RATE_1G_HALF; 11528c2ecf20Sopenharmony_ci break; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci case SPEED_2500: 11558c2ecf20Sopenharmony_ci rate = AQ_NIC_RATE_2G5; 11568c2ecf20Sopenharmony_ci break; 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci case SPEED_5000: 11598c2ecf20Sopenharmony_ci rate = AQ_NIC_RATE_5G; 11608c2ecf20Sopenharmony_ci break; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci case SPEED_10000: 11638c2ecf20Sopenharmony_ci rate = AQ_NIC_RATE_10G; 11648c2ecf20Sopenharmony_ci break; 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci default: 11678c2ecf20Sopenharmony_ci err = -1; 11688c2ecf20Sopenharmony_ci goto err_exit; 11698c2ecf20Sopenharmony_ci } 11708c2ecf20Sopenharmony_ci if (!(self->aq_nic_cfg.aq_hw_caps->link_speed_msk & rate)) { 11718c2ecf20Sopenharmony_ci err = -1; 11728c2ecf20Sopenharmony_ci goto err_exit; 11738c2ecf20Sopenharmony_ci } 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci self->aq_nic_cfg.is_autoneg = false; 11768c2ecf20Sopenharmony_ci } 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci mutex_lock(&self->fwreq_mutex); 11798c2ecf20Sopenharmony_ci err = self->aq_fw_ops->set_link_speed(self->aq_hw, rate); 11808c2ecf20Sopenharmony_ci mutex_unlock(&self->fwreq_mutex); 11818c2ecf20Sopenharmony_ci if (err < 0) 11828c2ecf20Sopenharmony_ci goto err_exit; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci self->aq_nic_cfg.link_speed_msk = rate; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_cierr_exit: 11878c2ecf20Sopenharmony_ci return err; 11888c2ecf20Sopenharmony_ci} 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_cistruct aq_nic_cfg_s *aq_nic_get_cfg(struct aq_nic_s *self) 11918c2ecf20Sopenharmony_ci{ 11928c2ecf20Sopenharmony_ci return &self->aq_nic_cfg; 11938c2ecf20Sopenharmony_ci} 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ciu32 aq_nic_get_fw_version(struct aq_nic_s *self) 11968c2ecf20Sopenharmony_ci{ 11978c2ecf20Sopenharmony_ci return self->aq_hw_ops->hw_get_fw_version(self->aq_hw); 11988c2ecf20Sopenharmony_ci} 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ciint aq_nic_set_loopback(struct aq_nic_s *self) 12018c2ecf20Sopenharmony_ci{ 12028c2ecf20Sopenharmony_ci struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg; 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci if (!self->aq_hw_ops->hw_set_loopback || 12058c2ecf20Sopenharmony_ci !self->aq_fw_ops->set_phyloopback) 12068c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci mutex_lock(&self->fwreq_mutex); 12098c2ecf20Sopenharmony_ci self->aq_hw_ops->hw_set_loopback(self->aq_hw, 12108c2ecf20Sopenharmony_ci AQ_HW_LOOPBACK_DMA_SYS, 12118c2ecf20Sopenharmony_ci !!(cfg->priv_flags & 12128c2ecf20Sopenharmony_ci BIT(AQ_HW_LOOPBACK_DMA_SYS))); 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci self->aq_hw_ops->hw_set_loopback(self->aq_hw, 12158c2ecf20Sopenharmony_ci AQ_HW_LOOPBACK_PKT_SYS, 12168c2ecf20Sopenharmony_ci !!(cfg->priv_flags & 12178c2ecf20Sopenharmony_ci BIT(AQ_HW_LOOPBACK_PKT_SYS))); 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci self->aq_hw_ops->hw_set_loopback(self->aq_hw, 12208c2ecf20Sopenharmony_ci AQ_HW_LOOPBACK_DMA_NET, 12218c2ecf20Sopenharmony_ci !!(cfg->priv_flags & 12228c2ecf20Sopenharmony_ci BIT(AQ_HW_LOOPBACK_DMA_NET))); 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci self->aq_fw_ops->set_phyloopback(self->aq_hw, 12258c2ecf20Sopenharmony_ci AQ_HW_LOOPBACK_PHYINT_SYS, 12268c2ecf20Sopenharmony_ci !!(cfg->priv_flags & 12278c2ecf20Sopenharmony_ci BIT(AQ_HW_LOOPBACK_PHYINT_SYS))); 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci self->aq_fw_ops->set_phyloopback(self->aq_hw, 12308c2ecf20Sopenharmony_ci AQ_HW_LOOPBACK_PHYEXT_SYS, 12318c2ecf20Sopenharmony_ci !!(cfg->priv_flags & 12328c2ecf20Sopenharmony_ci BIT(AQ_HW_LOOPBACK_PHYEXT_SYS))); 12338c2ecf20Sopenharmony_ci mutex_unlock(&self->fwreq_mutex); 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci return 0; 12368c2ecf20Sopenharmony_ci} 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ciint aq_nic_stop(struct aq_nic_s *self) 12398c2ecf20Sopenharmony_ci{ 12408c2ecf20Sopenharmony_ci unsigned int i = 0U; 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci netif_tx_disable(self->ndev); 12438c2ecf20Sopenharmony_ci netif_carrier_off(self->ndev); 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci del_timer_sync(&self->service_timer); 12468c2ecf20Sopenharmony_ci cancel_work_sync(&self->service_task); 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci self->aq_hw_ops->hw_irq_disable(self->aq_hw, AQ_CFG_IRQ_MASK); 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci if (self->aq_nic_cfg.is_polling) 12518c2ecf20Sopenharmony_ci del_timer_sync(&self->polling_timer); 12528c2ecf20Sopenharmony_ci else 12538c2ecf20Sopenharmony_ci aq_pci_func_free_irqs(self); 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci aq_ptp_irq_free(self); 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci for (i = 0U; self->aq_vecs > i; ++i) 12588c2ecf20Sopenharmony_ci aq_vec_stop(self->aq_vec[i]); 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci aq_ptp_ring_stop(self); 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci return self->aq_hw_ops->hw_stop(self->aq_hw); 12638c2ecf20Sopenharmony_ci} 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_civoid aq_nic_set_power(struct aq_nic_s *self) 12668c2ecf20Sopenharmony_ci{ 12678c2ecf20Sopenharmony_ci if (self->power_state != AQ_HW_POWER_STATE_D0 || 12688c2ecf20Sopenharmony_ci self->aq_hw->aq_nic_cfg->wol) 12698c2ecf20Sopenharmony_ci if (likely(self->aq_fw_ops->set_power)) { 12708c2ecf20Sopenharmony_ci mutex_lock(&self->fwreq_mutex); 12718c2ecf20Sopenharmony_ci self->aq_fw_ops->set_power(self->aq_hw, 12728c2ecf20Sopenharmony_ci self->power_state, 12738c2ecf20Sopenharmony_ci self->ndev->dev_addr); 12748c2ecf20Sopenharmony_ci mutex_unlock(&self->fwreq_mutex); 12758c2ecf20Sopenharmony_ci } 12768c2ecf20Sopenharmony_ci} 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_civoid aq_nic_deinit(struct aq_nic_s *self, bool link_down) 12798c2ecf20Sopenharmony_ci{ 12808c2ecf20Sopenharmony_ci struct aq_vec_s *aq_vec = NULL; 12818c2ecf20Sopenharmony_ci unsigned int i = 0U; 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci if (!self) 12848c2ecf20Sopenharmony_ci goto err_exit; 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci for (i = 0U; i < self->aq_vecs; i++) { 12878c2ecf20Sopenharmony_ci aq_vec = self->aq_vec[i]; 12888c2ecf20Sopenharmony_ci aq_vec_deinit(aq_vec); 12898c2ecf20Sopenharmony_ci aq_vec_ring_free(aq_vec); 12908c2ecf20Sopenharmony_ci } 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci aq_ptp_unregister(self); 12938c2ecf20Sopenharmony_ci aq_ptp_ring_deinit(self); 12948c2ecf20Sopenharmony_ci aq_ptp_ring_free(self); 12958c2ecf20Sopenharmony_ci aq_ptp_free(self); 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci if (likely(self->aq_fw_ops->deinit) && link_down) { 12988c2ecf20Sopenharmony_ci mutex_lock(&self->fwreq_mutex); 12998c2ecf20Sopenharmony_ci self->aq_fw_ops->deinit(self->aq_hw); 13008c2ecf20Sopenharmony_ci mutex_unlock(&self->fwreq_mutex); 13018c2ecf20Sopenharmony_ci } 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_cierr_exit:; 13048c2ecf20Sopenharmony_ci} 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_civoid aq_nic_free_vectors(struct aq_nic_s *self) 13078c2ecf20Sopenharmony_ci{ 13088c2ecf20Sopenharmony_ci unsigned int i = 0U; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci if (!self) 13118c2ecf20Sopenharmony_ci goto err_exit; 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci for (i = ARRAY_SIZE(self->aq_vec); i--;) { 13148c2ecf20Sopenharmony_ci if (self->aq_vec[i]) { 13158c2ecf20Sopenharmony_ci aq_vec_free(self->aq_vec[i]); 13168c2ecf20Sopenharmony_ci self->aq_vec[i] = NULL; 13178c2ecf20Sopenharmony_ci } 13188c2ecf20Sopenharmony_ci } 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_cierr_exit:; 13218c2ecf20Sopenharmony_ci} 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ciint aq_nic_realloc_vectors(struct aq_nic_s *self) 13248c2ecf20Sopenharmony_ci{ 13258c2ecf20Sopenharmony_ci struct aq_nic_cfg_s *cfg = aq_nic_get_cfg(self); 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci aq_nic_free_vectors(self); 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci for (self->aq_vecs = 0; self->aq_vecs < cfg->vecs; self->aq_vecs++) { 13308c2ecf20Sopenharmony_ci self->aq_vec[self->aq_vecs] = aq_vec_alloc(self, self->aq_vecs, 13318c2ecf20Sopenharmony_ci cfg); 13328c2ecf20Sopenharmony_ci if (unlikely(!self->aq_vec[self->aq_vecs])) 13338c2ecf20Sopenharmony_ci return -ENOMEM; 13348c2ecf20Sopenharmony_ci } 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci return 0; 13378c2ecf20Sopenharmony_ci} 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_civoid aq_nic_shutdown(struct aq_nic_s *self) 13408c2ecf20Sopenharmony_ci{ 13418c2ecf20Sopenharmony_ci int err = 0; 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci if (!self->ndev) 13448c2ecf20Sopenharmony_ci return; 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci rtnl_lock(); 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci netif_device_detach(self->ndev); 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci if (netif_running(self->ndev)) { 13518c2ecf20Sopenharmony_ci err = aq_nic_stop(self); 13528c2ecf20Sopenharmony_ci if (err < 0) 13538c2ecf20Sopenharmony_ci goto err_exit; 13548c2ecf20Sopenharmony_ci } 13558c2ecf20Sopenharmony_ci aq_nic_deinit(self, !self->aq_hw->aq_nic_cfg->wol); 13568c2ecf20Sopenharmony_ci aq_nic_set_power(self); 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_cierr_exit: 13598c2ecf20Sopenharmony_ci rtnl_unlock(); 13608c2ecf20Sopenharmony_ci} 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ciu8 aq_nic_reserve_filter(struct aq_nic_s *self, enum aq_rx_filter_type type) 13638c2ecf20Sopenharmony_ci{ 13648c2ecf20Sopenharmony_ci u8 location = 0xFF; 13658c2ecf20Sopenharmony_ci u32 fltr_cnt; 13668c2ecf20Sopenharmony_ci u32 n_bit; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci switch (type) { 13698c2ecf20Sopenharmony_ci case aq_rx_filter_ethertype: 13708c2ecf20Sopenharmony_ci location = AQ_RX_LAST_LOC_FETHERT - AQ_RX_FIRST_LOC_FETHERT - 13718c2ecf20Sopenharmony_ci self->aq_hw_rx_fltrs.fet_reserved_count; 13728c2ecf20Sopenharmony_ci self->aq_hw_rx_fltrs.fet_reserved_count++; 13738c2ecf20Sopenharmony_ci break; 13748c2ecf20Sopenharmony_ci case aq_rx_filter_l3l4: 13758c2ecf20Sopenharmony_ci fltr_cnt = AQ_RX_LAST_LOC_FL3L4 - AQ_RX_FIRST_LOC_FL3L4; 13768c2ecf20Sopenharmony_ci n_bit = fltr_cnt - self->aq_hw_rx_fltrs.fl3l4.reserved_count; 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci self->aq_hw_rx_fltrs.fl3l4.active_ipv4 |= BIT(n_bit); 13798c2ecf20Sopenharmony_ci self->aq_hw_rx_fltrs.fl3l4.reserved_count++; 13808c2ecf20Sopenharmony_ci location = n_bit; 13818c2ecf20Sopenharmony_ci break; 13828c2ecf20Sopenharmony_ci default: 13838c2ecf20Sopenharmony_ci break; 13848c2ecf20Sopenharmony_ci } 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci return location; 13878c2ecf20Sopenharmony_ci} 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_civoid aq_nic_release_filter(struct aq_nic_s *self, enum aq_rx_filter_type type, 13908c2ecf20Sopenharmony_ci u32 location) 13918c2ecf20Sopenharmony_ci{ 13928c2ecf20Sopenharmony_ci switch (type) { 13938c2ecf20Sopenharmony_ci case aq_rx_filter_ethertype: 13948c2ecf20Sopenharmony_ci self->aq_hw_rx_fltrs.fet_reserved_count--; 13958c2ecf20Sopenharmony_ci break; 13968c2ecf20Sopenharmony_ci case aq_rx_filter_l3l4: 13978c2ecf20Sopenharmony_ci self->aq_hw_rx_fltrs.fl3l4.reserved_count--; 13988c2ecf20Sopenharmony_ci self->aq_hw_rx_fltrs.fl3l4.active_ipv4 &= ~BIT(location); 13998c2ecf20Sopenharmony_ci break; 14008c2ecf20Sopenharmony_ci default: 14018c2ecf20Sopenharmony_ci break; 14028c2ecf20Sopenharmony_ci } 14038c2ecf20Sopenharmony_ci} 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ciint aq_nic_set_downshift(struct aq_nic_s *self, int val) 14068c2ecf20Sopenharmony_ci{ 14078c2ecf20Sopenharmony_ci int err = 0; 14088c2ecf20Sopenharmony_ci struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci if (!self->aq_fw_ops->set_downshift) 14118c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci if (val > 15) { 14148c2ecf20Sopenharmony_ci netdev_err(self->ndev, "downshift counter should be <= 15\n"); 14158c2ecf20Sopenharmony_ci return -EINVAL; 14168c2ecf20Sopenharmony_ci } 14178c2ecf20Sopenharmony_ci cfg->downshift_counter = val; 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci mutex_lock(&self->fwreq_mutex); 14208c2ecf20Sopenharmony_ci err = self->aq_fw_ops->set_downshift(self->aq_hw, cfg->downshift_counter); 14218c2ecf20Sopenharmony_ci mutex_unlock(&self->fwreq_mutex); 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci return err; 14248c2ecf20Sopenharmony_ci} 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ciint aq_nic_set_media_detect(struct aq_nic_s *self, int val) 14278c2ecf20Sopenharmony_ci{ 14288c2ecf20Sopenharmony_ci struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg; 14298c2ecf20Sopenharmony_ci int err = 0; 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci if (!self->aq_fw_ops->set_media_detect) 14328c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci if (val > 0 && val != AQ_HW_MEDIA_DETECT_CNT) { 14358c2ecf20Sopenharmony_ci netdev_err(self->ndev, "EDPD on this device could have only fixed value of %d\n", 14368c2ecf20Sopenharmony_ci AQ_HW_MEDIA_DETECT_CNT); 14378c2ecf20Sopenharmony_ci return -EINVAL; 14388c2ecf20Sopenharmony_ci } 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci mutex_lock(&self->fwreq_mutex); 14418c2ecf20Sopenharmony_ci err = self->aq_fw_ops->set_media_detect(self->aq_hw, !!val); 14428c2ecf20Sopenharmony_ci mutex_unlock(&self->fwreq_mutex); 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci /* msecs plays no role - configuration is always fixed in PHY */ 14458c2ecf20Sopenharmony_ci if (!err) 14468c2ecf20Sopenharmony_ci cfg->is_media_detect = !!val; 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci return err; 14498c2ecf20Sopenharmony_ci} 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ciint aq_nic_setup_tc_mqprio(struct aq_nic_s *self, u32 tcs, u8 *prio_tc_map) 14528c2ecf20Sopenharmony_ci{ 14538c2ecf20Sopenharmony_ci struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg; 14548c2ecf20Sopenharmony_ci const unsigned int prev_vecs = cfg->vecs; 14558c2ecf20Sopenharmony_ci bool ndev_running; 14568c2ecf20Sopenharmony_ci int err = 0; 14578c2ecf20Sopenharmony_ci int i; 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci /* if already the same configuration or 14608c2ecf20Sopenharmony_ci * disable request (tcs is 0) and we already is disabled 14618c2ecf20Sopenharmony_ci */ 14628c2ecf20Sopenharmony_ci if (tcs == cfg->tcs || (tcs == 0 && !cfg->is_qos)) 14638c2ecf20Sopenharmony_ci return 0; 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci ndev_running = netif_running(self->ndev); 14668c2ecf20Sopenharmony_ci if (ndev_running) 14678c2ecf20Sopenharmony_ci dev_close(self->ndev); 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci cfg->tcs = tcs; 14708c2ecf20Sopenharmony_ci if (cfg->tcs == 0) 14718c2ecf20Sopenharmony_ci cfg->tcs = 1; 14728c2ecf20Sopenharmony_ci if (prio_tc_map) 14738c2ecf20Sopenharmony_ci memcpy(cfg->prio_tc_map, prio_tc_map, sizeof(cfg->prio_tc_map)); 14748c2ecf20Sopenharmony_ci else 14758c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(cfg->prio_tc_map); i++) 14768c2ecf20Sopenharmony_ci cfg->prio_tc_map[i] = cfg->tcs * i / 8; 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci cfg->is_qos = (tcs != 0 ? true : false); 14798c2ecf20Sopenharmony_ci cfg->is_ptp = (cfg->tcs <= AQ_HW_PTP_TC); 14808c2ecf20Sopenharmony_ci if (!cfg->is_ptp) 14818c2ecf20Sopenharmony_ci netdev_warn(self->ndev, "%s\n", 14828c2ecf20Sopenharmony_ci "PTP is auto disabled due to requested TC count."); 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci netdev_set_num_tc(self->ndev, cfg->tcs); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci /* Changing the number of TCs might change the number of vectors */ 14878c2ecf20Sopenharmony_ci aq_nic_cfg_update_num_vecs(self); 14888c2ecf20Sopenharmony_ci if (prev_vecs != cfg->vecs) { 14898c2ecf20Sopenharmony_ci err = aq_nic_realloc_vectors(self); 14908c2ecf20Sopenharmony_ci if (err) 14918c2ecf20Sopenharmony_ci goto err_exit; 14928c2ecf20Sopenharmony_ci } 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci if (ndev_running) 14958c2ecf20Sopenharmony_ci err = dev_open(self->ndev, NULL); 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_cierr_exit: 14988c2ecf20Sopenharmony_ci return err; 14998c2ecf20Sopenharmony_ci} 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ciint aq_nic_setup_tc_max_rate(struct aq_nic_s *self, const unsigned int tc, 15028c2ecf20Sopenharmony_ci const u32 max_rate) 15038c2ecf20Sopenharmony_ci{ 15048c2ecf20Sopenharmony_ci struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg; 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci if (tc >= AQ_CFG_TCS_MAX) 15078c2ecf20Sopenharmony_ci return -EINVAL; 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci if (max_rate && max_rate < 10) { 15108c2ecf20Sopenharmony_ci netdev_warn(self->ndev, 15118c2ecf20Sopenharmony_ci "Setting %s to the minimum usable value of %dMbps.\n", 15128c2ecf20Sopenharmony_ci "max rate", 10); 15138c2ecf20Sopenharmony_ci cfg->tc_max_rate[tc] = 10; 15148c2ecf20Sopenharmony_ci } else { 15158c2ecf20Sopenharmony_ci cfg->tc_max_rate[tc] = max_rate; 15168c2ecf20Sopenharmony_ci } 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci return 0; 15198c2ecf20Sopenharmony_ci} 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ciint aq_nic_setup_tc_min_rate(struct aq_nic_s *self, const unsigned int tc, 15228c2ecf20Sopenharmony_ci const u32 min_rate) 15238c2ecf20Sopenharmony_ci{ 15248c2ecf20Sopenharmony_ci struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg; 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci if (tc >= AQ_CFG_TCS_MAX) 15278c2ecf20Sopenharmony_ci return -EINVAL; 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci if (min_rate) 15308c2ecf20Sopenharmony_ci set_bit(tc, &cfg->tc_min_rate_msk); 15318c2ecf20Sopenharmony_ci else 15328c2ecf20Sopenharmony_ci clear_bit(tc, &cfg->tc_min_rate_msk); 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci if (min_rate && min_rate < 20) { 15358c2ecf20Sopenharmony_ci netdev_warn(self->ndev, 15368c2ecf20Sopenharmony_ci "Setting %s to the minimum usable value of %dMbps.\n", 15378c2ecf20Sopenharmony_ci "min rate", 20); 15388c2ecf20Sopenharmony_ci cfg->tc_min_rate[tc] = 20; 15398c2ecf20Sopenharmony_ci } else { 15408c2ecf20Sopenharmony_ci cfg->tc_min_rate[tc] = min_rate; 15418c2ecf20Sopenharmony_ci } 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci return 0; 15448c2ecf20Sopenharmony_ci} 1545