162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 262306a36Sopenharmony_ci/* QLogic qede NIC Driver 362306a36Sopenharmony_ci * Copyright (c) 2015-2017 QLogic Corporation 462306a36Sopenharmony_ci * Copyright (c) 2019-2020 Marvell International Ltd. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/crash_dump.h> 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/pci.h> 1062306a36Sopenharmony_ci#include <linux/device.h> 1162306a36Sopenharmony_ci#include <linux/netdevice.h> 1262306a36Sopenharmony_ci#include <linux/etherdevice.h> 1362306a36Sopenharmony_ci#include <linux/skbuff.h> 1462306a36Sopenharmony_ci#include <linux/errno.h> 1562306a36Sopenharmony_ci#include <linux/list.h> 1662306a36Sopenharmony_ci#include <linux/string.h> 1762306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1862306a36Sopenharmony_ci#include <linux/interrupt.h> 1962306a36Sopenharmony_ci#include <asm/byteorder.h> 2062306a36Sopenharmony_ci#include <asm/param.h> 2162306a36Sopenharmony_ci#include <linux/io.h> 2262306a36Sopenharmony_ci#include <linux/netdev_features.h> 2362306a36Sopenharmony_ci#include <linux/udp.h> 2462306a36Sopenharmony_ci#include <linux/tcp.h> 2562306a36Sopenharmony_ci#include <net/udp_tunnel.h> 2662306a36Sopenharmony_ci#include <linux/ip.h> 2762306a36Sopenharmony_ci#include <net/ipv6.h> 2862306a36Sopenharmony_ci#include <net/tcp.h> 2962306a36Sopenharmony_ci#include <linux/if_ether.h> 3062306a36Sopenharmony_ci#include <linux/if_vlan.h> 3162306a36Sopenharmony_ci#include <linux/pkt_sched.h> 3262306a36Sopenharmony_ci#include <linux/ethtool.h> 3362306a36Sopenharmony_ci#include <linux/in.h> 3462306a36Sopenharmony_ci#include <linux/random.h> 3562306a36Sopenharmony_ci#include <net/ip6_checksum.h> 3662306a36Sopenharmony_ci#include <linux/bitops.h> 3762306a36Sopenharmony_ci#include <linux/vmalloc.h> 3862306a36Sopenharmony_ci#include "qede.h" 3962306a36Sopenharmony_ci#include "qede_ptp.h" 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ciMODULE_DESCRIPTION("QLogic FastLinQ 4xxxx Ethernet Driver"); 4262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic uint debug; 4562306a36Sopenharmony_cimodule_param(debug, uint, 0); 4662306a36Sopenharmony_ciMODULE_PARM_DESC(debug, " Default debug msglevel"); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic const struct qed_eth_ops *qed_ops; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define CHIP_NUM_57980S_40 0x1634 5162306a36Sopenharmony_ci#define CHIP_NUM_57980S_10 0x1666 5262306a36Sopenharmony_ci#define CHIP_NUM_57980S_MF 0x1636 5362306a36Sopenharmony_ci#define CHIP_NUM_57980S_100 0x1644 5462306a36Sopenharmony_ci#define CHIP_NUM_57980S_50 0x1654 5562306a36Sopenharmony_ci#define CHIP_NUM_57980S_25 0x1656 5662306a36Sopenharmony_ci#define CHIP_NUM_57980S_IOV 0x1664 5762306a36Sopenharmony_ci#define CHIP_NUM_AH 0x8070 5862306a36Sopenharmony_ci#define CHIP_NUM_AH_IOV 0x8090 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#ifndef PCI_DEVICE_ID_NX2_57980E 6162306a36Sopenharmony_ci#define PCI_DEVICE_ID_57980S_40 CHIP_NUM_57980S_40 6262306a36Sopenharmony_ci#define PCI_DEVICE_ID_57980S_10 CHIP_NUM_57980S_10 6362306a36Sopenharmony_ci#define PCI_DEVICE_ID_57980S_MF CHIP_NUM_57980S_MF 6462306a36Sopenharmony_ci#define PCI_DEVICE_ID_57980S_100 CHIP_NUM_57980S_100 6562306a36Sopenharmony_ci#define PCI_DEVICE_ID_57980S_50 CHIP_NUM_57980S_50 6662306a36Sopenharmony_ci#define PCI_DEVICE_ID_57980S_25 CHIP_NUM_57980S_25 6762306a36Sopenharmony_ci#define PCI_DEVICE_ID_57980S_IOV CHIP_NUM_57980S_IOV 6862306a36Sopenharmony_ci#define PCI_DEVICE_ID_AH CHIP_NUM_AH 6962306a36Sopenharmony_ci#define PCI_DEVICE_ID_AH_IOV CHIP_NUM_AH_IOV 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#endif 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cienum qede_pci_private { 7462306a36Sopenharmony_ci QEDE_PRIVATE_PF, 7562306a36Sopenharmony_ci QEDE_PRIVATE_VF 7662306a36Sopenharmony_ci}; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic const struct pci_device_id qede_pci_tbl[] = { 7962306a36Sopenharmony_ci {PCI_VDEVICE(QLOGIC, PCI_DEVICE_ID_57980S_40), QEDE_PRIVATE_PF}, 8062306a36Sopenharmony_ci {PCI_VDEVICE(QLOGIC, PCI_DEVICE_ID_57980S_10), QEDE_PRIVATE_PF}, 8162306a36Sopenharmony_ci {PCI_VDEVICE(QLOGIC, PCI_DEVICE_ID_57980S_MF), QEDE_PRIVATE_PF}, 8262306a36Sopenharmony_ci {PCI_VDEVICE(QLOGIC, PCI_DEVICE_ID_57980S_100), QEDE_PRIVATE_PF}, 8362306a36Sopenharmony_ci {PCI_VDEVICE(QLOGIC, PCI_DEVICE_ID_57980S_50), QEDE_PRIVATE_PF}, 8462306a36Sopenharmony_ci {PCI_VDEVICE(QLOGIC, PCI_DEVICE_ID_57980S_25), QEDE_PRIVATE_PF}, 8562306a36Sopenharmony_ci#ifdef CONFIG_QED_SRIOV 8662306a36Sopenharmony_ci {PCI_VDEVICE(QLOGIC, PCI_DEVICE_ID_57980S_IOV), QEDE_PRIVATE_VF}, 8762306a36Sopenharmony_ci#endif 8862306a36Sopenharmony_ci {PCI_VDEVICE(QLOGIC, PCI_DEVICE_ID_AH), QEDE_PRIVATE_PF}, 8962306a36Sopenharmony_ci#ifdef CONFIG_QED_SRIOV 9062306a36Sopenharmony_ci {PCI_VDEVICE(QLOGIC, PCI_DEVICE_ID_AH_IOV), QEDE_PRIVATE_VF}, 9162306a36Sopenharmony_ci#endif 9262306a36Sopenharmony_ci { 0 } 9362306a36Sopenharmony_ci}; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, qede_pci_tbl); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic int qede_probe(struct pci_dev *pdev, const struct pci_device_id *id); 9862306a36Sopenharmony_cistatic pci_ers_result_t 9962306a36Sopenharmony_ciqede_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci#define TX_TIMEOUT (5 * HZ) 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/* Utilize last protocol index for XDP */ 10462306a36Sopenharmony_ci#define XDP_PI 11 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic void qede_remove(struct pci_dev *pdev); 10762306a36Sopenharmony_cistatic void qede_shutdown(struct pci_dev *pdev); 10862306a36Sopenharmony_cistatic void qede_link_update(void *dev, struct qed_link_output *link); 10962306a36Sopenharmony_cistatic void qede_schedule_recovery_handler(void *dev); 11062306a36Sopenharmony_cistatic void qede_recovery_handler(struct qede_dev *edev); 11162306a36Sopenharmony_cistatic void qede_schedule_hw_err_handler(void *dev, 11262306a36Sopenharmony_ci enum qed_hw_err_type err_type); 11362306a36Sopenharmony_cistatic void qede_get_eth_tlv_data(void *edev, void *data); 11462306a36Sopenharmony_cistatic void qede_get_generic_tlv_data(void *edev, 11562306a36Sopenharmony_ci struct qed_generic_tlvs *data); 11662306a36Sopenharmony_cistatic void qede_generic_hw_err_handler(struct qede_dev *edev); 11762306a36Sopenharmony_ci#ifdef CONFIG_QED_SRIOV 11862306a36Sopenharmony_cistatic int qede_set_vf_vlan(struct net_device *ndev, int vf, u16 vlan, u8 qos, 11962306a36Sopenharmony_ci __be16 vlan_proto) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(ndev); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (vlan > 4095) { 12462306a36Sopenharmony_ci DP_NOTICE(edev, "Illegal vlan value %d\n", vlan); 12562306a36Sopenharmony_ci return -EINVAL; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if (vlan_proto != htons(ETH_P_8021Q)) 12962306a36Sopenharmony_ci return -EPROTONOSUPPORT; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_IOV, "Setting Vlan 0x%04x to VF [%d]\n", 13262306a36Sopenharmony_ci vlan, vf); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci return edev->ops->iov->set_vlan(edev->cdev, vlan, vf); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic int qede_set_vf_mac(struct net_device *ndev, int vfidx, u8 *mac) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(ndev); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_IOV, "Setting MAC %pM to VF [%d]\n", mac, vfidx); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (!is_valid_ether_addr(mac)) { 14462306a36Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_IOV, "MAC address isn't valid\n"); 14562306a36Sopenharmony_ci return -EINVAL; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci return edev->ops->iov->set_mac(edev->cdev, mac, vfidx); 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic int qede_sriov_configure(struct pci_dev *pdev, int num_vfs_param) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(pci_get_drvdata(pdev)); 15462306a36Sopenharmony_ci struct qed_dev_info *qed_info = &edev->dev_info.common; 15562306a36Sopenharmony_ci struct qed_update_vport_params *vport_params; 15662306a36Sopenharmony_ci int rc; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci vport_params = vzalloc(sizeof(*vport_params)); 15962306a36Sopenharmony_ci if (!vport_params) 16062306a36Sopenharmony_ci return -ENOMEM; 16162306a36Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_IOV, "Requested %d VFs\n", num_vfs_param); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci rc = edev->ops->iov->configure(edev->cdev, num_vfs_param); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci /* Enable/Disable Tx switching for PF */ 16662306a36Sopenharmony_ci if ((rc == num_vfs_param) && netif_running(edev->ndev) && 16762306a36Sopenharmony_ci !qed_info->b_inter_pf_switch && qed_info->tx_switching) { 16862306a36Sopenharmony_ci vport_params->vport_id = 0; 16962306a36Sopenharmony_ci vport_params->update_tx_switching_flg = 1; 17062306a36Sopenharmony_ci vport_params->tx_switching_flg = num_vfs_param ? 1 : 0; 17162306a36Sopenharmony_ci edev->ops->vport_update(edev->cdev, vport_params); 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci vfree(vport_params); 17562306a36Sopenharmony_ci return rc; 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci#endif 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic int __maybe_unused qede_suspend(struct device *dev) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci dev_info(dev, "Device does not support suspend operation\n"); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci return -EOPNOTSUPP; 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(qede_pm_ops, qede_suspend, NULL); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic const struct pci_error_handlers qede_err_handler = { 18962306a36Sopenharmony_ci .error_detected = qede_io_error_detected, 19062306a36Sopenharmony_ci}; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic struct pci_driver qede_pci_driver = { 19362306a36Sopenharmony_ci .name = "qede", 19462306a36Sopenharmony_ci .id_table = qede_pci_tbl, 19562306a36Sopenharmony_ci .probe = qede_probe, 19662306a36Sopenharmony_ci .remove = qede_remove, 19762306a36Sopenharmony_ci .shutdown = qede_shutdown, 19862306a36Sopenharmony_ci#ifdef CONFIG_QED_SRIOV 19962306a36Sopenharmony_ci .sriov_configure = qede_sriov_configure, 20062306a36Sopenharmony_ci#endif 20162306a36Sopenharmony_ci .err_handler = &qede_err_handler, 20262306a36Sopenharmony_ci .driver.pm = &qede_pm_ops, 20362306a36Sopenharmony_ci}; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic struct qed_eth_cb_ops qede_ll_ops = { 20662306a36Sopenharmony_ci { 20762306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 20862306a36Sopenharmony_ci .arfs_filter_op = qede_arfs_filter_op, 20962306a36Sopenharmony_ci#endif 21062306a36Sopenharmony_ci .link_update = qede_link_update, 21162306a36Sopenharmony_ci .schedule_recovery_handler = qede_schedule_recovery_handler, 21262306a36Sopenharmony_ci .schedule_hw_err_handler = qede_schedule_hw_err_handler, 21362306a36Sopenharmony_ci .get_generic_tlv_data = qede_get_generic_tlv_data, 21462306a36Sopenharmony_ci .get_protocol_tlv_data = qede_get_eth_tlv_data, 21562306a36Sopenharmony_ci }, 21662306a36Sopenharmony_ci .force_mac = qede_force_mac, 21762306a36Sopenharmony_ci .ports_update = qede_udp_ports_update, 21862306a36Sopenharmony_ci}; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic int qede_netdev_event(struct notifier_block *this, unsigned long event, 22162306a36Sopenharmony_ci void *ptr) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci struct net_device *ndev = netdev_notifier_info_to_dev(ptr); 22462306a36Sopenharmony_ci struct ethtool_drvinfo drvinfo; 22562306a36Sopenharmony_ci struct qede_dev *edev; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if (event != NETDEV_CHANGENAME && event != NETDEV_CHANGEADDR) 22862306a36Sopenharmony_ci goto done; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci /* Check whether this is a qede device */ 23162306a36Sopenharmony_ci if (!ndev || !ndev->ethtool_ops || !ndev->ethtool_ops->get_drvinfo) 23262306a36Sopenharmony_ci goto done; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci memset(&drvinfo, 0, sizeof(drvinfo)); 23562306a36Sopenharmony_ci ndev->ethtool_ops->get_drvinfo(ndev, &drvinfo); 23662306a36Sopenharmony_ci if (strcmp(drvinfo.driver, "qede")) 23762306a36Sopenharmony_ci goto done; 23862306a36Sopenharmony_ci edev = netdev_priv(ndev); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci switch (event) { 24162306a36Sopenharmony_ci case NETDEV_CHANGENAME: 24262306a36Sopenharmony_ci /* Notify qed of the name change */ 24362306a36Sopenharmony_ci if (!edev->ops || !edev->ops->common) 24462306a36Sopenharmony_ci goto done; 24562306a36Sopenharmony_ci edev->ops->common->set_name(edev->cdev, edev->ndev->name); 24662306a36Sopenharmony_ci break; 24762306a36Sopenharmony_ci case NETDEV_CHANGEADDR: 24862306a36Sopenharmony_ci edev = netdev_priv(ndev); 24962306a36Sopenharmony_ci qede_rdma_event_changeaddr(edev); 25062306a36Sopenharmony_ci break; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cidone: 25462306a36Sopenharmony_ci return NOTIFY_DONE; 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic struct notifier_block qede_netdev_notifier = { 25862306a36Sopenharmony_ci .notifier_call = qede_netdev_event, 25962306a36Sopenharmony_ci}; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cistatic 26262306a36Sopenharmony_ciint __init qede_init(void) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci int ret; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci pr_info("qede init: QLogic FastLinQ 4xxxx Ethernet Driver qede\n"); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci qede_forced_speed_maps_init(); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci qed_ops = qed_get_eth_ops(); 27162306a36Sopenharmony_ci if (!qed_ops) { 27262306a36Sopenharmony_ci pr_notice("Failed to get qed ethtool operations\n"); 27362306a36Sopenharmony_ci return -EINVAL; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* Must register notifier before pci ops, since we might miss 27762306a36Sopenharmony_ci * interface rename after pci probe and netdev registration. 27862306a36Sopenharmony_ci */ 27962306a36Sopenharmony_ci ret = register_netdevice_notifier(&qede_netdev_notifier); 28062306a36Sopenharmony_ci if (ret) { 28162306a36Sopenharmony_ci pr_notice("Failed to register netdevice_notifier\n"); 28262306a36Sopenharmony_ci qed_put_eth_ops(); 28362306a36Sopenharmony_ci return -EINVAL; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci ret = pci_register_driver(&qede_pci_driver); 28762306a36Sopenharmony_ci if (ret) { 28862306a36Sopenharmony_ci pr_notice("Failed to register driver\n"); 28962306a36Sopenharmony_ci unregister_netdevice_notifier(&qede_netdev_notifier); 29062306a36Sopenharmony_ci qed_put_eth_ops(); 29162306a36Sopenharmony_ci return -EINVAL; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci return 0; 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic void __exit qede_cleanup(void) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci if (debug & QED_LOG_INFO_MASK) 30062306a36Sopenharmony_ci pr_info("qede_cleanup called\n"); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci unregister_netdevice_notifier(&qede_netdev_notifier); 30362306a36Sopenharmony_ci pci_unregister_driver(&qede_pci_driver); 30462306a36Sopenharmony_ci qed_put_eth_ops(); 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cimodule_init(qede_init); 30862306a36Sopenharmony_cimodule_exit(qede_cleanup); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic int qede_open(struct net_device *ndev); 31162306a36Sopenharmony_cistatic int qede_close(struct net_device *ndev); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_civoid qede_fill_by_demand_stats(struct qede_dev *edev) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci struct qede_stats_common *p_common = &edev->stats.common; 31662306a36Sopenharmony_ci struct qed_eth_stats stats; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci edev->ops->get_vport_stats(edev->cdev, &stats); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci spin_lock(&edev->stats_lock); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci p_common->no_buff_discards = stats.common.no_buff_discards; 32362306a36Sopenharmony_ci p_common->packet_too_big_discard = stats.common.packet_too_big_discard; 32462306a36Sopenharmony_ci p_common->ttl0_discard = stats.common.ttl0_discard; 32562306a36Sopenharmony_ci p_common->rx_ucast_bytes = stats.common.rx_ucast_bytes; 32662306a36Sopenharmony_ci p_common->rx_mcast_bytes = stats.common.rx_mcast_bytes; 32762306a36Sopenharmony_ci p_common->rx_bcast_bytes = stats.common.rx_bcast_bytes; 32862306a36Sopenharmony_ci p_common->rx_ucast_pkts = stats.common.rx_ucast_pkts; 32962306a36Sopenharmony_ci p_common->rx_mcast_pkts = stats.common.rx_mcast_pkts; 33062306a36Sopenharmony_ci p_common->rx_bcast_pkts = stats.common.rx_bcast_pkts; 33162306a36Sopenharmony_ci p_common->mftag_filter_discards = stats.common.mftag_filter_discards; 33262306a36Sopenharmony_ci p_common->mac_filter_discards = stats.common.mac_filter_discards; 33362306a36Sopenharmony_ci p_common->gft_filter_drop = stats.common.gft_filter_drop; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci p_common->tx_ucast_bytes = stats.common.tx_ucast_bytes; 33662306a36Sopenharmony_ci p_common->tx_mcast_bytes = stats.common.tx_mcast_bytes; 33762306a36Sopenharmony_ci p_common->tx_bcast_bytes = stats.common.tx_bcast_bytes; 33862306a36Sopenharmony_ci p_common->tx_ucast_pkts = stats.common.tx_ucast_pkts; 33962306a36Sopenharmony_ci p_common->tx_mcast_pkts = stats.common.tx_mcast_pkts; 34062306a36Sopenharmony_ci p_common->tx_bcast_pkts = stats.common.tx_bcast_pkts; 34162306a36Sopenharmony_ci p_common->tx_err_drop_pkts = stats.common.tx_err_drop_pkts; 34262306a36Sopenharmony_ci p_common->coalesced_pkts = stats.common.tpa_coalesced_pkts; 34362306a36Sopenharmony_ci p_common->coalesced_events = stats.common.tpa_coalesced_events; 34462306a36Sopenharmony_ci p_common->coalesced_aborts_num = stats.common.tpa_aborts_num; 34562306a36Sopenharmony_ci p_common->non_coalesced_pkts = stats.common.tpa_not_coalesced_pkts; 34662306a36Sopenharmony_ci p_common->coalesced_bytes = stats.common.tpa_coalesced_bytes; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci p_common->rx_64_byte_packets = stats.common.rx_64_byte_packets; 34962306a36Sopenharmony_ci p_common->rx_65_to_127_byte_packets = 35062306a36Sopenharmony_ci stats.common.rx_65_to_127_byte_packets; 35162306a36Sopenharmony_ci p_common->rx_128_to_255_byte_packets = 35262306a36Sopenharmony_ci stats.common.rx_128_to_255_byte_packets; 35362306a36Sopenharmony_ci p_common->rx_256_to_511_byte_packets = 35462306a36Sopenharmony_ci stats.common.rx_256_to_511_byte_packets; 35562306a36Sopenharmony_ci p_common->rx_512_to_1023_byte_packets = 35662306a36Sopenharmony_ci stats.common.rx_512_to_1023_byte_packets; 35762306a36Sopenharmony_ci p_common->rx_1024_to_1518_byte_packets = 35862306a36Sopenharmony_ci stats.common.rx_1024_to_1518_byte_packets; 35962306a36Sopenharmony_ci p_common->rx_crc_errors = stats.common.rx_crc_errors; 36062306a36Sopenharmony_ci p_common->rx_mac_crtl_frames = stats.common.rx_mac_crtl_frames; 36162306a36Sopenharmony_ci p_common->rx_pause_frames = stats.common.rx_pause_frames; 36262306a36Sopenharmony_ci p_common->rx_pfc_frames = stats.common.rx_pfc_frames; 36362306a36Sopenharmony_ci p_common->rx_align_errors = stats.common.rx_align_errors; 36462306a36Sopenharmony_ci p_common->rx_carrier_errors = stats.common.rx_carrier_errors; 36562306a36Sopenharmony_ci p_common->rx_oversize_packets = stats.common.rx_oversize_packets; 36662306a36Sopenharmony_ci p_common->rx_jabbers = stats.common.rx_jabbers; 36762306a36Sopenharmony_ci p_common->rx_undersize_packets = stats.common.rx_undersize_packets; 36862306a36Sopenharmony_ci p_common->rx_fragments = stats.common.rx_fragments; 36962306a36Sopenharmony_ci p_common->tx_64_byte_packets = stats.common.tx_64_byte_packets; 37062306a36Sopenharmony_ci p_common->tx_65_to_127_byte_packets = 37162306a36Sopenharmony_ci stats.common.tx_65_to_127_byte_packets; 37262306a36Sopenharmony_ci p_common->tx_128_to_255_byte_packets = 37362306a36Sopenharmony_ci stats.common.tx_128_to_255_byte_packets; 37462306a36Sopenharmony_ci p_common->tx_256_to_511_byte_packets = 37562306a36Sopenharmony_ci stats.common.tx_256_to_511_byte_packets; 37662306a36Sopenharmony_ci p_common->tx_512_to_1023_byte_packets = 37762306a36Sopenharmony_ci stats.common.tx_512_to_1023_byte_packets; 37862306a36Sopenharmony_ci p_common->tx_1024_to_1518_byte_packets = 37962306a36Sopenharmony_ci stats.common.tx_1024_to_1518_byte_packets; 38062306a36Sopenharmony_ci p_common->tx_pause_frames = stats.common.tx_pause_frames; 38162306a36Sopenharmony_ci p_common->tx_pfc_frames = stats.common.tx_pfc_frames; 38262306a36Sopenharmony_ci p_common->brb_truncates = stats.common.brb_truncates; 38362306a36Sopenharmony_ci p_common->brb_discards = stats.common.brb_discards; 38462306a36Sopenharmony_ci p_common->tx_mac_ctrl_frames = stats.common.tx_mac_ctrl_frames; 38562306a36Sopenharmony_ci p_common->link_change_count = stats.common.link_change_count; 38662306a36Sopenharmony_ci p_common->ptp_skip_txts = edev->ptp_skip_txts; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci if (QEDE_IS_BB(edev)) { 38962306a36Sopenharmony_ci struct qede_stats_bb *p_bb = &edev->stats.bb; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci p_bb->rx_1519_to_1522_byte_packets = 39262306a36Sopenharmony_ci stats.bb.rx_1519_to_1522_byte_packets; 39362306a36Sopenharmony_ci p_bb->rx_1519_to_2047_byte_packets = 39462306a36Sopenharmony_ci stats.bb.rx_1519_to_2047_byte_packets; 39562306a36Sopenharmony_ci p_bb->rx_2048_to_4095_byte_packets = 39662306a36Sopenharmony_ci stats.bb.rx_2048_to_4095_byte_packets; 39762306a36Sopenharmony_ci p_bb->rx_4096_to_9216_byte_packets = 39862306a36Sopenharmony_ci stats.bb.rx_4096_to_9216_byte_packets; 39962306a36Sopenharmony_ci p_bb->rx_9217_to_16383_byte_packets = 40062306a36Sopenharmony_ci stats.bb.rx_9217_to_16383_byte_packets; 40162306a36Sopenharmony_ci p_bb->tx_1519_to_2047_byte_packets = 40262306a36Sopenharmony_ci stats.bb.tx_1519_to_2047_byte_packets; 40362306a36Sopenharmony_ci p_bb->tx_2048_to_4095_byte_packets = 40462306a36Sopenharmony_ci stats.bb.tx_2048_to_4095_byte_packets; 40562306a36Sopenharmony_ci p_bb->tx_4096_to_9216_byte_packets = 40662306a36Sopenharmony_ci stats.bb.tx_4096_to_9216_byte_packets; 40762306a36Sopenharmony_ci p_bb->tx_9217_to_16383_byte_packets = 40862306a36Sopenharmony_ci stats.bb.tx_9217_to_16383_byte_packets; 40962306a36Sopenharmony_ci p_bb->tx_lpi_entry_count = stats.bb.tx_lpi_entry_count; 41062306a36Sopenharmony_ci p_bb->tx_total_collisions = stats.bb.tx_total_collisions; 41162306a36Sopenharmony_ci } else { 41262306a36Sopenharmony_ci struct qede_stats_ah *p_ah = &edev->stats.ah; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci p_ah->rx_1519_to_max_byte_packets = 41562306a36Sopenharmony_ci stats.ah.rx_1519_to_max_byte_packets; 41662306a36Sopenharmony_ci p_ah->tx_1519_to_max_byte_packets = 41762306a36Sopenharmony_ci stats.ah.tx_1519_to_max_byte_packets; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci spin_unlock(&edev->stats_lock); 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic void qede_get_stats64(struct net_device *dev, 42462306a36Sopenharmony_ci struct rtnl_link_stats64 *stats) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 42762306a36Sopenharmony_ci struct qede_stats_common *p_common; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci p_common = &edev->stats.common; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci spin_lock(&edev->stats_lock); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci stats->rx_packets = p_common->rx_ucast_pkts + p_common->rx_mcast_pkts + 43462306a36Sopenharmony_ci p_common->rx_bcast_pkts; 43562306a36Sopenharmony_ci stats->tx_packets = p_common->tx_ucast_pkts + p_common->tx_mcast_pkts + 43662306a36Sopenharmony_ci p_common->tx_bcast_pkts; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci stats->rx_bytes = p_common->rx_ucast_bytes + p_common->rx_mcast_bytes + 43962306a36Sopenharmony_ci p_common->rx_bcast_bytes; 44062306a36Sopenharmony_ci stats->tx_bytes = p_common->tx_ucast_bytes + p_common->tx_mcast_bytes + 44162306a36Sopenharmony_ci p_common->tx_bcast_bytes; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci stats->tx_errors = p_common->tx_err_drop_pkts; 44462306a36Sopenharmony_ci stats->multicast = p_common->rx_mcast_pkts + p_common->rx_bcast_pkts; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci stats->rx_fifo_errors = p_common->no_buff_discards; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci if (QEDE_IS_BB(edev)) 44962306a36Sopenharmony_ci stats->collisions = edev->stats.bb.tx_total_collisions; 45062306a36Sopenharmony_ci stats->rx_crc_errors = p_common->rx_crc_errors; 45162306a36Sopenharmony_ci stats->rx_frame_errors = p_common->rx_align_errors; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci spin_unlock(&edev->stats_lock); 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci#ifdef CONFIG_QED_SRIOV 45762306a36Sopenharmony_cistatic int qede_get_vf_config(struct net_device *dev, int vfidx, 45862306a36Sopenharmony_ci struct ifla_vf_info *ivi) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci if (!edev->ops) 46362306a36Sopenharmony_ci return -EINVAL; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci return edev->ops->iov->get_config(edev->cdev, vfidx, ivi); 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cistatic int qede_set_vf_rate(struct net_device *dev, int vfidx, 46962306a36Sopenharmony_ci int min_tx_rate, int max_tx_rate) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci return edev->ops->iov->set_rate(edev->cdev, vfidx, min_tx_rate, 47462306a36Sopenharmony_ci max_tx_rate); 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic int qede_set_vf_spoofchk(struct net_device *dev, int vfidx, bool val) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci if (!edev->ops) 48262306a36Sopenharmony_ci return -EINVAL; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci return edev->ops->iov->set_spoof(edev->cdev, vfidx, val); 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic int qede_set_vf_link_state(struct net_device *dev, int vfidx, 48862306a36Sopenharmony_ci int link_state) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci if (!edev->ops) 49362306a36Sopenharmony_ci return -EINVAL; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci return edev->ops->iov->set_link_state(edev->cdev, vfidx, link_state); 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_cistatic int qede_set_vf_trust(struct net_device *dev, int vfidx, bool setting) 49962306a36Sopenharmony_ci{ 50062306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci if (!edev->ops) 50362306a36Sopenharmony_ci return -EINVAL; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci return edev->ops->iov->set_trust(edev->cdev, vfidx, setting); 50662306a36Sopenharmony_ci} 50762306a36Sopenharmony_ci#endif 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cistatic int qede_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 51062306a36Sopenharmony_ci{ 51162306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci if (!netif_running(dev)) 51462306a36Sopenharmony_ci return -EAGAIN; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci switch (cmd) { 51762306a36Sopenharmony_ci case SIOCSHWTSTAMP: 51862306a36Sopenharmony_ci return qede_ptp_hw_ts(edev, ifr); 51962306a36Sopenharmony_ci default: 52062306a36Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 52162306a36Sopenharmony_ci "default IOCTL cmd 0x%x\n", cmd); 52262306a36Sopenharmony_ci return -EOPNOTSUPP; 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci return 0; 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_cistatic void qede_fp_sb_dump(struct qede_dev *edev, struct qede_fastpath *fp) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci char *p_sb = (char *)fp->sb_info->sb_virt; 53162306a36Sopenharmony_ci u32 sb_size, i; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci sb_size = sizeof(struct status_block); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci for (i = 0; i < sb_size; i += 8) 53662306a36Sopenharmony_ci DP_NOTICE(edev, 53762306a36Sopenharmony_ci "%02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX\n", 53862306a36Sopenharmony_ci p_sb[i], p_sb[i + 1], p_sb[i + 2], p_sb[i + 3], 53962306a36Sopenharmony_ci p_sb[i + 4], p_sb[i + 5], p_sb[i + 6], p_sb[i + 7]); 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_cistatic void 54362306a36Sopenharmony_ciqede_txq_fp_log_metadata(struct qede_dev *edev, 54462306a36Sopenharmony_ci struct qede_fastpath *fp, struct qede_tx_queue *txq) 54562306a36Sopenharmony_ci{ 54662306a36Sopenharmony_ci struct qed_chain *p_chain = &txq->tx_pbl; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci /* Dump txq/fp/sb ids etc. other metadata */ 54962306a36Sopenharmony_ci DP_NOTICE(edev, 55062306a36Sopenharmony_ci "fpid 0x%x sbid 0x%x txqid [0x%x] ndev_qid [0x%x] cos [0x%x] p_chain %p cap %d size %d jiffies %lu HZ 0x%x\n", 55162306a36Sopenharmony_ci fp->id, fp->sb_info->igu_sb_id, txq->index, txq->ndev_txq_id, txq->cos, 55262306a36Sopenharmony_ci p_chain, p_chain->capacity, p_chain->size, jiffies, HZ); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci /* Dump all the relevant prod/cons indexes */ 55562306a36Sopenharmony_ci DP_NOTICE(edev, 55662306a36Sopenharmony_ci "hw cons %04x sw_tx_prod=0x%x, sw_tx_cons=0x%x, bd_prod 0x%x bd_cons 0x%x\n", 55762306a36Sopenharmony_ci le16_to_cpu(*txq->hw_cons_ptr), txq->sw_tx_prod, txq->sw_tx_cons, 55862306a36Sopenharmony_ci qed_chain_get_prod_idx(p_chain), qed_chain_get_cons_idx(p_chain)); 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_cistatic void 56262306a36Sopenharmony_ciqede_tx_log_print(struct qede_dev *edev, struct qede_fastpath *fp, struct qede_tx_queue *txq) 56362306a36Sopenharmony_ci{ 56462306a36Sopenharmony_ci struct qed_sb_info_dbg sb_dbg; 56562306a36Sopenharmony_ci int rc; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci /* sb info */ 56862306a36Sopenharmony_ci qede_fp_sb_dump(edev, fp); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci memset(&sb_dbg, 0, sizeof(sb_dbg)); 57162306a36Sopenharmony_ci rc = edev->ops->common->get_sb_info(edev->cdev, fp->sb_info, (u16)fp->id, &sb_dbg); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci DP_NOTICE(edev, "IGU: prod %08x cons %08x CAU Tx %04x\n", 57462306a36Sopenharmony_ci sb_dbg.igu_prod, sb_dbg.igu_cons, sb_dbg.pi[TX_PI(txq->cos)]); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci /* report to mfw */ 57762306a36Sopenharmony_ci edev->ops->common->mfw_report(edev->cdev, 57862306a36Sopenharmony_ci "Txq[%d]: FW cons [host] %04x, SW cons %04x, SW prod %04x [Jiffies %lu]\n", 57962306a36Sopenharmony_ci txq->index, le16_to_cpu(*txq->hw_cons_ptr), 58062306a36Sopenharmony_ci qed_chain_get_cons_idx(&txq->tx_pbl), 58162306a36Sopenharmony_ci qed_chain_get_prod_idx(&txq->tx_pbl), jiffies); 58262306a36Sopenharmony_ci if (!rc) 58362306a36Sopenharmony_ci edev->ops->common->mfw_report(edev->cdev, 58462306a36Sopenharmony_ci "Txq[%d]: SB[0x%04x] - IGU: prod %08x cons %08x CAU Tx %04x\n", 58562306a36Sopenharmony_ci txq->index, fp->sb_info->igu_sb_id, 58662306a36Sopenharmony_ci sb_dbg.igu_prod, sb_dbg.igu_cons, 58762306a36Sopenharmony_ci sb_dbg.pi[TX_PI(txq->cos)]); 58862306a36Sopenharmony_ci} 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_cistatic void qede_tx_timeout(struct net_device *dev, unsigned int txqueue) 59162306a36Sopenharmony_ci{ 59262306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 59362306a36Sopenharmony_ci int i; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci netif_carrier_off(dev); 59662306a36Sopenharmony_ci DP_NOTICE(edev, "TX timeout on queue %u!\n", txqueue); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci for_each_queue(i) { 59962306a36Sopenharmony_ci struct qede_tx_queue *txq; 60062306a36Sopenharmony_ci struct qede_fastpath *fp; 60162306a36Sopenharmony_ci int cos; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci fp = &edev->fp_array[i]; 60462306a36Sopenharmony_ci if (!(fp->type & QEDE_FASTPATH_TX)) 60562306a36Sopenharmony_ci continue; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci for_each_cos_in_txq(edev, cos) { 60862306a36Sopenharmony_ci txq = &fp->txq[cos]; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci /* Dump basic metadata for all queues */ 61162306a36Sopenharmony_ci qede_txq_fp_log_metadata(edev, fp, txq); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci if (qed_chain_get_cons_idx(&txq->tx_pbl) != 61462306a36Sopenharmony_ci qed_chain_get_prod_idx(&txq->tx_pbl)) 61562306a36Sopenharmony_ci qede_tx_log_print(edev, fp, txq); 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if (IS_VF(edev)) 62062306a36Sopenharmony_ci return; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci if (test_and_set_bit(QEDE_ERR_IS_HANDLED, &edev->err_flags) || 62362306a36Sopenharmony_ci edev->state == QEDE_STATE_RECOVERY) { 62462306a36Sopenharmony_ci DP_INFO(edev, 62562306a36Sopenharmony_ci "Avoid handling a Tx timeout while another HW error is being handled\n"); 62662306a36Sopenharmony_ci return; 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci set_bit(QEDE_ERR_GET_DBG_INFO, &edev->err_flags); 63062306a36Sopenharmony_ci set_bit(QEDE_SP_HW_ERR, &edev->sp_flags); 63162306a36Sopenharmony_ci schedule_delayed_work(&edev->sp_task, 0); 63262306a36Sopenharmony_ci} 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_cistatic int qede_setup_tc(struct net_device *ndev, u8 num_tc) 63562306a36Sopenharmony_ci{ 63662306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(ndev); 63762306a36Sopenharmony_ci int cos, count, offset; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci if (num_tc > edev->dev_info.num_tc) 64062306a36Sopenharmony_ci return -EINVAL; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci netdev_reset_tc(ndev); 64362306a36Sopenharmony_ci netdev_set_num_tc(ndev, num_tc); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci for_each_cos_in_txq(edev, cos) { 64662306a36Sopenharmony_ci count = QEDE_TSS_COUNT(edev); 64762306a36Sopenharmony_ci offset = cos * QEDE_TSS_COUNT(edev); 64862306a36Sopenharmony_ci netdev_set_tc_queue(ndev, cos, count, offset); 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci return 0; 65262306a36Sopenharmony_ci} 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_cistatic int 65562306a36Sopenharmony_ciqede_set_flower(struct qede_dev *edev, struct flow_cls_offload *f, 65662306a36Sopenharmony_ci __be16 proto) 65762306a36Sopenharmony_ci{ 65862306a36Sopenharmony_ci switch (f->command) { 65962306a36Sopenharmony_ci case FLOW_CLS_REPLACE: 66062306a36Sopenharmony_ci return qede_add_tc_flower_fltr(edev, proto, f); 66162306a36Sopenharmony_ci case FLOW_CLS_DESTROY: 66262306a36Sopenharmony_ci return qede_delete_flow_filter(edev, f->cookie); 66362306a36Sopenharmony_ci default: 66462306a36Sopenharmony_ci return -EOPNOTSUPP; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic int qede_setup_tc_block_cb(enum tc_setup_type type, void *type_data, 66962306a36Sopenharmony_ci void *cb_priv) 67062306a36Sopenharmony_ci{ 67162306a36Sopenharmony_ci struct flow_cls_offload *f; 67262306a36Sopenharmony_ci struct qede_dev *edev = cb_priv; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci if (!tc_cls_can_offload_and_chain0(edev->ndev, type_data)) 67562306a36Sopenharmony_ci return -EOPNOTSUPP; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci switch (type) { 67862306a36Sopenharmony_ci case TC_SETUP_CLSFLOWER: 67962306a36Sopenharmony_ci f = type_data; 68062306a36Sopenharmony_ci return qede_set_flower(edev, f, f->common.protocol); 68162306a36Sopenharmony_ci default: 68262306a36Sopenharmony_ci return -EOPNOTSUPP; 68362306a36Sopenharmony_ci } 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_cistatic LIST_HEAD(qede_block_cb_list); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_cistatic int 68962306a36Sopenharmony_ciqede_setup_tc_offload(struct net_device *dev, enum tc_setup_type type, 69062306a36Sopenharmony_ci void *type_data) 69162306a36Sopenharmony_ci{ 69262306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 69362306a36Sopenharmony_ci struct tc_mqprio_qopt *mqprio; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci switch (type) { 69662306a36Sopenharmony_ci case TC_SETUP_BLOCK: 69762306a36Sopenharmony_ci return flow_block_cb_setup_simple(type_data, 69862306a36Sopenharmony_ci &qede_block_cb_list, 69962306a36Sopenharmony_ci qede_setup_tc_block_cb, 70062306a36Sopenharmony_ci edev, edev, true); 70162306a36Sopenharmony_ci case TC_SETUP_QDISC_MQPRIO: 70262306a36Sopenharmony_ci mqprio = type_data; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS; 70562306a36Sopenharmony_ci return qede_setup_tc(dev, mqprio->num_tc); 70662306a36Sopenharmony_ci default: 70762306a36Sopenharmony_ci return -EOPNOTSUPP; 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci} 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_cistatic const struct net_device_ops qede_netdev_ops = { 71262306a36Sopenharmony_ci .ndo_open = qede_open, 71362306a36Sopenharmony_ci .ndo_stop = qede_close, 71462306a36Sopenharmony_ci .ndo_start_xmit = qede_start_xmit, 71562306a36Sopenharmony_ci .ndo_select_queue = qede_select_queue, 71662306a36Sopenharmony_ci .ndo_set_rx_mode = qede_set_rx_mode, 71762306a36Sopenharmony_ci .ndo_set_mac_address = qede_set_mac_addr, 71862306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 71962306a36Sopenharmony_ci .ndo_change_mtu = qede_change_mtu, 72062306a36Sopenharmony_ci .ndo_eth_ioctl = qede_ioctl, 72162306a36Sopenharmony_ci .ndo_tx_timeout = qede_tx_timeout, 72262306a36Sopenharmony_ci#ifdef CONFIG_QED_SRIOV 72362306a36Sopenharmony_ci .ndo_set_vf_mac = qede_set_vf_mac, 72462306a36Sopenharmony_ci .ndo_set_vf_vlan = qede_set_vf_vlan, 72562306a36Sopenharmony_ci .ndo_set_vf_trust = qede_set_vf_trust, 72662306a36Sopenharmony_ci#endif 72762306a36Sopenharmony_ci .ndo_vlan_rx_add_vid = qede_vlan_rx_add_vid, 72862306a36Sopenharmony_ci .ndo_vlan_rx_kill_vid = qede_vlan_rx_kill_vid, 72962306a36Sopenharmony_ci .ndo_fix_features = qede_fix_features, 73062306a36Sopenharmony_ci .ndo_set_features = qede_set_features, 73162306a36Sopenharmony_ci .ndo_get_stats64 = qede_get_stats64, 73262306a36Sopenharmony_ci#ifdef CONFIG_QED_SRIOV 73362306a36Sopenharmony_ci .ndo_set_vf_link_state = qede_set_vf_link_state, 73462306a36Sopenharmony_ci .ndo_set_vf_spoofchk = qede_set_vf_spoofchk, 73562306a36Sopenharmony_ci .ndo_get_vf_config = qede_get_vf_config, 73662306a36Sopenharmony_ci .ndo_set_vf_rate = qede_set_vf_rate, 73762306a36Sopenharmony_ci#endif 73862306a36Sopenharmony_ci .ndo_features_check = qede_features_check, 73962306a36Sopenharmony_ci .ndo_bpf = qede_xdp, 74062306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 74162306a36Sopenharmony_ci .ndo_rx_flow_steer = qede_rx_flow_steer, 74262306a36Sopenharmony_ci#endif 74362306a36Sopenharmony_ci .ndo_xdp_xmit = qede_xdp_transmit, 74462306a36Sopenharmony_ci .ndo_setup_tc = qede_setup_tc_offload, 74562306a36Sopenharmony_ci}; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_cistatic const struct net_device_ops qede_netdev_vf_ops = { 74862306a36Sopenharmony_ci .ndo_open = qede_open, 74962306a36Sopenharmony_ci .ndo_stop = qede_close, 75062306a36Sopenharmony_ci .ndo_start_xmit = qede_start_xmit, 75162306a36Sopenharmony_ci .ndo_select_queue = qede_select_queue, 75262306a36Sopenharmony_ci .ndo_set_rx_mode = qede_set_rx_mode, 75362306a36Sopenharmony_ci .ndo_set_mac_address = qede_set_mac_addr, 75462306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 75562306a36Sopenharmony_ci .ndo_change_mtu = qede_change_mtu, 75662306a36Sopenharmony_ci .ndo_vlan_rx_add_vid = qede_vlan_rx_add_vid, 75762306a36Sopenharmony_ci .ndo_vlan_rx_kill_vid = qede_vlan_rx_kill_vid, 75862306a36Sopenharmony_ci .ndo_fix_features = qede_fix_features, 75962306a36Sopenharmony_ci .ndo_set_features = qede_set_features, 76062306a36Sopenharmony_ci .ndo_get_stats64 = qede_get_stats64, 76162306a36Sopenharmony_ci .ndo_features_check = qede_features_check, 76262306a36Sopenharmony_ci}; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_cistatic const struct net_device_ops qede_netdev_vf_xdp_ops = { 76562306a36Sopenharmony_ci .ndo_open = qede_open, 76662306a36Sopenharmony_ci .ndo_stop = qede_close, 76762306a36Sopenharmony_ci .ndo_start_xmit = qede_start_xmit, 76862306a36Sopenharmony_ci .ndo_select_queue = qede_select_queue, 76962306a36Sopenharmony_ci .ndo_set_rx_mode = qede_set_rx_mode, 77062306a36Sopenharmony_ci .ndo_set_mac_address = qede_set_mac_addr, 77162306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 77262306a36Sopenharmony_ci .ndo_change_mtu = qede_change_mtu, 77362306a36Sopenharmony_ci .ndo_vlan_rx_add_vid = qede_vlan_rx_add_vid, 77462306a36Sopenharmony_ci .ndo_vlan_rx_kill_vid = qede_vlan_rx_kill_vid, 77562306a36Sopenharmony_ci .ndo_fix_features = qede_fix_features, 77662306a36Sopenharmony_ci .ndo_set_features = qede_set_features, 77762306a36Sopenharmony_ci .ndo_get_stats64 = qede_get_stats64, 77862306a36Sopenharmony_ci .ndo_features_check = qede_features_check, 77962306a36Sopenharmony_ci .ndo_bpf = qede_xdp, 78062306a36Sopenharmony_ci .ndo_xdp_xmit = qede_xdp_transmit, 78162306a36Sopenharmony_ci}; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci/* ------------------------------------------------------------------------- 78462306a36Sopenharmony_ci * START OF PROBE / REMOVE 78562306a36Sopenharmony_ci * ------------------------------------------------------------------------- 78662306a36Sopenharmony_ci */ 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_cistatic struct qede_dev *qede_alloc_etherdev(struct qed_dev *cdev, 78962306a36Sopenharmony_ci struct pci_dev *pdev, 79062306a36Sopenharmony_ci struct qed_dev_eth_info *info, 79162306a36Sopenharmony_ci u32 dp_module, u8 dp_level) 79262306a36Sopenharmony_ci{ 79362306a36Sopenharmony_ci struct net_device *ndev; 79462306a36Sopenharmony_ci struct qede_dev *edev; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci ndev = alloc_etherdev_mqs(sizeof(*edev), 79762306a36Sopenharmony_ci info->num_queues * info->num_tc, 79862306a36Sopenharmony_ci info->num_queues); 79962306a36Sopenharmony_ci if (!ndev) { 80062306a36Sopenharmony_ci pr_err("etherdev allocation failed\n"); 80162306a36Sopenharmony_ci return NULL; 80262306a36Sopenharmony_ci } 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci edev = netdev_priv(ndev); 80562306a36Sopenharmony_ci edev->ndev = ndev; 80662306a36Sopenharmony_ci edev->cdev = cdev; 80762306a36Sopenharmony_ci edev->pdev = pdev; 80862306a36Sopenharmony_ci edev->dp_module = dp_module; 80962306a36Sopenharmony_ci edev->dp_level = dp_level; 81062306a36Sopenharmony_ci edev->ops = qed_ops; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci if (is_kdump_kernel()) { 81362306a36Sopenharmony_ci edev->q_num_rx_buffers = NUM_RX_BDS_KDUMP_MIN; 81462306a36Sopenharmony_ci edev->q_num_tx_buffers = NUM_TX_BDS_KDUMP_MIN; 81562306a36Sopenharmony_ci } else { 81662306a36Sopenharmony_ci edev->q_num_rx_buffers = NUM_RX_BDS_DEF; 81762306a36Sopenharmony_ci edev->q_num_tx_buffers = NUM_TX_BDS_DEF; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci DP_INFO(edev, "Allocated netdev with %d tx queues and %d rx queues\n", 82162306a36Sopenharmony_ci info->num_queues, info->num_queues); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci SET_NETDEV_DEV(ndev, &pdev->dev); 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci memset(&edev->stats, 0, sizeof(edev->stats)); 82662306a36Sopenharmony_ci memcpy(&edev->dev_info, info, sizeof(*info)); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci /* As ethtool doesn't have the ability to show WoL behavior as 82962306a36Sopenharmony_ci * 'default', if device supports it declare it's enabled. 83062306a36Sopenharmony_ci */ 83162306a36Sopenharmony_ci if (edev->dev_info.common.wol_support) 83262306a36Sopenharmony_ci edev->wol_enabled = true; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci INIT_LIST_HEAD(&edev->vlan_list); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci return edev; 83762306a36Sopenharmony_ci} 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_cistatic void qede_init_ndev(struct qede_dev *edev) 84062306a36Sopenharmony_ci{ 84162306a36Sopenharmony_ci struct net_device *ndev = edev->ndev; 84262306a36Sopenharmony_ci struct pci_dev *pdev = edev->pdev; 84362306a36Sopenharmony_ci bool udp_tunnel_enable = false; 84462306a36Sopenharmony_ci netdev_features_t hw_features; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci pci_set_drvdata(pdev, ndev); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci ndev->mem_start = edev->dev_info.common.pci_mem_start; 84962306a36Sopenharmony_ci ndev->base_addr = ndev->mem_start; 85062306a36Sopenharmony_ci ndev->mem_end = edev->dev_info.common.pci_mem_end; 85162306a36Sopenharmony_ci ndev->irq = edev->dev_info.common.pci_irq; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci ndev->watchdog_timeo = TX_TIMEOUT; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci if (IS_VF(edev)) { 85662306a36Sopenharmony_ci if (edev->dev_info.xdp_supported) 85762306a36Sopenharmony_ci ndev->netdev_ops = &qede_netdev_vf_xdp_ops; 85862306a36Sopenharmony_ci else 85962306a36Sopenharmony_ci ndev->netdev_ops = &qede_netdev_vf_ops; 86062306a36Sopenharmony_ci } else { 86162306a36Sopenharmony_ci ndev->netdev_ops = &qede_netdev_ops; 86262306a36Sopenharmony_ci } 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci qede_set_ethtool_ops(ndev); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci ndev->priv_flags |= IFF_UNICAST_FLT; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci /* user-changeble features */ 86962306a36Sopenharmony_ci hw_features = NETIF_F_GRO | NETIF_F_GRO_HW | NETIF_F_SG | 87062306a36Sopenharmony_ci NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | 87162306a36Sopenharmony_ci NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_TC; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci if (edev->dev_info.common.b_arfs_capable) 87462306a36Sopenharmony_ci hw_features |= NETIF_F_NTUPLE; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci if (edev->dev_info.common.vxlan_enable || 87762306a36Sopenharmony_ci edev->dev_info.common.geneve_enable) 87862306a36Sopenharmony_ci udp_tunnel_enable = true; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci if (udp_tunnel_enable || edev->dev_info.common.gre_enable) { 88162306a36Sopenharmony_ci hw_features |= NETIF_F_TSO_ECN; 88262306a36Sopenharmony_ci ndev->hw_enc_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | 88362306a36Sopenharmony_ci NETIF_F_SG | NETIF_F_TSO | 88462306a36Sopenharmony_ci NETIF_F_TSO_ECN | NETIF_F_TSO6 | 88562306a36Sopenharmony_ci NETIF_F_RXCSUM; 88662306a36Sopenharmony_ci } 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci if (udp_tunnel_enable) { 88962306a36Sopenharmony_ci hw_features |= (NETIF_F_GSO_UDP_TUNNEL | 89062306a36Sopenharmony_ci NETIF_F_GSO_UDP_TUNNEL_CSUM); 89162306a36Sopenharmony_ci ndev->hw_enc_features |= (NETIF_F_GSO_UDP_TUNNEL | 89262306a36Sopenharmony_ci NETIF_F_GSO_UDP_TUNNEL_CSUM); 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci qede_set_udp_tunnels(edev); 89562306a36Sopenharmony_ci } 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci if (edev->dev_info.common.gre_enable) { 89862306a36Sopenharmony_ci hw_features |= (NETIF_F_GSO_GRE | NETIF_F_GSO_GRE_CSUM); 89962306a36Sopenharmony_ci ndev->hw_enc_features |= (NETIF_F_GSO_GRE | 90062306a36Sopenharmony_ci NETIF_F_GSO_GRE_CSUM); 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci ndev->vlan_features = hw_features | NETIF_F_RXHASH | NETIF_F_RXCSUM | 90462306a36Sopenharmony_ci NETIF_F_HIGHDMA; 90562306a36Sopenharmony_ci ndev->features = hw_features | NETIF_F_RXHASH | NETIF_F_RXCSUM | 90662306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HIGHDMA | 90762306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_CTAG_TX; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci ndev->hw_features = hw_features; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci ndev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | 91262306a36Sopenharmony_ci NETDEV_XDP_ACT_NDO_XMIT; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci /* MTU range: 46 - 9600 */ 91562306a36Sopenharmony_ci ndev->min_mtu = ETH_ZLEN - ETH_HLEN; 91662306a36Sopenharmony_ci ndev->max_mtu = QEDE_MAX_JUMBO_PACKET_SIZE; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci /* Set network device HW mac */ 91962306a36Sopenharmony_ci eth_hw_addr_set(edev->ndev, edev->dev_info.common.hw_mac); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci ndev->mtu = edev->dev_info.common.mtu; 92262306a36Sopenharmony_ci} 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci/* This function converts from 32b param to two params of level and module 92562306a36Sopenharmony_ci * Input 32b decoding: 92662306a36Sopenharmony_ci * b31 - enable all NOTICE prints. NOTICE prints are for deviation from the 92762306a36Sopenharmony_ci * 'happy' flow, e.g. memory allocation failed. 92862306a36Sopenharmony_ci * b30 - enable all INFO prints. INFO prints are for major steps in the flow 92962306a36Sopenharmony_ci * and provide important parameters. 93062306a36Sopenharmony_ci * b29-b0 - per-module bitmap, where each bit enables VERBOSE prints of that 93162306a36Sopenharmony_ci * module. VERBOSE prints are for tracking the specific flow in low level. 93262306a36Sopenharmony_ci * 93362306a36Sopenharmony_ci * Notice that the level should be that of the lowest required logs. 93462306a36Sopenharmony_ci */ 93562306a36Sopenharmony_civoid qede_config_debug(uint debug, u32 *p_dp_module, u8 *p_dp_level) 93662306a36Sopenharmony_ci{ 93762306a36Sopenharmony_ci *p_dp_level = QED_LEVEL_NOTICE; 93862306a36Sopenharmony_ci *p_dp_module = 0; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci if (debug & QED_LOG_VERBOSE_MASK) { 94162306a36Sopenharmony_ci *p_dp_level = QED_LEVEL_VERBOSE; 94262306a36Sopenharmony_ci *p_dp_module = (debug & 0x3FFFFFFF); 94362306a36Sopenharmony_ci } else if (debug & QED_LOG_INFO_MASK) { 94462306a36Sopenharmony_ci *p_dp_level = QED_LEVEL_INFO; 94562306a36Sopenharmony_ci } else if (debug & QED_LOG_NOTICE_MASK) { 94662306a36Sopenharmony_ci *p_dp_level = QED_LEVEL_NOTICE; 94762306a36Sopenharmony_ci } 94862306a36Sopenharmony_ci} 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_cistatic void qede_free_fp_array(struct qede_dev *edev) 95162306a36Sopenharmony_ci{ 95262306a36Sopenharmony_ci if (edev->fp_array) { 95362306a36Sopenharmony_ci struct qede_fastpath *fp; 95462306a36Sopenharmony_ci int i; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci for_each_queue(i) { 95762306a36Sopenharmony_ci fp = &edev->fp_array[i]; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci kfree(fp->sb_info); 96062306a36Sopenharmony_ci /* Handle mem alloc failure case where qede_init_fp 96162306a36Sopenharmony_ci * didn't register xdp_rxq_info yet. 96262306a36Sopenharmony_ci * Implicit only (fp->type & QEDE_FASTPATH_RX) 96362306a36Sopenharmony_ci */ 96462306a36Sopenharmony_ci if (fp->rxq && xdp_rxq_info_is_reg(&fp->rxq->xdp_rxq)) 96562306a36Sopenharmony_ci xdp_rxq_info_unreg(&fp->rxq->xdp_rxq); 96662306a36Sopenharmony_ci kfree(fp->rxq); 96762306a36Sopenharmony_ci kfree(fp->xdp_tx); 96862306a36Sopenharmony_ci kfree(fp->txq); 96962306a36Sopenharmony_ci } 97062306a36Sopenharmony_ci kfree(edev->fp_array); 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci edev->num_queues = 0; 97462306a36Sopenharmony_ci edev->fp_num_tx = 0; 97562306a36Sopenharmony_ci edev->fp_num_rx = 0; 97662306a36Sopenharmony_ci} 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_cistatic int qede_alloc_fp_array(struct qede_dev *edev) 97962306a36Sopenharmony_ci{ 98062306a36Sopenharmony_ci u8 fp_combined, fp_rx = edev->fp_num_rx; 98162306a36Sopenharmony_ci struct qede_fastpath *fp; 98262306a36Sopenharmony_ci int i; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci edev->fp_array = kcalloc(QEDE_QUEUE_CNT(edev), 98562306a36Sopenharmony_ci sizeof(*edev->fp_array), GFP_KERNEL); 98662306a36Sopenharmony_ci if (!edev->fp_array) { 98762306a36Sopenharmony_ci DP_NOTICE(edev, "fp array allocation failed\n"); 98862306a36Sopenharmony_ci goto err; 98962306a36Sopenharmony_ci } 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci if (!edev->coal_entry) { 99262306a36Sopenharmony_ci edev->coal_entry = kcalloc(QEDE_MAX_RSS_CNT(edev), 99362306a36Sopenharmony_ci sizeof(*edev->coal_entry), 99462306a36Sopenharmony_ci GFP_KERNEL); 99562306a36Sopenharmony_ci if (!edev->coal_entry) { 99662306a36Sopenharmony_ci DP_ERR(edev, "coalesce entry allocation failed\n"); 99762306a36Sopenharmony_ci goto err; 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci } 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci fp_combined = QEDE_QUEUE_CNT(edev) - fp_rx - edev->fp_num_tx; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci /* Allocate the FP elements for Rx queues followed by combined and then 100462306a36Sopenharmony_ci * the Tx. This ordering should be maintained so that the respective 100562306a36Sopenharmony_ci * queues (Rx or Tx) will be together in the fastpath array and the 100662306a36Sopenharmony_ci * associated ids will be sequential. 100762306a36Sopenharmony_ci */ 100862306a36Sopenharmony_ci for_each_queue(i) { 100962306a36Sopenharmony_ci fp = &edev->fp_array[i]; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci fp->sb_info = kzalloc(sizeof(*fp->sb_info), GFP_KERNEL); 101262306a36Sopenharmony_ci if (!fp->sb_info) { 101362306a36Sopenharmony_ci DP_NOTICE(edev, "sb info struct allocation failed\n"); 101462306a36Sopenharmony_ci goto err; 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci if (fp_rx) { 101862306a36Sopenharmony_ci fp->type = QEDE_FASTPATH_RX; 101962306a36Sopenharmony_ci fp_rx--; 102062306a36Sopenharmony_ci } else if (fp_combined) { 102162306a36Sopenharmony_ci fp->type = QEDE_FASTPATH_COMBINED; 102262306a36Sopenharmony_ci fp_combined--; 102362306a36Sopenharmony_ci } else { 102462306a36Sopenharmony_ci fp->type = QEDE_FASTPATH_TX; 102562306a36Sopenharmony_ci } 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_TX) { 102862306a36Sopenharmony_ci fp->txq = kcalloc(edev->dev_info.num_tc, 102962306a36Sopenharmony_ci sizeof(*fp->txq), GFP_KERNEL); 103062306a36Sopenharmony_ci if (!fp->txq) 103162306a36Sopenharmony_ci goto err; 103262306a36Sopenharmony_ci } 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_RX) { 103562306a36Sopenharmony_ci fp->rxq = kzalloc(sizeof(*fp->rxq), GFP_KERNEL); 103662306a36Sopenharmony_ci if (!fp->rxq) 103762306a36Sopenharmony_ci goto err; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci if (edev->xdp_prog) { 104062306a36Sopenharmony_ci fp->xdp_tx = kzalloc(sizeof(*fp->xdp_tx), 104162306a36Sopenharmony_ci GFP_KERNEL); 104262306a36Sopenharmony_ci if (!fp->xdp_tx) 104362306a36Sopenharmony_ci goto err; 104462306a36Sopenharmony_ci fp->type |= QEDE_FASTPATH_XDP; 104562306a36Sopenharmony_ci } 104662306a36Sopenharmony_ci } 104762306a36Sopenharmony_ci } 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci return 0; 105062306a36Sopenharmony_cierr: 105162306a36Sopenharmony_ci qede_free_fp_array(edev); 105262306a36Sopenharmony_ci return -ENOMEM; 105362306a36Sopenharmony_ci} 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci/* The qede lock is used to protect driver state change and driver flows that 105662306a36Sopenharmony_ci * are not reentrant. 105762306a36Sopenharmony_ci */ 105862306a36Sopenharmony_civoid __qede_lock(struct qede_dev *edev) 105962306a36Sopenharmony_ci{ 106062306a36Sopenharmony_ci mutex_lock(&edev->qede_lock); 106162306a36Sopenharmony_ci} 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_civoid __qede_unlock(struct qede_dev *edev) 106462306a36Sopenharmony_ci{ 106562306a36Sopenharmony_ci mutex_unlock(&edev->qede_lock); 106662306a36Sopenharmony_ci} 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci/* This version of the lock should be used when acquiring the RTNL lock is also 106962306a36Sopenharmony_ci * needed in addition to the internal qede lock. 107062306a36Sopenharmony_ci */ 107162306a36Sopenharmony_cistatic void qede_lock(struct qede_dev *edev) 107262306a36Sopenharmony_ci{ 107362306a36Sopenharmony_ci rtnl_lock(); 107462306a36Sopenharmony_ci __qede_lock(edev); 107562306a36Sopenharmony_ci} 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_cistatic void qede_unlock(struct qede_dev *edev) 107862306a36Sopenharmony_ci{ 107962306a36Sopenharmony_ci __qede_unlock(edev); 108062306a36Sopenharmony_ci rtnl_unlock(); 108162306a36Sopenharmony_ci} 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_cistatic void qede_periodic_task(struct work_struct *work) 108462306a36Sopenharmony_ci{ 108562306a36Sopenharmony_ci struct qede_dev *edev = container_of(work, struct qede_dev, 108662306a36Sopenharmony_ci periodic_task.work); 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci qede_fill_by_demand_stats(edev); 108962306a36Sopenharmony_ci schedule_delayed_work(&edev->periodic_task, edev->stats_coal_ticks); 109062306a36Sopenharmony_ci} 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_cistatic void qede_init_periodic_task(struct qede_dev *edev) 109362306a36Sopenharmony_ci{ 109462306a36Sopenharmony_ci INIT_DELAYED_WORK(&edev->periodic_task, qede_periodic_task); 109562306a36Sopenharmony_ci spin_lock_init(&edev->stats_lock); 109662306a36Sopenharmony_ci edev->stats_coal_usecs = USEC_PER_SEC; 109762306a36Sopenharmony_ci edev->stats_coal_ticks = usecs_to_jiffies(USEC_PER_SEC); 109862306a36Sopenharmony_ci} 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_cistatic void qede_sp_task(struct work_struct *work) 110162306a36Sopenharmony_ci{ 110262306a36Sopenharmony_ci struct qede_dev *edev = container_of(work, struct qede_dev, 110362306a36Sopenharmony_ci sp_task.work); 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci /* Disable execution of this deferred work once 110662306a36Sopenharmony_ci * qede removal is in progress, this stop any future 110762306a36Sopenharmony_ci * scheduling of sp_task. 110862306a36Sopenharmony_ci */ 110962306a36Sopenharmony_ci if (test_bit(QEDE_SP_DISABLE, &edev->sp_flags)) 111062306a36Sopenharmony_ci return; 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci /* The locking scheme depends on the specific flag: 111362306a36Sopenharmony_ci * In case of QEDE_SP_RECOVERY, acquiring the RTNL lock is required to 111462306a36Sopenharmony_ci * ensure that ongoing flows are ended and new ones are not started. 111562306a36Sopenharmony_ci * In other cases - only the internal qede lock should be acquired. 111662306a36Sopenharmony_ci */ 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci if (test_and_clear_bit(QEDE_SP_RECOVERY, &edev->sp_flags)) { 111962306a36Sopenharmony_ci cancel_delayed_work_sync(&edev->periodic_task); 112062306a36Sopenharmony_ci#ifdef CONFIG_QED_SRIOV 112162306a36Sopenharmony_ci /* SRIOV must be disabled outside the lock to avoid a deadlock. 112262306a36Sopenharmony_ci * The recovery of the active VFs is currently not supported. 112362306a36Sopenharmony_ci */ 112462306a36Sopenharmony_ci if (pci_num_vf(edev->pdev)) 112562306a36Sopenharmony_ci qede_sriov_configure(edev->pdev, 0); 112662306a36Sopenharmony_ci#endif 112762306a36Sopenharmony_ci qede_lock(edev); 112862306a36Sopenharmony_ci qede_recovery_handler(edev); 112962306a36Sopenharmony_ci qede_unlock(edev); 113062306a36Sopenharmony_ci } 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci __qede_lock(edev); 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci if (test_and_clear_bit(QEDE_SP_RX_MODE, &edev->sp_flags)) 113562306a36Sopenharmony_ci if (edev->state == QEDE_STATE_OPEN) 113662306a36Sopenharmony_ci qede_config_rx_mode(edev->ndev); 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 113962306a36Sopenharmony_ci if (test_and_clear_bit(QEDE_SP_ARFS_CONFIG, &edev->sp_flags)) { 114062306a36Sopenharmony_ci if (edev->state == QEDE_STATE_OPEN) 114162306a36Sopenharmony_ci qede_process_arfs_filters(edev, false); 114262306a36Sopenharmony_ci } 114362306a36Sopenharmony_ci#endif 114462306a36Sopenharmony_ci if (test_and_clear_bit(QEDE_SP_HW_ERR, &edev->sp_flags)) 114562306a36Sopenharmony_ci qede_generic_hw_err_handler(edev); 114662306a36Sopenharmony_ci __qede_unlock(edev); 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci if (test_and_clear_bit(QEDE_SP_AER, &edev->sp_flags)) { 114962306a36Sopenharmony_ci#ifdef CONFIG_QED_SRIOV 115062306a36Sopenharmony_ci /* SRIOV must be disabled outside the lock to avoid a deadlock. 115162306a36Sopenharmony_ci * The recovery of the active VFs is currently not supported. 115262306a36Sopenharmony_ci */ 115362306a36Sopenharmony_ci if (pci_num_vf(edev->pdev)) 115462306a36Sopenharmony_ci qede_sriov_configure(edev->pdev, 0); 115562306a36Sopenharmony_ci#endif 115662306a36Sopenharmony_ci edev->ops->common->recovery_process(edev->cdev); 115762306a36Sopenharmony_ci } 115862306a36Sopenharmony_ci} 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_cistatic void qede_update_pf_params(struct qed_dev *cdev) 116162306a36Sopenharmony_ci{ 116262306a36Sopenharmony_ci struct qed_pf_params pf_params; 116362306a36Sopenharmony_ci u16 num_cons; 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci /* 64 rx + 64 tx + 64 XDP */ 116662306a36Sopenharmony_ci memset(&pf_params, 0, sizeof(struct qed_pf_params)); 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci /* 1 rx + 1 xdp + max tx cos */ 116962306a36Sopenharmony_ci num_cons = QED_MIN_L2_CONS; 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci pf_params.eth_pf_params.num_cons = (MAX_SB_PER_PF_MIMD - 1) * num_cons; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci /* Same for VFs - make sure they'll have sufficient connections 117462306a36Sopenharmony_ci * to support XDP Tx queues. 117562306a36Sopenharmony_ci */ 117662306a36Sopenharmony_ci pf_params.eth_pf_params.num_vf_cons = 48; 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci pf_params.eth_pf_params.num_arfs_filters = QEDE_RFS_MAX_FLTR; 117962306a36Sopenharmony_ci qed_ops->common->update_pf_params(cdev, &pf_params); 118062306a36Sopenharmony_ci} 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci#define QEDE_FW_VER_STR_SIZE 80 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_cistatic void qede_log_probe(struct qede_dev *edev) 118562306a36Sopenharmony_ci{ 118662306a36Sopenharmony_ci struct qed_dev_info *p_dev_info = &edev->dev_info.common; 118762306a36Sopenharmony_ci u8 buf[QEDE_FW_VER_STR_SIZE]; 118862306a36Sopenharmony_ci size_t left_size; 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci snprintf(buf, QEDE_FW_VER_STR_SIZE, 119162306a36Sopenharmony_ci "Storm FW %d.%d.%d.%d, Management FW %d.%d.%d.%d", 119262306a36Sopenharmony_ci p_dev_info->fw_major, p_dev_info->fw_minor, p_dev_info->fw_rev, 119362306a36Sopenharmony_ci p_dev_info->fw_eng, 119462306a36Sopenharmony_ci (p_dev_info->mfw_rev & QED_MFW_VERSION_3_MASK) >> 119562306a36Sopenharmony_ci QED_MFW_VERSION_3_OFFSET, 119662306a36Sopenharmony_ci (p_dev_info->mfw_rev & QED_MFW_VERSION_2_MASK) >> 119762306a36Sopenharmony_ci QED_MFW_VERSION_2_OFFSET, 119862306a36Sopenharmony_ci (p_dev_info->mfw_rev & QED_MFW_VERSION_1_MASK) >> 119962306a36Sopenharmony_ci QED_MFW_VERSION_1_OFFSET, 120062306a36Sopenharmony_ci (p_dev_info->mfw_rev & QED_MFW_VERSION_0_MASK) >> 120162306a36Sopenharmony_ci QED_MFW_VERSION_0_OFFSET); 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci left_size = QEDE_FW_VER_STR_SIZE - strlen(buf); 120462306a36Sopenharmony_ci if (p_dev_info->mbi_version && left_size) 120562306a36Sopenharmony_ci snprintf(buf + strlen(buf), left_size, 120662306a36Sopenharmony_ci " [MBI %d.%d.%d]", 120762306a36Sopenharmony_ci (p_dev_info->mbi_version & QED_MBI_VERSION_2_MASK) >> 120862306a36Sopenharmony_ci QED_MBI_VERSION_2_OFFSET, 120962306a36Sopenharmony_ci (p_dev_info->mbi_version & QED_MBI_VERSION_1_MASK) >> 121062306a36Sopenharmony_ci QED_MBI_VERSION_1_OFFSET, 121162306a36Sopenharmony_ci (p_dev_info->mbi_version & QED_MBI_VERSION_0_MASK) >> 121262306a36Sopenharmony_ci QED_MBI_VERSION_0_OFFSET); 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci pr_info("qede %02x:%02x.%02x: %s [%s]\n", edev->pdev->bus->number, 121562306a36Sopenharmony_ci PCI_SLOT(edev->pdev->devfn), PCI_FUNC(edev->pdev->devfn), 121662306a36Sopenharmony_ci buf, edev->ndev->name); 121762306a36Sopenharmony_ci} 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_cienum qede_probe_mode { 122062306a36Sopenharmony_ci QEDE_PROBE_NORMAL, 122162306a36Sopenharmony_ci QEDE_PROBE_RECOVERY, 122262306a36Sopenharmony_ci}; 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_cistatic int __qede_probe(struct pci_dev *pdev, u32 dp_module, u8 dp_level, 122562306a36Sopenharmony_ci bool is_vf, enum qede_probe_mode mode) 122662306a36Sopenharmony_ci{ 122762306a36Sopenharmony_ci struct qed_probe_params probe_params; 122862306a36Sopenharmony_ci struct qed_slowpath_params sp_params; 122962306a36Sopenharmony_ci struct qed_dev_eth_info dev_info; 123062306a36Sopenharmony_ci struct qede_dev *edev; 123162306a36Sopenharmony_ci struct qed_dev *cdev; 123262306a36Sopenharmony_ci int rc; 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci if (unlikely(dp_level & QED_LEVEL_INFO)) 123562306a36Sopenharmony_ci pr_notice("Starting qede probe\n"); 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci memset(&probe_params, 0, sizeof(probe_params)); 123862306a36Sopenharmony_ci probe_params.protocol = QED_PROTOCOL_ETH; 123962306a36Sopenharmony_ci probe_params.dp_module = dp_module; 124062306a36Sopenharmony_ci probe_params.dp_level = dp_level; 124162306a36Sopenharmony_ci probe_params.is_vf = is_vf; 124262306a36Sopenharmony_ci probe_params.recov_in_prog = (mode == QEDE_PROBE_RECOVERY); 124362306a36Sopenharmony_ci cdev = qed_ops->common->probe(pdev, &probe_params); 124462306a36Sopenharmony_ci if (!cdev) { 124562306a36Sopenharmony_ci rc = -ENODEV; 124662306a36Sopenharmony_ci goto err0; 124762306a36Sopenharmony_ci } 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci qede_update_pf_params(cdev); 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci /* Start the Slowpath-process */ 125262306a36Sopenharmony_ci memset(&sp_params, 0, sizeof(sp_params)); 125362306a36Sopenharmony_ci sp_params.int_mode = QED_INT_MODE_MSIX; 125462306a36Sopenharmony_ci strscpy(sp_params.name, "qede LAN", QED_DRV_VER_STR_SIZE); 125562306a36Sopenharmony_ci rc = qed_ops->common->slowpath_start(cdev, &sp_params); 125662306a36Sopenharmony_ci if (rc) { 125762306a36Sopenharmony_ci pr_notice("Cannot start slowpath\n"); 125862306a36Sopenharmony_ci goto err1; 125962306a36Sopenharmony_ci } 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci /* Learn information crucial for qede to progress */ 126262306a36Sopenharmony_ci rc = qed_ops->fill_dev_info(cdev, &dev_info); 126362306a36Sopenharmony_ci if (rc) 126462306a36Sopenharmony_ci goto err2; 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci if (mode != QEDE_PROBE_RECOVERY) { 126762306a36Sopenharmony_ci edev = qede_alloc_etherdev(cdev, pdev, &dev_info, dp_module, 126862306a36Sopenharmony_ci dp_level); 126962306a36Sopenharmony_ci if (!edev) { 127062306a36Sopenharmony_ci rc = -ENOMEM; 127162306a36Sopenharmony_ci goto err2; 127262306a36Sopenharmony_ci } 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci edev->devlink = qed_ops->common->devlink_register(cdev); 127562306a36Sopenharmony_ci if (IS_ERR(edev->devlink)) { 127662306a36Sopenharmony_ci DP_NOTICE(edev, "Cannot register devlink\n"); 127762306a36Sopenharmony_ci rc = PTR_ERR(edev->devlink); 127862306a36Sopenharmony_ci edev->devlink = NULL; 127962306a36Sopenharmony_ci goto err3; 128062306a36Sopenharmony_ci } 128162306a36Sopenharmony_ci } else { 128262306a36Sopenharmony_ci struct net_device *ndev = pci_get_drvdata(pdev); 128362306a36Sopenharmony_ci struct qed_devlink *qdl; 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci edev = netdev_priv(ndev); 128662306a36Sopenharmony_ci qdl = devlink_priv(edev->devlink); 128762306a36Sopenharmony_ci qdl->cdev = cdev; 128862306a36Sopenharmony_ci edev->cdev = cdev; 128962306a36Sopenharmony_ci memset(&edev->stats, 0, sizeof(edev->stats)); 129062306a36Sopenharmony_ci memcpy(&edev->dev_info, &dev_info, sizeof(dev_info)); 129162306a36Sopenharmony_ci } 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci if (is_vf) 129462306a36Sopenharmony_ci set_bit(QEDE_FLAGS_IS_VF, &edev->flags); 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci qede_init_ndev(edev); 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci rc = qede_rdma_dev_add(edev, (mode == QEDE_PROBE_RECOVERY)); 129962306a36Sopenharmony_ci if (rc) 130062306a36Sopenharmony_ci goto err3; 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci if (mode != QEDE_PROBE_RECOVERY) { 130362306a36Sopenharmony_ci /* Prepare the lock prior to the registration of the netdev, 130462306a36Sopenharmony_ci * as once it's registered we might reach flows requiring it 130562306a36Sopenharmony_ci * [it's even possible to reach a flow needing it directly 130662306a36Sopenharmony_ci * from there, although it's unlikely]. 130762306a36Sopenharmony_ci */ 130862306a36Sopenharmony_ci INIT_DELAYED_WORK(&edev->sp_task, qede_sp_task); 130962306a36Sopenharmony_ci mutex_init(&edev->qede_lock); 131062306a36Sopenharmony_ci qede_init_periodic_task(edev); 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci rc = register_netdev(edev->ndev); 131362306a36Sopenharmony_ci if (rc) { 131462306a36Sopenharmony_ci DP_NOTICE(edev, "Cannot register net-device\n"); 131562306a36Sopenharmony_ci goto err4; 131662306a36Sopenharmony_ci } 131762306a36Sopenharmony_ci } 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci edev->ops->common->set_name(cdev, edev->ndev->name); 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci /* PTP not supported on VFs */ 132262306a36Sopenharmony_ci if (!is_vf) 132362306a36Sopenharmony_ci qede_ptp_enable(edev); 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci edev->ops->register_ops(cdev, &qede_ll_ops, edev); 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci#ifdef CONFIG_DCB 132862306a36Sopenharmony_ci if (!IS_VF(edev)) 132962306a36Sopenharmony_ci qede_set_dcbnl_ops(edev->ndev); 133062306a36Sopenharmony_ci#endif 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci edev->rx_copybreak = QEDE_RX_HDR_SIZE; 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci qede_log_probe(edev); 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci /* retain user config (for example - after recovery) */ 133762306a36Sopenharmony_ci if (edev->stats_coal_usecs) 133862306a36Sopenharmony_ci schedule_delayed_work(&edev->periodic_task, 0); 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci return 0; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_cierr4: 134362306a36Sopenharmony_ci qede_rdma_dev_remove(edev, (mode == QEDE_PROBE_RECOVERY)); 134462306a36Sopenharmony_cierr3: 134562306a36Sopenharmony_ci if (mode != QEDE_PROBE_RECOVERY) 134662306a36Sopenharmony_ci free_netdev(edev->ndev); 134762306a36Sopenharmony_ci else 134862306a36Sopenharmony_ci edev->cdev = NULL; 134962306a36Sopenharmony_cierr2: 135062306a36Sopenharmony_ci qed_ops->common->slowpath_stop(cdev); 135162306a36Sopenharmony_cierr1: 135262306a36Sopenharmony_ci qed_ops->common->remove(cdev); 135362306a36Sopenharmony_cierr0: 135462306a36Sopenharmony_ci return rc; 135562306a36Sopenharmony_ci} 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_cistatic int qede_probe(struct pci_dev *pdev, const struct pci_device_id *id) 135862306a36Sopenharmony_ci{ 135962306a36Sopenharmony_ci bool is_vf = false; 136062306a36Sopenharmony_ci u32 dp_module = 0; 136162306a36Sopenharmony_ci u8 dp_level = 0; 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci switch ((enum qede_pci_private)id->driver_data) { 136462306a36Sopenharmony_ci case QEDE_PRIVATE_VF: 136562306a36Sopenharmony_ci if (debug & QED_LOG_VERBOSE_MASK) 136662306a36Sopenharmony_ci dev_err(&pdev->dev, "Probing a VF\n"); 136762306a36Sopenharmony_ci is_vf = true; 136862306a36Sopenharmony_ci break; 136962306a36Sopenharmony_ci default: 137062306a36Sopenharmony_ci if (debug & QED_LOG_VERBOSE_MASK) 137162306a36Sopenharmony_ci dev_err(&pdev->dev, "Probing a PF\n"); 137262306a36Sopenharmony_ci } 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci qede_config_debug(debug, &dp_module, &dp_level); 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci return __qede_probe(pdev, dp_module, dp_level, is_vf, 137762306a36Sopenharmony_ci QEDE_PROBE_NORMAL); 137862306a36Sopenharmony_ci} 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_cienum qede_remove_mode { 138162306a36Sopenharmony_ci QEDE_REMOVE_NORMAL, 138262306a36Sopenharmony_ci QEDE_REMOVE_RECOVERY, 138362306a36Sopenharmony_ci}; 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_cistatic void __qede_remove(struct pci_dev *pdev, enum qede_remove_mode mode) 138662306a36Sopenharmony_ci{ 138762306a36Sopenharmony_ci struct net_device *ndev = pci_get_drvdata(pdev); 138862306a36Sopenharmony_ci struct qede_dev *edev; 138962306a36Sopenharmony_ci struct qed_dev *cdev; 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci if (!ndev) { 139262306a36Sopenharmony_ci dev_info(&pdev->dev, "Device has already been removed\n"); 139362306a36Sopenharmony_ci return; 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci edev = netdev_priv(ndev); 139762306a36Sopenharmony_ci cdev = edev->cdev; 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci DP_INFO(edev, "Starting qede_remove\n"); 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci qede_rdma_dev_remove(edev, (mode == QEDE_REMOVE_RECOVERY)); 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci if (mode != QEDE_REMOVE_RECOVERY) { 140462306a36Sopenharmony_ci set_bit(QEDE_SP_DISABLE, &edev->sp_flags); 140562306a36Sopenharmony_ci unregister_netdev(ndev); 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci cancel_delayed_work_sync(&edev->sp_task); 140862306a36Sopenharmony_ci cancel_delayed_work_sync(&edev->periodic_task); 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci edev->ops->common->set_power_state(cdev, PCI_D0); 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci pci_set_drvdata(pdev, NULL); 141362306a36Sopenharmony_ci } 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci qede_ptp_disable(edev); 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci /* Use global ops since we've freed edev */ 141862306a36Sopenharmony_ci qed_ops->common->slowpath_stop(cdev); 141962306a36Sopenharmony_ci if (system_state == SYSTEM_POWER_OFF) 142062306a36Sopenharmony_ci return; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci if (mode != QEDE_REMOVE_RECOVERY && edev->devlink) { 142362306a36Sopenharmony_ci qed_ops->common->devlink_unregister(edev->devlink); 142462306a36Sopenharmony_ci edev->devlink = NULL; 142562306a36Sopenharmony_ci } 142662306a36Sopenharmony_ci qed_ops->common->remove(cdev); 142762306a36Sopenharmony_ci edev->cdev = NULL; 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci /* Since this can happen out-of-sync with other flows, 143062306a36Sopenharmony_ci * don't release the netdevice until after slowpath stop 143162306a36Sopenharmony_ci * has been called to guarantee various other contexts 143262306a36Sopenharmony_ci * [e.g., QED register callbacks] won't break anything when 143362306a36Sopenharmony_ci * accessing the netdevice. 143462306a36Sopenharmony_ci */ 143562306a36Sopenharmony_ci if (mode != QEDE_REMOVE_RECOVERY) { 143662306a36Sopenharmony_ci kfree(edev->coal_entry); 143762306a36Sopenharmony_ci free_netdev(ndev); 143862306a36Sopenharmony_ci } 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci dev_info(&pdev->dev, "Ending qede_remove successfully\n"); 144162306a36Sopenharmony_ci} 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_cistatic void qede_remove(struct pci_dev *pdev) 144462306a36Sopenharmony_ci{ 144562306a36Sopenharmony_ci __qede_remove(pdev, QEDE_REMOVE_NORMAL); 144662306a36Sopenharmony_ci} 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_cistatic void qede_shutdown(struct pci_dev *pdev) 144962306a36Sopenharmony_ci{ 145062306a36Sopenharmony_ci __qede_remove(pdev, QEDE_REMOVE_NORMAL); 145162306a36Sopenharmony_ci} 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci/* ------------------------------------------------------------------------- 145462306a36Sopenharmony_ci * START OF LOAD / UNLOAD 145562306a36Sopenharmony_ci * ------------------------------------------------------------------------- 145662306a36Sopenharmony_ci */ 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_cistatic int qede_set_num_queues(struct qede_dev *edev) 145962306a36Sopenharmony_ci{ 146062306a36Sopenharmony_ci int rc; 146162306a36Sopenharmony_ci u16 rss_num; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci /* Setup queues according to possible resources*/ 146462306a36Sopenharmony_ci if (edev->req_queues) 146562306a36Sopenharmony_ci rss_num = edev->req_queues; 146662306a36Sopenharmony_ci else 146762306a36Sopenharmony_ci rss_num = netif_get_num_default_rss_queues() * 146862306a36Sopenharmony_ci edev->dev_info.common.num_hwfns; 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci rss_num = min_t(u16, QEDE_MAX_RSS_CNT(edev), rss_num); 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci rc = edev->ops->common->set_fp_int(edev->cdev, rss_num); 147362306a36Sopenharmony_ci if (rc > 0) { 147462306a36Sopenharmony_ci /* Managed to request interrupts for our queues */ 147562306a36Sopenharmony_ci edev->num_queues = rc; 147662306a36Sopenharmony_ci DP_INFO(edev, "Managed %d [of %d] RSS queues\n", 147762306a36Sopenharmony_ci QEDE_QUEUE_CNT(edev), rss_num); 147862306a36Sopenharmony_ci rc = 0; 147962306a36Sopenharmony_ci } 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci edev->fp_num_tx = edev->req_num_tx; 148262306a36Sopenharmony_ci edev->fp_num_rx = edev->req_num_rx; 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci return rc; 148562306a36Sopenharmony_ci} 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_cistatic void qede_free_mem_sb(struct qede_dev *edev, struct qed_sb_info *sb_info, 148862306a36Sopenharmony_ci u16 sb_id) 148962306a36Sopenharmony_ci{ 149062306a36Sopenharmony_ci if (sb_info->sb_virt) { 149162306a36Sopenharmony_ci edev->ops->common->sb_release(edev->cdev, sb_info, sb_id, 149262306a36Sopenharmony_ci QED_SB_TYPE_L2_QUEUE); 149362306a36Sopenharmony_ci dma_free_coherent(&edev->pdev->dev, sizeof(*sb_info->sb_virt), 149462306a36Sopenharmony_ci (void *)sb_info->sb_virt, sb_info->sb_phys); 149562306a36Sopenharmony_ci memset(sb_info, 0, sizeof(*sb_info)); 149662306a36Sopenharmony_ci } 149762306a36Sopenharmony_ci} 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci/* This function allocates fast-path status block memory */ 150062306a36Sopenharmony_cistatic int qede_alloc_mem_sb(struct qede_dev *edev, 150162306a36Sopenharmony_ci struct qed_sb_info *sb_info, u16 sb_id) 150262306a36Sopenharmony_ci{ 150362306a36Sopenharmony_ci struct status_block *sb_virt; 150462306a36Sopenharmony_ci dma_addr_t sb_phys; 150562306a36Sopenharmony_ci int rc; 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci sb_virt = dma_alloc_coherent(&edev->pdev->dev, 150862306a36Sopenharmony_ci sizeof(*sb_virt), &sb_phys, GFP_KERNEL); 150962306a36Sopenharmony_ci if (!sb_virt) { 151062306a36Sopenharmony_ci DP_ERR(edev, "Status block allocation failed\n"); 151162306a36Sopenharmony_ci return -ENOMEM; 151262306a36Sopenharmony_ci } 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci rc = edev->ops->common->sb_init(edev->cdev, sb_info, 151562306a36Sopenharmony_ci sb_virt, sb_phys, sb_id, 151662306a36Sopenharmony_ci QED_SB_TYPE_L2_QUEUE); 151762306a36Sopenharmony_ci if (rc) { 151862306a36Sopenharmony_ci DP_ERR(edev, "Status block initialization failed\n"); 151962306a36Sopenharmony_ci dma_free_coherent(&edev->pdev->dev, sizeof(*sb_virt), 152062306a36Sopenharmony_ci sb_virt, sb_phys); 152162306a36Sopenharmony_ci return rc; 152262306a36Sopenharmony_ci } 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci return 0; 152562306a36Sopenharmony_ci} 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_cistatic void qede_free_rx_buffers(struct qede_dev *edev, 152862306a36Sopenharmony_ci struct qede_rx_queue *rxq) 152962306a36Sopenharmony_ci{ 153062306a36Sopenharmony_ci u16 i; 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci for (i = rxq->sw_rx_cons; i != rxq->sw_rx_prod; i++) { 153362306a36Sopenharmony_ci struct sw_rx_data *rx_buf; 153462306a36Sopenharmony_ci struct page *data; 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci rx_buf = &rxq->sw_rx_ring[i & NUM_RX_BDS_MAX]; 153762306a36Sopenharmony_ci data = rx_buf->data; 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci dma_unmap_page(&edev->pdev->dev, 154062306a36Sopenharmony_ci rx_buf->mapping, PAGE_SIZE, rxq->data_direction); 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci rx_buf->data = NULL; 154362306a36Sopenharmony_ci __free_page(data); 154462306a36Sopenharmony_ci } 154562306a36Sopenharmony_ci} 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_cistatic void qede_free_mem_rxq(struct qede_dev *edev, struct qede_rx_queue *rxq) 154862306a36Sopenharmony_ci{ 154962306a36Sopenharmony_ci /* Free rx buffers */ 155062306a36Sopenharmony_ci qede_free_rx_buffers(edev, rxq); 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci /* Free the parallel SW ring */ 155362306a36Sopenharmony_ci kfree(rxq->sw_rx_ring); 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci /* Free the real RQ ring used by FW */ 155662306a36Sopenharmony_ci edev->ops->common->chain_free(edev->cdev, &rxq->rx_bd_ring); 155762306a36Sopenharmony_ci edev->ops->common->chain_free(edev->cdev, &rxq->rx_comp_ring); 155862306a36Sopenharmony_ci} 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_cistatic void qede_set_tpa_param(struct qede_rx_queue *rxq) 156162306a36Sopenharmony_ci{ 156262306a36Sopenharmony_ci int i; 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci for (i = 0; i < ETH_TPA_MAX_AGGS_NUM; i++) { 156562306a36Sopenharmony_ci struct qede_agg_info *tpa_info = &rxq->tpa_info[i]; 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci tpa_info->state = QEDE_AGG_STATE_NONE; 156862306a36Sopenharmony_ci } 156962306a36Sopenharmony_ci} 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci/* This function allocates all memory needed per Rx queue */ 157262306a36Sopenharmony_cistatic int qede_alloc_mem_rxq(struct qede_dev *edev, struct qede_rx_queue *rxq) 157362306a36Sopenharmony_ci{ 157462306a36Sopenharmony_ci struct qed_chain_init_params params = { 157562306a36Sopenharmony_ci .cnt_type = QED_CHAIN_CNT_TYPE_U16, 157662306a36Sopenharmony_ci .num_elems = RX_RING_SIZE, 157762306a36Sopenharmony_ci }; 157862306a36Sopenharmony_ci struct qed_dev *cdev = edev->cdev; 157962306a36Sopenharmony_ci int i, rc, size; 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci rxq->num_rx_buffers = edev->q_num_rx_buffers; 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci rxq->rx_buf_size = NET_IP_ALIGN + ETH_OVERHEAD + edev->ndev->mtu; 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci rxq->rx_headroom = edev->xdp_prog ? XDP_PACKET_HEADROOM : NET_SKB_PAD; 158662306a36Sopenharmony_ci size = rxq->rx_headroom + 158762306a36Sopenharmony_ci SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci /* Make sure that the headroom and payload fit in a single page */ 159062306a36Sopenharmony_ci if (rxq->rx_buf_size + size > PAGE_SIZE) 159162306a36Sopenharmony_ci rxq->rx_buf_size = PAGE_SIZE - size; 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci /* Segment size to split a page in multiple equal parts, 159462306a36Sopenharmony_ci * unless XDP is used in which case we'd use the entire page. 159562306a36Sopenharmony_ci */ 159662306a36Sopenharmony_ci if (!edev->xdp_prog) { 159762306a36Sopenharmony_ci size = size + rxq->rx_buf_size; 159862306a36Sopenharmony_ci rxq->rx_buf_seg_size = roundup_pow_of_two(size); 159962306a36Sopenharmony_ci } else { 160062306a36Sopenharmony_ci rxq->rx_buf_seg_size = PAGE_SIZE; 160162306a36Sopenharmony_ci edev->ndev->features &= ~NETIF_F_GRO_HW; 160262306a36Sopenharmony_ci } 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci /* Allocate the parallel driver ring for Rx buffers */ 160562306a36Sopenharmony_ci size = sizeof(*rxq->sw_rx_ring) * RX_RING_SIZE; 160662306a36Sopenharmony_ci rxq->sw_rx_ring = kzalloc(size, GFP_KERNEL); 160762306a36Sopenharmony_ci if (!rxq->sw_rx_ring) { 160862306a36Sopenharmony_ci DP_ERR(edev, "Rx buffers ring allocation failed\n"); 160962306a36Sopenharmony_ci rc = -ENOMEM; 161062306a36Sopenharmony_ci goto err; 161162306a36Sopenharmony_ci } 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci /* Allocate FW Rx ring */ 161462306a36Sopenharmony_ci params.mode = QED_CHAIN_MODE_NEXT_PTR; 161562306a36Sopenharmony_ci params.intended_use = QED_CHAIN_USE_TO_CONSUME_PRODUCE; 161662306a36Sopenharmony_ci params.elem_size = sizeof(struct eth_rx_bd); 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci rc = edev->ops->common->chain_alloc(cdev, &rxq->rx_bd_ring, ¶ms); 161962306a36Sopenharmony_ci if (rc) 162062306a36Sopenharmony_ci goto err; 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci /* Allocate FW completion ring */ 162362306a36Sopenharmony_ci params.mode = QED_CHAIN_MODE_PBL; 162462306a36Sopenharmony_ci params.intended_use = QED_CHAIN_USE_TO_CONSUME; 162562306a36Sopenharmony_ci params.elem_size = sizeof(union eth_rx_cqe); 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci rc = edev->ops->common->chain_alloc(cdev, &rxq->rx_comp_ring, ¶ms); 162862306a36Sopenharmony_ci if (rc) 162962306a36Sopenharmony_ci goto err; 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci /* Allocate buffers for the Rx ring */ 163262306a36Sopenharmony_ci rxq->filled_buffers = 0; 163362306a36Sopenharmony_ci for (i = 0; i < rxq->num_rx_buffers; i++) { 163462306a36Sopenharmony_ci rc = qede_alloc_rx_buffer(rxq, false); 163562306a36Sopenharmony_ci if (rc) { 163662306a36Sopenharmony_ci DP_ERR(edev, 163762306a36Sopenharmony_ci "Rx buffers allocation failed at index %d\n", i); 163862306a36Sopenharmony_ci goto err; 163962306a36Sopenharmony_ci } 164062306a36Sopenharmony_ci } 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci edev->gro_disable = !(edev->ndev->features & NETIF_F_GRO_HW); 164362306a36Sopenharmony_ci if (!edev->gro_disable) 164462306a36Sopenharmony_ci qede_set_tpa_param(rxq); 164562306a36Sopenharmony_cierr: 164662306a36Sopenharmony_ci return rc; 164762306a36Sopenharmony_ci} 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_cistatic void qede_free_mem_txq(struct qede_dev *edev, struct qede_tx_queue *txq) 165062306a36Sopenharmony_ci{ 165162306a36Sopenharmony_ci /* Free the parallel SW ring */ 165262306a36Sopenharmony_ci if (txq->is_xdp) 165362306a36Sopenharmony_ci kfree(txq->sw_tx_ring.xdp); 165462306a36Sopenharmony_ci else 165562306a36Sopenharmony_ci kfree(txq->sw_tx_ring.skbs); 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci /* Free the real RQ ring used by FW */ 165862306a36Sopenharmony_ci edev->ops->common->chain_free(edev->cdev, &txq->tx_pbl); 165962306a36Sopenharmony_ci} 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci/* This function allocates all memory needed per Tx queue */ 166262306a36Sopenharmony_cistatic int qede_alloc_mem_txq(struct qede_dev *edev, struct qede_tx_queue *txq) 166362306a36Sopenharmony_ci{ 166462306a36Sopenharmony_ci struct qed_chain_init_params params = { 166562306a36Sopenharmony_ci .mode = QED_CHAIN_MODE_PBL, 166662306a36Sopenharmony_ci .intended_use = QED_CHAIN_USE_TO_CONSUME_PRODUCE, 166762306a36Sopenharmony_ci .cnt_type = QED_CHAIN_CNT_TYPE_U16, 166862306a36Sopenharmony_ci .num_elems = edev->q_num_tx_buffers, 166962306a36Sopenharmony_ci .elem_size = sizeof(union eth_tx_bd_types), 167062306a36Sopenharmony_ci }; 167162306a36Sopenharmony_ci int size, rc; 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci txq->num_tx_buffers = edev->q_num_tx_buffers; 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci /* Allocate the parallel driver ring for Tx buffers */ 167662306a36Sopenharmony_ci if (txq->is_xdp) { 167762306a36Sopenharmony_ci size = sizeof(*txq->sw_tx_ring.xdp) * txq->num_tx_buffers; 167862306a36Sopenharmony_ci txq->sw_tx_ring.xdp = kzalloc(size, GFP_KERNEL); 167962306a36Sopenharmony_ci if (!txq->sw_tx_ring.xdp) 168062306a36Sopenharmony_ci goto err; 168162306a36Sopenharmony_ci } else { 168262306a36Sopenharmony_ci size = sizeof(*txq->sw_tx_ring.skbs) * txq->num_tx_buffers; 168362306a36Sopenharmony_ci txq->sw_tx_ring.skbs = kzalloc(size, GFP_KERNEL); 168462306a36Sopenharmony_ci if (!txq->sw_tx_ring.skbs) 168562306a36Sopenharmony_ci goto err; 168662306a36Sopenharmony_ci } 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci rc = edev->ops->common->chain_alloc(edev->cdev, &txq->tx_pbl, ¶ms); 168962306a36Sopenharmony_ci if (rc) 169062306a36Sopenharmony_ci goto err; 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci return 0; 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_cierr: 169562306a36Sopenharmony_ci qede_free_mem_txq(edev, txq); 169662306a36Sopenharmony_ci return -ENOMEM; 169762306a36Sopenharmony_ci} 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci/* This function frees all memory of a single fp */ 170062306a36Sopenharmony_cistatic void qede_free_mem_fp(struct qede_dev *edev, struct qede_fastpath *fp) 170162306a36Sopenharmony_ci{ 170262306a36Sopenharmony_ci qede_free_mem_sb(edev, fp->sb_info, fp->id); 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_RX) 170562306a36Sopenharmony_ci qede_free_mem_rxq(edev, fp->rxq); 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_XDP) 170862306a36Sopenharmony_ci qede_free_mem_txq(edev, fp->xdp_tx); 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_TX) { 171162306a36Sopenharmony_ci int cos; 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci for_each_cos_in_txq(edev, cos) 171462306a36Sopenharmony_ci qede_free_mem_txq(edev, &fp->txq[cos]); 171562306a36Sopenharmony_ci } 171662306a36Sopenharmony_ci} 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci/* This function allocates all memory needed for a single fp (i.e. an entity 171962306a36Sopenharmony_ci * which contains status block, one rx queue and/or multiple per-TC tx queues. 172062306a36Sopenharmony_ci */ 172162306a36Sopenharmony_cistatic int qede_alloc_mem_fp(struct qede_dev *edev, struct qede_fastpath *fp) 172262306a36Sopenharmony_ci{ 172362306a36Sopenharmony_ci int rc = 0; 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci rc = qede_alloc_mem_sb(edev, fp->sb_info, fp->id); 172662306a36Sopenharmony_ci if (rc) 172762306a36Sopenharmony_ci goto out; 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_RX) { 173062306a36Sopenharmony_ci rc = qede_alloc_mem_rxq(edev, fp->rxq); 173162306a36Sopenharmony_ci if (rc) 173262306a36Sopenharmony_ci goto out; 173362306a36Sopenharmony_ci } 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_XDP) { 173662306a36Sopenharmony_ci rc = qede_alloc_mem_txq(edev, fp->xdp_tx); 173762306a36Sopenharmony_ci if (rc) 173862306a36Sopenharmony_ci goto out; 173962306a36Sopenharmony_ci } 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_TX) { 174262306a36Sopenharmony_ci int cos; 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_ci for_each_cos_in_txq(edev, cos) { 174562306a36Sopenharmony_ci rc = qede_alloc_mem_txq(edev, &fp->txq[cos]); 174662306a36Sopenharmony_ci if (rc) 174762306a36Sopenharmony_ci goto out; 174862306a36Sopenharmony_ci } 174962306a36Sopenharmony_ci } 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ciout: 175262306a36Sopenharmony_ci return rc; 175362306a36Sopenharmony_ci} 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_cistatic void qede_free_mem_load(struct qede_dev *edev) 175662306a36Sopenharmony_ci{ 175762306a36Sopenharmony_ci int i; 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_ci for_each_queue(i) { 176062306a36Sopenharmony_ci struct qede_fastpath *fp = &edev->fp_array[i]; 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ci qede_free_mem_fp(edev, fp); 176362306a36Sopenharmony_ci } 176462306a36Sopenharmony_ci} 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_ci/* This function allocates all qede memory at NIC load. */ 176762306a36Sopenharmony_cistatic int qede_alloc_mem_load(struct qede_dev *edev) 176862306a36Sopenharmony_ci{ 176962306a36Sopenharmony_ci int rc = 0, queue_id; 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci for (queue_id = 0; queue_id < QEDE_QUEUE_CNT(edev); queue_id++) { 177262306a36Sopenharmony_ci struct qede_fastpath *fp = &edev->fp_array[queue_id]; 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci rc = qede_alloc_mem_fp(edev, fp); 177562306a36Sopenharmony_ci if (rc) { 177662306a36Sopenharmony_ci DP_ERR(edev, 177762306a36Sopenharmony_ci "Failed to allocate memory for fastpath - rss id = %d\n", 177862306a36Sopenharmony_ci queue_id); 177962306a36Sopenharmony_ci qede_free_mem_load(edev); 178062306a36Sopenharmony_ci return rc; 178162306a36Sopenharmony_ci } 178262306a36Sopenharmony_ci } 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci return 0; 178562306a36Sopenharmony_ci} 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_cistatic void qede_empty_tx_queue(struct qede_dev *edev, 178862306a36Sopenharmony_ci struct qede_tx_queue *txq) 178962306a36Sopenharmony_ci{ 179062306a36Sopenharmony_ci unsigned int pkts_compl = 0, bytes_compl = 0; 179162306a36Sopenharmony_ci struct netdev_queue *netdev_txq; 179262306a36Sopenharmony_ci int rc, len = 0; 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci netdev_txq = netdev_get_tx_queue(edev->ndev, txq->ndev_txq_id); 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci while (qed_chain_get_cons_idx(&txq->tx_pbl) != 179762306a36Sopenharmony_ci qed_chain_get_prod_idx(&txq->tx_pbl)) { 179862306a36Sopenharmony_ci DP_VERBOSE(edev, NETIF_MSG_IFDOWN, 179962306a36Sopenharmony_ci "Freeing a packet on tx queue[%d]: chain_cons 0x%x, chain_prod 0x%x\n", 180062306a36Sopenharmony_ci txq->index, qed_chain_get_cons_idx(&txq->tx_pbl), 180162306a36Sopenharmony_ci qed_chain_get_prod_idx(&txq->tx_pbl)); 180262306a36Sopenharmony_ci 180362306a36Sopenharmony_ci rc = qede_free_tx_pkt(edev, txq, &len); 180462306a36Sopenharmony_ci if (rc) { 180562306a36Sopenharmony_ci DP_NOTICE(edev, 180662306a36Sopenharmony_ci "Failed to free a packet on tx queue[%d]: chain_cons 0x%x, chain_prod 0x%x\n", 180762306a36Sopenharmony_ci txq->index, 180862306a36Sopenharmony_ci qed_chain_get_cons_idx(&txq->tx_pbl), 180962306a36Sopenharmony_ci qed_chain_get_prod_idx(&txq->tx_pbl)); 181062306a36Sopenharmony_ci break; 181162306a36Sopenharmony_ci } 181262306a36Sopenharmony_ci 181362306a36Sopenharmony_ci bytes_compl += len; 181462306a36Sopenharmony_ci pkts_compl++; 181562306a36Sopenharmony_ci txq->sw_tx_cons++; 181662306a36Sopenharmony_ci } 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci netdev_tx_completed_queue(netdev_txq, pkts_compl, bytes_compl); 181962306a36Sopenharmony_ci} 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_cistatic void qede_empty_tx_queues(struct qede_dev *edev) 182262306a36Sopenharmony_ci{ 182362306a36Sopenharmony_ci int i; 182462306a36Sopenharmony_ci 182562306a36Sopenharmony_ci for_each_queue(i) 182662306a36Sopenharmony_ci if (edev->fp_array[i].type & QEDE_FASTPATH_TX) { 182762306a36Sopenharmony_ci int cos; 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_ci for_each_cos_in_txq(edev, cos) { 183062306a36Sopenharmony_ci struct qede_fastpath *fp; 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_ci fp = &edev->fp_array[i]; 183362306a36Sopenharmony_ci qede_empty_tx_queue(edev, 183462306a36Sopenharmony_ci &fp->txq[cos]); 183562306a36Sopenharmony_ci } 183662306a36Sopenharmony_ci } 183762306a36Sopenharmony_ci} 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci/* This function inits fp content and resets the SB, RXQ and TXQ structures */ 184062306a36Sopenharmony_cistatic void qede_init_fp(struct qede_dev *edev) 184162306a36Sopenharmony_ci{ 184262306a36Sopenharmony_ci int queue_id, rxq_index = 0, txq_index = 0; 184362306a36Sopenharmony_ci struct qede_fastpath *fp; 184462306a36Sopenharmony_ci bool init_xdp = false; 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci for_each_queue(queue_id) { 184762306a36Sopenharmony_ci fp = &edev->fp_array[queue_id]; 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_ci fp->edev = edev; 185062306a36Sopenharmony_ci fp->id = queue_id; 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_XDP) { 185362306a36Sopenharmony_ci fp->xdp_tx->index = QEDE_TXQ_IDX_TO_XDP(edev, 185462306a36Sopenharmony_ci rxq_index); 185562306a36Sopenharmony_ci fp->xdp_tx->is_xdp = 1; 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci spin_lock_init(&fp->xdp_tx->xdp_tx_lock); 185862306a36Sopenharmony_ci init_xdp = true; 185962306a36Sopenharmony_ci } 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_RX) { 186262306a36Sopenharmony_ci fp->rxq->rxq_id = rxq_index++; 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci /* Determine how to map buffers for this queue */ 186562306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_XDP) 186662306a36Sopenharmony_ci fp->rxq->data_direction = DMA_BIDIRECTIONAL; 186762306a36Sopenharmony_ci else 186862306a36Sopenharmony_ci fp->rxq->data_direction = DMA_FROM_DEVICE; 186962306a36Sopenharmony_ci fp->rxq->dev = &edev->pdev->dev; 187062306a36Sopenharmony_ci 187162306a36Sopenharmony_ci /* Driver have no error path from here */ 187262306a36Sopenharmony_ci WARN_ON(xdp_rxq_info_reg(&fp->rxq->xdp_rxq, edev->ndev, 187362306a36Sopenharmony_ci fp->rxq->rxq_id, 0) < 0); 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_ci if (xdp_rxq_info_reg_mem_model(&fp->rxq->xdp_rxq, 187662306a36Sopenharmony_ci MEM_TYPE_PAGE_ORDER0, 187762306a36Sopenharmony_ci NULL)) { 187862306a36Sopenharmony_ci DP_NOTICE(edev, 187962306a36Sopenharmony_ci "Failed to register XDP memory model\n"); 188062306a36Sopenharmony_ci } 188162306a36Sopenharmony_ci } 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_TX) { 188462306a36Sopenharmony_ci int cos; 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci for_each_cos_in_txq(edev, cos) { 188762306a36Sopenharmony_ci struct qede_tx_queue *txq = &fp->txq[cos]; 188862306a36Sopenharmony_ci u16 ndev_tx_id; 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ci txq->cos = cos; 189162306a36Sopenharmony_ci txq->index = txq_index; 189262306a36Sopenharmony_ci ndev_tx_id = QEDE_TXQ_TO_NDEV_TXQ_ID(edev, txq); 189362306a36Sopenharmony_ci txq->ndev_txq_id = ndev_tx_id; 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci if (edev->dev_info.is_legacy) 189662306a36Sopenharmony_ci txq->is_legacy = true; 189762306a36Sopenharmony_ci txq->dev = &edev->pdev->dev; 189862306a36Sopenharmony_ci } 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci txq_index++; 190162306a36Sopenharmony_ci } 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci snprintf(fp->name, sizeof(fp->name), "%s-fp-%d", 190462306a36Sopenharmony_ci edev->ndev->name, queue_id); 190562306a36Sopenharmony_ci } 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci if (init_xdp) { 190862306a36Sopenharmony_ci edev->total_xdp_queues = QEDE_RSS_COUNT(edev); 190962306a36Sopenharmony_ci DP_INFO(edev, "Total XDP queues: %u\n", edev->total_xdp_queues); 191062306a36Sopenharmony_ci } 191162306a36Sopenharmony_ci} 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_cistatic int qede_set_real_num_queues(struct qede_dev *edev) 191462306a36Sopenharmony_ci{ 191562306a36Sopenharmony_ci int rc = 0; 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci rc = netif_set_real_num_tx_queues(edev->ndev, 191862306a36Sopenharmony_ci QEDE_TSS_COUNT(edev) * 191962306a36Sopenharmony_ci edev->dev_info.num_tc); 192062306a36Sopenharmony_ci if (rc) { 192162306a36Sopenharmony_ci DP_NOTICE(edev, "Failed to set real number of Tx queues\n"); 192262306a36Sopenharmony_ci return rc; 192362306a36Sopenharmony_ci } 192462306a36Sopenharmony_ci 192562306a36Sopenharmony_ci rc = netif_set_real_num_rx_queues(edev->ndev, QEDE_RSS_COUNT(edev)); 192662306a36Sopenharmony_ci if (rc) { 192762306a36Sopenharmony_ci DP_NOTICE(edev, "Failed to set real number of Rx queues\n"); 192862306a36Sopenharmony_ci return rc; 192962306a36Sopenharmony_ci } 193062306a36Sopenharmony_ci 193162306a36Sopenharmony_ci return 0; 193262306a36Sopenharmony_ci} 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_cistatic void qede_napi_disable_remove(struct qede_dev *edev) 193562306a36Sopenharmony_ci{ 193662306a36Sopenharmony_ci int i; 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_ci for_each_queue(i) { 193962306a36Sopenharmony_ci napi_disable(&edev->fp_array[i].napi); 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ci netif_napi_del(&edev->fp_array[i].napi); 194262306a36Sopenharmony_ci } 194362306a36Sopenharmony_ci} 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_cistatic void qede_napi_add_enable(struct qede_dev *edev) 194662306a36Sopenharmony_ci{ 194762306a36Sopenharmony_ci int i; 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci /* Add NAPI objects */ 195062306a36Sopenharmony_ci for_each_queue(i) { 195162306a36Sopenharmony_ci netif_napi_add(edev->ndev, &edev->fp_array[i].napi, qede_poll); 195262306a36Sopenharmony_ci napi_enable(&edev->fp_array[i].napi); 195362306a36Sopenharmony_ci } 195462306a36Sopenharmony_ci} 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_cistatic void qede_sync_free_irqs(struct qede_dev *edev) 195762306a36Sopenharmony_ci{ 195862306a36Sopenharmony_ci int i; 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_ci for (i = 0; i < edev->int_info.used_cnt; i++) { 196162306a36Sopenharmony_ci if (edev->int_info.msix_cnt) { 196262306a36Sopenharmony_ci free_irq(edev->int_info.msix[i].vector, 196362306a36Sopenharmony_ci &edev->fp_array[i]); 196462306a36Sopenharmony_ci } else { 196562306a36Sopenharmony_ci edev->ops->common->simd_handler_clean(edev->cdev, i); 196662306a36Sopenharmony_ci } 196762306a36Sopenharmony_ci } 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_ci edev->int_info.used_cnt = 0; 197062306a36Sopenharmony_ci edev->int_info.msix_cnt = 0; 197162306a36Sopenharmony_ci} 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_cistatic int qede_req_msix_irqs(struct qede_dev *edev) 197462306a36Sopenharmony_ci{ 197562306a36Sopenharmony_ci int i, rc; 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_ci /* Sanitize number of interrupts == number of prepared RSS queues */ 197862306a36Sopenharmony_ci if (QEDE_QUEUE_CNT(edev) > edev->int_info.msix_cnt) { 197962306a36Sopenharmony_ci DP_ERR(edev, 198062306a36Sopenharmony_ci "Interrupt mismatch: %d RSS queues > %d MSI-x vectors\n", 198162306a36Sopenharmony_ci QEDE_QUEUE_CNT(edev), edev->int_info.msix_cnt); 198262306a36Sopenharmony_ci return -EINVAL; 198362306a36Sopenharmony_ci } 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_ci for (i = 0; i < QEDE_QUEUE_CNT(edev); i++) { 198662306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 198762306a36Sopenharmony_ci struct qede_fastpath *fp = &edev->fp_array[i]; 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci if (edev->ndev->rx_cpu_rmap && (fp->type & QEDE_FASTPATH_RX)) { 199062306a36Sopenharmony_ci rc = irq_cpu_rmap_add(edev->ndev->rx_cpu_rmap, 199162306a36Sopenharmony_ci edev->int_info.msix[i].vector); 199262306a36Sopenharmony_ci if (rc) { 199362306a36Sopenharmony_ci DP_ERR(edev, "Failed to add CPU rmap\n"); 199462306a36Sopenharmony_ci qede_free_arfs(edev); 199562306a36Sopenharmony_ci } 199662306a36Sopenharmony_ci } 199762306a36Sopenharmony_ci#endif 199862306a36Sopenharmony_ci rc = request_irq(edev->int_info.msix[i].vector, 199962306a36Sopenharmony_ci qede_msix_fp_int, 0, edev->fp_array[i].name, 200062306a36Sopenharmony_ci &edev->fp_array[i]); 200162306a36Sopenharmony_ci if (rc) { 200262306a36Sopenharmony_ci DP_ERR(edev, "Request fp %d irq failed\n", i); 200362306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 200462306a36Sopenharmony_ci if (edev->ndev->rx_cpu_rmap) 200562306a36Sopenharmony_ci free_irq_cpu_rmap(edev->ndev->rx_cpu_rmap); 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci edev->ndev->rx_cpu_rmap = NULL; 200862306a36Sopenharmony_ci#endif 200962306a36Sopenharmony_ci qede_sync_free_irqs(edev); 201062306a36Sopenharmony_ci return rc; 201162306a36Sopenharmony_ci } 201262306a36Sopenharmony_ci DP_VERBOSE(edev, NETIF_MSG_INTR, 201362306a36Sopenharmony_ci "Requested fp irq for %s [entry %d]. Cookie is at %p\n", 201462306a36Sopenharmony_ci edev->fp_array[i].name, i, 201562306a36Sopenharmony_ci &edev->fp_array[i]); 201662306a36Sopenharmony_ci edev->int_info.used_cnt++; 201762306a36Sopenharmony_ci } 201862306a36Sopenharmony_ci 201962306a36Sopenharmony_ci return 0; 202062306a36Sopenharmony_ci} 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_cistatic void qede_simd_fp_handler(void *cookie) 202362306a36Sopenharmony_ci{ 202462306a36Sopenharmony_ci struct qede_fastpath *fp = (struct qede_fastpath *)cookie; 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_ci napi_schedule_irqoff(&fp->napi); 202762306a36Sopenharmony_ci} 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_cistatic int qede_setup_irqs(struct qede_dev *edev) 203062306a36Sopenharmony_ci{ 203162306a36Sopenharmony_ci int i, rc = 0; 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_ci /* Learn Interrupt configuration */ 203462306a36Sopenharmony_ci rc = edev->ops->common->get_fp_int(edev->cdev, &edev->int_info); 203562306a36Sopenharmony_ci if (rc) 203662306a36Sopenharmony_ci return rc; 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ci if (edev->int_info.msix_cnt) { 203962306a36Sopenharmony_ci rc = qede_req_msix_irqs(edev); 204062306a36Sopenharmony_ci if (rc) 204162306a36Sopenharmony_ci return rc; 204262306a36Sopenharmony_ci edev->ndev->irq = edev->int_info.msix[0].vector; 204362306a36Sopenharmony_ci } else { 204462306a36Sopenharmony_ci const struct qed_common_ops *ops; 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_ci /* qed should learn receive the RSS ids and callbacks */ 204762306a36Sopenharmony_ci ops = edev->ops->common; 204862306a36Sopenharmony_ci for (i = 0; i < QEDE_QUEUE_CNT(edev); i++) 204962306a36Sopenharmony_ci ops->simd_handler_config(edev->cdev, 205062306a36Sopenharmony_ci &edev->fp_array[i], i, 205162306a36Sopenharmony_ci qede_simd_fp_handler); 205262306a36Sopenharmony_ci edev->int_info.used_cnt = QEDE_QUEUE_CNT(edev); 205362306a36Sopenharmony_ci } 205462306a36Sopenharmony_ci return 0; 205562306a36Sopenharmony_ci} 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_cistatic int qede_drain_txq(struct qede_dev *edev, 205862306a36Sopenharmony_ci struct qede_tx_queue *txq, bool allow_drain) 205962306a36Sopenharmony_ci{ 206062306a36Sopenharmony_ci int rc, cnt = 1000; 206162306a36Sopenharmony_ci 206262306a36Sopenharmony_ci while (txq->sw_tx_cons != txq->sw_tx_prod) { 206362306a36Sopenharmony_ci if (!cnt) { 206462306a36Sopenharmony_ci if (allow_drain) { 206562306a36Sopenharmony_ci DP_NOTICE(edev, 206662306a36Sopenharmony_ci "Tx queue[%d] is stuck, requesting MCP to drain\n", 206762306a36Sopenharmony_ci txq->index); 206862306a36Sopenharmony_ci rc = edev->ops->common->drain(edev->cdev); 206962306a36Sopenharmony_ci if (rc) 207062306a36Sopenharmony_ci return rc; 207162306a36Sopenharmony_ci return qede_drain_txq(edev, txq, false); 207262306a36Sopenharmony_ci } 207362306a36Sopenharmony_ci DP_NOTICE(edev, 207462306a36Sopenharmony_ci "Timeout waiting for tx queue[%d]: PROD=%d, CONS=%d\n", 207562306a36Sopenharmony_ci txq->index, txq->sw_tx_prod, 207662306a36Sopenharmony_ci txq->sw_tx_cons); 207762306a36Sopenharmony_ci return -ENODEV; 207862306a36Sopenharmony_ci } 207962306a36Sopenharmony_ci cnt--; 208062306a36Sopenharmony_ci usleep_range(1000, 2000); 208162306a36Sopenharmony_ci barrier(); 208262306a36Sopenharmony_ci } 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_ci /* FW finished processing, wait for HW to transmit all tx packets */ 208562306a36Sopenharmony_ci usleep_range(1000, 2000); 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_ci return 0; 208862306a36Sopenharmony_ci} 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_cistatic int qede_stop_txq(struct qede_dev *edev, 209162306a36Sopenharmony_ci struct qede_tx_queue *txq, int rss_id) 209262306a36Sopenharmony_ci{ 209362306a36Sopenharmony_ci /* delete doorbell from doorbell recovery mechanism */ 209462306a36Sopenharmony_ci edev->ops->common->db_recovery_del(edev->cdev, txq->doorbell_addr, 209562306a36Sopenharmony_ci &txq->tx_db); 209662306a36Sopenharmony_ci 209762306a36Sopenharmony_ci return edev->ops->q_tx_stop(edev->cdev, rss_id, txq->handle); 209862306a36Sopenharmony_ci} 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_cistatic int qede_stop_queues(struct qede_dev *edev) 210162306a36Sopenharmony_ci{ 210262306a36Sopenharmony_ci struct qed_update_vport_params *vport_update_params; 210362306a36Sopenharmony_ci struct qed_dev *cdev = edev->cdev; 210462306a36Sopenharmony_ci struct qede_fastpath *fp; 210562306a36Sopenharmony_ci int rc, i; 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci /* Disable the vport */ 210862306a36Sopenharmony_ci vport_update_params = vzalloc(sizeof(*vport_update_params)); 210962306a36Sopenharmony_ci if (!vport_update_params) 211062306a36Sopenharmony_ci return -ENOMEM; 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_ci vport_update_params->vport_id = 0; 211362306a36Sopenharmony_ci vport_update_params->update_vport_active_flg = 1; 211462306a36Sopenharmony_ci vport_update_params->vport_active_flg = 0; 211562306a36Sopenharmony_ci vport_update_params->update_rss_flg = 0; 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci rc = edev->ops->vport_update(cdev, vport_update_params); 211862306a36Sopenharmony_ci vfree(vport_update_params); 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_ci if (rc) { 212162306a36Sopenharmony_ci DP_ERR(edev, "Failed to update vport\n"); 212262306a36Sopenharmony_ci return rc; 212362306a36Sopenharmony_ci } 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_ci /* Flush Tx queues. If needed, request drain from MCP */ 212662306a36Sopenharmony_ci for_each_queue(i) { 212762306a36Sopenharmony_ci fp = &edev->fp_array[i]; 212862306a36Sopenharmony_ci 212962306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_TX) { 213062306a36Sopenharmony_ci int cos; 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_ci for_each_cos_in_txq(edev, cos) { 213362306a36Sopenharmony_ci rc = qede_drain_txq(edev, &fp->txq[cos], true); 213462306a36Sopenharmony_ci if (rc) 213562306a36Sopenharmony_ci return rc; 213662306a36Sopenharmony_ci } 213762306a36Sopenharmony_ci } 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_XDP) { 214062306a36Sopenharmony_ci rc = qede_drain_txq(edev, fp->xdp_tx, true); 214162306a36Sopenharmony_ci if (rc) 214262306a36Sopenharmony_ci return rc; 214362306a36Sopenharmony_ci } 214462306a36Sopenharmony_ci } 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci /* Stop all Queues in reverse order */ 214762306a36Sopenharmony_ci for (i = QEDE_QUEUE_CNT(edev) - 1; i >= 0; i--) { 214862306a36Sopenharmony_ci fp = &edev->fp_array[i]; 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_ci /* Stop the Tx Queue(s) */ 215162306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_TX) { 215262306a36Sopenharmony_ci int cos; 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ci for_each_cos_in_txq(edev, cos) { 215562306a36Sopenharmony_ci rc = qede_stop_txq(edev, &fp->txq[cos], i); 215662306a36Sopenharmony_ci if (rc) 215762306a36Sopenharmony_ci return rc; 215862306a36Sopenharmony_ci } 215962306a36Sopenharmony_ci } 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_ci /* Stop the Rx Queue */ 216262306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_RX) { 216362306a36Sopenharmony_ci rc = edev->ops->q_rx_stop(cdev, i, fp->rxq->handle); 216462306a36Sopenharmony_ci if (rc) { 216562306a36Sopenharmony_ci DP_ERR(edev, "Failed to stop RXQ #%d\n", i); 216662306a36Sopenharmony_ci return rc; 216762306a36Sopenharmony_ci } 216862306a36Sopenharmony_ci } 216962306a36Sopenharmony_ci 217062306a36Sopenharmony_ci /* Stop the XDP forwarding queue */ 217162306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_XDP) { 217262306a36Sopenharmony_ci rc = qede_stop_txq(edev, fp->xdp_tx, i); 217362306a36Sopenharmony_ci if (rc) 217462306a36Sopenharmony_ci return rc; 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci bpf_prog_put(fp->rxq->xdp_prog); 217762306a36Sopenharmony_ci } 217862306a36Sopenharmony_ci } 217962306a36Sopenharmony_ci 218062306a36Sopenharmony_ci /* Stop the vport */ 218162306a36Sopenharmony_ci rc = edev->ops->vport_stop(cdev, 0); 218262306a36Sopenharmony_ci if (rc) 218362306a36Sopenharmony_ci DP_ERR(edev, "Failed to stop VPORT\n"); 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ci return rc; 218662306a36Sopenharmony_ci} 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_cistatic int qede_start_txq(struct qede_dev *edev, 218962306a36Sopenharmony_ci struct qede_fastpath *fp, 219062306a36Sopenharmony_ci struct qede_tx_queue *txq, u8 rss_id, u16 sb_idx) 219162306a36Sopenharmony_ci{ 219262306a36Sopenharmony_ci dma_addr_t phys_table = qed_chain_get_pbl_phys(&txq->tx_pbl); 219362306a36Sopenharmony_ci u32 page_cnt = qed_chain_get_page_cnt(&txq->tx_pbl); 219462306a36Sopenharmony_ci struct qed_queue_start_common_params params; 219562306a36Sopenharmony_ci struct qed_txq_start_ret_params ret_params; 219662306a36Sopenharmony_ci int rc; 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 219962306a36Sopenharmony_ci memset(&ret_params, 0, sizeof(ret_params)); 220062306a36Sopenharmony_ci 220162306a36Sopenharmony_ci /* Let the XDP queue share the queue-zone with one of the regular txq. 220262306a36Sopenharmony_ci * We don't really care about its coalescing. 220362306a36Sopenharmony_ci */ 220462306a36Sopenharmony_ci if (txq->is_xdp) 220562306a36Sopenharmony_ci params.queue_id = QEDE_TXQ_XDP_TO_IDX(edev, txq); 220662306a36Sopenharmony_ci else 220762306a36Sopenharmony_ci params.queue_id = txq->index; 220862306a36Sopenharmony_ci 220962306a36Sopenharmony_ci params.p_sb = fp->sb_info; 221062306a36Sopenharmony_ci params.sb_idx = sb_idx; 221162306a36Sopenharmony_ci params.tc = txq->cos; 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci rc = edev->ops->q_tx_start(edev->cdev, rss_id, ¶ms, phys_table, 221462306a36Sopenharmony_ci page_cnt, &ret_params); 221562306a36Sopenharmony_ci if (rc) { 221662306a36Sopenharmony_ci DP_ERR(edev, "Start TXQ #%d failed %d\n", txq->index, rc); 221762306a36Sopenharmony_ci return rc; 221862306a36Sopenharmony_ci } 221962306a36Sopenharmony_ci 222062306a36Sopenharmony_ci txq->doorbell_addr = ret_params.p_doorbell; 222162306a36Sopenharmony_ci txq->handle = ret_params.p_handle; 222262306a36Sopenharmony_ci 222362306a36Sopenharmony_ci /* Determine the FW consumer address associated */ 222462306a36Sopenharmony_ci txq->hw_cons_ptr = &fp->sb_info->sb_virt->pi_array[sb_idx]; 222562306a36Sopenharmony_ci 222662306a36Sopenharmony_ci /* Prepare the doorbell parameters */ 222762306a36Sopenharmony_ci SET_FIELD(txq->tx_db.data.params, ETH_DB_DATA_DEST, DB_DEST_XCM); 222862306a36Sopenharmony_ci SET_FIELD(txq->tx_db.data.params, ETH_DB_DATA_AGG_CMD, DB_AGG_CMD_SET); 222962306a36Sopenharmony_ci SET_FIELD(txq->tx_db.data.params, ETH_DB_DATA_AGG_VAL_SEL, 223062306a36Sopenharmony_ci DQ_XCM_ETH_TX_BD_PROD_CMD); 223162306a36Sopenharmony_ci txq->tx_db.data.agg_flags = DQ_XCM_ETH_DQ_CF_CMD; 223262306a36Sopenharmony_ci 223362306a36Sopenharmony_ci /* register doorbell with doorbell recovery mechanism */ 223462306a36Sopenharmony_ci rc = edev->ops->common->db_recovery_add(edev->cdev, txq->doorbell_addr, 223562306a36Sopenharmony_ci &txq->tx_db, DB_REC_WIDTH_32B, 223662306a36Sopenharmony_ci DB_REC_KERNEL); 223762306a36Sopenharmony_ci 223862306a36Sopenharmony_ci return rc; 223962306a36Sopenharmony_ci} 224062306a36Sopenharmony_ci 224162306a36Sopenharmony_cistatic int qede_start_queues(struct qede_dev *edev, bool clear_stats) 224262306a36Sopenharmony_ci{ 224362306a36Sopenharmony_ci int vlan_removal_en = 1; 224462306a36Sopenharmony_ci struct qed_dev *cdev = edev->cdev; 224562306a36Sopenharmony_ci struct qed_dev_info *qed_info = &edev->dev_info.common; 224662306a36Sopenharmony_ci struct qed_update_vport_params *vport_update_params; 224762306a36Sopenharmony_ci struct qed_queue_start_common_params q_params; 224862306a36Sopenharmony_ci struct qed_start_vport_params start = {0}; 224962306a36Sopenharmony_ci int rc, i; 225062306a36Sopenharmony_ci 225162306a36Sopenharmony_ci if (!edev->num_queues) { 225262306a36Sopenharmony_ci DP_ERR(edev, 225362306a36Sopenharmony_ci "Cannot update V-VPORT as active as there are no Rx queues\n"); 225462306a36Sopenharmony_ci return -EINVAL; 225562306a36Sopenharmony_ci } 225662306a36Sopenharmony_ci 225762306a36Sopenharmony_ci vport_update_params = vzalloc(sizeof(*vport_update_params)); 225862306a36Sopenharmony_ci if (!vport_update_params) 225962306a36Sopenharmony_ci return -ENOMEM; 226062306a36Sopenharmony_ci 226162306a36Sopenharmony_ci start.handle_ptp_pkts = !!(edev->ptp); 226262306a36Sopenharmony_ci start.gro_enable = !edev->gro_disable; 226362306a36Sopenharmony_ci start.mtu = edev->ndev->mtu; 226462306a36Sopenharmony_ci start.vport_id = 0; 226562306a36Sopenharmony_ci start.drop_ttl0 = true; 226662306a36Sopenharmony_ci start.remove_inner_vlan = vlan_removal_en; 226762306a36Sopenharmony_ci start.clear_stats = clear_stats; 226862306a36Sopenharmony_ci 226962306a36Sopenharmony_ci rc = edev->ops->vport_start(cdev, &start); 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci if (rc) { 227262306a36Sopenharmony_ci DP_ERR(edev, "Start V-PORT failed %d\n", rc); 227362306a36Sopenharmony_ci goto out; 227462306a36Sopenharmony_ci } 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_ci DP_VERBOSE(edev, NETIF_MSG_IFUP, 227762306a36Sopenharmony_ci "Start vport ramrod passed, vport_id = %d, MTU = %d, vlan_removal_en = %d\n", 227862306a36Sopenharmony_ci start.vport_id, edev->ndev->mtu + 0xe, vlan_removal_en); 227962306a36Sopenharmony_ci 228062306a36Sopenharmony_ci for_each_queue(i) { 228162306a36Sopenharmony_ci struct qede_fastpath *fp = &edev->fp_array[i]; 228262306a36Sopenharmony_ci dma_addr_t p_phys_table; 228362306a36Sopenharmony_ci u32 page_cnt; 228462306a36Sopenharmony_ci 228562306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_RX) { 228662306a36Sopenharmony_ci struct qed_rxq_start_ret_params ret_params; 228762306a36Sopenharmony_ci struct qede_rx_queue *rxq = fp->rxq; 228862306a36Sopenharmony_ci __le16 *val; 228962306a36Sopenharmony_ci 229062306a36Sopenharmony_ci memset(&ret_params, 0, sizeof(ret_params)); 229162306a36Sopenharmony_ci memset(&q_params, 0, sizeof(q_params)); 229262306a36Sopenharmony_ci q_params.queue_id = rxq->rxq_id; 229362306a36Sopenharmony_ci q_params.vport_id = 0; 229462306a36Sopenharmony_ci q_params.p_sb = fp->sb_info; 229562306a36Sopenharmony_ci q_params.sb_idx = RX_PI; 229662306a36Sopenharmony_ci 229762306a36Sopenharmony_ci p_phys_table = 229862306a36Sopenharmony_ci qed_chain_get_pbl_phys(&rxq->rx_comp_ring); 229962306a36Sopenharmony_ci page_cnt = qed_chain_get_page_cnt(&rxq->rx_comp_ring); 230062306a36Sopenharmony_ci 230162306a36Sopenharmony_ci rc = edev->ops->q_rx_start(cdev, i, &q_params, 230262306a36Sopenharmony_ci rxq->rx_buf_size, 230362306a36Sopenharmony_ci rxq->rx_bd_ring.p_phys_addr, 230462306a36Sopenharmony_ci p_phys_table, 230562306a36Sopenharmony_ci page_cnt, &ret_params); 230662306a36Sopenharmony_ci if (rc) { 230762306a36Sopenharmony_ci DP_ERR(edev, "Start RXQ #%d failed %d\n", i, 230862306a36Sopenharmony_ci rc); 230962306a36Sopenharmony_ci goto out; 231062306a36Sopenharmony_ci } 231162306a36Sopenharmony_ci 231262306a36Sopenharmony_ci /* Use the return parameters */ 231362306a36Sopenharmony_ci rxq->hw_rxq_prod_addr = ret_params.p_prod; 231462306a36Sopenharmony_ci rxq->handle = ret_params.p_handle; 231562306a36Sopenharmony_ci 231662306a36Sopenharmony_ci val = &fp->sb_info->sb_virt->pi_array[RX_PI]; 231762306a36Sopenharmony_ci rxq->hw_cons_ptr = val; 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci qede_update_rx_prod(edev, rxq); 232062306a36Sopenharmony_ci } 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_XDP) { 232362306a36Sopenharmony_ci rc = qede_start_txq(edev, fp, fp->xdp_tx, i, XDP_PI); 232462306a36Sopenharmony_ci if (rc) 232562306a36Sopenharmony_ci goto out; 232662306a36Sopenharmony_ci 232762306a36Sopenharmony_ci bpf_prog_add(edev->xdp_prog, 1); 232862306a36Sopenharmony_ci fp->rxq->xdp_prog = edev->xdp_prog; 232962306a36Sopenharmony_ci } 233062306a36Sopenharmony_ci 233162306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_TX) { 233262306a36Sopenharmony_ci int cos; 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci for_each_cos_in_txq(edev, cos) { 233562306a36Sopenharmony_ci rc = qede_start_txq(edev, fp, &fp->txq[cos], i, 233662306a36Sopenharmony_ci TX_PI(cos)); 233762306a36Sopenharmony_ci if (rc) 233862306a36Sopenharmony_ci goto out; 233962306a36Sopenharmony_ci } 234062306a36Sopenharmony_ci } 234162306a36Sopenharmony_ci } 234262306a36Sopenharmony_ci 234362306a36Sopenharmony_ci /* Prepare and send the vport enable */ 234462306a36Sopenharmony_ci vport_update_params->vport_id = start.vport_id; 234562306a36Sopenharmony_ci vport_update_params->update_vport_active_flg = 1; 234662306a36Sopenharmony_ci vport_update_params->vport_active_flg = 1; 234762306a36Sopenharmony_ci 234862306a36Sopenharmony_ci if ((qed_info->b_inter_pf_switch || pci_num_vf(edev->pdev)) && 234962306a36Sopenharmony_ci qed_info->tx_switching) { 235062306a36Sopenharmony_ci vport_update_params->update_tx_switching_flg = 1; 235162306a36Sopenharmony_ci vport_update_params->tx_switching_flg = 1; 235262306a36Sopenharmony_ci } 235362306a36Sopenharmony_ci 235462306a36Sopenharmony_ci qede_fill_rss_params(edev, &vport_update_params->rss_params, 235562306a36Sopenharmony_ci &vport_update_params->update_rss_flg); 235662306a36Sopenharmony_ci 235762306a36Sopenharmony_ci rc = edev->ops->vport_update(cdev, vport_update_params); 235862306a36Sopenharmony_ci if (rc) 235962306a36Sopenharmony_ci DP_ERR(edev, "Update V-PORT failed %d\n", rc); 236062306a36Sopenharmony_ci 236162306a36Sopenharmony_ciout: 236262306a36Sopenharmony_ci vfree(vport_update_params); 236362306a36Sopenharmony_ci return rc; 236462306a36Sopenharmony_ci} 236562306a36Sopenharmony_ci 236662306a36Sopenharmony_cienum qede_unload_mode { 236762306a36Sopenharmony_ci QEDE_UNLOAD_NORMAL, 236862306a36Sopenharmony_ci QEDE_UNLOAD_RECOVERY, 236962306a36Sopenharmony_ci}; 237062306a36Sopenharmony_ci 237162306a36Sopenharmony_cistatic void qede_unload(struct qede_dev *edev, enum qede_unload_mode mode, 237262306a36Sopenharmony_ci bool is_locked) 237362306a36Sopenharmony_ci{ 237462306a36Sopenharmony_ci struct qed_link_params link_params; 237562306a36Sopenharmony_ci int rc; 237662306a36Sopenharmony_ci 237762306a36Sopenharmony_ci DP_INFO(edev, "Starting qede unload\n"); 237862306a36Sopenharmony_ci 237962306a36Sopenharmony_ci if (!is_locked) 238062306a36Sopenharmony_ci __qede_lock(edev); 238162306a36Sopenharmony_ci 238262306a36Sopenharmony_ci clear_bit(QEDE_FLAGS_LINK_REQUESTED, &edev->flags); 238362306a36Sopenharmony_ci 238462306a36Sopenharmony_ci if (mode != QEDE_UNLOAD_RECOVERY) 238562306a36Sopenharmony_ci edev->state = QEDE_STATE_CLOSED; 238662306a36Sopenharmony_ci 238762306a36Sopenharmony_ci qede_rdma_dev_event_close(edev); 238862306a36Sopenharmony_ci 238962306a36Sopenharmony_ci /* Close OS Tx */ 239062306a36Sopenharmony_ci netif_tx_disable(edev->ndev); 239162306a36Sopenharmony_ci netif_carrier_off(edev->ndev); 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_ci if (mode != QEDE_UNLOAD_RECOVERY) { 239462306a36Sopenharmony_ci /* Reset the link */ 239562306a36Sopenharmony_ci memset(&link_params, 0, sizeof(link_params)); 239662306a36Sopenharmony_ci link_params.link_up = false; 239762306a36Sopenharmony_ci edev->ops->common->set_link(edev->cdev, &link_params); 239862306a36Sopenharmony_ci 239962306a36Sopenharmony_ci rc = qede_stop_queues(edev); 240062306a36Sopenharmony_ci if (rc) { 240162306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 240262306a36Sopenharmony_ci if (edev->dev_info.common.b_arfs_capable) { 240362306a36Sopenharmony_ci qede_poll_for_freeing_arfs_filters(edev); 240462306a36Sopenharmony_ci if (edev->ndev->rx_cpu_rmap) 240562306a36Sopenharmony_ci free_irq_cpu_rmap(edev->ndev->rx_cpu_rmap); 240662306a36Sopenharmony_ci 240762306a36Sopenharmony_ci edev->ndev->rx_cpu_rmap = NULL; 240862306a36Sopenharmony_ci } 240962306a36Sopenharmony_ci#endif 241062306a36Sopenharmony_ci qede_sync_free_irqs(edev); 241162306a36Sopenharmony_ci goto out; 241262306a36Sopenharmony_ci } 241362306a36Sopenharmony_ci 241462306a36Sopenharmony_ci DP_INFO(edev, "Stopped Queues\n"); 241562306a36Sopenharmony_ci } 241662306a36Sopenharmony_ci 241762306a36Sopenharmony_ci qede_vlan_mark_nonconfigured(edev); 241862306a36Sopenharmony_ci edev->ops->fastpath_stop(edev->cdev); 241962306a36Sopenharmony_ci 242062306a36Sopenharmony_ci if (edev->dev_info.common.b_arfs_capable) { 242162306a36Sopenharmony_ci qede_poll_for_freeing_arfs_filters(edev); 242262306a36Sopenharmony_ci qede_free_arfs(edev); 242362306a36Sopenharmony_ci } 242462306a36Sopenharmony_ci 242562306a36Sopenharmony_ci /* Release the interrupts */ 242662306a36Sopenharmony_ci qede_sync_free_irqs(edev); 242762306a36Sopenharmony_ci edev->ops->common->set_fp_int(edev->cdev, 0); 242862306a36Sopenharmony_ci 242962306a36Sopenharmony_ci qede_napi_disable_remove(edev); 243062306a36Sopenharmony_ci 243162306a36Sopenharmony_ci if (mode == QEDE_UNLOAD_RECOVERY) 243262306a36Sopenharmony_ci qede_empty_tx_queues(edev); 243362306a36Sopenharmony_ci 243462306a36Sopenharmony_ci qede_free_mem_load(edev); 243562306a36Sopenharmony_ci qede_free_fp_array(edev); 243662306a36Sopenharmony_ci 243762306a36Sopenharmony_ciout: 243862306a36Sopenharmony_ci if (!is_locked) 243962306a36Sopenharmony_ci __qede_unlock(edev); 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_ci if (mode != QEDE_UNLOAD_RECOVERY) 244262306a36Sopenharmony_ci DP_NOTICE(edev, "Link is down\n"); 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_ci edev->ptp_skip_txts = 0; 244562306a36Sopenharmony_ci 244662306a36Sopenharmony_ci DP_INFO(edev, "Ending qede unload\n"); 244762306a36Sopenharmony_ci} 244862306a36Sopenharmony_ci 244962306a36Sopenharmony_cienum qede_load_mode { 245062306a36Sopenharmony_ci QEDE_LOAD_NORMAL, 245162306a36Sopenharmony_ci QEDE_LOAD_RELOAD, 245262306a36Sopenharmony_ci QEDE_LOAD_RECOVERY, 245362306a36Sopenharmony_ci}; 245462306a36Sopenharmony_ci 245562306a36Sopenharmony_cistatic int qede_load(struct qede_dev *edev, enum qede_load_mode mode, 245662306a36Sopenharmony_ci bool is_locked) 245762306a36Sopenharmony_ci{ 245862306a36Sopenharmony_ci struct qed_link_params link_params; 245962306a36Sopenharmony_ci struct ethtool_coalesce coal = {}; 246062306a36Sopenharmony_ci u8 num_tc; 246162306a36Sopenharmony_ci int rc, i; 246262306a36Sopenharmony_ci 246362306a36Sopenharmony_ci DP_INFO(edev, "Starting qede load\n"); 246462306a36Sopenharmony_ci 246562306a36Sopenharmony_ci if (!is_locked) 246662306a36Sopenharmony_ci __qede_lock(edev); 246762306a36Sopenharmony_ci 246862306a36Sopenharmony_ci rc = qede_set_num_queues(edev); 246962306a36Sopenharmony_ci if (rc) 247062306a36Sopenharmony_ci goto out; 247162306a36Sopenharmony_ci 247262306a36Sopenharmony_ci rc = qede_alloc_fp_array(edev); 247362306a36Sopenharmony_ci if (rc) 247462306a36Sopenharmony_ci goto out; 247562306a36Sopenharmony_ci 247662306a36Sopenharmony_ci qede_init_fp(edev); 247762306a36Sopenharmony_ci 247862306a36Sopenharmony_ci rc = qede_alloc_mem_load(edev); 247962306a36Sopenharmony_ci if (rc) 248062306a36Sopenharmony_ci goto err1; 248162306a36Sopenharmony_ci DP_INFO(edev, "Allocated %d Rx, %d Tx queues\n", 248262306a36Sopenharmony_ci QEDE_RSS_COUNT(edev), QEDE_TSS_COUNT(edev)); 248362306a36Sopenharmony_ci 248462306a36Sopenharmony_ci rc = qede_set_real_num_queues(edev); 248562306a36Sopenharmony_ci if (rc) 248662306a36Sopenharmony_ci goto err2; 248762306a36Sopenharmony_ci 248862306a36Sopenharmony_ci if (qede_alloc_arfs(edev)) { 248962306a36Sopenharmony_ci edev->ndev->features &= ~NETIF_F_NTUPLE; 249062306a36Sopenharmony_ci edev->dev_info.common.b_arfs_capable = false; 249162306a36Sopenharmony_ci } 249262306a36Sopenharmony_ci 249362306a36Sopenharmony_ci qede_napi_add_enable(edev); 249462306a36Sopenharmony_ci DP_INFO(edev, "Napi added and enabled\n"); 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_ci rc = qede_setup_irqs(edev); 249762306a36Sopenharmony_ci if (rc) 249862306a36Sopenharmony_ci goto err3; 249962306a36Sopenharmony_ci DP_INFO(edev, "Setup IRQs succeeded\n"); 250062306a36Sopenharmony_ci 250162306a36Sopenharmony_ci rc = qede_start_queues(edev, mode != QEDE_LOAD_RELOAD); 250262306a36Sopenharmony_ci if (rc) 250362306a36Sopenharmony_ci goto err4; 250462306a36Sopenharmony_ci DP_INFO(edev, "Start VPORT, RXQ and TXQ succeeded\n"); 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_ci num_tc = netdev_get_num_tc(edev->ndev); 250762306a36Sopenharmony_ci num_tc = num_tc ? num_tc : edev->dev_info.num_tc; 250862306a36Sopenharmony_ci qede_setup_tc(edev->ndev, num_tc); 250962306a36Sopenharmony_ci 251062306a36Sopenharmony_ci /* Program un-configured VLANs */ 251162306a36Sopenharmony_ci qede_configure_vlan_filters(edev); 251262306a36Sopenharmony_ci 251362306a36Sopenharmony_ci set_bit(QEDE_FLAGS_LINK_REQUESTED, &edev->flags); 251462306a36Sopenharmony_ci 251562306a36Sopenharmony_ci /* Ask for link-up using current configuration */ 251662306a36Sopenharmony_ci memset(&link_params, 0, sizeof(link_params)); 251762306a36Sopenharmony_ci link_params.link_up = true; 251862306a36Sopenharmony_ci edev->ops->common->set_link(edev->cdev, &link_params); 251962306a36Sopenharmony_ci 252062306a36Sopenharmony_ci edev->state = QEDE_STATE_OPEN; 252162306a36Sopenharmony_ci 252262306a36Sopenharmony_ci coal.rx_coalesce_usecs = QED_DEFAULT_RX_USECS; 252362306a36Sopenharmony_ci coal.tx_coalesce_usecs = QED_DEFAULT_TX_USECS; 252462306a36Sopenharmony_ci 252562306a36Sopenharmony_ci for_each_queue(i) { 252662306a36Sopenharmony_ci if (edev->coal_entry[i].isvalid) { 252762306a36Sopenharmony_ci coal.rx_coalesce_usecs = edev->coal_entry[i].rxc; 252862306a36Sopenharmony_ci coal.tx_coalesce_usecs = edev->coal_entry[i].txc; 252962306a36Sopenharmony_ci } 253062306a36Sopenharmony_ci __qede_unlock(edev); 253162306a36Sopenharmony_ci qede_set_per_coalesce(edev->ndev, i, &coal); 253262306a36Sopenharmony_ci __qede_lock(edev); 253362306a36Sopenharmony_ci } 253462306a36Sopenharmony_ci DP_INFO(edev, "Ending successfully qede load\n"); 253562306a36Sopenharmony_ci 253662306a36Sopenharmony_ci goto out; 253762306a36Sopenharmony_cierr4: 253862306a36Sopenharmony_ci qede_sync_free_irqs(edev); 253962306a36Sopenharmony_cierr3: 254062306a36Sopenharmony_ci qede_napi_disable_remove(edev); 254162306a36Sopenharmony_cierr2: 254262306a36Sopenharmony_ci qede_free_mem_load(edev); 254362306a36Sopenharmony_cierr1: 254462306a36Sopenharmony_ci edev->ops->common->set_fp_int(edev->cdev, 0); 254562306a36Sopenharmony_ci qede_free_fp_array(edev); 254662306a36Sopenharmony_ci edev->num_queues = 0; 254762306a36Sopenharmony_ci edev->fp_num_tx = 0; 254862306a36Sopenharmony_ci edev->fp_num_rx = 0; 254962306a36Sopenharmony_ciout: 255062306a36Sopenharmony_ci if (!is_locked) 255162306a36Sopenharmony_ci __qede_unlock(edev); 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_ci return rc; 255462306a36Sopenharmony_ci} 255562306a36Sopenharmony_ci 255662306a36Sopenharmony_ci/* 'func' should be able to run between unload and reload assuming interface 255762306a36Sopenharmony_ci * is actually running, or afterwards in case it's currently DOWN. 255862306a36Sopenharmony_ci */ 255962306a36Sopenharmony_civoid qede_reload(struct qede_dev *edev, 256062306a36Sopenharmony_ci struct qede_reload_args *args, bool is_locked) 256162306a36Sopenharmony_ci{ 256262306a36Sopenharmony_ci if (!is_locked) 256362306a36Sopenharmony_ci __qede_lock(edev); 256462306a36Sopenharmony_ci 256562306a36Sopenharmony_ci /* Since qede_lock is held, internal state wouldn't change even 256662306a36Sopenharmony_ci * if netdev state would start transitioning. Check whether current 256762306a36Sopenharmony_ci * internal configuration indicates device is up, then reload. 256862306a36Sopenharmony_ci */ 256962306a36Sopenharmony_ci if (edev->state == QEDE_STATE_OPEN) { 257062306a36Sopenharmony_ci qede_unload(edev, QEDE_UNLOAD_NORMAL, true); 257162306a36Sopenharmony_ci if (args) 257262306a36Sopenharmony_ci args->func(edev, args); 257362306a36Sopenharmony_ci qede_load(edev, QEDE_LOAD_RELOAD, true); 257462306a36Sopenharmony_ci 257562306a36Sopenharmony_ci /* Since no one is going to do it for us, re-configure */ 257662306a36Sopenharmony_ci qede_config_rx_mode(edev->ndev); 257762306a36Sopenharmony_ci } else if (args) { 257862306a36Sopenharmony_ci args->func(edev, args); 257962306a36Sopenharmony_ci } 258062306a36Sopenharmony_ci 258162306a36Sopenharmony_ci if (!is_locked) 258262306a36Sopenharmony_ci __qede_unlock(edev); 258362306a36Sopenharmony_ci} 258462306a36Sopenharmony_ci 258562306a36Sopenharmony_ci/* called with rtnl_lock */ 258662306a36Sopenharmony_cistatic int qede_open(struct net_device *ndev) 258762306a36Sopenharmony_ci{ 258862306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(ndev); 258962306a36Sopenharmony_ci int rc; 259062306a36Sopenharmony_ci 259162306a36Sopenharmony_ci netif_carrier_off(ndev); 259262306a36Sopenharmony_ci 259362306a36Sopenharmony_ci edev->ops->common->set_power_state(edev->cdev, PCI_D0); 259462306a36Sopenharmony_ci 259562306a36Sopenharmony_ci rc = qede_load(edev, QEDE_LOAD_NORMAL, false); 259662306a36Sopenharmony_ci if (rc) 259762306a36Sopenharmony_ci return rc; 259862306a36Sopenharmony_ci 259962306a36Sopenharmony_ci udp_tunnel_nic_reset_ntf(ndev); 260062306a36Sopenharmony_ci 260162306a36Sopenharmony_ci edev->ops->common->update_drv_state(edev->cdev, true); 260262306a36Sopenharmony_ci 260362306a36Sopenharmony_ci return 0; 260462306a36Sopenharmony_ci} 260562306a36Sopenharmony_ci 260662306a36Sopenharmony_cistatic int qede_close(struct net_device *ndev) 260762306a36Sopenharmony_ci{ 260862306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(ndev); 260962306a36Sopenharmony_ci 261062306a36Sopenharmony_ci qede_unload(edev, QEDE_UNLOAD_NORMAL, false); 261162306a36Sopenharmony_ci 261262306a36Sopenharmony_ci if (edev->cdev) 261362306a36Sopenharmony_ci edev->ops->common->update_drv_state(edev->cdev, false); 261462306a36Sopenharmony_ci 261562306a36Sopenharmony_ci return 0; 261662306a36Sopenharmony_ci} 261762306a36Sopenharmony_ci 261862306a36Sopenharmony_cistatic void qede_link_update(void *dev, struct qed_link_output *link) 261962306a36Sopenharmony_ci{ 262062306a36Sopenharmony_ci struct qede_dev *edev = dev; 262162306a36Sopenharmony_ci 262262306a36Sopenharmony_ci if (!test_bit(QEDE_FLAGS_LINK_REQUESTED, &edev->flags)) { 262362306a36Sopenharmony_ci DP_VERBOSE(edev, NETIF_MSG_LINK, "Interface is not ready\n"); 262462306a36Sopenharmony_ci return; 262562306a36Sopenharmony_ci } 262662306a36Sopenharmony_ci 262762306a36Sopenharmony_ci if (link->link_up) { 262862306a36Sopenharmony_ci if (!netif_carrier_ok(edev->ndev)) { 262962306a36Sopenharmony_ci DP_NOTICE(edev, "Link is up\n"); 263062306a36Sopenharmony_ci netif_tx_start_all_queues(edev->ndev); 263162306a36Sopenharmony_ci netif_carrier_on(edev->ndev); 263262306a36Sopenharmony_ci qede_rdma_dev_event_open(edev); 263362306a36Sopenharmony_ci } 263462306a36Sopenharmony_ci } else { 263562306a36Sopenharmony_ci if (netif_carrier_ok(edev->ndev)) { 263662306a36Sopenharmony_ci DP_NOTICE(edev, "Link is down\n"); 263762306a36Sopenharmony_ci netif_tx_disable(edev->ndev); 263862306a36Sopenharmony_ci netif_carrier_off(edev->ndev); 263962306a36Sopenharmony_ci qede_rdma_dev_event_close(edev); 264062306a36Sopenharmony_ci } 264162306a36Sopenharmony_ci } 264262306a36Sopenharmony_ci} 264362306a36Sopenharmony_ci 264462306a36Sopenharmony_cistatic void qede_schedule_recovery_handler(void *dev) 264562306a36Sopenharmony_ci{ 264662306a36Sopenharmony_ci struct qede_dev *edev = dev; 264762306a36Sopenharmony_ci 264862306a36Sopenharmony_ci if (edev->state == QEDE_STATE_RECOVERY) { 264962306a36Sopenharmony_ci DP_NOTICE(edev, 265062306a36Sopenharmony_ci "Avoid scheduling a recovery handling since already in recovery state\n"); 265162306a36Sopenharmony_ci return; 265262306a36Sopenharmony_ci } 265362306a36Sopenharmony_ci 265462306a36Sopenharmony_ci set_bit(QEDE_SP_RECOVERY, &edev->sp_flags); 265562306a36Sopenharmony_ci schedule_delayed_work(&edev->sp_task, 0); 265662306a36Sopenharmony_ci 265762306a36Sopenharmony_ci DP_INFO(edev, "Scheduled a recovery handler\n"); 265862306a36Sopenharmony_ci} 265962306a36Sopenharmony_ci 266062306a36Sopenharmony_cistatic void qede_recovery_failed(struct qede_dev *edev) 266162306a36Sopenharmony_ci{ 266262306a36Sopenharmony_ci netdev_err(edev->ndev, "Recovery handling has failed. Power cycle is needed.\n"); 266362306a36Sopenharmony_ci 266462306a36Sopenharmony_ci netif_device_detach(edev->ndev); 266562306a36Sopenharmony_ci 266662306a36Sopenharmony_ci if (edev->cdev) 266762306a36Sopenharmony_ci edev->ops->common->set_power_state(edev->cdev, PCI_D3hot); 266862306a36Sopenharmony_ci} 266962306a36Sopenharmony_ci 267062306a36Sopenharmony_cistatic void qede_recovery_handler(struct qede_dev *edev) 267162306a36Sopenharmony_ci{ 267262306a36Sopenharmony_ci u32 curr_state = edev->state; 267362306a36Sopenharmony_ci int rc; 267462306a36Sopenharmony_ci 267562306a36Sopenharmony_ci DP_NOTICE(edev, "Starting a recovery process\n"); 267662306a36Sopenharmony_ci 267762306a36Sopenharmony_ci /* No need to acquire first the qede_lock since is done by qede_sp_task 267862306a36Sopenharmony_ci * before calling this function. 267962306a36Sopenharmony_ci */ 268062306a36Sopenharmony_ci edev->state = QEDE_STATE_RECOVERY; 268162306a36Sopenharmony_ci 268262306a36Sopenharmony_ci edev->ops->common->recovery_prolog(edev->cdev); 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_ci if (curr_state == QEDE_STATE_OPEN) 268562306a36Sopenharmony_ci qede_unload(edev, QEDE_UNLOAD_RECOVERY, true); 268662306a36Sopenharmony_ci 268762306a36Sopenharmony_ci __qede_remove(edev->pdev, QEDE_REMOVE_RECOVERY); 268862306a36Sopenharmony_ci 268962306a36Sopenharmony_ci rc = __qede_probe(edev->pdev, edev->dp_module, edev->dp_level, 269062306a36Sopenharmony_ci IS_VF(edev), QEDE_PROBE_RECOVERY); 269162306a36Sopenharmony_ci if (rc) { 269262306a36Sopenharmony_ci edev->cdev = NULL; 269362306a36Sopenharmony_ci goto err; 269462306a36Sopenharmony_ci } 269562306a36Sopenharmony_ci 269662306a36Sopenharmony_ci if (curr_state == QEDE_STATE_OPEN) { 269762306a36Sopenharmony_ci rc = qede_load(edev, QEDE_LOAD_RECOVERY, true); 269862306a36Sopenharmony_ci if (rc) 269962306a36Sopenharmony_ci goto err; 270062306a36Sopenharmony_ci 270162306a36Sopenharmony_ci qede_config_rx_mode(edev->ndev); 270262306a36Sopenharmony_ci udp_tunnel_nic_reset_ntf(edev->ndev); 270362306a36Sopenharmony_ci } 270462306a36Sopenharmony_ci 270562306a36Sopenharmony_ci edev->state = curr_state; 270662306a36Sopenharmony_ci 270762306a36Sopenharmony_ci DP_NOTICE(edev, "Recovery handling is done\n"); 270862306a36Sopenharmony_ci 270962306a36Sopenharmony_ci return; 271062306a36Sopenharmony_ci 271162306a36Sopenharmony_cierr: 271262306a36Sopenharmony_ci qede_recovery_failed(edev); 271362306a36Sopenharmony_ci} 271462306a36Sopenharmony_ci 271562306a36Sopenharmony_cistatic void qede_atomic_hw_err_handler(struct qede_dev *edev) 271662306a36Sopenharmony_ci{ 271762306a36Sopenharmony_ci struct qed_dev *cdev = edev->cdev; 271862306a36Sopenharmony_ci 271962306a36Sopenharmony_ci DP_NOTICE(edev, 272062306a36Sopenharmony_ci "Generic non-sleepable HW error handling started - err_flags 0x%lx\n", 272162306a36Sopenharmony_ci edev->err_flags); 272262306a36Sopenharmony_ci 272362306a36Sopenharmony_ci /* Get a call trace of the flow that led to the error */ 272462306a36Sopenharmony_ci WARN_ON(test_bit(QEDE_ERR_WARN, &edev->err_flags)); 272562306a36Sopenharmony_ci 272662306a36Sopenharmony_ci /* Prevent HW attentions from being reasserted */ 272762306a36Sopenharmony_ci if (test_bit(QEDE_ERR_ATTN_CLR_EN, &edev->err_flags)) 272862306a36Sopenharmony_ci edev->ops->common->attn_clr_enable(cdev, true); 272962306a36Sopenharmony_ci 273062306a36Sopenharmony_ci DP_NOTICE(edev, "Generic non-sleepable HW error handling is done\n"); 273162306a36Sopenharmony_ci} 273262306a36Sopenharmony_ci 273362306a36Sopenharmony_cistatic void qede_generic_hw_err_handler(struct qede_dev *edev) 273462306a36Sopenharmony_ci{ 273562306a36Sopenharmony_ci DP_NOTICE(edev, 273662306a36Sopenharmony_ci "Generic sleepable HW error handling started - err_flags 0x%lx\n", 273762306a36Sopenharmony_ci edev->err_flags); 273862306a36Sopenharmony_ci 273962306a36Sopenharmony_ci if (edev->devlink) { 274062306a36Sopenharmony_ci DP_NOTICE(edev, "Reporting fatal error to devlink\n"); 274162306a36Sopenharmony_ci edev->ops->common->report_fatal_error(edev->devlink, edev->last_err_type); 274262306a36Sopenharmony_ci } 274362306a36Sopenharmony_ci 274462306a36Sopenharmony_ci clear_bit(QEDE_ERR_IS_HANDLED, &edev->err_flags); 274562306a36Sopenharmony_ci 274662306a36Sopenharmony_ci DP_NOTICE(edev, "Generic sleepable HW error handling is done\n"); 274762306a36Sopenharmony_ci} 274862306a36Sopenharmony_ci 274962306a36Sopenharmony_cistatic void qede_set_hw_err_flags(struct qede_dev *edev, 275062306a36Sopenharmony_ci enum qed_hw_err_type err_type) 275162306a36Sopenharmony_ci{ 275262306a36Sopenharmony_ci unsigned long err_flags = 0; 275362306a36Sopenharmony_ci 275462306a36Sopenharmony_ci switch (err_type) { 275562306a36Sopenharmony_ci case QED_HW_ERR_DMAE_FAIL: 275662306a36Sopenharmony_ci set_bit(QEDE_ERR_WARN, &err_flags); 275762306a36Sopenharmony_ci fallthrough; 275862306a36Sopenharmony_ci case QED_HW_ERR_MFW_RESP_FAIL: 275962306a36Sopenharmony_ci case QED_HW_ERR_HW_ATTN: 276062306a36Sopenharmony_ci case QED_HW_ERR_RAMROD_FAIL: 276162306a36Sopenharmony_ci case QED_HW_ERR_FW_ASSERT: 276262306a36Sopenharmony_ci set_bit(QEDE_ERR_ATTN_CLR_EN, &err_flags); 276362306a36Sopenharmony_ci set_bit(QEDE_ERR_GET_DBG_INFO, &err_flags); 276462306a36Sopenharmony_ci /* make this error as recoverable and start recovery*/ 276562306a36Sopenharmony_ci set_bit(QEDE_ERR_IS_RECOVERABLE, &err_flags); 276662306a36Sopenharmony_ci break; 276762306a36Sopenharmony_ci 276862306a36Sopenharmony_ci default: 276962306a36Sopenharmony_ci DP_NOTICE(edev, "Unexpected HW error [%d]\n", err_type); 277062306a36Sopenharmony_ci break; 277162306a36Sopenharmony_ci } 277262306a36Sopenharmony_ci 277362306a36Sopenharmony_ci edev->err_flags |= err_flags; 277462306a36Sopenharmony_ci} 277562306a36Sopenharmony_ci 277662306a36Sopenharmony_cistatic void qede_schedule_hw_err_handler(void *dev, 277762306a36Sopenharmony_ci enum qed_hw_err_type err_type) 277862306a36Sopenharmony_ci{ 277962306a36Sopenharmony_ci struct qede_dev *edev = dev; 278062306a36Sopenharmony_ci 278162306a36Sopenharmony_ci /* Fan failure cannot be masked by handling of another HW error or by a 278262306a36Sopenharmony_ci * concurrent recovery process. 278362306a36Sopenharmony_ci */ 278462306a36Sopenharmony_ci if ((test_and_set_bit(QEDE_ERR_IS_HANDLED, &edev->err_flags) || 278562306a36Sopenharmony_ci edev->state == QEDE_STATE_RECOVERY) && 278662306a36Sopenharmony_ci err_type != QED_HW_ERR_FAN_FAIL) { 278762306a36Sopenharmony_ci DP_INFO(edev, 278862306a36Sopenharmony_ci "Avoid scheduling an error handling while another HW error is being handled\n"); 278962306a36Sopenharmony_ci return; 279062306a36Sopenharmony_ci } 279162306a36Sopenharmony_ci 279262306a36Sopenharmony_ci if (err_type >= QED_HW_ERR_LAST) { 279362306a36Sopenharmony_ci DP_NOTICE(edev, "Unknown HW error [%d]\n", err_type); 279462306a36Sopenharmony_ci clear_bit(QEDE_ERR_IS_HANDLED, &edev->err_flags); 279562306a36Sopenharmony_ci return; 279662306a36Sopenharmony_ci } 279762306a36Sopenharmony_ci 279862306a36Sopenharmony_ci edev->last_err_type = err_type; 279962306a36Sopenharmony_ci qede_set_hw_err_flags(edev, err_type); 280062306a36Sopenharmony_ci qede_atomic_hw_err_handler(edev); 280162306a36Sopenharmony_ci set_bit(QEDE_SP_HW_ERR, &edev->sp_flags); 280262306a36Sopenharmony_ci schedule_delayed_work(&edev->sp_task, 0); 280362306a36Sopenharmony_ci 280462306a36Sopenharmony_ci DP_INFO(edev, "Scheduled a error handler [err_type %d]\n", err_type); 280562306a36Sopenharmony_ci} 280662306a36Sopenharmony_ci 280762306a36Sopenharmony_cistatic bool qede_is_txq_full(struct qede_dev *edev, struct qede_tx_queue *txq) 280862306a36Sopenharmony_ci{ 280962306a36Sopenharmony_ci struct netdev_queue *netdev_txq; 281062306a36Sopenharmony_ci 281162306a36Sopenharmony_ci netdev_txq = netdev_get_tx_queue(edev->ndev, txq->ndev_txq_id); 281262306a36Sopenharmony_ci if (netif_xmit_stopped(netdev_txq)) 281362306a36Sopenharmony_ci return true; 281462306a36Sopenharmony_ci 281562306a36Sopenharmony_ci return false; 281662306a36Sopenharmony_ci} 281762306a36Sopenharmony_ci 281862306a36Sopenharmony_cistatic void qede_get_generic_tlv_data(void *dev, struct qed_generic_tlvs *data) 281962306a36Sopenharmony_ci{ 282062306a36Sopenharmony_ci struct qede_dev *edev = dev; 282162306a36Sopenharmony_ci struct netdev_hw_addr *ha; 282262306a36Sopenharmony_ci int i; 282362306a36Sopenharmony_ci 282462306a36Sopenharmony_ci if (edev->ndev->features & NETIF_F_IP_CSUM) 282562306a36Sopenharmony_ci data->feat_flags |= QED_TLV_IP_CSUM; 282662306a36Sopenharmony_ci if (edev->ndev->features & NETIF_F_TSO) 282762306a36Sopenharmony_ci data->feat_flags |= QED_TLV_LSO; 282862306a36Sopenharmony_ci 282962306a36Sopenharmony_ci ether_addr_copy(data->mac[0], edev->ndev->dev_addr); 283062306a36Sopenharmony_ci eth_zero_addr(data->mac[1]); 283162306a36Sopenharmony_ci eth_zero_addr(data->mac[2]); 283262306a36Sopenharmony_ci /* Copy the first two UC macs */ 283362306a36Sopenharmony_ci netif_addr_lock_bh(edev->ndev); 283462306a36Sopenharmony_ci i = 1; 283562306a36Sopenharmony_ci netdev_for_each_uc_addr(ha, edev->ndev) { 283662306a36Sopenharmony_ci ether_addr_copy(data->mac[i++], ha->addr); 283762306a36Sopenharmony_ci if (i == QED_TLV_MAC_COUNT) 283862306a36Sopenharmony_ci break; 283962306a36Sopenharmony_ci } 284062306a36Sopenharmony_ci 284162306a36Sopenharmony_ci netif_addr_unlock_bh(edev->ndev); 284262306a36Sopenharmony_ci} 284362306a36Sopenharmony_ci 284462306a36Sopenharmony_cistatic void qede_get_eth_tlv_data(void *dev, void *data) 284562306a36Sopenharmony_ci{ 284662306a36Sopenharmony_ci struct qed_mfw_tlv_eth *etlv = data; 284762306a36Sopenharmony_ci struct qede_dev *edev = dev; 284862306a36Sopenharmony_ci struct qede_fastpath *fp; 284962306a36Sopenharmony_ci int i; 285062306a36Sopenharmony_ci 285162306a36Sopenharmony_ci etlv->lso_maxoff_size = 0XFFFF; 285262306a36Sopenharmony_ci etlv->lso_maxoff_size_set = true; 285362306a36Sopenharmony_ci etlv->lso_minseg_size = (u16)ETH_TX_LSO_WINDOW_MIN_LEN; 285462306a36Sopenharmony_ci etlv->lso_minseg_size_set = true; 285562306a36Sopenharmony_ci etlv->prom_mode = !!(edev->ndev->flags & IFF_PROMISC); 285662306a36Sopenharmony_ci etlv->prom_mode_set = true; 285762306a36Sopenharmony_ci etlv->tx_descr_size = QEDE_TSS_COUNT(edev); 285862306a36Sopenharmony_ci etlv->tx_descr_size_set = true; 285962306a36Sopenharmony_ci etlv->rx_descr_size = QEDE_RSS_COUNT(edev); 286062306a36Sopenharmony_ci etlv->rx_descr_size_set = true; 286162306a36Sopenharmony_ci etlv->iov_offload = QED_MFW_TLV_IOV_OFFLOAD_VEB; 286262306a36Sopenharmony_ci etlv->iov_offload_set = true; 286362306a36Sopenharmony_ci 286462306a36Sopenharmony_ci /* Fill information regarding queues; Should be done under the qede 286562306a36Sopenharmony_ci * lock to guarantee those don't change beneath our feet. 286662306a36Sopenharmony_ci */ 286762306a36Sopenharmony_ci etlv->txqs_empty = true; 286862306a36Sopenharmony_ci etlv->rxqs_empty = true; 286962306a36Sopenharmony_ci etlv->num_txqs_full = 0; 287062306a36Sopenharmony_ci etlv->num_rxqs_full = 0; 287162306a36Sopenharmony_ci 287262306a36Sopenharmony_ci __qede_lock(edev); 287362306a36Sopenharmony_ci for_each_queue(i) { 287462306a36Sopenharmony_ci fp = &edev->fp_array[i]; 287562306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_TX) { 287662306a36Sopenharmony_ci struct qede_tx_queue *txq = QEDE_FP_TC0_TXQ(fp); 287762306a36Sopenharmony_ci 287862306a36Sopenharmony_ci if (txq->sw_tx_cons != txq->sw_tx_prod) 287962306a36Sopenharmony_ci etlv->txqs_empty = false; 288062306a36Sopenharmony_ci if (qede_is_txq_full(edev, txq)) 288162306a36Sopenharmony_ci etlv->num_txqs_full++; 288262306a36Sopenharmony_ci } 288362306a36Sopenharmony_ci if (fp->type & QEDE_FASTPATH_RX) { 288462306a36Sopenharmony_ci if (qede_has_rx_work(fp->rxq)) 288562306a36Sopenharmony_ci etlv->rxqs_empty = false; 288662306a36Sopenharmony_ci 288762306a36Sopenharmony_ci /* This one is a bit tricky; Firmware might stop 288862306a36Sopenharmony_ci * placing packets if ring is not yet full. 288962306a36Sopenharmony_ci * Give an approximation. 289062306a36Sopenharmony_ci */ 289162306a36Sopenharmony_ci if (le16_to_cpu(*fp->rxq->hw_cons_ptr) - 289262306a36Sopenharmony_ci qed_chain_get_cons_idx(&fp->rxq->rx_comp_ring) > 289362306a36Sopenharmony_ci RX_RING_SIZE - 100) 289462306a36Sopenharmony_ci etlv->num_rxqs_full++; 289562306a36Sopenharmony_ci } 289662306a36Sopenharmony_ci } 289762306a36Sopenharmony_ci __qede_unlock(edev); 289862306a36Sopenharmony_ci 289962306a36Sopenharmony_ci etlv->txqs_empty_set = true; 290062306a36Sopenharmony_ci etlv->rxqs_empty_set = true; 290162306a36Sopenharmony_ci etlv->num_txqs_full_set = true; 290262306a36Sopenharmony_ci etlv->num_rxqs_full_set = true; 290362306a36Sopenharmony_ci} 290462306a36Sopenharmony_ci 290562306a36Sopenharmony_ci/** 290662306a36Sopenharmony_ci * qede_io_error_detected(): Called when PCI error is detected 290762306a36Sopenharmony_ci * 290862306a36Sopenharmony_ci * @pdev: Pointer to PCI device 290962306a36Sopenharmony_ci * @state: The current pci connection state 291062306a36Sopenharmony_ci * 291162306a36Sopenharmony_ci *Return: pci_ers_result_t. 291262306a36Sopenharmony_ci * 291362306a36Sopenharmony_ci * This function is called after a PCI bus error affecting 291462306a36Sopenharmony_ci * this device has been detected. 291562306a36Sopenharmony_ci */ 291662306a36Sopenharmony_cistatic pci_ers_result_t 291762306a36Sopenharmony_ciqede_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) 291862306a36Sopenharmony_ci{ 291962306a36Sopenharmony_ci struct net_device *dev = pci_get_drvdata(pdev); 292062306a36Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 292162306a36Sopenharmony_ci 292262306a36Sopenharmony_ci if (!edev) 292362306a36Sopenharmony_ci return PCI_ERS_RESULT_NONE; 292462306a36Sopenharmony_ci 292562306a36Sopenharmony_ci DP_NOTICE(edev, "IO error detected [%d]\n", state); 292662306a36Sopenharmony_ci 292762306a36Sopenharmony_ci __qede_lock(edev); 292862306a36Sopenharmony_ci if (edev->state == QEDE_STATE_RECOVERY) { 292962306a36Sopenharmony_ci DP_NOTICE(edev, "Device already in the recovery state\n"); 293062306a36Sopenharmony_ci __qede_unlock(edev); 293162306a36Sopenharmony_ci return PCI_ERS_RESULT_NONE; 293262306a36Sopenharmony_ci } 293362306a36Sopenharmony_ci 293462306a36Sopenharmony_ci /* PF handles the recovery of its VFs */ 293562306a36Sopenharmony_ci if (IS_VF(edev)) { 293662306a36Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_IOV, 293762306a36Sopenharmony_ci "VF recovery is handled by its PF\n"); 293862306a36Sopenharmony_ci __qede_unlock(edev); 293962306a36Sopenharmony_ci return PCI_ERS_RESULT_RECOVERED; 294062306a36Sopenharmony_ci } 294162306a36Sopenharmony_ci 294262306a36Sopenharmony_ci /* Close OS Tx */ 294362306a36Sopenharmony_ci netif_tx_disable(edev->ndev); 294462306a36Sopenharmony_ci netif_carrier_off(edev->ndev); 294562306a36Sopenharmony_ci 294662306a36Sopenharmony_ci set_bit(QEDE_SP_AER, &edev->sp_flags); 294762306a36Sopenharmony_ci schedule_delayed_work(&edev->sp_task, 0); 294862306a36Sopenharmony_ci 294962306a36Sopenharmony_ci __qede_unlock(edev); 295062306a36Sopenharmony_ci 295162306a36Sopenharmony_ci return PCI_ERS_RESULT_CAN_RECOVER; 295262306a36Sopenharmony_ci} 2953