162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Huawei HiNIC PCI Express Linux driver 462306a36Sopenharmony_ci * Copyright(c) 2017 Huawei Technologies Co., Ltd 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/kernel.h> 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/moduleparam.h> 1062306a36Sopenharmony_ci#include <linux/pci.h> 1162306a36Sopenharmony_ci#include <linux/device.h> 1262306a36Sopenharmony_ci#include <linux/errno.h> 1362306a36Sopenharmony_ci#include <linux/types.h> 1462306a36Sopenharmony_ci#include <linux/etherdevice.h> 1562306a36Sopenharmony_ci#include <linux/netdevice.h> 1662306a36Sopenharmony_ci#include <linux/slab.h> 1762306a36Sopenharmony_ci#include <linux/if_vlan.h> 1862306a36Sopenharmony_ci#include <linux/semaphore.h> 1962306a36Sopenharmony_ci#include <linux/workqueue.h> 2062306a36Sopenharmony_ci#include <net/ip.h> 2162306a36Sopenharmony_ci#include <net/devlink.h> 2262306a36Sopenharmony_ci#include <linux/bitops.h> 2362306a36Sopenharmony_ci#include <linux/bitmap.h> 2462306a36Sopenharmony_ci#include <linux/delay.h> 2562306a36Sopenharmony_ci#include <linux/err.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include "hinic_debugfs.h" 2862306a36Sopenharmony_ci#include "hinic_hw_qp.h" 2962306a36Sopenharmony_ci#include "hinic_hw_dev.h" 3062306a36Sopenharmony_ci#include "hinic_devlink.h" 3162306a36Sopenharmony_ci#include "hinic_port.h" 3262306a36Sopenharmony_ci#include "hinic_tx.h" 3362306a36Sopenharmony_ci#include "hinic_rx.h" 3462306a36Sopenharmony_ci#include "hinic_dev.h" 3562306a36Sopenharmony_ci#include "hinic_sriov.h" 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ciMODULE_AUTHOR("Huawei Technologies CO., Ltd"); 3862306a36Sopenharmony_ciMODULE_DESCRIPTION("Huawei Intelligent NIC driver"); 3962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic unsigned int tx_weight = 64; 4262306a36Sopenharmony_cimodule_param(tx_weight, uint, 0644); 4362306a36Sopenharmony_ciMODULE_PARM_DESC(tx_weight, "Number Tx packets for NAPI budget (default=64)"); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic unsigned int rx_weight = 64; 4662306a36Sopenharmony_cimodule_param(rx_weight, uint, 0644); 4762306a36Sopenharmony_ciMODULE_PARM_DESC(rx_weight, "Number Rx packets for NAPI budget (default=64)"); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#define HINIC_DEV_ID_QUAD_PORT_25GE 0x1822 5062306a36Sopenharmony_ci#define HINIC_DEV_ID_DUAL_PORT_100GE 0x0200 5162306a36Sopenharmony_ci#define HINIC_DEV_ID_DUAL_PORT_100GE_MEZZ 0x0205 5262306a36Sopenharmony_ci#define HINIC_DEV_ID_QUAD_PORT_25GE_MEZZ 0x0210 5362306a36Sopenharmony_ci#define HINIC_DEV_ID_VF 0x375e 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#define HINIC_WQ_NAME "hinic_dev" 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#define MSG_ENABLE_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | \ 5862306a36Sopenharmony_ci NETIF_MSG_IFUP | \ 5962306a36Sopenharmony_ci NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR) 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#define HINIC_LRO_MAX_WQE_NUM_DEFAULT 8 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#define HINIC_LRO_RX_TIMER_DEFAULT 16 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#define work_to_rx_mode_work(work) \ 6662306a36Sopenharmony_ci container_of(work, struct hinic_rx_mode_work, work) 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci#define rx_mode_work_to_nic_dev(rx_mode_work) \ 6962306a36Sopenharmony_ci container_of(rx_mode_work, struct hinic_dev, rx_mode_work) 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#define HINIC_WAIT_SRIOV_CFG_TIMEOUT 15000 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci#define HINIC_DEAULT_TXRX_MSIX_PENDING_LIMIT 2 7462306a36Sopenharmony_ci#define HINIC_DEAULT_TXRX_MSIX_COALESC_TIMER_CFG 32 7562306a36Sopenharmony_ci#define HINIC_DEAULT_TXRX_MSIX_RESEND_TIMER_CFG 7 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic int change_mac_addr(struct net_device *netdev, const u8 *addr); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic int set_features(struct hinic_dev *nic_dev, 8062306a36Sopenharmony_ci netdev_features_t pre_features, 8162306a36Sopenharmony_ci netdev_features_t features, bool force_change); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic void gather_rx_stats(struct hinic_rxq_stats *nic_rx_stats, struct hinic_rxq *rxq) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci struct hinic_rxq_stats rx_stats; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci hinic_rxq_get_stats(rxq, &rx_stats); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci nic_rx_stats->bytes += rx_stats.bytes; 9062306a36Sopenharmony_ci nic_rx_stats->pkts += rx_stats.pkts; 9162306a36Sopenharmony_ci nic_rx_stats->errors += rx_stats.errors; 9262306a36Sopenharmony_ci nic_rx_stats->csum_errors += rx_stats.csum_errors; 9362306a36Sopenharmony_ci nic_rx_stats->other_errors += rx_stats.other_errors; 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic void gather_tx_stats(struct hinic_txq_stats *nic_tx_stats, struct hinic_txq *txq) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci struct hinic_txq_stats tx_stats; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci hinic_txq_get_stats(txq, &tx_stats); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci nic_tx_stats->bytes += tx_stats.bytes; 10362306a36Sopenharmony_ci nic_tx_stats->pkts += tx_stats.pkts; 10462306a36Sopenharmony_ci nic_tx_stats->tx_busy += tx_stats.tx_busy; 10562306a36Sopenharmony_ci nic_tx_stats->tx_wake += tx_stats.tx_wake; 10662306a36Sopenharmony_ci nic_tx_stats->tx_dropped += tx_stats.tx_dropped; 10762306a36Sopenharmony_ci nic_tx_stats->big_frags_pkts += tx_stats.big_frags_pkts; 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic void gather_nic_stats(struct hinic_dev *nic_dev, 11162306a36Sopenharmony_ci struct hinic_rxq_stats *nic_rx_stats, 11262306a36Sopenharmony_ci struct hinic_txq_stats *nic_tx_stats) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci int i, num_qps = hinic_hwdev_num_qps(nic_dev->hwdev); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci for (i = 0; i < num_qps; i++) 11762306a36Sopenharmony_ci gather_rx_stats(nic_rx_stats, &nic_dev->rxqs[i]); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci for (i = 0; i < num_qps; i++) 12062306a36Sopenharmony_ci gather_tx_stats(nic_tx_stats, &nic_dev->txqs[i]); 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci/** 12462306a36Sopenharmony_ci * create_txqs - Create the Logical Tx Queues of specific NIC device 12562306a36Sopenharmony_ci * @nic_dev: the specific NIC device 12662306a36Sopenharmony_ci * 12762306a36Sopenharmony_ci * Return 0 - Success, negative - Failure 12862306a36Sopenharmony_ci **/ 12962306a36Sopenharmony_cistatic int create_txqs(struct hinic_dev *nic_dev) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci int err, i, j, num_txqs = hinic_hwdev_num_qps(nic_dev->hwdev); 13262306a36Sopenharmony_ci struct net_device *netdev = nic_dev->netdev; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (nic_dev->txqs) 13562306a36Sopenharmony_ci return -EINVAL; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci nic_dev->txqs = devm_kcalloc(&netdev->dev, num_txqs, 13862306a36Sopenharmony_ci sizeof(*nic_dev->txqs), GFP_KERNEL); 13962306a36Sopenharmony_ci if (!nic_dev->txqs) 14062306a36Sopenharmony_ci return -ENOMEM; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci hinic_sq_dbgfs_init(nic_dev); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci for (i = 0; i < num_txqs; i++) { 14562306a36Sopenharmony_ci struct hinic_sq *sq = hinic_hwdev_get_sq(nic_dev->hwdev, i); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci err = hinic_init_txq(&nic_dev->txqs[i], sq, netdev); 14862306a36Sopenharmony_ci if (err) { 14962306a36Sopenharmony_ci netif_err(nic_dev, drv, netdev, 15062306a36Sopenharmony_ci "Failed to init Txq\n"); 15162306a36Sopenharmony_ci goto err_init_txq; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci err = hinic_sq_debug_add(nic_dev, i); 15562306a36Sopenharmony_ci if (err) { 15662306a36Sopenharmony_ci netif_err(nic_dev, drv, netdev, 15762306a36Sopenharmony_ci "Failed to add SQ%d debug\n", i); 15862306a36Sopenharmony_ci goto err_add_sq_dbg; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci return 0; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cierr_add_sq_dbg: 16562306a36Sopenharmony_ci hinic_clean_txq(&nic_dev->txqs[i]); 16662306a36Sopenharmony_cierr_init_txq: 16762306a36Sopenharmony_ci for (j = 0; j < i; j++) { 16862306a36Sopenharmony_ci hinic_sq_debug_rem(nic_dev->txqs[j].sq); 16962306a36Sopenharmony_ci hinic_clean_txq(&nic_dev->txqs[j]); 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci hinic_sq_dbgfs_uninit(nic_dev); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci devm_kfree(&netdev->dev, nic_dev->txqs); 17562306a36Sopenharmony_ci return err; 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic void enable_txqs_napi(struct hinic_dev *nic_dev) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci int num_txqs = hinic_hwdev_num_qps(nic_dev->hwdev); 18162306a36Sopenharmony_ci int i; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci for (i = 0; i < num_txqs; i++) 18462306a36Sopenharmony_ci napi_enable(&nic_dev->txqs[i].napi); 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistatic void disable_txqs_napi(struct hinic_dev *nic_dev) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci int num_txqs = hinic_hwdev_num_qps(nic_dev->hwdev); 19062306a36Sopenharmony_ci int i; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci for (i = 0; i < num_txqs; i++) 19362306a36Sopenharmony_ci napi_disable(&nic_dev->txqs[i].napi); 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci/** 19762306a36Sopenharmony_ci * free_txqs - Free the Logical Tx Queues of specific NIC device 19862306a36Sopenharmony_ci * @nic_dev: the specific NIC device 19962306a36Sopenharmony_ci **/ 20062306a36Sopenharmony_cistatic void free_txqs(struct hinic_dev *nic_dev) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci int i, num_txqs = hinic_hwdev_num_qps(nic_dev->hwdev); 20362306a36Sopenharmony_ci struct net_device *netdev = nic_dev->netdev; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (!nic_dev->txqs) 20662306a36Sopenharmony_ci return; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci for (i = 0; i < num_txqs; i++) { 20962306a36Sopenharmony_ci hinic_sq_debug_rem(nic_dev->txqs[i].sq); 21062306a36Sopenharmony_ci hinic_clean_txq(&nic_dev->txqs[i]); 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci hinic_sq_dbgfs_uninit(nic_dev); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci devm_kfree(&netdev->dev, nic_dev->txqs); 21662306a36Sopenharmony_ci nic_dev->txqs = NULL; 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci/** 22062306a36Sopenharmony_ci * create_rxqs - Create the Logical Rx Queues of specific NIC device 22162306a36Sopenharmony_ci * @nic_dev: the specific NIC device 22262306a36Sopenharmony_ci * 22362306a36Sopenharmony_ci * Return 0 - Success, negative - Failure 22462306a36Sopenharmony_ci **/ 22562306a36Sopenharmony_cistatic int create_rxqs(struct hinic_dev *nic_dev) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci int err, i, j, num_rxqs = hinic_hwdev_num_qps(nic_dev->hwdev); 22862306a36Sopenharmony_ci struct net_device *netdev = nic_dev->netdev; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci if (nic_dev->rxqs) 23162306a36Sopenharmony_ci return -EINVAL; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci nic_dev->rxqs = devm_kcalloc(&netdev->dev, num_rxqs, 23462306a36Sopenharmony_ci sizeof(*nic_dev->rxqs), GFP_KERNEL); 23562306a36Sopenharmony_ci if (!nic_dev->rxqs) 23662306a36Sopenharmony_ci return -ENOMEM; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci hinic_rq_dbgfs_init(nic_dev); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci for (i = 0; i < num_rxqs; i++) { 24162306a36Sopenharmony_ci struct hinic_rq *rq = hinic_hwdev_get_rq(nic_dev->hwdev, i); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci err = hinic_init_rxq(&nic_dev->rxqs[i], rq, netdev); 24462306a36Sopenharmony_ci if (err) { 24562306a36Sopenharmony_ci netif_err(nic_dev, drv, netdev, 24662306a36Sopenharmony_ci "Failed to init rxq\n"); 24762306a36Sopenharmony_ci goto err_init_rxq; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci err = hinic_rq_debug_add(nic_dev, i); 25162306a36Sopenharmony_ci if (err) { 25262306a36Sopenharmony_ci netif_err(nic_dev, drv, netdev, 25362306a36Sopenharmony_ci "Failed to add RQ%d debug\n", i); 25462306a36Sopenharmony_ci goto err_add_rq_dbg; 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci return 0; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cierr_add_rq_dbg: 26162306a36Sopenharmony_ci hinic_clean_rxq(&nic_dev->rxqs[i]); 26262306a36Sopenharmony_cierr_init_rxq: 26362306a36Sopenharmony_ci for (j = 0; j < i; j++) { 26462306a36Sopenharmony_ci hinic_rq_debug_rem(nic_dev->rxqs[j].rq); 26562306a36Sopenharmony_ci hinic_clean_rxq(&nic_dev->rxqs[j]); 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci hinic_rq_dbgfs_uninit(nic_dev); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci devm_kfree(&netdev->dev, nic_dev->rxqs); 27162306a36Sopenharmony_ci return err; 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci/** 27562306a36Sopenharmony_ci * free_rxqs - Free the Logical Rx Queues of specific NIC device 27662306a36Sopenharmony_ci * @nic_dev: the specific NIC device 27762306a36Sopenharmony_ci **/ 27862306a36Sopenharmony_cistatic void free_rxqs(struct hinic_dev *nic_dev) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci int i, num_rxqs = hinic_hwdev_num_qps(nic_dev->hwdev); 28162306a36Sopenharmony_ci struct net_device *netdev = nic_dev->netdev; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (!nic_dev->rxqs) 28462306a36Sopenharmony_ci return; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci for (i = 0; i < num_rxqs; i++) { 28762306a36Sopenharmony_ci hinic_rq_debug_rem(nic_dev->rxqs[i].rq); 28862306a36Sopenharmony_ci hinic_clean_rxq(&nic_dev->rxqs[i]); 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci hinic_rq_dbgfs_uninit(nic_dev); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci devm_kfree(&netdev->dev, nic_dev->rxqs); 29462306a36Sopenharmony_ci nic_dev->rxqs = NULL; 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic int hinic_configure_max_qnum(struct hinic_dev *nic_dev) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci return hinic_set_max_qnum(nic_dev, nic_dev->hwdev->nic_cap.max_qps); 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic int hinic_rss_init(struct hinic_dev *nic_dev) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci u8 default_rss_key[HINIC_RSS_KEY_SIZE]; 30562306a36Sopenharmony_ci u8 tmpl_idx = nic_dev->rss_tmpl_idx; 30662306a36Sopenharmony_ci u32 *indir_tbl; 30762306a36Sopenharmony_ci int err, i; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci indir_tbl = kcalloc(HINIC_RSS_INDIR_SIZE, sizeof(u32), GFP_KERNEL); 31062306a36Sopenharmony_ci if (!indir_tbl) 31162306a36Sopenharmony_ci return -ENOMEM; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci netdev_rss_key_fill(default_rss_key, sizeof(default_rss_key)); 31462306a36Sopenharmony_ci for (i = 0; i < HINIC_RSS_INDIR_SIZE; i++) 31562306a36Sopenharmony_ci indir_tbl[i] = ethtool_rxfh_indir_default(i, nic_dev->num_rss); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci err = hinic_rss_set_template_tbl(nic_dev, tmpl_idx, default_rss_key); 31862306a36Sopenharmony_ci if (err) 31962306a36Sopenharmony_ci goto out; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci err = hinic_rss_set_indir_tbl(nic_dev, tmpl_idx, indir_tbl); 32262306a36Sopenharmony_ci if (err) 32362306a36Sopenharmony_ci goto out; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci err = hinic_set_rss_type(nic_dev, tmpl_idx, nic_dev->rss_type); 32662306a36Sopenharmony_ci if (err) 32762306a36Sopenharmony_ci goto out; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci err = hinic_rss_set_hash_engine(nic_dev, tmpl_idx, 33062306a36Sopenharmony_ci nic_dev->rss_hash_engine); 33162306a36Sopenharmony_ci if (err) 33262306a36Sopenharmony_ci goto out; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci err = hinic_rss_cfg(nic_dev, 1, tmpl_idx); 33562306a36Sopenharmony_ci if (err) 33662306a36Sopenharmony_ci goto out; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ciout: 33962306a36Sopenharmony_ci kfree(indir_tbl); 34062306a36Sopenharmony_ci return err; 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic void hinic_rss_deinit(struct hinic_dev *nic_dev) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci hinic_rss_cfg(nic_dev, 0, nic_dev->rss_tmpl_idx); 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic void hinic_init_rss_parameters(struct hinic_dev *nic_dev) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci nic_dev->rss_hash_engine = HINIC_RSS_HASH_ENGINE_TYPE_XOR; 35162306a36Sopenharmony_ci nic_dev->rss_type.tcp_ipv6_ext = 1; 35262306a36Sopenharmony_ci nic_dev->rss_type.ipv6_ext = 1; 35362306a36Sopenharmony_ci nic_dev->rss_type.tcp_ipv6 = 1; 35462306a36Sopenharmony_ci nic_dev->rss_type.ipv6 = 1; 35562306a36Sopenharmony_ci nic_dev->rss_type.tcp_ipv4 = 1; 35662306a36Sopenharmony_ci nic_dev->rss_type.ipv4 = 1; 35762306a36Sopenharmony_ci nic_dev->rss_type.udp_ipv6 = 1; 35862306a36Sopenharmony_ci nic_dev->rss_type.udp_ipv4 = 1; 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic void hinic_enable_rss(struct hinic_dev *nic_dev) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci struct net_device *netdev = nic_dev->netdev; 36462306a36Sopenharmony_ci struct hinic_hwdev *hwdev = nic_dev->hwdev; 36562306a36Sopenharmony_ci struct hinic_hwif *hwif = hwdev->hwif; 36662306a36Sopenharmony_ci struct pci_dev *pdev = hwif->pdev; 36762306a36Sopenharmony_ci int i, node, err = 0; 36862306a36Sopenharmony_ci u16 num_cpus = 0; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci if (nic_dev->max_qps <= 1) { 37162306a36Sopenharmony_ci nic_dev->flags &= ~HINIC_RSS_ENABLE; 37262306a36Sopenharmony_ci nic_dev->rss_limit = nic_dev->max_qps; 37362306a36Sopenharmony_ci nic_dev->num_qps = nic_dev->max_qps; 37462306a36Sopenharmony_ci nic_dev->num_rss = nic_dev->max_qps; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci return; 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci err = hinic_rss_template_alloc(nic_dev, &nic_dev->rss_tmpl_idx); 38062306a36Sopenharmony_ci if (err) { 38162306a36Sopenharmony_ci netif_err(nic_dev, drv, netdev, 38262306a36Sopenharmony_ci "Failed to alloc tmpl_idx for rss, can't enable rss for this function\n"); 38362306a36Sopenharmony_ci nic_dev->flags &= ~HINIC_RSS_ENABLE; 38462306a36Sopenharmony_ci nic_dev->max_qps = 1; 38562306a36Sopenharmony_ci nic_dev->rss_limit = nic_dev->max_qps; 38662306a36Sopenharmony_ci nic_dev->num_qps = nic_dev->max_qps; 38762306a36Sopenharmony_ci nic_dev->num_rss = nic_dev->max_qps; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci return; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci nic_dev->flags |= HINIC_RSS_ENABLE; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci for (i = 0; i < num_online_cpus(); i++) { 39562306a36Sopenharmony_ci node = cpu_to_node(i); 39662306a36Sopenharmony_ci if (node == dev_to_node(&pdev->dev)) 39762306a36Sopenharmony_ci num_cpus++; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci if (!num_cpus) 40162306a36Sopenharmony_ci num_cpus = num_online_cpus(); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci nic_dev->num_qps = hinic_hwdev_num_qps(hwdev); 40462306a36Sopenharmony_ci nic_dev->num_qps = min_t(u16, nic_dev->num_qps, num_cpus); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci nic_dev->rss_limit = nic_dev->num_qps; 40762306a36Sopenharmony_ci nic_dev->num_rss = nic_dev->num_qps; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci hinic_init_rss_parameters(nic_dev); 41062306a36Sopenharmony_ci err = hinic_rss_init(nic_dev); 41162306a36Sopenharmony_ci if (err) 41262306a36Sopenharmony_ci netif_err(nic_dev, drv, netdev, "Failed to init rss\n"); 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ciint hinic_open(struct net_device *netdev) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci struct hinic_dev *nic_dev = netdev_priv(netdev); 41862306a36Sopenharmony_ci enum hinic_port_link_state link_state; 41962306a36Sopenharmony_ci int err, ret; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (!(nic_dev->flags & HINIC_INTF_UP)) { 42262306a36Sopenharmony_ci err = hinic_hwdev_ifup(nic_dev->hwdev, nic_dev->sq_depth, 42362306a36Sopenharmony_ci nic_dev->rq_depth); 42462306a36Sopenharmony_ci if (err) { 42562306a36Sopenharmony_ci netif_err(nic_dev, drv, netdev, 42662306a36Sopenharmony_ci "Failed - HW interface up\n"); 42762306a36Sopenharmony_ci return err; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci err = create_txqs(nic_dev); 43262306a36Sopenharmony_ci if (err) { 43362306a36Sopenharmony_ci netif_err(nic_dev, drv, netdev, 43462306a36Sopenharmony_ci "Failed to create Tx queues\n"); 43562306a36Sopenharmony_ci goto err_create_txqs; 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci enable_txqs_napi(nic_dev); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci err = create_rxqs(nic_dev); 44162306a36Sopenharmony_ci if (err) { 44262306a36Sopenharmony_ci netif_err(nic_dev, drv, netdev, 44362306a36Sopenharmony_ci "Failed to create Rx queues\n"); 44462306a36Sopenharmony_ci goto err_create_rxqs; 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci hinic_enable_rss(nic_dev); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci err = hinic_configure_max_qnum(nic_dev); 45062306a36Sopenharmony_ci if (err) { 45162306a36Sopenharmony_ci netif_err(nic_dev, drv, nic_dev->netdev, 45262306a36Sopenharmony_ci "Failed to configure the maximum number of queues\n"); 45362306a36Sopenharmony_ci goto err_port_state; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci netif_set_real_num_tx_queues(netdev, nic_dev->num_qps); 45762306a36Sopenharmony_ci netif_set_real_num_rx_queues(netdev, nic_dev->num_qps); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci err = hinic_port_set_state(nic_dev, HINIC_PORT_ENABLE); 46062306a36Sopenharmony_ci if (err) { 46162306a36Sopenharmony_ci netif_err(nic_dev, drv, netdev, 46262306a36Sopenharmony_ci "Failed to set port state\n"); 46362306a36Sopenharmony_ci goto err_port_state; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci err = hinic_port_set_func_state(nic_dev, HINIC_FUNC_PORT_ENABLE); 46762306a36Sopenharmony_ci if (err) { 46862306a36Sopenharmony_ci netif_err(nic_dev, drv, netdev, 46962306a36Sopenharmony_ci "Failed to set func port state\n"); 47062306a36Sopenharmony_ci goto err_func_port_state; 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci down(&nic_dev->mgmt_lock); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci err = hinic_port_link_state(nic_dev, &link_state); 47662306a36Sopenharmony_ci if (err) { 47762306a36Sopenharmony_ci netif_err(nic_dev, drv, netdev, "Failed to get link state\n"); 47862306a36Sopenharmony_ci goto err_port_link; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci if (!HINIC_IS_VF(nic_dev->hwdev->hwif)) 48262306a36Sopenharmony_ci hinic_notify_all_vfs_link_changed(nic_dev->hwdev, link_state); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci if (link_state == HINIC_LINK_STATE_UP) { 48562306a36Sopenharmony_ci nic_dev->flags |= HINIC_LINK_UP; 48662306a36Sopenharmony_ci nic_dev->cable_unplugged = false; 48762306a36Sopenharmony_ci nic_dev->module_unrecognized = false; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci nic_dev->flags |= HINIC_INTF_UP; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci if ((nic_dev->flags & (HINIC_LINK_UP | HINIC_INTF_UP)) == 49362306a36Sopenharmony_ci (HINIC_LINK_UP | HINIC_INTF_UP)) { 49462306a36Sopenharmony_ci netif_info(nic_dev, drv, netdev, "link + intf UP\n"); 49562306a36Sopenharmony_ci netif_carrier_on(netdev); 49662306a36Sopenharmony_ci netif_tx_wake_all_queues(netdev); 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci up(&nic_dev->mgmt_lock); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci netif_info(nic_dev, drv, netdev, "HINIC_INTF is UP\n"); 50262306a36Sopenharmony_ci return 0; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cierr_port_link: 50562306a36Sopenharmony_ci up(&nic_dev->mgmt_lock); 50662306a36Sopenharmony_ci ret = hinic_port_set_func_state(nic_dev, HINIC_FUNC_PORT_DISABLE); 50762306a36Sopenharmony_ci if (ret) 50862306a36Sopenharmony_ci netif_warn(nic_dev, drv, netdev, 50962306a36Sopenharmony_ci "Failed to revert func port state\n"); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_cierr_func_port_state: 51262306a36Sopenharmony_ci ret = hinic_port_set_state(nic_dev, HINIC_PORT_DISABLE); 51362306a36Sopenharmony_ci if (ret) 51462306a36Sopenharmony_ci netif_warn(nic_dev, drv, netdev, 51562306a36Sopenharmony_ci "Failed to revert port state\n"); 51662306a36Sopenharmony_cierr_port_state: 51762306a36Sopenharmony_ci free_rxqs(nic_dev); 51862306a36Sopenharmony_ci if (nic_dev->flags & HINIC_RSS_ENABLE) { 51962306a36Sopenharmony_ci hinic_rss_deinit(nic_dev); 52062306a36Sopenharmony_ci hinic_rss_template_free(nic_dev, nic_dev->rss_tmpl_idx); 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cierr_create_rxqs: 52462306a36Sopenharmony_ci disable_txqs_napi(nic_dev); 52562306a36Sopenharmony_ci free_txqs(nic_dev); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cierr_create_txqs: 52862306a36Sopenharmony_ci if (!(nic_dev->flags & HINIC_INTF_UP)) 52962306a36Sopenharmony_ci hinic_hwdev_ifdown(nic_dev->hwdev); 53062306a36Sopenharmony_ci return err; 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ciint hinic_close(struct net_device *netdev) 53462306a36Sopenharmony_ci{ 53562306a36Sopenharmony_ci struct hinic_dev *nic_dev = netdev_priv(netdev); 53662306a36Sopenharmony_ci unsigned int flags; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci /* Disable txq napi firstly to aviod rewaking txq in free_tx_poll */ 53962306a36Sopenharmony_ci disable_txqs_napi(nic_dev); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci down(&nic_dev->mgmt_lock); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci flags = nic_dev->flags; 54462306a36Sopenharmony_ci nic_dev->flags &= ~HINIC_INTF_UP; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci netif_carrier_off(netdev); 54762306a36Sopenharmony_ci netif_tx_disable(netdev); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci up(&nic_dev->mgmt_lock); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci if (!HINIC_IS_VF(nic_dev->hwdev->hwif)) 55262306a36Sopenharmony_ci hinic_notify_all_vfs_link_changed(nic_dev->hwdev, 0); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci hinic_port_set_state(nic_dev, HINIC_PORT_DISABLE); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci hinic_port_set_func_state(nic_dev, HINIC_FUNC_PORT_DISABLE); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci if (nic_dev->flags & HINIC_RSS_ENABLE) { 55962306a36Sopenharmony_ci hinic_rss_deinit(nic_dev); 56062306a36Sopenharmony_ci hinic_rss_template_free(nic_dev, nic_dev->rss_tmpl_idx); 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci free_rxqs(nic_dev); 56462306a36Sopenharmony_ci free_txqs(nic_dev); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (flags & HINIC_INTF_UP) 56762306a36Sopenharmony_ci hinic_hwdev_ifdown(nic_dev->hwdev); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci netif_info(nic_dev, drv, netdev, "HINIC_INTF is DOWN\n"); 57062306a36Sopenharmony_ci return 0; 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_cistatic int hinic_change_mtu(struct net_device *netdev, int new_mtu) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci struct hinic_dev *nic_dev = netdev_priv(netdev); 57662306a36Sopenharmony_ci int err; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci netif_info(nic_dev, drv, netdev, "set_mtu = %d\n", new_mtu); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci err = hinic_port_set_mtu(nic_dev, new_mtu); 58162306a36Sopenharmony_ci if (err) 58262306a36Sopenharmony_ci netif_err(nic_dev, drv, netdev, "Failed to set port mtu\n"); 58362306a36Sopenharmony_ci else 58462306a36Sopenharmony_ci netdev->mtu = new_mtu; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci return err; 58762306a36Sopenharmony_ci} 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci/** 59062306a36Sopenharmony_ci * change_mac_addr - change the main mac address of network device 59162306a36Sopenharmony_ci * @netdev: network device 59262306a36Sopenharmony_ci * @addr: mac address to set 59362306a36Sopenharmony_ci * 59462306a36Sopenharmony_ci * Return 0 - Success, negative - Failure 59562306a36Sopenharmony_ci **/ 59662306a36Sopenharmony_cistatic int change_mac_addr(struct net_device *netdev, const u8 *addr) 59762306a36Sopenharmony_ci{ 59862306a36Sopenharmony_ci struct hinic_dev *nic_dev = netdev_priv(netdev); 59962306a36Sopenharmony_ci u16 vid = 0; 60062306a36Sopenharmony_ci int err; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci if (!is_valid_ether_addr(addr)) 60362306a36Sopenharmony_ci return -EADDRNOTAVAIL; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci netif_info(nic_dev, drv, netdev, "change mac addr = %02x %02x %02x %02x %02x %02x\n", 60662306a36Sopenharmony_ci addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci down(&nic_dev->mgmt_lock); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci do { 61162306a36Sopenharmony_ci err = hinic_port_del_mac(nic_dev, netdev->dev_addr, vid); 61262306a36Sopenharmony_ci if (err) { 61362306a36Sopenharmony_ci netif_err(nic_dev, drv, netdev, 61462306a36Sopenharmony_ci "Failed to delete mac\n"); 61562306a36Sopenharmony_ci break; 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci err = hinic_port_add_mac(nic_dev, addr, vid); 61962306a36Sopenharmony_ci if (err) { 62062306a36Sopenharmony_ci netif_err(nic_dev, drv, netdev, "Failed to add mac\n"); 62162306a36Sopenharmony_ci break; 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci vid = find_next_bit(nic_dev->vlan_bitmap, VLAN_N_VID, vid + 1); 62562306a36Sopenharmony_ci } while (vid != VLAN_N_VID); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci up(&nic_dev->mgmt_lock); 62862306a36Sopenharmony_ci return err; 62962306a36Sopenharmony_ci} 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_cistatic int hinic_set_mac_addr(struct net_device *netdev, void *addr) 63262306a36Sopenharmony_ci{ 63362306a36Sopenharmony_ci unsigned char new_mac[ETH_ALEN]; 63462306a36Sopenharmony_ci struct sockaddr *saddr = addr; 63562306a36Sopenharmony_ci int err; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci memcpy(new_mac, saddr->sa_data, ETH_ALEN); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci err = change_mac_addr(netdev, new_mac); 64062306a36Sopenharmony_ci if (!err) 64162306a36Sopenharmony_ci eth_hw_addr_set(netdev, new_mac); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci return err; 64462306a36Sopenharmony_ci} 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci/** 64762306a36Sopenharmony_ci * add_mac_addr - add mac address to network device 64862306a36Sopenharmony_ci * @netdev: network device 64962306a36Sopenharmony_ci * @addr: mac address to add 65062306a36Sopenharmony_ci * 65162306a36Sopenharmony_ci * Return 0 - Success, negative - Failure 65262306a36Sopenharmony_ci **/ 65362306a36Sopenharmony_cistatic int add_mac_addr(struct net_device *netdev, const u8 *addr) 65462306a36Sopenharmony_ci{ 65562306a36Sopenharmony_ci struct hinic_dev *nic_dev = netdev_priv(netdev); 65662306a36Sopenharmony_ci u16 vid = 0; 65762306a36Sopenharmony_ci int err; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci netif_info(nic_dev, drv, netdev, "set mac addr = %02x %02x %02x %02x %02x %02x\n", 66062306a36Sopenharmony_ci addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci down(&nic_dev->mgmt_lock); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci do { 66562306a36Sopenharmony_ci err = hinic_port_add_mac(nic_dev, addr, vid); 66662306a36Sopenharmony_ci if (err) { 66762306a36Sopenharmony_ci netif_err(nic_dev, drv, netdev, "Failed to add mac\n"); 66862306a36Sopenharmony_ci break; 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci vid = find_next_bit(nic_dev->vlan_bitmap, VLAN_N_VID, vid + 1); 67262306a36Sopenharmony_ci } while (vid != VLAN_N_VID); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci up(&nic_dev->mgmt_lock); 67562306a36Sopenharmony_ci return err; 67662306a36Sopenharmony_ci} 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci/** 67962306a36Sopenharmony_ci * remove_mac_addr - remove mac address from network device 68062306a36Sopenharmony_ci * @netdev: network device 68162306a36Sopenharmony_ci * @addr: mac address to remove 68262306a36Sopenharmony_ci * 68362306a36Sopenharmony_ci * Return 0 - Success, negative - Failure 68462306a36Sopenharmony_ci **/ 68562306a36Sopenharmony_cistatic int remove_mac_addr(struct net_device *netdev, const u8 *addr) 68662306a36Sopenharmony_ci{ 68762306a36Sopenharmony_ci struct hinic_dev *nic_dev = netdev_priv(netdev); 68862306a36Sopenharmony_ci u16 vid = 0; 68962306a36Sopenharmony_ci int err; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci if (!is_valid_ether_addr(addr)) 69262306a36Sopenharmony_ci return -EADDRNOTAVAIL; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci netif_info(nic_dev, drv, netdev, "remove mac addr = %02x %02x %02x %02x %02x %02x\n", 69562306a36Sopenharmony_ci addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci down(&nic_dev->mgmt_lock); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci do { 70062306a36Sopenharmony_ci err = hinic_port_del_mac(nic_dev, addr, vid); 70162306a36Sopenharmony_ci if (err) { 70262306a36Sopenharmony_ci netif_err(nic_dev, drv, netdev, 70362306a36Sopenharmony_ci "Failed to delete mac\n"); 70462306a36Sopenharmony_ci break; 70562306a36Sopenharmony_ci } 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci vid = find_next_bit(nic_dev->vlan_bitmap, VLAN_N_VID, vid + 1); 70862306a36Sopenharmony_ci } while (vid != VLAN_N_VID); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci up(&nic_dev->mgmt_lock); 71162306a36Sopenharmony_ci return err; 71262306a36Sopenharmony_ci} 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_cistatic int hinic_vlan_rx_add_vid(struct net_device *netdev, 71562306a36Sopenharmony_ci __always_unused __be16 proto, u16 vid) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci struct hinic_dev *nic_dev = netdev_priv(netdev); 71862306a36Sopenharmony_ci int ret, err; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci netif_info(nic_dev, drv, netdev, "add vid = %d\n", vid); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci down(&nic_dev->mgmt_lock); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci err = hinic_port_add_vlan(nic_dev, vid); 72562306a36Sopenharmony_ci if (err) { 72662306a36Sopenharmony_ci netif_err(nic_dev, drv, netdev, "Failed to add vlan\n"); 72762306a36Sopenharmony_ci goto err_vlan_add; 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci err = hinic_port_add_mac(nic_dev, netdev->dev_addr, vid); 73162306a36Sopenharmony_ci if (err && err != HINIC_PF_SET_VF_ALREADY) { 73262306a36Sopenharmony_ci netif_err(nic_dev, drv, netdev, "Failed to set mac\n"); 73362306a36Sopenharmony_ci goto err_add_mac; 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci bitmap_set(nic_dev->vlan_bitmap, vid, 1); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci up(&nic_dev->mgmt_lock); 73962306a36Sopenharmony_ci return 0; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cierr_add_mac: 74262306a36Sopenharmony_ci ret = hinic_port_del_vlan(nic_dev, vid); 74362306a36Sopenharmony_ci if (ret) 74462306a36Sopenharmony_ci netif_err(nic_dev, drv, netdev, 74562306a36Sopenharmony_ci "Failed to revert by removing vlan\n"); 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_cierr_vlan_add: 74862306a36Sopenharmony_ci up(&nic_dev->mgmt_lock); 74962306a36Sopenharmony_ci return err; 75062306a36Sopenharmony_ci} 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_cistatic int hinic_vlan_rx_kill_vid(struct net_device *netdev, 75362306a36Sopenharmony_ci __always_unused __be16 proto, u16 vid) 75462306a36Sopenharmony_ci{ 75562306a36Sopenharmony_ci struct hinic_dev *nic_dev = netdev_priv(netdev); 75662306a36Sopenharmony_ci int err; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci netif_info(nic_dev, drv, netdev, "remove vid = %d\n", vid); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci down(&nic_dev->mgmt_lock); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci err = hinic_port_del_vlan(nic_dev, vid); 76362306a36Sopenharmony_ci if (err) { 76462306a36Sopenharmony_ci netif_err(nic_dev, drv, netdev, "Failed to delete vlan\n"); 76562306a36Sopenharmony_ci goto err_del_vlan; 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci bitmap_clear(nic_dev->vlan_bitmap, vid, 1); 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci up(&nic_dev->mgmt_lock); 77162306a36Sopenharmony_ci return 0; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_cierr_del_vlan: 77462306a36Sopenharmony_ci up(&nic_dev->mgmt_lock); 77562306a36Sopenharmony_ci return err; 77662306a36Sopenharmony_ci} 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_cistatic void set_rx_mode(struct work_struct *work) 77962306a36Sopenharmony_ci{ 78062306a36Sopenharmony_ci struct hinic_rx_mode_work *rx_mode_work = work_to_rx_mode_work(work); 78162306a36Sopenharmony_ci struct hinic_dev *nic_dev = rx_mode_work_to_nic_dev(rx_mode_work); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci hinic_port_set_rx_mode(nic_dev, rx_mode_work->rx_mode); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci __dev_uc_sync(nic_dev->netdev, add_mac_addr, remove_mac_addr); 78662306a36Sopenharmony_ci __dev_mc_sync(nic_dev->netdev, add_mac_addr, remove_mac_addr); 78762306a36Sopenharmony_ci} 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_cistatic void hinic_set_rx_mode(struct net_device *netdev) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci struct hinic_dev *nic_dev = netdev_priv(netdev); 79262306a36Sopenharmony_ci struct hinic_rx_mode_work *rx_mode_work; 79362306a36Sopenharmony_ci u32 rx_mode; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci rx_mode_work = &nic_dev->rx_mode_work; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci rx_mode = HINIC_RX_MODE_UC | 79862306a36Sopenharmony_ci HINIC_RX_MODE_MC | 79962306a36Sopenharmony_ci HINIC_RX_MODE_BC; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci if (netdev->flags & IFF_PROMISC) { 80262306a36Sopenharmony_ci if (!HINIC_IS_VF(nic_dev->hwdev->hwif)) 80362306a36Sopenharmony_ci rx_mode |= HINIC_RX_MODE_PROMISC; 80462306a36Sopenharmony_ci } else if (netdev->flags & IFF_ALLMULTI) { 80562306a36Sopenharmony_ci rx_mode |= HINIC_RX_MODE_MC_ALL; 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci rx_mode_work->rx_mode = rx_mode; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci queue_work(nic_dev->workq, &rx_mode_work->work); 81162306a36Sopenharmony_ci} 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_cistatic void hinic_tx_timeout(struct net_device *netdev, unsigned int txqueue) 81462306a36Sopenharmony_ci{ 81562306a36Sopenharmony_ci struct hinic_dev *nic_dev = netdev_priv(netdev); 81662306a36Sopenharmony_ci u16 sw_pi, hw_ci, sw_ci; 81762306a36Sopenharmony_ci struct hinic_sq *sq; 81862306a36Sopenharmony_ci u16 num_sqs, q_id; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci num_sqs = hinic_hwdev_num_qps(nic_dev->hwdev); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci netif_err(nic_dev, drv, netdev, "Tx timeout\n"); 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci for (q_id = 0; q_id < num_sqs; q_id++) { 82562306a36Sopenharmony_ci if (!netif_xmit_stopped(netdev_get_tx_queue(netdev, q_id))) 82662306a36Sopenharmony_ci continue; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci sq = hinic_hwdev_get_sq(nic_dev->hwdev, q_id); 82962306a36Sopenharmony_ci sw_pi = atomic_read(&sq->wq->prod_idx) & sq->wq->mask; 83062306a36Sopenharmony_ci hw_ci = be16_to_cpu(*(u16 *)(sq->hw_ci_addr)) & sq->wq->mask; 83162306a36Sopenharmony_ci sw_ci = atomic_read(&sq->wq->cons_idx) & sq->wq->mask; 83262306a36Sopenharmony_ci netif_err(nic_dev, drv, netdev, "Txq%d: sw_pi: %d, hw_ci: %d, sw_ci: %d, napi->state: 0x%lx\n", 83362306a36Sopenharmony_ci q_id, sw_pi, hw_ci, sw_ci, 83462306a36Sopenharmony_ci nic_dev->txqs[q_id].napi.state); 83562306a36Sopenharmony_ci } 83662306a36Sopenharmony_ci} 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_cistatic void hinic_get_stats64(struct net_device *netdev, 83962306a36Sopenharmony_ci struct rtnl_link_stats64 *stats) 84062306a36Sopenharmony_ci{ 84162306a36Sopenharmony_ci struct hinic_dev *nic_dev = netdev_priv(netdev); 84262306a36Sopenharmony_ci struct hinic_rxq_stats nic_rx_stats = {}; 84362306a36Sopenharmony_ci struct hinic_txq_stats nic_tx_stats = {}; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci if (nic_dev->flags & HINIC_INTF_UP) 84662306a36Sopenharmony_ci gather_nic_stats(nic_dev, &nic_rx_stats, &nic_tx_stats); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci stats->rx_bytes = nic_rx_stats.bytes; 84962306a36Sopenharmony_ci stats->rx_packets = nic_rx_stats.pkts; 85062306a36Sopenharmony_ci stats->rx_errors = nic_rx_stats.errors; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci stats->tx_bytes = nic_tx_stats.bytes; 85362306a36Sopenharmony_ci stats->tx_packets = nic_tx_stats.pkts; 85462306a36Sopenharmony_ci stats->tx_errors = nic_tx_stats.tx_dropped; 85562306a36Sopenharmony_ci} 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_cistatic int hinic_set_features(struct net_device *netdev, 85862306a36Sopenharmony_ci netdev_features_t features) 85962306a36Sopenharmony_ci{ 86062306a36Sopenharmony_ci struct hinic_dev *nic_dev = netdev_priv(netdev); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci return set_features(nic_dev, nic_dev->netdev->features, 86362306a36Sopenharmony_ci features, false); 86462306a36Sopenharmony_ci} 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_cistatic netdev_features_t hinic_fix_features(struct net_device *netdev, 86762306a36Sopenharmony_ci netdev_features_t features) 86862306a36Sopenharmony_ci{ 86962306a36Sopenharmony_ci struct hinic_dev *nic_dev = netdev_priv(netdev); 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci /* If Rx checksum is disabled, then LRO should also be disabled */ 87262306a36Sopenharmony_ci if (!(features & NETIF_F_RXCSUM)) { 87362306a36Sopenharmony_ci netif_info(nic_dev, drv, netdev, "disabling LRO as RXCSUM is off\n"); 87462306a36Sopenharmony_ci features &= ~NETIF_F_LRO; 87562306a36Sopenharmony_ci } 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci return features; 87862306a36Sopenharmony_ci} 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_cistatic const struct net_device_ops hinic_netdev_ops = { 88162306a36Sopenharmony_ci .ndo_open = hinic_open, 88262306a36Sopenharmony_ci .ndo_stop = hinic_close, 88362306a36Sopenharmony_ci .ndo_change_mtu = hinic_change_mtu, 88462306a36Sopenharmony_ci .ndo_set_mac_address = hinic_set_mac_addr, 88562306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 88662306a36Sopenharmony_ci .ndo_vlan_rx_add_vid = hinic_vlan_rx_add_vid, 88762306a36Sopenharmony_ci .ndo_vlan_rx_kill_vid = hinic_vlan_rx_kill_vid, 88862306a36Sopenharmony_ci .ndo_set_rx_mode = hinic_set_rx_mode, 88962306a36Sopenharmony_ci .ndo_start_xmit = hinic_xmit_frame, 89062306a36Sopenharmony_ci .ndo_tx_timeout = hinic_tx_timeout, 89162306a36Sopenharmony_ci .ndo_get_stats64 = hinic_get_stats64, 89262306a36Sopenharmony_ci .ndo_fix_features = hinic_fix_features, 89362306a36Sopenharmony_ci .ndo_set_features = hinic_set_features, 89462306a36Sopenharmony_ci .ndo_set_vf_mac = hinic_ndo_set_vf_mac, 89562306a36Sopenharmony_ci .ndo_set_vf_vlan = hinic_ndo_set_vf_vlan, 89662306a36Sopenharmony_ci .ndo_get_vf_config = hinic_ndo_get_vf_config, 89762306a36Sopenharmony_ci .ndo_set_vf_trust = hinic_ndo_set_vf_trust, 89862306a36Sopenharmony_ci .ndo_set_vf_rate = hinic_ndo_set_vf_bw, 89962306a36Sopenharmony_ci .ndo_set_vf_spoofchk = hinic_ndo_set_vf_spoofchk, 90062306a36Sopenharmony_ci .ndo_set_vf_link_state = hinic_ndo_set_vf_link_state, 90162306a36Sopenharmony_ci}; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_cistatic const struct net_device_ops hinicvf_netdev_ops = { 90462306a36Sopenharmony_ci .ndo_open = hinic_open, 90562306a36Sopenharmony_ci .ndo_stop = hinic_close, 90662306a36Sopenharmony_ci .ndo_change_mtu = hinic_change_mtu, 90762306a36Sopenharmony_ci .ndo_set_mac_address = hinic_set_mac_addr, 90862306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 90962306a36Sopenharmony_ci .ndo_vlan_rx_add_vid = hinic_vlan_rx_add_vid, 91062306a36Sopenharmony_ci .ndo_vlan_rx_kill_vid = hinic_vlan_rx_kill_vid, 91162306a36Sopenharmony_ci .ndo_set_rx_mode = hinic_set_rx_mode, 91262306a36Sopenharmony_ci .ndo_start_xmit = hinic_xmit_frame, 91362306a36Sopenharmony_ci .ndo_tx_timeout = hinic_tx_timeout, 91462306a36Sopenharmony_ci .ndo_get_stats64 = hinic_get_stats64, 91562306a36Sopenharmony_ci .ndo_fix_features = hinic_fix_features, 91662306a36Sopenharmony_ci .ndo_set_features = hinic_set_features, 91762306a36Sopenharmony_ci}; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_cistatic void netdev_features_init(struct net_device *netdev) 92062306a36Sopenharmony_ci{ 92162306a36Sopenharmony_ci netdev->hw_features = NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_IP_CSUM | 92262306a36Sopenharmony_ci NETIF_F_IPV6_CSUM | NETIF_F_TSO | NETIF_F_TSO6 | 92362306a36Sopenharmony_ci NETIF_F_RXCSUM | NETIF_F_LRO | 92462306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX | 92562306a36Sopenharmony_ci NETIF_F_GSO_UDP_TUNNEL | NETIF_F_GSO_UDP_TUNNEL_CSUM; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci netdev->vlan_features = netdev->hw_features; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci netdev->features = netdev->hw_features | NETIF_F_HW_VLAN_CTAG_FILTER; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci netdev->hw_enc_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_SCTP_CRC | 93262306a36Sopenharmony_ci NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN | 93362306a36Sopenharmony_ci NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_GSO_UDP_TUNNEL; 93462306a36Sopenharmony_ci} 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_cistatic void hinic_refresh_nic_cfg(struct hinic_dev *nic_dev) 93762306a36Sopenharmony_ci{ 93862306a36Sopenharmony_ci struct hinic_nic_cfg *nic_cfg = &nic_dev->hwdev->func_to_io.nic_cfg; 93962306a36Sopenharmony_ci struct hinic_pause_config pause_info = {0}; 94062306a36Sopenharmony_ci struct hinic_port_cap port_cap = {0}; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci if (hinic_port_get_cap(nic_dev, &port_cap)) 94362306a36Sopenharmony_ci return; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci mutex_lock(&nic_cfg->cfg_mutex); 94662306a36Sopenharmony_ci if (nic_cfg->pause_set || !port_cap.autoneg_state) { 94762306a36Sopenharmony_ci nic_cfg->auto_neg = port_cap.autoneg_state; 94862306a36Sopenharmony_ci pause_info.auto_neg = nic_cfg->auto_neg; 94962306a36Sopenharmony_ci pause_info.rx_pause = nic_cfg->rx_pause; 95062306a36Sopenharmony_ci pause_info.tx_pause = nic_cfg->tx_pause; 95162306a36Sopenharmony_ci hinic_set_hw_pause_info(nic_dev->hwdev, &pause_info); 95262306a36Sopenharmony_ci } 95362306a36Sopenharmony_ci mutex_unlock(&nic_cfg->cfg_mutex); 95462306a36Sopenharmony_ci} 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci/** 95762306a36Sopenharmony_ci * link_status_event_handler - link event handler 95862306a36Sopenharmony_ci * @handle: nic device for the handler 95962306a36Sopenharmony_ci * @buf_in: input buffer 96062306a36Sopenharmony_ci * @in_size: input size 96162306a36Sopenharmony_ci * @buf_out: output buffer 96262306a36Sopenharmony_ci * @out_size: returned output size 96362306a36Sopenharmony_ci **/ 96462306a36Sopenharmony_cistatic void link_status_event_handler(void *handle, void *buf_in, u16 in_size, 96562306a36Sopenharmony_ci void *buf_out, u16 *out_size) 96662306a36Sopenharmony_ci{ 96762306a36Sopenharmony_ci struct hinic_port_link_status *link_status, *ret_link_status; 96862306a36Sopenharmony_ci struct hinic_dev *nic_dev = handle; 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci link_status = buf_in; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci if (link_status->link == HINIC_LINK_STATE_UP) { 97362306a36Sopenharmony_ci down(&nic_dev->mgmt_lock); 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci nic_dev->flags |= HINIC_LINK_UP; 97662306a36Sopenharmony_ci nic_dev->cable_unplugged = false; 97762306a36Sopenharmony_ci nic_dev->module_unrecognized = false; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci if ((nic_dev->flags & (HINIC_LINK_UP | HINIC_INTF_UP)) == 98062306a36Sopenharmony_ci (HINIC_LINK_UP | HINIC_INTF_UP)) { 98162306a36Sopenharmony_ci netif_carrier_on(nic_dev->netdev); 98262306a36Sopenharmony_ci netif_tx_wake_all_queues(nic_dev->netdev); 98362306a36Sopenharmony_ci } 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci up(&nic_dev->mgmt_lock); 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci if (!HINIC_IS_VF(nic_dev->hwdev->hwif)) 98862306a36Sopenharmony_ci hinic_refresh_nic_cfg(nic_dev); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci netif_info(nic_dev, drv, nic_dev->netdev, "HINIC_Link is UP\n"); 99162306a36Sopenharmony_ci } else { 99262306a36Sopenharmony_ci down(&nic_dev->mgmt_lock); 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci nic_dev->flags &= ~HINIC_LINK_UP; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci netif_carrier_off(nic_dev->netdev); 99762306a36Sopenharmony_ci netif_tx_disable(nic_dev->netdev); 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci up(&nic_dev->mgmt_lock); 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci netif_info(nic_dev, drv, nic_dev->netdev, "HINIC_Link is DOWN\n"); 100262306a36Sopenharmony_ci } 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci if (!HINIC_IS_VF(nic_dev->hwdev->hwif)) 100562306a36Sopenharmony_ci hinic_notify_all_vfs_link_changed(nic_dev->hwdev, 100662306a36Sopenharmony_ci link_status->link); 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci ret_link_status = buf_out; 100962306a36Sopenharmony_ci ret_link_status->status = 0; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci *out_size = sizeof(*ret_link_status); 101262306a36Sopenharmony_ci} 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_cistatic void cable_plug_event(void *handle, 101562306a36Sopenharmony_ci void *buf_in, u16 in_size, 101662306a36Sopenharmony_ci void *buf_out, u16 *out_size) 101762306a36Sopenharmony_ci{ 101862306a36Sopenharmony_ci struct hinic_cable_plug_event *plug_event = buf_in; 101962306a36Sopenharmony_ci struct hinic_dev *nic_dev = handle; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci nic_dev->cable_unplugged = plug_event->plugged ? false : true; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci *out_size = sizeof(*plug_event); 102462306a36Sopenharmony_ci plug_event = buf_out; 102562306a36Sopenharmony_ci plug_event->status = 0; 102662306a36Sopenharmony_ci} 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_cistatic void link_err_event(void *handle, 102962306a36Sopenharmony_ci void *buf_in, u16 in_size, 103062306a36Sopenharmony_ci void *buf_out, u16 *out_size) 103162306a36Sopenharmony_ci{ 103262306a36Sopenharmony_ci struct hinic_link_err_event *link_err = buf_in; 103362306a36Sopenharmony_ci struct hinic_dev *nic_dev = handle; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci if (link_err->err_type >= LINK_ERR_NUM) 103662306a36Sopenharmony_ci netif_info(nic_dev, link, nic_dev->netdev, 103762306a36Sopenharmony_ci "Link failed, Unknown error type: 0x%x\n", 103862306a36Sopenharmony_ci link_err->err_type); 103962306a36Sopenharmony_ci else 104062306a36Sopenharmony_ci nic_dev->module_unrecognized = true; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci *out_size = sizeof(*link_err); 104362306a36Sopenharmony_ci link_err = buf_out; 104462306a36Sopenharmony_ci link_err->status = 0; 104562306a36Sopenharmony_ci} 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_cistatic int set_features(struct hinic_dev *nic_dev, 104862306a36Sopenharmony_ci netdev_features_t pre_features, 104962306a36Sopenharmony_ci netdev_features_t features, bool force_change) 105062306a36Sopenharmony_ci{ 105162306a36Sopenharmony_ci netdev_features_t changed = force_change ? ~0 : pre_features ^ features; 105262306a36Sopenharmony_ci u32 csum_en = HINIC_RX_CSUM_OFFLOAD_EN; 105362306a36Sopenharmony_ci netdev_features_t failed_features = 0; 105462306a36Sopenharmony_ci int ret = 0; 105562306a36Sopenharmony_ci int err = 0; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci if (changed & NETIF_F_TSO) { 105862306a36Sopenharmony_ci ret = hinic_port_set_tso(nic_dev, (features & NETIF_F_TSO) ? 105962306a36Sopenharmony_ci HINIC_TSO_ENABLE : HINIC_TSO_DISABLE); 106062306a36Sopenharmony_ci if (ret) { 106162306a36Sopenharmony_ci err = ret; 106262306a36Sopenharmony_ci failed_features |= NETIF_F_TSO; 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ci } 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci if (changed & NETIF_F_RXCSUM) { 106762306a36Sopenharmony_ci ret = hinic_set_rx_csum_offload(nic_dev, csum_en); 106862306a36Sopenharmony_ci if (ret) { 106962306a36Sopenharmony_ci err = ret; 107062306a36Sopenharmony_ci failed_features |= NETIF_F_RXCSUM; 107162306a36Sopenharmony_ci } 107262306a36Sopenharmony_ci } 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci if (changed & NETIF_F_LRO) { 107562306a36Sopenharmony_ci ret = hinic_set_rx_lro_state(nic_dev, 107662306a36Sopenharmony_ci !!(features & NETIF_F_LRO), 107762306a36Sopenharmony_ci HINIC_LRO_RX_TIMER_DEFAULT, 107862306a36Sopenharmony_ci HINIC_LRO_MAX_WQE_NUM_DEFAULT); 107962306a36Sopenharmony_ci if (ret) { 108062306a36Sopenharmony_ci err = ret; 108162306a36Sopenharmony_ci failed_features |= NETIF_F_LRO; 108262306a36Sopenharmony_ci } 108362306a36Sopenharmony_ci } 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci if (changed & NETIF_F_HW_VLAN_CTAG_RX) { 108662306a36Sopenharmony_ci ret = hinic_set_rx_vlan_offload(nic_dev, 108762306a36Sopenharmony_ci !!(features & 108862306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_RX)); 108962306a36Sopenharmony_ci if (ret) { 109062306a36Sopenharmony_ci err = ret; 109162306a36Sopenharmony_ci failed_features |= NETIF_F_HW_VLAN_CTAG_RX; 109262306a36Sopenharmony_ci } 109362306a36Sopenharmony_ci } 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci if (changed & NETIF_F_HW_VLAN_CTAG_FILTER) { 109662306a36Sopenharmony_ci ret = hinic_set_vlan_fliter(nic_dev, 109762306a36Sopenharmony_ci !!(features & 109862306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_FILTER)); 109962306a36Sopenharmony_ci if (ret) { 110062306a36Sopenharmony_ci err = ret; 110162306a36Sopenharmony_ci failed_features |= NETIF_F_HW_VLAN_CTAG_FILTER; 110262306a36Sopenharmony_ci } 110362306a36Sopenharmony_ci } 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci if (err) { 110662306a36Sopenharmony_ci nic_dev->netdev->features = features ^ failed_features; 110762306a36Sopenharmony_ci return -EIO; 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci return 0; 111162306a36Sopenharmony_ci} 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_cistatic int hinic_init_intr_coalesce(struct hinic_dev *nic_dev) 111462306a36Sopenharmony_ci{ 111562306a36Sopenharmony_ci u64 size; 111662306a36Sopenharmony_ci u16 i; 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci size = sizeof(struct hinic_intr_coal_info) * nic_dev->max_qps; 111962306a36Sopenharmony_ci nic_dev->rx_intr_coalesce = kzalloc(size, GFP_KERNEL); 112062306a36Sopenharmony_ci if (!nic_dev->rx_intr_coalesce) 112162306a36Sopenharmony_ci return -ENOMEM; 112262306a36Sopenharmony_ci nic_dev->tx_intr_coalesce = kzalloc(size, GFP_KERNEL); 112362306a36Sopenharmony_ci if (!nic_dev->tx_intr_coalesce) { 112462306a36Sopenharmony_ci kfree(nic_dev->rx_intr_coalesce); 112562306a36Sopenharmony_ci return -ENOMEM; 112662306a36Sopenharmony_ci } 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci for (i = 0; i < nic_dev->max_qps; i++) { 112962306a36Sopenharmony_ci nic_dev->rx_intr_coalesce[i].pending_limt = 113062306a36Sopenharmony_ci HINIC_DEAULT_TXRX_MSIX_PENDING_LIMIT; 113162306a36Sopenharmony_ci nic_dev->rx_intr_coalesce[i].coalesce_timer_cfg = 113262306a36Sopenharmony_ci HINIC_DEAULT_TXRX_MSIX_COALESC_TIMER_CFG; 113362306a36Sopenharmony_ci nic_dev->rx_intr_coalesce[i].resend_timer_cfg = 113462306a36Sopenharmony_ci HINIC_DEAULT_TXRX_MSIX_RESEND_TIMER_CFG; 113562306a36Sopenharmony_ci nic_dev->tx_intr_coalesce[i].pending_limt = 113662306a36Sopenharmony_ci HINIC_DEAULT_TXRX_MSIX_PENDING_LIMIT; 113762306a36Sopenharmony_ci nic_dev->tx_intr_coalesce[i].coalesce_timer_cfg = 113862306a36Sopenharmony_ci HINIC_DEAULT_TXRX_MSIX_COALESC_TIMER_CFG; 113962306a36Sopenharmony_ci nic_dev->tx_intr_coalesce[i].resend_timer_cfg = 114062306a36Sopenharmony_ci HINIC_DEAULT_TXRX_MSIX_RESEND_TIMER_CFG; 114162306a36Sopenharmony_ci } 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci return 0; 114462306a36Sopenharmony_ci} 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_cistatic void hinic_free_intr_coalesce(struct hinic_dev *nic_dev) 114762306a36Sopenharmony_ci{ 114862306a36Sopenharmony_ci kfree(nic_dev->tx_intr_coalesce); 114962306a36Sopenharmony_ci kfree(nic_dev->rx_intr_coalesce); 115062306a36Sopenharmony_ci} 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci/** 115362306a36Sopenharmony_ci * nic_dev_init - Initialize the NIC device 115462306a36Sopenharmony_ci * @pdev: the NIC pci device 115562306a36Sopenharmony_ci * 115662306a36Sopenharmony_ci * Return 0 - Success, negative - Failure 115762306a36Sopenharmony_ci **/ 115862306a36Sopenharmony_cistatic int nic_dev_init(struct pci_dev *pdev) 115962306a36Sopenharmony_ci{ 116062306a36Sopenharmony_ci struct hinic_rx_mode_work *rx_mode_work; 116162306a36Sopenharmony_ci struct hinic_dev *nic_dev; 116262306a36Sopenharmony_ci struct net_device *netdev; 116362306a36Sopenharmony_ci struct hinic_hwdev *hwdev; 116462306a36Sopenharmony_ci struct devlink *devlink; 116562306a36Sopenharmony_ci u8 addr[ETH_ALEN]; 116662306a36Sopenharmony_ci int err, num_qps; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci devlink = hinic_devlink_alloc(&pdev->dev); 116962306a36Sopenharmony_ci if (!devlink) { 117062306a36Sopenharmony_ci dev_err(&pdev->dev, "Hinic devlink alloc failed\n"); 117162306a36Sopenharmony_ci return -ENOMEM; 117262306a36Sopenharmony_ci } 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci hwdev = hinic_init_hwdev(pdev, devlink); 117562306a36Sopenharmony_ci if (IS_ERR(hwdev)) { 117662306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to initialize HW device\n"); 117762306a36Sopenharmony_ci hinic_devlink_free(devlink); 117862306a36Sopenharmony_ci return PTR_ERR(hwdev); 117962306a36Sopenharmony_ci } 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci num_qps = hinic_hwdev_num_qps(hwdev); 118262306a36Sopenharmony_ci if (num_qps <= 0) { 118362306a36Sopenharmony_ci dev_err(&pdev->dev, "Invalid number of QPS\n"); 118462306a36Sopenharmony_ci err = -EINVAL; 118562306a36Sopenharmony_ci goto err_num_qps; 118662306a36Sopenharmony_ci } 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci netdev = alloc_etherdev_mq(sizeof(*nic_dev), num_qps); 118962306a36Sopenharmony_ci if (!netdev) { 119062306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to allocate Ethernet device\n"); 119162306a36Sopenharmony_ci err = -ENOMEM; 119262306a36Sopenharmony_ci goto err_alloc_etherdev; 119362306a36Sopenharmony_ci } 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci if (!HINIC_IS_VF(hwdev->hwif)) 119662306a36Sopenharmony_ci netdev->netdev_ops = &hinic_netdev_ops; 119762306a36Sopenharmony_ci else 119862306a36Sopenharmony_ci netdev->netdev_ops = &hinicvf_netdev_ops; 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci netdev->max_mtu = HINIC_MAX_MTU_SIZE; 120162306a36Sopenharmony_ci netdev->min_mtu = HINIC_MIN_MTU_SIZE; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci nic_dev = netdev_priv(netdev); 120462306a36Sopenharmony_ci nic_dev->netdev = netdev; 120562306a36Sopenharmony_ci nic_dev->hwdev = hwdev; 120662306a36Sopenharmony_ci nic_dev->msg_enable = MSG_ENABLE_DEFAULT; 120762306a36Sopenharmony_ci nic_dev->flags = 0; 120862306a36Sopenharmony_ci nic_dev->txqs = NULL; 120962306a36Sopenharmony_ci nic_dev->rxqs = NULL; 121062306a36Sopenharmony_ci nic_dev->tx_weight = tx_weight; 121162306a36Sopenharmony_ci nic_dev->rx_weight = rx_weight; 121262306a36Sopenharmony_ci nic_dev->sq_depth = HINIC_SQ_DEPTH; 121362306a36Sopenharmony_ci nic_dev->rq_depth = HINIC_RQ_DEPTH; 121462306a36Sopenharmony_ci nic_dev->sriov_info.hwdev = hwdev; 121562306a36Sopenharmony_ci nic_dev->sriov_info.pdev = pdev; 121662306a36Sopenharmony_ci nic_dev->max_qps = num_qps; 121762306a36Sopenharmony_ci nic_dev->devlink = devlink; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci hinic_set_ethtool_ops(netdev); 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci sema_init(&nic_dev->mgmt_lock, 1); 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci nic_dev->vlan_bitmap = devm_bitmap_zalloc(&pdev->dev, VLAN_N_VID, 122462306a36Sopenharmony_ci GFP_KERNEL); 122562306a36Sopenharmony_ci if (!nic_dev->vlan_bitmap) { 122662306a36Sopenharmony_ci err = -ENOMEM; 122762306a36Sopenharmony_ci goto err_vlan_bitmap; 122862306a36Sopenharmony_ci } 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci nic_dev->workq = create_singlethread_workqueue(HINIC_WQ_NAME); 123162306a36Sopenharmony_ci if (!nic_dev->workq) { 123262306a36Sopenharmony_ci err = -ENOMEM; 123362306a36Sopenharmony_ci goto err_workq; 123462306a36Sopenharmony_ci } 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci pci_set_drvdata(pdev, netdev); 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci err = hinic_port_get_mac(nic_dev, addr); 123962306a36Sopenharmony_ci if (err) { 124062306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to get mac address\n"); 124162306a36Sopenharmony_ci goto err_get_mac; 124262306a36Sopenharmony_ci } 124362306a36Sopenharmony_ci eth_hw_addr_set(netdev, addr); 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci if (!is_valid_ether_addr(netdev->dev_addr)) { 124662306a36Sopenharmony_ci if (!HINIC_IS_VF(nic_dev->hwdev->hwif)) { 124762306a36Sopenharmony_ci dev_err(&pdev->dev, "Invalid MAC address\n"); 124862306a36Sopenharmony_ci err = -EIO; 124962306a36Sopenharmony_ci goto err_add_mac; 125062306a36Sopenharmony_ci } 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci dev_info(&pdev->dev, "Invalid MAC address %pM, using random\n", 125362306a36Sopenharmony_ci netdev->dev_addr); 125462306a36Sopenharmony_ci eth_hw_addr_random(netdev); 125562306a36Sopenharmony_ci } 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci err = hinic_port_add_mac(nic_dev, netdev->dev_addr, 0); 125862306a36Sopenharmony_ci if (err && err != HINIC_PF_SET_VF_ALREADY) { 125962306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to add mac\n"); 126062306a36Sopenharmony_ci goto err_add_mac; 126162306a36Sopenharmony_ci } 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci err = hinic_port_set_mtu(nic_dev, netdev->mtu); 126462306a36Sopenharmony_ci if (err) { 126562306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to set mtu\n"); 126662306a36Sopenharmony_ci goto err_set_mtu; 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci rx_mode_work = &nic_dev->rx_mode_work; 127062306a36Sopenharmony_ci INIT_WORK(&rx_mode_work->work, set_rx_mode); 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci netdev_features_init(netdev); 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci netif_carrier_off(netdev); 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci hinic_hwdev_cb_register(nic_dev->hwdev, HINIC_MGMT_MSG_CMD_LINK_STATUS, 127762306a36Sopenharmony_ci nic_dev, link_status_event_handler); 127862306a36Sopenharmony_ci hinic_hwdev_cb_register(nic_dev->hwdev, 127962306a36Sopenharmony_ci HINIC_MGMT_MSG_CMD_CABLE_PLUG_EVENT, 128062306a36Sopenharmony_ci nic_dev, cable_plug_event); 128162306a36Sopenharmony_ci hinic_hwdev_cb_register(nic_dev->hwdev, 128262306a36Sopenharmony_ci HINIC_MGMT_MSG_CMD_LINK_ERR_EVENT, 128362306a36Sopenharmony_ci nic_dev, link_err_event); 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci err = set_features(nic_dev, 0, nic_dev->netdev->features, true); 128662306a36Sopenharmony_ci if (err) 128762306a36Sopenharmony_ci goto err_set_features; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci /* enable pause and disable pfc by default */ 129062306a36Sopenharmony_ci err = hinic_dcb_set_pfc(nic_dev->hwdev, 0, 0); 129162306a36Sopenharmony_ci if (err) 129262306a36Sopenharmony_ci goto err_set_pfc; 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci SET_NETDEV_DEV(netdev, &pdev->dev); 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci err = hinic_init_intr_coalesce(nic_dev); 129762306a36Sopenharmony_ci if (err) { 129862306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to init_intr_coalesce\n"); 129962306a36Sopenharmony_ci goto err_init_intr; 130062306a36Sopenharmony_ci } 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci hinic_dbg_init(nic_dev); 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci hinic_func_tbl_dbgfs_init(nic_dev); 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci err = hinic_func_table_debug_add(nic_dev); 130762306a36Sopenharmony_ci if (err) { 130862306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to add func_table debug\n"); 130962306a36Sopenharmony_ci goto err_add_func_table_dbg; 131062306a36Sopenharmony_ci } 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci err = register_netdev(netdev); 131362306a36Sopenharmony_ci if (err) { 131462306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to register netdev\n"); 131562306a36Sopenharmony_ci goto err_reg_netdev; 131662306a36Sopenharmony_ci } 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci return 0; 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_cierr_reg_netdev: 132162306a36Sopenharmony_ci hinic_func_table_debug_rem(nic_dev); 132262306a36Sopenharmony_cierr_add_func_table_dbg: 132362306a36Sopenharmony_ci hinic_func_tbl_dbgfs_uninit(nic_dev); 132462306a36Sopenharmony_ci hinic_dbg_uninit(nic_dev); 132562306a36Sopenharmony_ci hinic_free_intr_coalesce(nic_dev); 132662306a36Sopenharmony_cierr_init_intr: 132762306a36Sopenharmony_cierr_set_pfc: 132862306a36Sopenharmony_cierr_set_features: 132962306a36Sopenharmony_ci hinic_hwdev_cb_unregister(nic_dev->hwdev, 133062306a36Sopenharmony_ci HINIC_MGMT_MSG_CMD_LINK_ERR_EVENT); 133162306a36Sopenharmony_ci hinic_hwdev_cb_unregister(nic_dev->hwdev, 133262306a36Sopenharmony_ci HINIC_MGMT_MSG_CMD_CABLE_PLUG_EVENT); 133362306a36Sopenharmony_ci hinic_hwdev_cb_unregister(nic_dev->hwdev, 133462306a36Sopenharmony_ci HINIC_MGMT_MSG_CMD_LINK_STATUS); 133562306a36Sopenharmony_ci cancel_work_sync(&rx_mode_work->work); 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_cierr_set_mtu: 133862306a36Sopenharmony_ci hinic_port_del_mac(nic_dev, netdev->dev_addr, 0); 133962306a36Sopenharmony_cierr_add_mac: 134062306a36Sopenharmony_cierr_get_mac: 134162306a36Sopenharmony_ci pci_set_drvdata(pdev, NULL); 134262306a36Sopenharmony_ci destroy_workqueue(nic_dev->workq); 134362306a36Sopenharmony_cierr_workq: 134462306a36Sopenharmony_cierr_vlan_bitmap: 134562306a36Sopenharmony_ci free_netdev(netdev); 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_cierr_alloc_etherdev: 134862306a36Sopenharmony_cierr_num_qps: 134962306a36Sopenharmony_ci hinic_free_hwdev(hwdev); 135062306a36Sopenharmony_ci hinic_devlink_free(devlink); 135162306a36Sopenharmony_ci return err; 135262306a36Sopenharmony_ci} 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_cistatic int hinic_probe(struct pci_dev *pdev, 135562306a36Sopenharmony_ci const struct pci_device_id *id) 135662306a36Sopenharmony_ci{ 135762306a36Sopenharmony_ci int err = pci_enable_device(pdev); 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci if (err) 136062306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, err, "Failed to enable PCI device\n"); 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci err = pci_request_regions(pdev, HINIC_DRV_NAME); 136362306a36Sopenharmony_ci if (err) { 136462306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to request PCI regions\n"); 136562306a36Sopenharmony_ci goto err_pci_regions; 136662306a36Sopenharmony_ci } 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci pci_set_master(pdev); 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 137162306a36Sopenharmony_ci if (err) { 137262306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to set DMA mask\n"); 137362306a36Sopenharmony_ci goto err_dma_mask; 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci err = nic_dev_init(pdev); 137762306a36Sopenharmony_ci if (err) { 137862306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to initialize NIC device\n"); 137962306a36Sopenharmony_ci goto err_nic_dev_init; 138062306a36Sopenharmony_ci } 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci dev_info(&pdev->dev, "HiNIC driver - probed\n"); 138362306a36Sopenharmony_ci return 0; 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_cierr_nic_dev_init: 138662306a36Sopenharmony_cierr_dma_mask: 138762306a36Sopenharmony_ci pci_release_regions(pdev); 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_cierr_pci_regions: 139062306a36Sopenharmony_ci pci_disable_device(pdev); 139162306a36Sopenharmony_ci return err; 139262306a36Sopenharmony_ci} 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_cistatic void wait_sriov_cfg_complete(struct hinic_dev *nic_dev) 139562306a36Sopenharmony_ci{ 139662306a36Sopenharmony_ci struct hinic_sriov_info *sriov_info = &nic_dev->sriov_info; 139762306a36Sopenharmony_ci u32 loop_cnt = 0; 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci set_bit(HINIC_FUNC_REMOVE, &sriov_info->state); 140062306a36Sopenharmony_ci usleep_range(9900, 10000); 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci while (loop_cnt < HINIC_WAIT_SRIOV_CFG_TIMEOUT) { 140362306a36Sopenharmony_ci if (!test_bit(HINIC_SRIOV_ENABLE, &sriov_info->state) && 140462306a36Sopenharmony_ci !test_bit(HINIC_SRIOV_DISABLE, &sriov_info->state)) 140562306a36Sopenharmony_ci return; 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci usleep_range(9900, 10000); 140862306a36Sopenharmony_ci loop_cnt++; 140962306a36Sopenharmony_ci } 141062306a36Sopenharmony_ci} 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_cistatic void hinic_remove(struct pci_dev *pdev) 141362306a36Sopenharmony_ci{ 141462306a36Sopenharmony_ci struct net_device *netdev = pci_get_drvdata(pdev); 141562306a36Sopenharmony_ci struct hinic_dev *nic_dev = netdev_priv(netdev); 141662306a36Sopenharmony_ci struct devlink *devlink = nic_dev->devlink; 141762306a36Sopenharmony_ci struct hinic_rx_mode_work *rx_mode_work; 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci if (!HINIC_IS_VF(nic_dev->hwdev->hwif)) { 142062306a36Sopenharmony_ci wait_sriov_cfg_complete(nic_dev); 142162306a36Sopenharmony_ci hinic_pci_sriov_disable(pdev); 142262306a36Sopenharmony_ci } 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci unregister_netdev(netdev); 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci hinic_func_table_debug_rem(nic_dev); 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci hinic_func_tbl_dbgfs_uninit(nic_dev); 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci hinic_dbg_uninit(nic_dev); 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci hinic_free_intr_coalesce(nic_dev); 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci hinic_port_del_mac(nic_dev, netdev->dev_addr, 0); 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci hinic_hwdev_cb_unregister(nic_dev->hwdev, 143762306a36Sopenharmony_ci HINIC_MGMT_MSG_CMD_LINK_ERR_EVENT); 143862306a36Sopenharmony_ci hinic_hwdev_cb_unregister(nic_dev->hwdev, 143962306a36Sopenharmony_ci HINIC_MGMT_MSG_CMD_CABLE_PLUG_EVENT); 144062306a36Sopenharmony_ci hinic_hwdev_cb_unregister(nic_dev->hwdev, 144162306a36Sopenharmony_ci HINIC_MGMT_MSG_CMD_LINK_STATUS); 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci rx_mode_work = &nic_dev->rx_mode_work; 144462306a36Sopenharmony_ci cancel_work_sync(&rx_mode_work->work); 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci pci_set_drvdata(pdev, NULL); 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci destroy_workqueue(nic_dev->workq); 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci hinic_free_hwdev(nic_dev->hwdev); 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci free_netdev(netdev); 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci hinic_devlink_free(devlink); 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci pci_release_regions(pdev); 145762306a36Sopenharmony_ci pci_disable_device(pdev); 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci dev_info(&pdev->dev, "HiNIC driver - removed\n"); 146062306a36Sopenharmony_ci} 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_cistatic void hinic_shutdown(struct pci_dev *pdev) 146362306a36Sopenharmony_ci{ 146462306a36Sopenharmony_ci pci_disable_device(pdev); 146562306a36Sopenharmony_ci} 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_cistatic const struct pci_device_id hinic_pci_table[] = { 146862306a36Sopenharmony_ci { PCI_VDEVICE(HUAWEI, HINIC_DEV_ID_QUAD_PORT_25GE), 0}, 146962306a36Sopenharmony_ci { PCI_VDEVICE(HUAWEI, HINIC_DEV_ID_DUAL_PORT_100GE), 0}, 147062306a36Sopenharmony_ci { PCI_VDEVICE(HUAWEI, HINIC_DEV_ID_DUAL_PORT_100GE_MEZZ), 0}, 147162306a36Sopenharmony_ci { PCI_VDEVICE(HUAWEI, HINIC_DEV_ID_QUAD_PORT_25GE_MEZZ), 0}, 147262306a36Sopenharmony_ci { PCI_VDEVICE(HUAWEI, HINIC_DEV_ID_VF), 0}, 147362306a36Sopenharmony_ci { 0, 0} 147462306a36Sopenharmony_ci}; 147562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, hinic_pci_table); 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_cistatic struct pci_driver hinic_driver = { 147862306a36Sopenharmony_ci .name = HINIC_DRV_NAME, 147962306a36Sopenharmony_ci .id_table = hinic_pci_table, 148062306a36Sopenharmony_ci .probe = hinic_probe, 148162306a36Sopenharmony_ci .remove = hinic_remove, 148262306a36Sopenharmony_ci .shutdown = hinic_shutdown, 148362306a36Sopenharmony_ci .sriov_configure = hinic_pci_sriov_configure, 148462306a36Sopenharmony_ci}; 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_cistatic int __init hinic_module_init(void) 148762306a36Sopenharmony_ci{ 148862306a36Sopenharmony_ci int ret; 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci hinic_dbg_register_debugfs(HINIC_DRV_NAME); 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci ret = pci_register_driver(&hinic_driver); 149362306a36Sopenharmony_ci if (ret) 149462306a36Sopenharmony_ci hinic_dbg_unregister_debugfs(); 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci return ret; 149762306a36Sopenharmony_ci} 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_cistatic void __exit hinic_module_exit(void) 150062306a36Sopenharmony_ci{ 150162306a36Sopenharmony_ci pci_unregister_driver(&hinic_driver); 150262306a36Sopenharmony_ci hinic_dbg_unregister_debugfs(); 150362306a36Sopenharmony_ci} 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_cimodule_init(hinic_module_init); 150662306a36Sopenharmony_cimodule_exit(hinic_module_exit); 1507