18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 28c2ecf20Sopenharmony_ci/* QLogic qede NIC Driver 38c2ecf20Sopenharmony_ci * Copyright (c) 2015-2017 QLogic Corporation 48c2ecf20Sopenharmony_ci * Copyright (c) 2019-2020 Marvell International Ltd. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/crash_dump.h> 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/pci.h> 108c2ecf20Sopenharmony_ci#include <linux/version.h> 118c2ecf20Sopenharmony_ci#include <linux/device.h> 128c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 138c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 148c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 158c2ecf20Sopenharmony_ci#include <linux/errno.h> 168c2ecf20Sopenharmony_ci#include <linux/list.h> 178c2ecf20Sopenharmony_ci#include <linux/string.h> 188c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 198c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 208c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 218c2ecf20Sopenharmony_ci#include <asm/param.h> 228c2ecf20Sopenharmony_ci#include <linux/io.h> 238c2ecf20Sopenharmony_ci#include <linux/netdev_features.h> 248c2ecf20Sopenharmony_ci#include <linux/udp.h> 258c2ecf20Sopenharmony_ci#include <linux/tcp.h> 268c2ecf20Sopenharmony_ci#include <net/udp_tunnel.h> 278c2ecf20Sopenharmony_ci#include <linux/ip.h> 288c2ecf20Sopenharmony_ci#include <net/ipv6.h> 298c2ecf20Sopenharmony_ci#include <net/tcp.h> 308c2ecf20Sopenharmony_ci#include <linux/if_ether.h> 318c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 328c2ecf20Sopenharmony_ci#include <linux/pkt_sched.h> 338c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 348c2ecf20Sopenharmony_ci#include <linux/in.h> 358c2ecf20Sopenharmony_ci#include <linux/random.h> 368c2ecf20Sopenharmony_ci#include <net/ip6_checksum.h> 378c2ecf20Sopenharmony_ci#include <linux/bitops.h> 388c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 398c2ecf20Sopenharmony_ci#include <linux/aer.h> 408c2ecf20Sopenharmony_ci#include "qede.h" 418c2ecf20Sopenharmony_ci#include "qede_ptp.h" 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic char version[] = 448c2ecf20Sopenharmony_ci "QLogic FastLinQ 4xxxx Ethernet Driver qede " DRV_MODULE_VERSION "\n"; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("QLogic FastLinQ 4xxxx Ethernet Driver"); 478c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 488c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_MODULE_VERSION); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic uint debug; 518c2ecf20Sopenharmony_cimodule_param(debug, uint, 0); 528c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, " Default debug msglevel"); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic const struct qed_eth_ops *qed_ops; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define CHIP_NUM_57980S_40 0x1634 578c2ecf20Sopenharmony_ci#define CHIP_NUM_57980S_10 0x1666 588c2ecf20Sopenharmony_ci#define CHIP_NUM_57980S_MF 0x1636 598c2ecf20Sopenharmony_ci#define CHIP_NUM_57980S_100 0x1644 608c2ecf20Sopenharmony_ci#define CHIP_NUM_57980S_50 0x1654 618c2ecf20Sopenharmony_ci#define CHIP_NUM_57980S_25 0x1656 628c2ecf20Sopenharmony_ci#define CHIP_NUM_57980S_IOV 0x1664 638c2ecf20Sopenharmony_ci#define CHIP_NUM_AH 0x8070 648c2ecf20Sopenharmony_ci#define CHIP_NUM_AH_IOV 0x8090 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci#ifndef PCI_DEVICE_ID_NX2_57980E 678c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_57980S_40 CHIP_NUM_57980S_40 688c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_57980S_10 CHIP_NUM_57980S_10 698c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_57980S_MF CHIP_NUM_57980S_MF 708c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_57980S_100 CHIP_NUM_57980S_100 718c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_57980S_50 CHIP_NUM_57980S_50 728c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_57980S_25 CHIP_NUM_57980S_25 738c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_57980S_IOV CHIP_NUM_57980S_IOV 748c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_AH CHIP_NUM_AH 758c2ecf20Sopenharmony_ci#define PCI_DEVICE_ID_AH_IOV CHIP_NUM_AH_IOV 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#endif 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cienum qede_pci_private { 808c2ecf20Sopenharmony_ci QEDE_PRIVATE_PF, 818c2ecf20Sopenharmony_ci QEDE_PRIVATE_VF 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic const struct pci_device_id qede_pci_tbl[] = { 858c2ecf20Sopenharmony_ci {PCI_VDEVICE(QLOGIC, PCI_DEVICE_ID_57980S_40), QEDE_PRIVATE_PF}, 868c2ecf20Sopenharmony_ci {PCI_VDEVICE(QLOGIC, PCI_DEVICE_ID_57980S_10), QEDE_PRIVATE_PF}, 878c2ecf20Sopenharmony_ci {PCI_VDEVICE(QLOGIC, PCI_DEVICE_ID_57980S_MF), QEDE_PRIVATE_PF}, 888c2ecf20Sopenharmony_ci {PCI_VDEVICE(QLOGIC, PCI_DEVICE_ID_57980S_100), QEDE_PRIVATE_PF}, 898c2ecf20Sopenharmony_ci {PCI_VDEVICE(QLOGIC, PCI_DEVICE_ID_57980S_50), QEDE_PRIVATE_PF}, 908c2ecf20Sopenharmony_ci {PCI_VDEVICE(QLOGIC, PCI_DEVICE_ID_57980S_25), QEDE_PRIVATE_PF}, 918c2ecf20Sopenharmony_ci#ifdef CONFIG_QED_SRIOV 928c2ecf20Sopenharmony_ci {PCI_VDEVICE(QLOGIC, PCI_DEVICE_ID_57980S_IOV), QEDE_PRIVATE_VF}, 938c2ecf20Sopenharmony_ci#endif 948c2ecf20Sopenharmony_ci {PCI_VDEVICE(QLOGIC, PCI_DEVICE_ID_AH), QEDE_PRIVATE_PF}, 958c2ecf20Sopenharmony_ci#ifdef CONFIG_QED_SRIOV 968c2ecf20Sopenharmony_ci {PCI_VDEVICE(QLOGIC, PCI_DEVICE_ID_AH_IOV), QEDE_PRIVATE_VF}, 978c2ecf20Sopenharmony_ci#endif 988c2ecf20Sopenharmony_ci { 0 } 998c2ecf20Sopenharmony_ci}; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, qede_pci_tbl); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic int qede_probe(struct pci_dev *pdev, const struct pci_device_id *id); 1048c2ecf20Sopenharmony_cistatic pci_ers_result_t 1058c2ecf20Sopenharmony_ciqede_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci#define TX_TIMEOUT (5 * HZ) 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/* Utilize last protocol index for XDP */ 1108c2ecf20Sopenharmony_ci#define XDP_PI 11 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic void qede_remove(struct pci_dev *pdev); 1138c2ecf20Sopenharmony_cistatic void qede_shutdown(struct pci_dev *pdev); 1148c2ecf20Sopenharmony_cistatic void qede_link_update(void *dev, struct qed_link_output *link); 1158c2ecf20Sopenharmony_cistatic void qede_schedule_recovery_handler(void *dev); 1168c2ecf20Sopenharmony_cistatic void qede_recovery_handler(struct qede_dev *edev); 1178c2ecf20Sopenharmony_cistatic void qede_schedule_hw_err_handler(void *dev, 1188c2ecf20Sopenharmony_ci enum qed_hw_err_type err_type); 1198c2ecf20Sopenharmony_cistatic void qede_get_eth_tlv_data(void *edev, void *data); 1208c2ecf20Sopenharmony_cistatic void qede_get_generic_tlv_data(void *edev, 1218c2ecf20Sopenharmony_ci struct qed_generic_tlvs *data); 1228c2ecf20Sopenharmony_cistatic void qede_generic_hw_err_handler(struct qede_dev *edev); 1238c2ecf20Sopenharmony_ci#ifdef CONFIG_QED_SRIOV 1248c2ecf20Sopenharmony_cistatic int qede_set_vf_vlan(struct net_device *ndev, int vf, u16 vlan, u8 qos, 1258c2ecf20Sopenharmony_ci __be16 vlan_proto) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(ndev); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci if (vlan > 4095) { 1308c2ecf20Sopenharmony_ci DP_NOTICE(edev, "Illegal vlan value %d\n", vlan); 1318c2ecf20Sopenharmony_ci return -EINVAL; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (vlan_proto != htons(ETH_P_8021Q)) 1358c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_IOV, "Setting Vlan 0x%04x to VF [%d]\n", 1388c2ecf20Sopenharmony_ci vlan, vf); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci return edev->ops->iov->set_vlan(edev->cdev, vlan, vf); 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic int qede_set_vf_mac(struct net_device *ndev, int vfidx, u8 *mac) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(ndev); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_IOV, "Setting MAC %pM to VF [%d]\n", mac, vfidx); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(mac)) { 1508c2ecf20Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_IOV, "MAC address isn't valid\n"); 1518c2ecf20Sopenharmony_ci return -EINVAL; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci return edev->ops->iov->set_mac(edev->cdev, mac, vfidx); 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic int qede_sriov_configure(struct pci_dev *pdev, int num_vfs_param) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(pci_get_drvdata(pdev)); 1608c2ecf20Sopenharmony_ci struct qed_dev_info *qed_info = &edev->dev_info.common; 1618c2ecf20Sopenharmony_ci struct qed_update_vport_params *vport_params; 1628c2ecf20Sopenharmony_ci int rc; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci vport_params = vzalloc(sizeof(*vport_params)); 1658c2ecf20Sopenharmony_ci if (!vport_params) 1668c2ecf20Sopenharmony_ci return -ENOMEM; 1678c2ecf20Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_IOV, "Requested %d VFs\n", num_vfs_param); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci rc = edev->ops->iov->configure(edev->cdev, num_vfs_param); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* Enable/Disable Tx switching for PF */ 1728c2ecf20Sopenharmony_ci if ((rc == num_vfs_param) && netif_running(edev->ndev) && 1738c2ecf20Sopenharmony_ci !qed_info->b_inter_pf_switch && qed_info->tx_switching) { 1748c2ecf20Sopenharmony_ci vport_params->vport_id = 0; 1758c2ecf20Sopenharmony_ci vport_params->update_tx_switching_flg = 1; 1768c2ecf20Sopenharmony_ci vport_params->tx_switching_flg = num_vfs_param ? 1 : 0; 1778c2ecf20Sopenharmony_ci edev->ops->vport_update(edev->cdev, vport_params); 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci vfree(vport_params); 1818c2ecf20Sopenharmony_ci return rc; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci#endif 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic const struct pci_error_handlers qede_err_handler = { 1868c2ecf20Sopenharmony_ci .error_detected = qede_io_error_detected, 1878c2ecf20Sopenharmony_ci}; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic struct pci_driver qede_pci_driver = { 1908c2ecf20Sopenharmony_ci .name = "qede", 1918c2ecf20Sopenharmony_ci .id_table = qede_pci_tbl, 1928c2ecf20Sopenharmony_ci .probe = qede_probe, 1938c2ecf20Sopenharmony_ci .remove = qede_remove, 1948c2ecf20Sopenharmony_ci .shutdown = qede_shutdown, 1958c2ecf20Sopenharmony_ci#ifdef CONFIG_QED_SRIOV 1968c2ecf20Sopenharmony_ci .sriov_configure = qede_sriov_configure, 1978c2ecf20Sopenharmony_ci#endif 1988c2ecf20Sopenharmony_ci .err_handler = &qede_err_handler, 1998c2ecf20Sopenharmony_ci}; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic struct qed_eth_cb_ops qede_ll_ops = { 2028c2ecf20Sopenharmony_ci { 2038c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 2048c2ecf20Sopenharmony_ci .arfs_filter_op = qede_arfs_filter_op, 2058c2ecf20Sopenharmony_ci#endif 2068c2ecf20Sopenharmony_ci .link_update = qede_link_update, 2078c2ecf20Sopenharmony_ci .schedule_recovery_handler = qede_schedule_recovery_handler, 2088c2ecf20Sopenharmony_ci .schedule_hw_err_handler = qede_schedule_hw_err_handler, 2098c2ecf20Sopenharmony_ci .get_generic_tlv_data = qede_get_generic_tlv_data, 2108c2ecf20Sopenharmony_ci .get_protocol_tlv_data = qede_get_eth_tlv_data, 2118c2ecf20Sopenharmony_ci }, 2128c2ecf20Sopenharmony_ci .force_mac = qede_force_mac, 2138c2ecf20Sopenharmony_ci .ports_update = qede_udp_ports_update, 2148c2ecf20Sopenharmony_ci}; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic int qede_netdev_event(struct notifier_block *this, unsigned long event, 2178c2ecf20Sopenharmony_ci void *ptr) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci struct net_device *ndev = netdev_notifier_info_to_dev(ptr); 2208c2ecf20Sopenharmony_ci struct ethtool_drvinfo drvinfo; 2218c2ecf20Sopenharmony_ci struct qede_dev *edev; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci if (event != NETDEV_CHANGENAME && event != NETDEV_CHANGEADDR) 2248c2ecf20Sopenharmony_ci goto done; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* Check whether this is a qede device */ 2278c2ecf20Sopenharmony_ci if (!ndev || !ndev->ethtool_ops || !ndev->ethtool_ops->get_drvinfo) 2288c2ecf20Sopenharmony_ci goto done; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci memset(&drvinfo, 0, sizeof(drvinfo)); 2318c2ecf20Sopenharmony_ci ndev->ethtool_ops->get_drvinfo(ndev, &drvinfo); 2328c2ecf20Sopenharmony_ci if (strcmp(drvinfo.driver, "qede")) 2338c2ecf20Sopenharmony_ci goto done; 2348c2ecf20Sopenharmony_ci edev = netdev_priv(ndev); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci switch (event) { 2378c2ecf20Sopenharmony_ci case NETDEV_CHANGENAME: 2388c2ecf20Sopenharmony_ci /* Notify qed of the name change */ 2398c2ecf20Sopenharmony_ci if (!edev->ops || !edev->ops->common) 2408c2ecf20Sopenharmony_ci goto done; 2418c2ecf20Sopenharmony_ci edev->ops->common->set_name(edev->cdev, edev->ndev->name); 2428c2ecf20Sopenharmony_ci break; 2438c2ecf20Sopenharmony_ci case NETDEV_CHANGEADDR: 2448c2ecf20Sopenharmony_ci edev = netdev_priv(ndev); 2458c2ecf20Sopenharmony_ci qede_rdma_event_changeaddr(edev); 2468c2ecf20Sopenharmony_ci break; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cidone: 2508c2ecf20Sopenharmony_ci return NOTIFY_DONE; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic struct notifier_block qede_netdev_notifier = { 2548c2ecf20Sopenharmony_ci .notifier_call = qede_netdev_event, 2558c2ecf20Sopenharmony_ci}; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic 2588c2ecf20Sopenharmony_ciint __init qede_init(void) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci int ret; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci pr_info("qede_init: %s\n", version); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci qede_forced_speed_maps_init(); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci qed_ops = qed_get_eth_ops(); 2678c2ecf20Sopenharmony_ci if (!qed_ops) { 2688c2ecf20Sopenharmony_ci pr_notice("Failed to get qed ethtool operations\n"); 2698c2ecf20Sopenharmony_ci return -EINVAL; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci /* Must register notifier before pci ops, since we might miss 2738c2ecf20Sopenharmony_ci * interface rename after pci probe and netdev registration. 2748c2ecf20Sopenharmony_ci */ 2758c2ecf20Sopenharmony_ci ret = register_netdevice_notifier(&qede_netdev_notifier); 2768c2ecf20Sopenharmony_ci if (ret) { 2778c2ecf20Sopenharmony_ci pr_notice("Failed to register netdevice_notifier\n"); 2788c2ecf20Sopenharmony_ci qed_put_eth_ops(); 2798c2ecf20Sopenharmony_ci return -EINVAL; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci ret = pci_register_driver(&qede_pci_driver); 2838c2ecf20Sopenharmony_ci if (ret) { 2848c2ecf20Sopenharmony_ci pr_notice("Failed to register driver\n"); 2858c2ecf20Sopenharmony_ci unregister_netdevice_notifier(&qede_netdev_notifier); 2868c2ecf20Sopenharmony_ci qed_put_eth_ops(); 2878c2ecf20Sopenharmony_ci return -EINVAL; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci return 0; 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic void __exit qede_cleanup(void) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci if (debug & QED_LOG_INFO_MASK) 2968c2ecf20Sopenharmony_ci pr_info("qede_cleanup called\n"); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci unregister_netdevice_notifier(&qede_netdev_notifier); 2998c2ecf20Sopenharmony_ci pci_unregister_driver(&qede_pci_driver); 3008c2ecf20Sopenharmony_ci qed_put_eth_ops(); 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cimodule_init(qede_init); 3048c2ecf20Sopenharmony_cimodule_exit(qede_cleanup); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic int qede_open(struct net_device *ndev); 3078c2ecf20Sopenharmony_cistatic int qede_close(struct net_device *ndev); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_civoid qede_fill_by_demand_stats(struct qede_dev *edev) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci struct qede_stats_common *p_common = &edev->stats.common; 3128c2ecf20Sopenharmony_ci struct qed_eth_stats stats; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci edev->ops->get_vport_stats(edev->cdev, &stats); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci spin_lock(&edev->stats_lock); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci p_common->no_buff_discards = stats.common.no_buff_discards; 3198c2ecf20Sopenharmony_ci p_common->packet_too_big_discard = stats.common.packet_too_big_discard; 3208c2ecf20Sopenharmony_ci p_common->ttl0_discard = stats.common.ttl0_discard; 3218c2ecf20Sopenharmony_ci p_common->rx_ucast_bytes = stats.common.rx_ucast_bytes; 3228c2ecf20Sopenharmony_ci p_common->rx_mcast_bytes = stats.common.rx_mcast_bytes; 3238c2ecf20Sopenharmony_ci p_common->rx_bcast_bytes = stats.common.rx_bcast_bytes; 3248c2ecf20Sopenharmony_ci p_common->rx_ucast_pkts = stats.common.rx_ucast_pkts; 3258c2ecf20Sopenharmony_ci p_common->rx_mcast_pkts = stats.common.rx_mcast_pkts; 3268c2ecf20Sopenharmony_ci p_common->rx_bcast_pkts = stats.common.rx_bcast_pkts; 3278c2ecf20Sopenharmony_ci p_common->mftag_filter_discards = stats.common.mftag_filter_discards; 3288c2ecf20Sopenharmony_ci p_common->mac_filter_discards = stats.common.mac_filter_discards; 3298c2ecf20Sopenharmony_ci p_common->gft_filter_drop = stats.common.gft_filter_drop; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci p_common->tx_ucast_bytes = stats.common.tx_ucast_bytes; 3328c2ecf20Sopenharmony_ci p_common->tx_mcast_bytes = stats.common.tx_mcast_bytes; 3338c2ecf20Sopenharmony_ci p_common->tx_bcast_bytes = stats.common.tx_bcast_bytes; 3348c2ecf20Sopenharmony_ci p_common->tx_ucast_pkts = stats.common.tx_ucast_pkts; 3358c2ecf20Sopenharmony_ci p_common->tx_mcast_pkts = stats.common.tx_mcast_pkts; 3368c2ecf20Sopenharmony_ci p_common->tx_bcast_pkts = stats.common.tx_bcast_pkts; 3378c2ecf20Sopenharmony_ci p_common->tx_err_drop_pkts = stats.common.tx_err_drop_pkts; 3388c2ecf20Sopenharmony_ci p_common->coalesced_pkts = stats.common.tpa_coalesced_pkts; 3398c2ecf20Sopenharmony_ci p_common->coalesced_events = stats.common.tpa_coalesced_events; 3408c2ecf20Sopenharmony_ci p_common->coalesced_aborts_num = stats.common.tpa_aborts_num; 3418c2ecf20Sopenharmony_ci p_common->non_coalesced_pkts = stats.common.tpa_not_coalesced_pkts; 3428c2ecf20Sopenharmony_ci p_common->coalesced_bytes = stats.common.tpa_coalesced_bytes; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci p_common->rx_64_byte_packets = stats.common.rx_64_byte_packets; 3458c2ecf20Sopenharmony_ci p_common->rx_65_to_127_byte_packets = 3468c2ecf20Sopenharmony_ci stats.common.rx_65_to_127_byte_packets; 3478c2ecf20Sopenharmony_ci p_common->rx_128_to_255_byte_packets = 3488c2ecf20Sopenharmony_ci stats.common.rx_128_to_255_byte_packets; 3498c2ecf20Sopenharmony_ci p_common->rx_256_to_511_byte_packets = 3508c2ecf20Sopenharmony_ci stats.common.rx_256_to_511_byte_packets; 3518c2ecf20Sopenharmony_ci p_common->rx_512_to_1023_byte_packets = 3528c2ecf20Sopenharmony_ci stats.common.rx_512_to_1023_byte_packets; 3538c2ecf20Sopenharmony_ci p_common->rx_1024_to_1518_byte_packets = 3548c2ecf20Sopenharmony_ci stats.common.rx_1024_to_1518_byte_packets; 3558c2ecf20Sopenharmony_ci p_common->rx_crc_errors = stats.common.rx_crc_errors; 3568c2ecf20Sopenharmony_ci p_common->rx_mac_crtl_frames = stats.common.rx_mac_crtl_frames; 3578c2ecf20Sopenharmony_ci p_common->rx_pause_frames = stats.common.rx_pause_frames; 3588c2ecf20Sopenharmony_ci p_common->rx_pfc_frames = stats.common.rx_pfc_frames; 3598c2ecf20Sopenharmony_ci p_common->rx_align_errors = stats.common.rx_align_errors; 3608c2ecf20Sopenharmony_ci p_common->rx_carrier_errors = stats.common.rx_carrier_errors; 3618c2ecf20Sopenharmony_ci p_common->rx_oversize_packets = stats.common.rx_oversize_packets; 3628c2ecf20Sopenharmony_ci p_common->rx_jabbers = stats.common.rx_jabbers; 3638c2ecf20Sopenharmony_ci p_common->rx_undersize_packets = stats.common.rx_undersize_packets; 3648c2ecf20Sopenharmony_ci p_common->rx_fragments = stats.common.rx_fragments; 3658c2ecf20Sopenharmony_ci p_common->tx_64_byte_packets = stats.common.tx_64_byte_packets; 3668c2ecf20Sopenharmony_ci p_common->tx_65_to_127_byte_packets = 3678c2ecf20Sopenharmony_ci stats.common.tx_65_to_127_byte_packets; 3688c2ecf20Sopenharmony_ci p_common->tx_128_to_255_byte_packets = 3698c2ecf20Sopenharmony_ci stats.common.tx_128_to_255_byte_packets; 3708c2ecf20Sopenharmony_ci p_common->tx_256_to_511_byte_packets = 3718c2ecf20Sopenharmony_ci stats.common.tx_256_to_511_byte_packets; 3728c2ecf20Sopenharmony_ci p_common->tx_512_to_1023_byte_packets = 3738c2ecf20Sopenharmony_ci stats.common.tx_512_to_1023_byte_packets; 3748c2ecf20Sopenharmony_ci p_common->tx_1024_to_1518_byte_packets = 3758c2ecf20Sopenharmony_ci stats.common.tx_1024_to_1518_byte_packets; 3768c2ecf20Sopenharmony_ci p_common->tx_pause_frames = stats.common.tx_pause_frames; 3778c2ecf20Sopenharmony_ci p_common->tx_pfc_frames = stats.common.tx_pfc_frames; 3788c2ecf20Sopenharmony_ci p_common->brb_truncates = stats.common.brb_truncates; 3798c2ecf20Sopenharmony_ci p_common->brb_discards = stats.common.brb_discards; 3808c2ecf20Sopenharmony_ci p_common->tx_mac_ctrl_frames = stats.common.tx_mac_ctrl_frames; 3818c2ecf20Sopenharmony_ci p_common->link_change_count = stats.common.link_change_count; 3828c2ecf20Sopenharmony_ci p_common->ptp_skip_txts = edev->ptp_skip_txts; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (QEDE_IS_BB(edev)) { 3858c2ecf20Sopenharmony_ci struct qede_stats_bb *p_bb = &edev->stats.bb; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci p_bb->rx_1519_to_1522_byte_packets = 3888c2ecf20Sopenharmony_ci stats.bb.rx_1519_to_1522_byte_packets; 3898c2ecf20Sopenharmony_ci p_bb->rx_1519_to_2047_byte_packets = 3908c2ecf20Sopenharmony_ci stats.bb.rx_1519_to_2047_byte_packets; 3918c2ecf20Sopenharmony_ci p_bb->rx_2048_to_4095_byte_packets = 3928c2ecf20Sopenharmony_ci stats.bb.rx_2048_to_4095_byte_packets; 3938c2ecf20Sopenharmony_ci p_bb->rx_4096_to_9216_byte_packets = 3948c2ecf20Sopenharmony_ci stats.bb.rx_4096_to_9216_byte_packets; 3958c2ecf20Sopenharmony_ci p_bb->rx_9217_to_16383_byte_packets = 3968c2ecf20Sopenharmony_ci stats.bb.rx_9217_to_16383_byte_packets; 3978c2ecf20Sopenharmony_ci p_bb->tx_1519_to_2047_byte_packets = 3988c2ecf20Sopenharmony_ci stats.bb.tx_1519_to_2047_byte_packets; 3998c2ecf20Sopenharmony_ci p_bb->tx_2048_to_4095_byte_packets = 4008c2ecf20Sopenharmony_ci stats.bb.tx_2048_to_4095_byte_packets; 4018c2ecf20Sopenharmony_ci p_bb->tx_4096_to_9216_byte_packets = 4028c2ecf20Sopenharmony_ci stats.bb.tx_4096_to_9216_byte_packets; 4038c2ecf20Sopenharmony_ci p_bb->tx_9217_to_16383_byte_packets = 4048c2ecf20Sopenharmony_ci stats.bb.tx_9217_to_16383_byte_packets; 4058c2ecf20Sopenharmony_ci p_bb->tx_lpi_entry_count = stats.bb.tx_lpi_entry_count; 4068c2ecf20Sopenharmony_ci p_bb->tx_total_collisions = stats.bb.tx_total_collisions; 4078c2ecf20Sopenharmony_ci } else { 4088c2ecf20Sopenharmony_ci struct qede_stats_ah *p_ah = &edev->stats.ah; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci p_ah->rx_1519_to_max_byte_packets = 4118c2ecf20Sopenharmony_ci stats.ah.rx_1519_to_max_byte_packets; 4128c2ecf20Sopenharmony_ci p_ah->tx_1519_to_max_byte_packets = 4138c2ecf20Sopenharmony_ci stats.ah.tx_1519_to_max_byte_packets; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci spin_unlock(&edev->stats_lock); 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_cistatic void qede_get_stats64(struct net_device *dev, 4208c2ecf20Sopenharmony_ci struct rtnl_link_stats64 *stats) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 4238c2ecf20Sopenharmony_ci struct qede_stats_common *p_common; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci p_common = &edev->stats.common; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci spin_lock(&edev->stats_lock); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci stats->rx_packets = p_common->rx_ucast_pkts + p_common->rx_mcast_pkts + 4308c2ecf20Sopenharmony_ci p_common->rx_bcast_pkts; 4318c2ecf20Sopenharmony_ci stats->tx_packets = p_common->tx_ucast_pkts + p_common->tx_mcast_pkts + 4328c2ecf20Sopenharmony_ci p_common->tx_bcast_pkts; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci stats->rx_bytes = p_common->rx_ucast_bytes + p_common->rx_mcast_bytes + 4358c2ecf20Sopenharmony_ci p_common->rx_bcast_bytes; 4368c2ecf20Sopenharmony_ci stats->tx_bytes = p_common->tx_ucast_bytes + p_common->tx_mcast_bytes + 4378c2ecf20Sopenharmony_ci p_common->tx_bcast_bytes; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci stats->tx_errors = p_common->tx_err_drop_pkts; 4408c2ecf20Sopenharmony_ci stats->multicast = p_common->rx_mcast_pkts + p_common->rx_bcast_pkts; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci stats->rx_fifo_errors = p_common->no_buff_discards; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci if (QEDE_IS_BB(edev)) 4458c2ecf20Sopenharmony_ci stats->collisions = edev->stats.bb.tx_total_collisions; 4468c2ecf20Sopenharmony_ci stats->rx_crc_errors = p_common->rx_crc_errors; 4478c2ecf20Sopenharmony_ci stats->rx_frame_errors = p_common->rx_align_errors; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci spin_unlock(&edev->stats_lock); 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci#ifdef CONFIG_QED_SRIOV 4538c2ecf20Sopenharmony_cistatic int qede_get_vf_config(struct net_device *dev, int vfidx, 4548c2ecf20Sopenharmony_ci struct ifla_vf_info *ivi) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci if (!edev->ops) 4598c2ecf20Sopenharmony_ci return -EINVAL; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci return edev->ops->iov->get_config(edev->cdev, vfidx, ivi); 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_cistatic int qede_set_vf_rate(struct net_device *dev, int vfidx, 4658c2ecf20Sopenharmony_ci int min_tx_rate, int max_tx_rate) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci return edev->ops->iov->set_rate(edev->cdev, vfidx, min_tx_rate, 4708c2ecf20Sopenharmony_ci max_tx_rate); 4718c2ecf20Sopenharmony_ci} 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_cistatic int qede_set_vf_spoofchk(struct net_device *dev, int vfidx, bool val) 4748c2ecf20Sopenharmony_ci{ 4758c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if (!edev->ops) 4788c2ecf20Sopenharmony_ci return -EINVAL; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci return edev->ops->iov->set_spoof(edev->cdev, vfidx, val); 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic int qede_set_vf_link_state(struct net_device *dev, int vfidx, 4848c2ecf20Sopenharmony_ci int link_state) 4858c2ecf20Sopenharmony_ci{ 4868c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci if (!edev->ops) 4898c2ecf20Sopenharmony_ci return -EINVAL; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci return edev->ops->iov->set_link_state(edev->cdev, vfidx, link_state); 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic int qede_set_vf_trust(struct net_device *dev, int vfidx, bool setting) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci if (!edev->ops) 4998c2ecf20Sopenharmony_ci return -EINVAL; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci return edev->ops->iov->set_trust(edev->cdev, vfidx, setting); 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci#endif 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_cistatic int qede_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci if (!netif_running(dev)) 5108c2ecf20Sopenharmony_ci return -EAGAIN; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci switch (cmd) { 5138c2ecf20Sopenharmony_ci case SIOCSHWTSTAMP: 5148c2ecf20Sopenharmony_ci return qede_ptp_hw_ts(edev, ifr); 5158c2ecf20Sopenharmony_ci default: 5168c2ecf20Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_DEBUG, 5178c2ecf20Sopenharmony_ci "default IOCTL cmd 0x%x\n", cmd); 5188c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci return 0; 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_cistatic void qede_tx_log_print(struct qede_dev *edev, struct qede_tx_queue *txq) 5258c2ecf20Sopenharmony_ci{ 5268c2ecf20Sopenharmony_ci DP_NOTICE(edev, 5278c2ecf20Sopenharmony_ci "Txq[%d]: FW cons [host] %04x, SW cons %04x, SW prod %04x [Jiffies %lu]\n", 5288c2ecf20Sopenharmony_ci txq->index, le16_to_cpu(*txq->hw_cons_ptr), 5298c2ecf20Sopenharmony_ci qed_chain_get_cons_idx(&txq->tx_pbl), 5308c2ecf20Sopenharmony_ci qed_chain_get_prod_idx(&txq->tx_pbl), 5318c2ecf20Sopenharmony_ci jiffies); 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_cistatic void qede_tx_timeout(struct net_device *dev, unsigned int txqueue) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 5378c2ecf20Sopenharmony_ci struct qede_tx_queue *txq; 5388c2ecf20Sopenharmony_ci int cos; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci netif_carrier_off(dev); 5418c2ecf20Sopenharmony_ci DP_NOTICE(edev, "TX timeout on queue %u!\n", txqueue); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci if (!(edev->fp_array[txqueue].type & QEDE_FASTPATH_TX)) 5448c2ecf20Sopenharmony_ci return; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci for_each_cos_in_txq(edev, cos) { 5478c2ecf20Sopenharmony_ci txq = &edev->fp_array[txqueue].txq[cos]; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci if (qed_chain_get_cons_idx(&txq->tx_pbl) != 5508c2ecf20Sopenharmony_ci qed_chain_get_prod_idx(&txq->tx_pbl)) 5518c2ecf20Sopenharmony_ci qede_tx_log_print(edev, txq); 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (IS_VF(edev)) 5558c2ecf20Sopenharmony_ci return; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci if (test_and_set_bit(QEDE_ERR_IS_HANDLED, &edev->err_flags) || 5588c2ecf20Sopenharmony_ci edev->state == QEDE_STATE_RECOVERY) { 5598c2ecf20Sopenharmony_ci DP_INFO(edev, 5608c2ecf20Sopenharmony_ci "Avoid handling a Tx timeout while another HW error is being handled\n"); 5618c2ecf20Sopenharmony_ci return; 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci set_bit(QEDE_ERR_GET_DBG_INFO, &edev->err_flags); 5658c2ecf20Sopenharmony_ci set_bit(QEDE_SP_HW_ERR, &edev->sp_flags); 5668c2ecf20Sopenharmony_ci schedule_delayed_work(&edev->sp_task, 0); 5678c2ecf20Sopenharmony_ci} 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_cistatic int qede_setup_tc(struct net_device *ndev, u8 num_tc) 5708c2ecf20Sopenharmony_ci{ 5718c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(ndev); 5728c2ecf20Sopenharmony_ci int cos, count, offset; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci if (num_tc > edev->dev_info.num_tc) 5758c2ecf20Sopenharmony_ci return -EINVAL; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci netdev_reset_tc(ndev); 5788c2ecf20Sopenharmony_ci netdev_set_num_tc(ndev, num_tc); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci for_each_cos_in_txq(edev, cos) { 5818c2ecf20Sopenharmony_ci count = QEDE_TSS_COUNT(edev); 5828c2ecf20Sopenharmony_ci offset = cos * QEDE_TSS_COUNT(edev); 5838c2ecf20Sopenharmony_ci netdev_set_tc_queue(ndev, cos, count, offset); 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci return 0; 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_cistatic int 5908c2ecf20Sopenharmony_ciqede_set_flower(struct qede_dev *edev, struct flow_cls_offload *f, 5918c2ecf20Sopenharmony_ci __be16 proto) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci switch (f->command) { 5948c2ecf20Sopenharmony_ci case FLOW_CLS_REPLACE: 5958c2ecf20Sopenharmony_ci return qede_add_tc_flower_fltr(edev, proto, f); 5968c2ecf20Sopenharmony_ci case FLOW_CLS_DESTROY: 5978c2ecf20Sopenharmony_ci return qede_delete_flow_filter(edev, f->cookie); 5988c2ecf20Sopenharmony_ci default: 5998c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_cistatic int qede_setup_tc_block_cb(enum tc_setup_type type, void *type_data, 6048c2ecf20Sopenharmony_ci void *cb_priv) 6058c2ecf20Sopenharmony_ci{ 6068c2ecf20Sopenharmony_ci struct flow_cls_offload *f; 6078c2ecf20Sopenharmony_ci struct qede_dev *edev = cb_priv; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci if (!tc_cls_can_offload_and_chain0(edev->ndev, type_data)) 6108c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci switch (type) { 6138c2ecf20Sopenharmony_ci case TC_SETUP_CLSFLOWER: 6148c2ecf20Sopenharmony_ci f = type_data; 6158c2ecf20Sopenharmony_ci return qede_set_flower(edev, f, f->common.protocol); 6168c2ecf20Sopenharmony_ci default: 6178c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci} 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_cistatic LIST_HEAD(qede_block_cb_list); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_cistatic int 6248c2ecf20Sopenharmony_ciqede_setup_tc_offload(struct net_device *dev, enum tc_setup_type type, 6258c2ecf20Sopenharmony_ci void *type_data) 6268c2ecf20Sopenharmony_ci{ 6278c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 6288c2ecf20Sopenharmony_ci struct tc_mqprio_qopt *mqprio; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci switch (type) { 6318c2ecf20Sopenharmony_ci case TC_SETUP_BLOCK: 6328c2ecf20Sopenharmony_ci return flow_block_cb_setup_simple(type_data, 6338c2ecf20Sopenharmony_ci &qede_block_cb_list, 6348c2ecf20Sopenharmony_ci qede_setup_tc_block_cb, 6358c2ecf20Sopenharmony_ci edev, edev, true); 6368c2ecf20Sopenharmony_ci case TC_SETUP_QDISC_MQPRIO: 6378c2ecf20Sopenharmony_ci mqprio = type_data; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS; 6408c2ecf20Sopenharmony_ci return qede_setup_tc(dev, mqprio->num_tc); 6418c2ecf20Sopenharmony_ci default: 6428c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_cistatic const struct net_device_ops qede_netdev_ops = { 6478c2ecf20Sopenharmony_ci .ndo_open = qede_open, 6488c2ecf20Sopenharmony_ci .ndo_stop = qede_close, 6498c2ecf20Sopenharmony_ci .ndo_start_xmit = qede_start_xmit, 6508c2ecf20Sopenharmony_ci .ndo_select_queue = qede_select_queue, 6518c2ecf20Sopenharmony_ci .ndo_set_rx_mode = qede_set_rx_mode, 6528c2ecf20Sopenharmony_ci .ndo_set_mac_address = qede_set_mac_addr, 6538c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 6548c2ecf20Sopenharmony_ci .ndo_change_mtu = qede_change_mtu, 6558c2ecf20Sopenharmony_ci .ndo_do_ioctl = qede_ioctl, 6568c2ecf20Sopenharmony_ci .ndo_tx_timeout = qede_tx_timeout, 6578c2ecf20Sopenharmony_ci#ifdef CONFIG_QED_SRIOV 6588c2ecf20Sopenharmony_ci .ndo_set_vf_mac = qede_set_vf_mac, 6598c2ecf20Sopenharmony_ci .ndo_set_vf_vlan = qede_set_vf_vlan, 6608c2ecf20Sopenharmony_ci .ndo_set_vf_trust = qede_set_vf_trust, 6618c2ecf20Sopenharmony_ci#endif 6628c2ecf20Sopenharmony_ci .ndo_vlan_rx_add_vid = qede_vlan_rx_add_vid, 6638c2ecf20Sopenharmony_ci .ndo_vlan_rx_kill_vid = qede_vlan_rx_kill_vid, 6648c2ecf20Sopenharmony_ci .ndo_fix_features = qede_fix_features, 6658c2ecf20Sopenharmony_ci .ndo_set_features = qede_set_features, 6668c2ecf20Sopenharmony_ci .ndo_get_stats64 = qede_get_stats64, 6678c2ecf20Sopenharmony_ci#ifdef CONFIG_QED_SRIOV 6688c2ecf20Sopenharmony_ci .ndo_set_vf_link_state = qede_set_vf_link_state, 6698c2ecf20Sopenharmony_ci .ndo_set_vf_spoofchk = qede_set_vf_spoofchk, 6708c2ecf20Sopenharmony_ci .ndo_get_vf_config = qede_get_vf_config, 6718c2ecf20Sopenharmony_ci .ndo_set_vf_rate = qede_set_vf_rate, 6728c2ecf20Sopenharmony_ci#endif 6738c2ecf20Sopenharmony_ci .ndo_udp_tunnel_add = udp_tunnel_nic_add_port, 6748c2ecf20Sopenharmony_ci .ndo_udp_tunnel_del = udp_tunnel_nic_del_port, 6758c2ecf20Sopenharmony_ci .ndo_features_check = qede_features_check, 6768c2ecf20Sopenharmony_ci .ndo_bpf = qede_xdp, 6778c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 6788c2ecf20Sopenharmony_ci .ndo_rx_flow_steer = qede_rx_flow_steer, 6798c2ecf20Sopenharmony_ci#endif 6808c2ecf20Sopenharmony_ci .ndo_xdp_xmit = qede_xdp_transmit, 6818c2ecf20Sopenharmony_ci .ndo_setup_tc = qede_setup_tc_offload, 6828c2ecf20Sopenharmony_ci}; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_cistatic const struct net_device_ops qede_netdev_vf_ops = { 6858c2ecf20Sopenharmony_ci .ndo_open = qede_open, 6868c2ecf20Sopenharmony_ci .ndo_stop = qede_close, 6878c2ecf20Sopenharmony_ci .ndo_start_xmit = qede_start_xmit, 6888c2ecf20Sopenharmony_ci .ndo_select_queue = qede_select_queue, 6898c2ecf20Sopenharmony_ci .ndo_set_rx_mode = qede_set_rx_mode, 6908c2ecf20Sopenharmony_ci .ndo_set_mac_address = qede_set_mac_addr, 6918c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 6928c2ecf20Sopenharmony_ci .ndo_change_mtu = qede_change_mtu, 6938c2ecf20Sopenharmony_ci .ndo_vlan_rx_add_vid = qede_vlan_rx_add_vid, 6948c2ecf20Sopenharmony_ci .ndo_vlan_rx_kill_vid = qede_vlan_rx_kill_vid, 6958c2ecf20Sopenharmony_ci .ndo_fix_features = qede_fix_features, 6968c2ecf20Sopenharmony_ci .ndo_set_features = qede_set_features, 6978c2ecf20Sopenharmony_ci .ndo_get_stats64 = qede_get_stats64, 6988c2ecf20Sopenharmony_ci .ndo_udp_tunnel_add = udp_tunnel_nic_add_port, 6998c2ecf20Sopenharmony_ci .ndo_udp_tunnel_del = udp_tunnel_nic_del_port, 7008c2ecf20Sopenharmony_ci .ndo_features_check = qede_features_check, 7018c2ecf20Sopenharmony_ci}; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_cistatic const struct net_device_ops qede_netdev_vf_xdp_ops = { 7048c2ecf20Sopenharmony_ci .ndo_open = qede_open, 7058c2ecf20Sopenharmony_ci .ndo_stop = qede_close, 7068c2ecf20Sopenharmony_ci .ndo_start_xmit = qede_start_xmit, 7078c2ecf20Sopenharmony_ci .ndo_select_queue = qede_select_queue, 7088c2ecf20Sopenharmony_ci .ndo_set_rx_mode = qede_set_rx_mode, 7098c2ecf20Sopenharmony_ci .ndo_set_mac_address = qede_set_mac_addr, 7108c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 7118c2ecf20Sopenharmony_ci .ndo_change_mtu = qede_change_mtu, 7128c2ecf20Sopenharmony_ci .ndo_vlan_rx_add_vid = qede_vlan_rx_add_vid, 7138c2ecf20Sopenharmony_ci .ndo_vlan_rx_kill_vid = qede_vlan_rx_kill_vid, 7148c2ecf20Sopenharmony_ci .ndo_fix_features = qede_fix_features, 7158c2ecf20Sopenharmony_ci .ndo_set_features = qede_set_features, 7168c2ecf20Sopenharmony_ci .ndo_get_stats64 = qede_get_stats64, 7178c2ecf20Sopenharmony_ci .ndo_udp_tunnel_add = udp_tunnel_nic_add_port, 7188c2ecf20Sopenharmony_ci .ndo_udp_tunnel_del = udp_tunnel_nic_del_port, 7198c2ecf20Sopenharmony_ci .ndo_features_check = qede_features_check, 7208c2ecf20Sopenharmony_ci .ndo_bpf = qede_xdp, 7218c2ecf20Sopenharmony_ci .ndo_xdp_xmit = qede_xdp_transmit, 7228c2ecf20Sopenharmony_ci}; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------------- 7258c2ecf20Sopenharmony_ci * START OF PROBE / REMOVE 7268c2ecf20Sopenharmony_ci * ------------------------------------------------------------------------- 7278c2ecf20Sopenharmony_ci */ 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_cistatic struct qede_dev *qede_alloc_etherdev(struct qed_dev *cdev, 7308c2ecf20Sopenharmony_ci struct pci_dev *pdev, 7318c2ecf20Sopenharmony_ci struct qed_dev_eth_info *info, 7328c2ecf20Sopenharmony_ci u32 dp_module, u8 dp_level) 7338c2ecf20Sopenharmony_ci{ 7348c2ecf20Sopenharmony_ci struct net_device *ndev; 7358c2ecf20Sopenharmony_ci struct qede_dev *edev; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci ndev = alloc_etherdev_mqs(sizeof(*edev), 7388c2ecf20Sopenharmony_ci info->num_queues * info->num_tc, 7398c2ecf20Sopenharmony_ci info->num_queues); 7408c2ecf20Sopenharmony_ci if (!ndev) { 7418c2ecf20Sopenharmony_ci pr_err("etherdev allocation failed\n"); 7428c2ecf20Sopenharmony_ci return NULL; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci edev = netdev_priv(ndev); 7468c2ecf20Sopenharmony_ci edev->ndev = ndev; 7478c2ecf20Sopenharmony_ci edev->cdev = cdev; 7488c2ecf20Sopenharmony_ci edev->pdev = pdev; 7498c2ecf20Sopenharmony_ci edev->dp_module = dp_module; 7508c2ecf20Sopenharmony_ci edev->dp_level = dp_level; 7518c2ecf20Sopenharmony_ci edev->ops = qed_ops; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci if (is_kdump_kernel()) { 7548c2ecf20Sopenharmony_ci edev->q_num_rx_buffers = NUM_RX_BDS_KDUMP_MIN; 7558c2ecf20Sopenharmony_ci edev->q_num_tx_buffers = NUM_TX_BDS_KDUMP_MIN; 7568c2ecf20Sopenharmony_ci } else { 7578c2ecf20Sopenharmony_ci edev->q_num_rx_buffers = NUM_RX_BDS_DEF; 7588c2ecf20Sopenharmony_ci edev->q_num_tx_buffers = NUM_TX_BDS_DEF; 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci DP_INFO(edev, "Allocated netdev with %d tx queues and %d rx queues\n", 7628c2ecf20Sopenharmony_ci info->num_queues, info->num_queues); 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci SET_NETDEV_DEV(ndev, &pdev->dev); 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci memset(&edev->stats, 0, sizeof(edev->stats)); 7678c2ecf20Sopenharmony_ci memcpy(&edev->dev_info, info, sizeof(*info)); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci /* As ethtool doesn't have the ability to show WoL behavior as 7708c2ecf20Sopenharmony_ci * 'default', if device supports it declare it's enabled. 7718c2ecf20Sopenharmony_ci */ 7728c2ecf20Sopenharmony_ci if (edev->dev_info.common.wol_support) 7738c2ecf20Sopenharmony_ci edev->wol_enabled = true; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&edev->vlan_list); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci return edev; 7788c2ecf20Sopenharmony_ci} 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_cistatic void qede_init_ndev(struct qede_dev *edev) 7818c2ecf20Sopenharmony_ci{ 7828c2ecf20Sopenharmony_ci struct net_device *ndev = edev->ndev; 7838c2ecf20Sopenharmony_ci struct pci_dev *pdev = edev->pdev; 7848c2ecf20Sopenharmony_ci bool udp_tunnel_enable = false; 7858c2ecf20Sopenharmony_ci netdev_features_t hw_features; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, ndev); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci ndev->mem_start = edev->dev_info.common.pci_mem_start; 7908c2ecf20Sopenharmony_ci ndev->base_addr = ndev->mem_start; 7918c2ecf20Sopenharmony_ci ndev->mem_end = edev->dev_info.common.pci_mem_end; 7928c2ecf20Sopenharmony_ci ndev->irq = edev->dev_info.common.pci_irq; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci ndev->watchdog_timeo = TX_TIMEOUT; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci if (IS_VF(edev)) { 7978c2ecf20Sopenharmony_ci if (edev->dev_info.xdp_supported) 7988c2ecf20Sopenharmony_ci ndev->netdev_ops = &qede_netdev_vf_xdp_ops; 7998c2ecf20Sopenharmony_ci else 8008c2ecf20Sopenharmony_ci ndev->netdev_ops = &qede_netdev_vf_ops; 8018c2ecf20Sopenharmony_ci } else { 8028c2ecf20Sopenharmony_ci ndev->netdev_ops = &qede_netdev_ops; 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci qede_set_ethtool_ops(ndev); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci ndev->priv_flags |= IFF_UNICAST_FLT; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci /* user-changeble features */ 8108c2ecf20Sopenharmony_ci hw_features = NETIF_F_GRO | NETIF_F_GRO_HW | NETIF_F_SG | 8118c2ecf20Sopenharmony_ci NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | 8128c2ecf20Sopenharmony_ci NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_TC; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci if (edev->dev_info.common.b_arfs_capable) 8158c2ecf20Sopenharmony_ci hw_features |= NETIF_F_NTUPLE; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci if (edev->dev_info.common.vxlan_enable || 8188c2ecf20Sopenharmony_ci edev->dev_info.common.geneve_enable) 8198c2ecf20Sopenharmony_ci udp_tunnel_enable = true; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci if (udp_tunnel_enable || edev->dev_info.common.gre_enable) { 8228c2ecf20Sopenharmony_ci hw_features |= NETIF_F_TSO_ECN; 8238c2ecf20Sopenharmony_ci ndev->hw_enc_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | 8248c2ecf20Sopenharmony_ci NETIF_F_SG | NETIF_F_TSO | 8258c2ecf20Sopenharmony_ci NETIF_F_TSO_ECN | NETIF_F_TSO6 | 8268c2ecf20Sopenharmony_ci NETIF_F_RXCSUM; 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci if (udp_tunnel_enable) { 8308c2ecf20Sopenharmony_ci hw_features |= (NETIF_F_GSO_UDP_TUNNEL | 8318c2ecf20Sopenharmony_ci NETIF_F_GSO_UDP_TUNNEL_CSUM); 8328c2ecf20Sopenharmony_ci ndev->hw_enc_features |= (NETIF_F_GSO_UDP_TUNNEL | 8338c2ecf20Sopenharmony_ci NETIF_F_GSO_UDP_TUNNEL_CSUM); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci qede_set_udp_tunnels(edev); 8368c2ecf20Sopenharmony_ci } 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci if (edev->dev_info.common.gre_enable) { 8398c2ecf20Sopenharmony_ci hw_features |= (NETIF_F_GSO_GRE | NETIF_F_GSO_GRE_CSUM); 8408c2ecf20Sopenharmony_ci ndev->hw_enc_features |= (NETIF_F_GSO_GRE | 8418c2ecf20Sopenharmony_ci NETIF_F_GSO_GRE_CSUM); 8428c2ecf20Sopenharmony_ci } 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci ndev->vlan_features = hw_features | NETIF_F_RXHASH | NETIF_F_RXCSUM | 8458c2ecf20Sopenharmony_ci NETIF_F_HIGHDMA; 8468c2ecf20Sopenharmony_ci ndev->features = hw_features | NETIF_F_RXHASH | NETIF_F_RXCSUM | 8478c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HIGHDMA | 8488c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_CTAG_TX; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci ndev->hw_features = hw_features; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci /* MTU range: 46 - 9600 */ 8538c2ecf20Sopenharmony_ci ndev->min_mtu = ETH_ZLEN - ETH_HLEN; 8548c2ecf20Sopenharmony_ci ndev->max_mtu = QEDE_MAX_JUMBO_PACKET_SIZE; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci /* Set network device HW mac */ 8578c2ecf20Sopenharmony_ci ether_addr_copy(edev->ndev->dev_addr, edev->dev_info.common.hw_mac); 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci ndev->mtu = edev->dev_info.common.mtu; 8608c2ecf20Sopenharmony_ci} 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci/* This function converts from 32b param to two params of level and module 8638c2ecf20Sopenharmony_ci * Input 32b decoding: 8648c2ecf20Sopenharmony_ci * b31 - enable all NOTICE prints. NOTICE prints are for deviation from the 8658c2ecf20Sopenharmony_ci * 'happy' flow, e.g. memory allocation failed. 8668c2ecf20Sopenharmony_ci * b30 - enable all INFO prints. INFO prints are for major steps in the flow 8678c2ecf20Sopenharmony_ci * and provide important parameters. 8688c2ecf20Sopenharmony_ci * b29-b0 - per-module bitmap, where each bit enables VERBOSE prints of that 8698c2ecf20Sopenharmony_ci * module. VERBOSE prints are for tracking the specific flow in low level. 8708c2ecf20Sopenharmony_ci * 8718c2ecf20Sopenharmony_ci * Notice that the level should be that of the lowest required logs. 8728c2ecf20Sopenharmony_ci */ 8738c2ecf20Sopenharmony_civoid qede_config_debug(uint debug, u32 *p_dp_module, u8 *p_dp_level) 8748c2ecf20Sopenharmony_ci{ 8758c2ecf20Sopenharmony_ci *p_dp_level = QED_LEVEL_NOTICE; 8768c2ecf20Sopenharmony_ci *p_dp_module = 0; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci if (debug & QED_LOG_VERBOSE_MASK) { 8798c2ecf20Sopenharmony_ci *p_dp_level = QED_LEVEL_VERBOSE; 8808c2ecf20Sopenharmony_ci *p_dp_module = (debug & 0x3FFFFFFF); 8818c2ecf20Sopenharmony_ci } else if (debug & QED_LOG_INFO_MASK) { 8828c2ecf20Sopenharmony_ci *p_dp_level = QED_LEVEL_INFO; 8838c2ecf20Sopenharmony_ci } else if (debug & QED_LOG_NOTICE_MASK) { 8848c2ecf20Sopenharmony_ci *p_dp_level = QED_LEVEL_NOTICE; 8858c2ecf20Sopenharmony_ci } 8868c2ecf20Sopenharmony_ci} 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_cistatic void qede_free_fp_array(struct qede_dev *edev) 8898c2ecf20Sopenharmony_ci{ 8908c2ecf20Sopenharmony_ci if (edev->fp_array) { 8918c2ecf20Sopenharmony_ci struct qede_fastpath *fp; 8928c2ecf20Sopenharmony_ci int i; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci for_each_queue(i) { 8958c2ecf20Sopenharmony_ci fp = &edev->fp_array[i]; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci kfree(fp->sb_info); 8988c2ecf20Sopenharmony_ci /* Handle mem alloc failure case where qede_init_fp 8998c2ecf20Sopenharmony_ci * didn't register xdp_rxq_info yet. 9008c2ecf20Sopenharmony_ci * Implicit only (fp->type & QEDE_FASTPATH_RX) 9018c2ecf20Sopenharmony_ci */ 9028c2ecf20Sopenharmony_ci if (fp->rxq && xdp_rxq_info_is_reg(&fp->rxq->xdp_rxq)) 9038c2ecf20Sopenharmony_ci xdp_rxq_info_unreg(&fp->rxq->xdp_rxq); 9048c2ecf20Sopenharmony_ci kfree(fp->rxq); 9058c2ecf20Sopenharmony_ci kfree(fp->xdp_tx); 9068c2ecf20Sopenharmony_ci kfree(fp->txq); 9078c2ecf20Sopenharmony_ci } 9088c2ecf20Sopenharmony_ci kfree(edev->fp_array); 9098c2ecf20Sopenharmony_ci } 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci edev->num_queues = 0; 9128c2ecf20Sopenharmony_ci edev->fp_num_tx = 0; 9138c2ecf20Sopenharmony_ci edev->fp_num_rx = 0; 9148c2ecf20Sopenharmony_ci} 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_cistatic int qede_alloc_fp_array(struct qede_dev *edev) 9178c2ecf20Sopenharmony_ci{ 9188c2ecf20Sopenharmony_ci u8 fp_combined, fp_rx = edev->fp_num_rx; 9198c2ecf20Sopenharmony_ci struct qede_fastpath *fp; 9208c2ecf20Sopenharmony_ci int i; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci edev->fp_array = kcalloc(QEDE_QUEUE_CNT(edev), 9238c2ecf20Sopenharmony_ci sizeof(*edev->fp_array), GFP_KERNEL); 9248c2ecf20Sopenharmony_ci if (!edev->fp_array) { 9258c2ecf20Sopenharmony_ci DP_NOTICE(edev, "fp array allocation failed\n"); 9268c2ecf20Sopenharmony_ci goto err; 9278c2ecf20Sopenharmony_ci } 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci fp_combined = QEDE_QUEUE_CNT(edev) - fp_rx - edev->fp_num_tx; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci /* Allocate the FP elements for Rx queues followed by combined and then 9328c2ecf20Sopenharmony_ci * the Tx. This ordering should be maintained so that the respective 9338c2ecf20Sopenharmony_ci * queues (Rx or Tx) will be together in the fastpath array and the 9348c2ecf20Sopenharmony_ci * associated ids will be sequential. 9358c2ecf20Sopenharmony_ci */ 9368c2ecf20Sopenharmony_ci for_each_queue(i) { 9378c2ecf20Sopenharmony_ci fp = &edev->fp_array[i]; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci fp->sb_info = kzalloc(sizeof(*fp->sb_info), GFP_KERNEL); 9408c2ecf20Sopenharmony_ci if (!fp->sb_info) { 9418c2ecf20Sopenharmony_ci DP_NOTICE(edev, "sb info struct allocation failed\n"); 9428c2ecf20Sopenharmony_ci goto err; 9438c2ecf20Sopenharmony_ci } 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci if (fp_rx) { 9468c2ecf20Sopenharmony_ci fp->type = QEDE_FASTPATH_RX; 9478c2ecf20Sopenharmony_ci fp_rx--; 9488c2ecf20Sopenharmony_ci } else if (fp_combined) { 9498c2ecf20Sopenharmony_ci fp->type = QEDE_FASTPATH_COMBINED; 9508c2ecf20Sopenharmony_ci fp_combined--; 9518c2ecf20Sopenharmony_ci } else { 9528c2ecf20Sopenharmony_ci fp->type = QEDE_FASTPATH_TX; 9538c2ecf20Sopenharmony_ci } 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_TX) { 9568c2ecf20Sopenharmony_ci fp->txq = kcalloc(edev->dev_info.num_tc, 9578c2ecf20Sopenharmony_ci sizeof(*fp->txq), GFP_KERNEL); 9588c2ecf20Sopenharmony_ci if (!fp->txq) 9598c2ecf20Sopenharmony_ci goto err; 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_RX) { 9638c2ecf20Sopenharmony_ci fp->rxq = kzalloc(sizeof(*fp->rxq), GFP_KERNEL); 9648c2ecf20Sopenharmony_ci if (!fp->rxq) 9658c2ecf20Sopenharmony_ci goto err; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci if (edev->xdp_prog) { 9688c2ecf20Sopenharmony_ci fp->xdp_tx = kzalloc(sizeof(*fp->xdp_tx), 9698c2ecf20Sopenharmony_ci GFP_KERNEL); 9708c2ecf20Sopenharmony_ci if (!fp->xdp_tx) 9718c2ecf20Sopenharmony_ci goto err; 9728c2ecf20Sopenharmony_ci fp->type |= QEDE_FASTPATH_XDP; 9738c2ecf20Sopenharmony_ci } 9748c2ecf20Sopenharmony_ci } 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci return 0; 9788c2ecf20Sopenharmony_cierr: 9798c2ecf20Sopenharmony_ci qede_free_fp_array(edev); 9808c2ecf20Sopenharmony_ci return -ENOMEM; 9818c2ecf20Sopenharmony_ci} 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci/* The qede lock is used to protect driver state change and driver flows that 9848c2ecf20Sopenharmony_ci * are not reentrant. 9858c2ecf20Sopenharmony_ci */ 9868c2ecf20Sopenharmony_civoid __qede_lock(struct qede_dev *edev) 9878c2ecf20Sopenharmony_ci{ 9888c2ecf20Sopenharmony_ci mutex_lock(&edev->qede_lock); 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_civoid __qede_unlock(struct qede_dev *edev) 9928c2ecf20Sopenharmony_ci{ 9938c2ecf20Sopenharmony_ci mutex_unlock(&edev->qede_lock); 9948c2ecf20Sopenharmony_ci} 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci/* This version of the lock should be used when acquiring the RTNL lock is also 9978c2ecf20Sopenharmony_ci * needed in addition to the internal qede lock. 9988c2ecf20Sopenharmony_ci */ 9998c2ecf20Sopenharmony_cistatic void qede_lock(struct qede_dev *edev) 10008c2ecf20Sopenharmony_ci{ 10018c2ecf20Sopenharmony_ci rtnl_lock(); 10028c2ecf20Sopenharmony_ci __qede_lock(edev); 10038c2ecf20Sopenharmony_ci} 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_cistatic void qede_unlock(struct qede_dev *edev) 10068c2ecf20Sopenharmony_ci{ 10078c2ecf20Sopenharmony_ci __qede_unlock(edev); 10088c2ecf20Sopenharmony_ci rtnl_unlock(); 10098c2ecf20Sopenharmony_ci} 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_cistatic void qede_periodic_task(struct work_struct *work) 10128c2ecf20Sopenharmony_ci{ 10138c2ecf20Sopenharmony_ci struct qede_dev *edev = container_of(work, struct qede_dev, 10148c2ecf20Sopenharmony_ci periodic_task.work); 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci qede_fill_by_demand_stats(edev); 10178c2ecf20Sopenharmony_ci schedule_delayed_work(&edev->periodic_task, edev->stats_coal_ticks); 10188c2ecf20Sopenharmony_ci} 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_cistatic void qede_init_periodic_task(struct qede_dev *edev) 10218c2ecf20Sopenharmony_ci{ 10228c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&edev->periodic_task, qede_periodic_task); 10238c2ecf20Sopenharmony_ci spin_lock_init(&edev->stats_lock); 10248c2ecf20Sopenharmony_ci edev->stats_coal_usecs = USEC_PER_SEC; 10258c2ecf20Sopenharmony_ci edev->stats_coal_ticks = usecs_to_jiffies(USEC_PER_SEC); 10268c2ecf20Sopenharmony_ci} 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_cistatic void qede_sp_task(struct work_struct *work) 10298c2ecf20Sopenharmony_ci{ 10308c2ecf20Sopenharmony_ci struct qede_dev *edev = container_of(work, struct qede_dev, 10318c2ecf20Sopenharmony_ci sp_task.work); 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci /* Disable execution of this deferred work once 10348c2ecf20Sopenharmony_ci * qede removal is in progress, this stop any future 10358c2ecf20Sopenharmony_ci * scheduling of sp_task. 10368c2ecf20Sopenharmony_ci */ 10378c2ecf20Sopenharmony_ci if (test_bit(QEDE_SP_DISABLE, &edev->sp_flags)) 10388c2ecf20Sopenharmony_ci return; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci /* The locking scheme depends on the specific flag: 10418c2ecf20Sopenharmony_ci * In case of QEDE_SP_RECOVERY, acquiring the RTNL lock is required to 10428c2ecf20Sopenharmony_ci * ensure that ongoing flows are ended and new ones are not started. 10438c2ecf20Sopenharmony_ci * In other cases - only the internal qede lock should be acquired. 10448c2ecf20Sopenharmony_ci */ 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci if (test_and_clear_bit(QEDE_SP_RECOVERY, &edev->sp_flags)) { 10478c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&edev->periodic_task); 10488c2ecf20Sopenharmony_ci#ifdef CONFIG_QED_SRIOV 10498c2ecf20Sopenharmony_ci /* SRIOV must be disabled outside the lock to avoid a deadlock. 10508c2ecf20Sopenharmony_ci * The recovery of the active VFs is currently not supported. 10518c2ecf20Sopenharmony_ci */ 10528c2ecf20Sopenharmony_ci if (pci_num_vf(edev->pdev)) 10538c2ecf20Sopenharmony_ci qede_sriov_configure(edev->pdev, 0); 10548c2ecf20Sopenharmony_ci#endif 10558c2ecf20Sopenharmony_ci qede_lock(edev); 10568c2ecf20Sopenharmony_ci qede_recovery_handler(edev); 10578c2ecf20Sopenharmony_ci qede_unlock(edev); 10588c2ecf20Sopenharmony_ci } 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci __qede_lock(edev); 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci if (test_and_clear_bit(QEDE_SP_RX_MODE, &edev->sp_flags)) 10638c2ecf20Sopenharmony_ci if (edev->state == QEDE_STATE_OPEN) 10648c2ecf20Sopenharmony_ci qede_config_rx_mode(edev->ndev); 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 10678c2ecf20Sopenharmony_ci if (test_and_clear_bit(QEDE_SP_ARFS_CONFIG, &edev->sp_flags)) { 10688c2ecf20Sopenharmony_ci if (edev->state == QEDE_STATE_OPEN) 10698c2ecf20Sopenharmony_ci qede_process_arfs_filters(edev, false); 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci#endif 10728c2ecf20Sopenharmony_ci if (test_and_clear_bit(QEDE_SP_HW_ERR, &edev->sp_flags)) 10738c2ecf20Sopenharmony_ci qede_generic_hw_err_handler(edev); 10748c2ecf20Sopenharmony_ci __qede_unlock(edev); 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci if (test_and_clear_bit(QEDE_SP_AER, &edev->sp_flags)) { 10778c2ecf20Sopenharmony_ci#ifdef CONFIG_QED_SRIOV 10788c2ecf20Sopenharmony_ci /* SRIOV must be disabled outside the lock to avoid a deadlock. 10798c2ecf20Sopenharmony_ci * The recovery of the active VFs is currently not supported. 10808c2ecf20Sopenharmony_ci */ 10818c2ecf20Sopenharmony_ci if (pci_num_vf(edev->pdev)) 10828c2ecf20Sopenharmony_ci qede_sriov_configure(edev->pdev, 0); 10838c2ecf20Sopenharmony_ci#endif 10848c2ecf20Sopenharmony_ci edev->ops->common->recovery_process(edev->cdev); 10858c2ecf20Sopenharmony_ci } 10868c2ecf20Sopenharmony_ci} 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_cistatic void qede_update_pf_params(struct qed_dev *cdev) 10898c2ecf20Sopenharmony_ci{ 10908c2ecf20Sopenharmony_ci struct qed_pf_params pf_params; 10918c2ecf20Sopenharmony_ci u16 num_cons; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci /* 64 rx + 64 tx + 64 XDP */ 10948c2ecf20Sopenharmony_ci memset(&pf_params, 0, sizeof(struct qed_pf_params)); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci /* 1 rx + 1 xdp + max tx cos */ 10978c2ecf20Sopenharmony_ci num_cons = QED_MIN_L2_CONS; 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci pf_params.eth_pf_params.num_cons = (MAX_SB_PER_PF_MIMD - 1) * num_cons; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci /* Same for VFs - make sure they'll have sufficient connections 11028c2ecf20Sopenharmony_ci * to support XDP Tx queues. 11038c2ecf20Sopenharmony_ci */ 11048c2ecf20Sopenharmony_ci pf_params.eth_pf_params.num_vf_cons = 48; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci pf_params.eth_pf_params.num_arfs_filters = QEDE_RFS_MAX_FLTR; 11078c2ecf20Sopenharmony_ci qed_ops->common->update_pf_params(cdev, &pf_params); 11088c2ecf20Sopenharmony_ci} 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci#define QEDE_FW_VER_STR_SIZE 80 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_cistatic void qede_log_probe(struct qede_dev *edev) 11138c2ecf20Sopenharmony_ci{ 11148c2ecf20Sopenharmony_ci struct qed_dev_info *p_dev_info = &edev->dev_info.common; 11158c2ecf20Sopenharmony_ci u8 buf[QEDE_FW_VER_STR_SIZE]; 11168c2ecf20Sopenharmony_ci size_t left_size; 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci snprintf(buf, QEDE_FW_VER_STR_SIZE, 11198c2ecf20Sopenharmony_ci "Storm FW %d.%d.%d.%d, Management FW %d.%d.%d.%d", 11208c2ecf20Sopenharmony_ci p_dev_info->fw_major, p_dev_info->fw_minor, p_dev_info->fw_rev, 11218c2ecf20Sopenharmony_ci p_dev_info->fw_eng, 11228c2ecf20Sopenharmony_ci (p_dev_info->mfw_rev & QED_MFW_VERSION_3_MASK) >> 11238c2ecf20Sopenharmony_ci QED_MFW_VERSION_3_OFFSET, 11248c2ecf20Sopenharmony_ci (p_dev_info->mfw_rev & QED_MFW_VERSION_2_MASK) >> 11258c2ecf20Sopenharmony_ci QED_MFW_VERSION_2_OFFSET, 11268c2ecf20Sopenharmony_ci (p_dev_info->mfw_rev & QED_MFW_VERSION_1_MASK) >> 11278c2ecf20Sopenharmony_ci QED_MFW_VERSION_1_OFFSET, 11288c2ecf20Sopenharmony_ci (p_dev_info->mfw_rev & QED_MFW_VERSION_0_MASK) >> 11298c2ecf20Sopenharmony_ci QED_MFW_VERSION_0_OFFSET); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci left_size = QEDE_FW_VER_STR_SIZE - strlen(buf); 11328c2ecf20Sopenharmony_ci if (p_dev_info->mbi_version && left_size) 11338c2ecf20Sopenharmony_ci snprintf(buf + strlen(buf), left_size, 11348c2ecf20Sopenharmony_ci " [MBI %d.%d.%d]", 11358c2ecf20Sopenharmony_ci (p_dev_info->mbi_version & QED_MBI_VERSION_2_MASK) >> 11368c2ecf20Sopenharmony_ci QED_MBI_VERSION_2_OFFSET, 11378c2ecf20Sopenharmony_ci (p_dev_info->mbi_version & QED_MBI_VERSION_1_MASK) >> 11388c2ecf20Sopenharmony_ci QED_MBI_VERSION_1_OFFSET, 11398c2ecf20Sopenharmony_ci (p_dev_info->mbi_version & QED_MBI_VERSION_0_MASK) >> 11408c2ecf20Sopenharmony_ci QED_MBI_VERSION_0_OFFSET); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci pr_info("qede %02x:%02x.%02x: %s [%s]\n", edev->pdev->bus->number, 11438c2ecf20Sopenharmony_ci PCI_SLOT(edev->pdev->devfn), PCI_FUNC(edev->pdev->devfn), 11448c2ecf20Sopenharmony_ci buf, edev->ndev->name); 11458c2ecf20Sopenharmony_ci} 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_cienum qede_probe_mode { 11488c2ecf20Sopenharmony_ci QEDE_PROBE_NORMAL, 11498c2ecf20Sopenharmony_ci QEDE_PROBE_RECOVERY, 11508c2ecf20Sopenharmony_ci}; 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_cistatic int __qede_probe(struct pci_dev *pdev, u32 dp_module, u8 dp_level, 11538c2ecf20Sopenharmony_ci bool is_vf, enum qede_probe_mode mode) 11548c2ecf20Sopenharmony_ci{ 11558c2ecf20Sopenharmony_ci struct qed_probe_params probe_params; 11568c2ecf20Sopenharmony_ci struct qed_slowpath_params sp_params; 11578c2ecf20Sopenharmony_ci struct qed_dev_eth_info dev_info; 11588c2ecf20Sopenharmony_ci struct qede_dev *edev; 11598c2ecf20Sopenharmony_ci struct qed_dev *cdev; 11608c2ecf20Sopenharmony_ci int rc; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci if (unlikely(dp_level & QED_LEVEL_INFO)) 11638c2ecf20Sopenharmony_ci pr_notice("Starting qede probe\n"); 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci memset(&probe_params, 0, sizeof(probe_params)); 11668c2ecf20Sopenharmony_ci probe_params.protocol = QED_PROTOCOL_ETH; 11678c2ecf20Sopenharmony_ci probe_params.dp_module = dp_module; 11688c2ecf20Sopenharmony_ci probe_params.dp_level = dp_level; 11698c2ecf20Sopenharmony_ci probe_params.is_vf = is_vf; 11708c2ecf20Sopenharmony_ci probe_params.recov_in_prog = (mode == QEDE_PROBE_RECOVERY); 11718c2ecf20Sopenharmony_ci cdev = qed_ops->common->probe(pdev, &probe_params); 11728c2ecf20Sopenharmony_ci if (!cdev) { 11738c2ecf20Sopenharmony_ci rc = -ENODEV; 11748c2ecf20Sopenharmony_ci goto err0; 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci qede_update_pf_params(cdev); 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci /* Start the Slowpath-process */ 11808c2ecf20Sopenharmony_ci memset(&sp_params, 0, sizeof(sp_params)); 11818c2ecf20Sopenharmony_ci sp_params.int_mode = QED_INT_MODE_MSIX; 11828c2ecf20Sopenharmony_ci sp_params.drv_major = QEDE_MAJOR_VERSION; 11838c2ecf20Sopenharmony_ci sp_params.drv_minor = QEDE_MINOR_VERSION; 11848c2ecf20Sopenharmony_ci sp_params.drv_rev = QEDE_REVISION_VERSION; 11858c2ecf20Sopenharmony_ci sp_params.drv_eng = QEDE_ENGINEERING_VERSION; 11868c2ecf20Sopenharmony_ci strlcpy(sp_params.name, "qede LAN", QED_DRV_VER_STR_SIZE); 11878c2ecf20Sopenharmony_ci rc = qed_ops->common->slowpath_start(cdev, &sp_params); 11888c2ecf20Sopenharmony_ci if (rc) { 11898c2ecf20Sopenharmony_ci pr_notice("Cannot start slowpath\n"); 11908c2ecf20Sopenharmony_ci goto err1; 11918c2ecf20Sopenharmony_ci } 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci /* Learn information crucial for qede to progress */ 11948c2ecf20Sopenharmony_ci rc = qed_ops->fill_dev_info(cdev, &dev_info); 11958c2ecf20Sopenharmony_ci if (rc) 11968c2ecf20Sopenharmony_ci goto err2; 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci if (mode != QEDE_PROBE_RECOVERY) { 11998c2ecf20Sopenharmony_ci edev = qede_alloc_etherdev(cdev, pdev, &dev_info, dp_module, 12008c2ecf20Sopenharmony_ci dp_level); 12018c2ecf20Sopenharmony_ci if (!edev) { 12028c2ecf20Sopenharmony_ci rc = -ENOMEM; 12038c2ecf20Sopenharmony_ci goto err2; 12048c2ecf20Sopenharmony_ci } 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci edev->devlink = qed_ops->common->devlink_register(cdev); 12078c2ecf20Sopenharmony_ci if (IS_ERR(edev->devlink)) { 12088c2ecf20Sopenharmony_ci DP_NOTICE(edev, "Cannot register devlink\n"); 12098c2ecf20Sopenharmony_ci edev->devlink = NULL; 12108c2ecf20Sopenharmony_ci /* Go on, we can live without devlink */ 12118c2ecf20Sopenharmony_ci } 12128c2ecf20Sopenharmony_ci } else { 12138c2ecf20Sopenharmony_ci struct net_device *ndev = pci_get_drvdata(pdev); 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci edev = netdev_priv(ndev); 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci if (edev->devlink) { 12188c2ecf20Sopenharmony_ci struct qed_devlink *qdl = devlink_priv(edev->devlink); 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci qdl->cdev = cdev; 12218c2ecf20Sopenharmony_ci } 12228c2ecf20Sopenharmony_ci edev->cdev = cdev; 12238c2ecf20Sopenharmony_ci memset(&edev->stats, 0, sizeof(edev->stats)); 12248c2ecf20Sopenharmony_ci memcpy(&edev->dev_info, &dev_info, sizeof(dev_info)); 12258c2ecf20Sopenharmony_ci } 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci if (is_vf) 12288c2ecf20Sopenharmony_ci set_bit(QEDE_FLAGS_IS_VF, &edev->flags); 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci qede_init_ndev(edev); 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci rc = qede_rdma_dev_add(edev, (mode == QEDE_PROBE_RECOVERY)); 12338c2ecf20Sopenharmony_ci if (rc) 12348c2ecf20Sopenharmony_ci goto err3; 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci if (mode != QEDE_PROBE_RECOVERY) { 12378c2ecf20Sopenharmony_ci /* Prepare the lock prior to the registration of the netdev, 12388c2ecf20Sopenharmony_ci * as once it's registered we might reach flows requiring it 12398c2ecf20Sopenharmony_ci * [it's even possible to reach a flow needing it directly 12408c2ecf20Sopenharmony_ci * from there, although it's unlikely]. 12418c2ecf20Sopenharmony_ci */ 12428c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&edev->sp_task, qede_sp_task); 12438c2ecf20Sopenharmony_ci mutex_init(&edev->qede_lock); 12448c2ecf20Sopenharmony_ci qede_init_periodic_task(edev); 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci rc = register_netdev(edev->ndev); 12478c2ecf20Sopenharmony_ci if (rc) { 12488c2ecf20Sopenharmony_ci DP_NOTICE(edev, "Cannot register net-device\n"); 12498c2ecf20Sopenharmony_ci goto err4; 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ci } 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci edev->ops->common->set_name(cdev, edev->ndev->name); 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci /* PTP not supported on VFs */ 12568c2ecf20Sopenharmony_ci if (!is_vf) 12578c2ecf20Sopenharmony_ci qede_ptp_enable(edev); 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci edev->ops->register_ops(cdev, &qede_ll_ops, edev); 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci#ifdef CONFIG_DCB 12628c2ecf20Sopenharmony_ci if (!IS_VF(edev)) 12638c2ecf20Sopenharmony_ci qede_set_dcbnl_ops(edev->ndev); 12648c2ecf20Sopenharmony_ci#endif 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci edev->rx_copybreak = QEDE_RX_HDR_SIZE; 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci qede_log_probe(edev); 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci /* retain user config (for example - after recovery) */ 12718c2ecf20Sopenharmony_ci if (edev->stats_coal_usecs) 12728c2ecf20Sopenharmony_ci schedule_delayed_work(&edev->periodic_task, 0); 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci return 0; 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_cierr4: 12778c2ecf20Sopenharmony_ci qede_rdma_dev_remove(edev, (mode == QEDE_PROBE_RECOVERY)); 12788c2ecf20Sopenharmony_cierr3: 12798c2ecf20Sopenharmony_ci if (mode != QEDE_PROBE_RECOVERY) 12808c2ecf20Sopenharmony_ci free_netdev(edev->ndev); 12818c2ecf20Sopenharmony_ci else 12828c2ecf20Sopenharmony_ci edev->cdev = NULL; 12838c2ecf20Sopenharmony_cierr2: 12848c2ecf20Sopenharmony_ci qed_ops->common->slowpath_stop(cdev); 12858c2ecf20Sopenharmony_cierr1: 12868c2ecf20Sopenharmony_ci qed_ops->common->remove(cdev); 12878c2ecf20Sopenharmony_cierr0: 12888c2ecf20Sopenharmony_ci return rc; 12898c2ecf20Sopenharmony_ci} 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_cistatic int qede_probe(struct pci_dev *pdev, const struct pci_device_id *id) 12928c2ecf20Sopenharmony_ci{ 12938c2ecf20Sopenharmony_ci bool is_vf = false; 12948c2ecf20Sopenharmony_ci u32 dp_module = 0; 12958c2ecf20Sopenharmony_ci u8 dp_level = 0; 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci switch ((enum qede_pci_private)id->driver_data) { 12988c2ecf20Sopenharmony_ci case QEDE_PRIVATE_VF: 12998c2ecf20Sopenharmony_ci if (debug & QED_LOG_VERBOSE_MASK) 13008c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Probing a VF\n"); 13018c2ecf20Sopenharmony_ci is_vf = true; 13028c2ecf20Sopenharmony_ci break; 13038c2ecf20Sopenharmony_ci default: 13048c2ecf20Sopenharmony_ci if (debug & QED_LOG_VERBOSE_MASK) 13058c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Probing a PF\n"); 13068c2ecf20Sopenharmony_ci } 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci qede_config_debug(debug, &dp_module, &dp_level); 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci return __qede_probe(pdev, dp_module, dp_level, is_vf, 13118c2ecf20Sopenharmony_ci QEDE_PROBE_NORMAL); 13128c2ecf20Sopenharmony_ci} 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_cienum qede_remove_mode { 13158c2ecf20Sopenharmony_ci QEDE_REMOVE_NORMAL, 13168c2ecf20Sopenharmony_ci QEDE_REMOVE_RECOVERY, 13178c2ecf20Sopenharmony_ci}; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_cistatic void __qede_remove(struct pci_dev *pdev, enum qede_remove_mode mode) 13208c2ecf20Sopenharmony_ci{ 13218c2ecf20Sopenharmony_ci struct net_device *ndev = pci_get_drvdata(pdev); 13228c2ecf20Sopenharmony_ci struct qede_dev *edev; 13238c2ecf20Sopenharmony_ci struct qed_dev *cdev; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci if (!ndev) { 13268c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "Device has already been removed\n"); 13278c2ecf20Sopenharmony_ci return; 13288c2ecf20Sopenharmony_ci } 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci edev = netdev_priv(ndev); 13318c2ecf20Sopenharmony_ci cdev = edev->cdev; 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci DP_INFO(edev, "Starting qede_remove\n"); 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci qede_rdma_dev_remove(edev, (mode == QEDE_REMOVE_RECOVERY)); 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci if (mode != QEDE_REMOVE_RECOVERY) { 13388c2ecf20Sopenharmony_ci set_bit(QEDE_SP_DISABLE, &edev->sp_flags); 13398c2ecf20Sopenharmony_ci unregister_netdev(ndev); 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&edev->sp_task); 13428c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&edev->periodic_task); 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci edev->ops->common->set_power_state(cdev, PCI_D0); 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, NULL); 13478c2ecf20Sopenharmony_ci } 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci qede_ptp_disable(edev); 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci /* Use global ops since we've freed edev */ 13528c2ecf20Sopenharmony_ci qed_ops->common->slowpath_stop(cdev); 13538c2ecf20Sopenharmony_ci if (system_state == SYSTEM_POWER_OFF) 13548c2ecf20Sopenharmony_ci return; 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci if (mode != QEDE_REMOVE_RECOVERY && edev->devlink) { 13578c2ecf20Sopenharmony_ci qed_ops->common->devlink_unregister(edev->devlink); 13588c2ecf20Sopenharmony_ci edev->devlink = NULL; 13598c2ecf20Sopenharmony_ci } 13608c2ecf20Sopenharmony_ci qed_ops->common->remove(cdev); 13618c2ecf20Sopenharmony_ci edev->cdev = NULL; 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci /* Since this can happen out-of-sync with other flows, 13648c2ecf20Sopenharmony_ci * don't release the netdevice until after slowpath stop 13658c2ecf20Sopenharmony_ci * has been called to guarantee various other contexts 13668c2ecf20Sopenharmony_ci * [e.g., QED register callbacks] won't break anything when 13678c2ecf20Sopenharmony_ci * accessing the netdevice. 13688c2ecf20Sopenharmony_ci */ 13698c2ecf20Sopenharmony_ci if (mode != QEDE_REMOVE_RECOVERY) 13708c2ecf20Sopenharmony_ci free_netdev(ndev); 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "Ending qede_remove successfully\n"); 13738c2ecf20Sopenharmony_ci} 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_cistatic void qede_remove(struct pci_dev *pdev) 13768c2ecf20Sopenharmony_ci{ 13778c2ecf20Sopenharmony_ci __qede_remove(pdev, QEDE_REMOVE_NORMAL); 13788c2ecf20Sopenharmony_ci} 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_cistatic void qede_shutdown(struct pci_dev *pdev) 13818c2ecf20Sopenharmony_ci{ 13828c2ecf20Sopenharmony_ci __qede_remove(pdev, QEDE_REMOVE_NORMAL); 13838c2ecf20Sopenharmony_ci} 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------------- 13868c2ecf20Sopenharmony_ci * START OF LOAD / UNLOAD 13878c2ecf20Sopenharmony_ci * ------------------------------------------------------------------------- 13888c2ecf20Sopenharmony_ci */ 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_cistatic int qede_set_num_queues(struct qede_dev *edev) 13918c2ecf20Sopenharmony_ci{ 13928c2ecf20Sopenharmony_ci int rc; 13938c2ecf20Sopenharmony_ci u16 rss_num; 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci /* Setup queues according to possible resources*/ 13968c2ecf20Sopenharmony_ci if (edev->req_queues) 13978c2ecf20Sopenharmony_ci rss_num = edev->req_queues; 13988c2ecf20Sopenharmony_ci else 13998c2ecf20Sopenharmony_ci rss_num = netif_get_num_default_rss_queues() * 14008c2ecf20Sopenharmony_ci edev->dev_info.common.num_hwfns; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci rss_num = min_t(u16, QEDE_MAX_RSS_CNT(edev), rss_num); 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci rc = edev->ops->common->set_fp_int(edev->cdev, rss_num); 14058c2ecf20Sopenharmony_ci if (rc > 0) { 14068c2ecf20Sopenharmony_ci /* Managed to request interrupts for our queues */ 14078c2ecf20Sopenharmony_ci edev->num_queues = rc; 14088c2ecf20Sopenharmony_ci DP_INFO(edev, "Managed %d [of %d] RSS queues\n", 14098c2ecf20Sopenharmony_ci QEDE_QUEUE_CNT(edev), rss_num); 14108c2ecf20Sopenharmony_ci rc = 0; 14118c2ecf20Sopenharmony_ci } 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci edev->fp_num_tx = edev->req_num_tx; 14148c2ecf20Sopenharmony_ci edev->fp_num_rx = edev->req_num_rx; 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci return rc; 14178c2ecf20Sopenharmony_ci} 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_cistatic void qede_free_mem_sb(struct qede_dev *edev, struct qed_sb_info *sb_info, 14208c2ecf20Sopenharmony_ci u16 sb_id) 14218c2ecf20Sopenharmony_ci{ 14228c2ecf20Sopenharmony_ci if (sb_info->sb_virt) { 14238c2ecf20Sopenharmony_ci edev->ops->common->sb_release(edev->cdev, sb_info, sb_id, 14248c2ecf20Sopenharmony_ci QED_SB_TYPE_L2_QUEUE); 14258c2ecf20Sopenharmony_ci dma_free_coherent(&edev->pdev->dev, sizeof(*sb_info->sb_virt), 14268c2ecf20Sopenharmony_ci (void *)sb_info->sb_virt, sb_info->sb_phys); 14278c2ecf20Sopenharmony_ci memset(sb_info, 0, sizeof(*sb_info)); 14288c2ecf20Sopenharmony_ci } 14298c2ecf20Sopenharmony_ci} 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci/* This function allocates fast-path status block memory */ 14328c2ecf20Sopenharmony_cistatic int qede_alloc_mem_sb(struct qede_dev *edev, 14338c2ecf20Sopenharmony_ci struct qed_sb_info *sb_info, u16 sb_id) 14348c2ecf20Sopenharmony_ci{ 14358c2ecf20Sopenharmony_ci struct status_block_e4 *sb_virt; 14368c2ecf20Sopenharmony_ci dma_addr_t sb_phys; 14378c2ecf20Sopenharmony_ci int rc; 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci sb_virt = dma_alloc_coherent(&edev->pdev->dev, 14408c2ecf20Sopenharmony_ci sizeof(*sb_virt), &sb_phys, GFP_KERNEL); 14418c2ecf20Sopenharmony_ci if (!sb_virt) { 14428c2ecf20Sopenharmony_ci DP_ERR(edev, "Status block allocation failed\n"); 14438c2ecf20Sopenharmony_ci return -ENOMEM; 14448c2ecf20Sopenharmony_ci } 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci rc = edev->ops->common->sb_init(edev->cdev, sb_info, 14478c2ecf20Sopenharmony_ci sb_virt, sb_phys, sb_id, 14488c2ecf20Sopenharmony_ci QED_SB_TYPE_L2_QUEUE); 14498c2ecf20Sopenharmony_ci if (rc) { 14508c2ecf20Sopenharmony_ci DP_ERR(edev, "Status block initialization failed\n"); 14518c2ecf20Sopenharmony_ci dma_free_coherent(&edev->pdev->dev, sizeof(*sb_virt), 14528c2ecf20Sopenharmony_ci sb_virt, sb_phys); 14538c2ecf20Sopenharmony_ci return rc; 14548c2ecf20Sopenharmony_ci } 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci return 0; 14578c2ecf20Sopenharmony_ci} 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_cistatic void qede_free_rx_buffers(struct qede_dev *edev, 14608c2ecf20Sopenharmony_ci struct qede_rx_queue *rxq) 14618c2ecf20Sopenharmony_ci{ 14628c2ecf20Sopenharmony_ci u16 i; 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci for (i = rxq->sw_rx_cons; i != rxq->sw_rx_prod; i++) { 14658c2ecf20Sopenharmony_ci struct sw_rx_data *rx_buf; 14668c2ecf20Sopenharmony_ci struct page *data; 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci rx_buf = &rxq->sw_rx_ring[i & NUM_RX_BDS_MAX]; 14698c2ecf20Sopenharmony_ci data = rx_buf->data; 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci dma_unmap_page(&edev->pdev->dev, 14728c2ecf20Sopenharmony_ci rx_buf->mapping, PAGE_SIZE, rxq->data_direction); 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci rx_buf->data = NULL; 14758c2ecf20Sopenharmony_ci __free_page(data); 14768c2ecf20Sopenharmony_ci } 14778c2ecf20Sopenharmony_ci} 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_cistatic void qede_free_mem_rxq(struct qede_dev *edev, struct qede_rx_queue *rxq) 14808c2ecf20Sopenharmony_ci{ 14818c2ecf20Sopenharmony_ci /* Free rx buffers */ 14828c2ecf20Sopenharmony_ci qede_free_rx_buffers(edev, rxq); 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci /* Free the parallel SW ring */ 14858c2ecf20Sopenharmony_ci kfree(rxq->sw_rx_ring); 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci /* Free the real RQ ring used by FW */ 14888c2ecf20Sopenharmony_ci edev->ops->common->chain_free(edev->cdev, &rxq->rx_bd_ring); 14898c2ecf20Sopenharmony_ci edev->ops->common->chain_free(edev->cdev, &rxq->rx_comp_ring); 14908c2ecf20Sopenharmony_ci} 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_cistatic void qede_set_tpa_param(struct qede_rx_queue *rxq) 14938c2ecf20Sopenharmony_ci{ 14948c2ecf20Sopenharmony_ci int i; 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci for (i = 0; i < ETH_TPA_MAX_AGGS_NUM; i++) { 14978c2ecf20Sopenharmony_ci struct qede_agg_info *tpa_info = &rxq->tpa_info[i]; 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci tpa_info->state = QEDE_AGG_STATE_NONE; 15008c2ecf20Sopenharmony_ci } 15018c2ecf20Sopenharmony_ci} 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci/* This function allocates all memory needed per Rx queue */ 15048c2ecf20Sopenharmony_cistatic int qede_alloc_mem_rxq(struct qede_dev *edev, struct qede_rx_queue *rxq) 15058c2ecf20Sopenharmony_ci{ 15068c2ecf20Sopenharmony_ci struct qed_chain_init_params params = { 15078c2ecf20Sopenharmony_ci .cnt_type = QED_CHAIN_CNT_TYPE_U16, 15088c2ecf20Sopenharmony_ci .num_elems = RX_RING_SIZE, 15098c2ecf20Sopenharmony_ci }; 15108c2ecf20Sopenharmony_ci struct qed_dev *cdev = edev->cdev; 15118c2ecf20Sopenharmony_ci int i, rc, size; 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci rxq->num_rx_buffers = edev->q_num_rx_buffers; 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci rxq->rx_buf_size = NET_IP_ALIGN + ETH_OVERHEAD + edev->ndev->mtu; 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci rxq->rx_headroom = edev->xdp_prog ? XDP_PACKET_HEADROOM : NET_SKB_PAD; 15188c2ecf20Sopenharmony_ci size = rxq->rx_headroom + 15198c2ecf20Sopenharmony_ci SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci /* Make sure that the headroom and payload fit in a single page */ 15228c2ecf20Sopenharmony_ci if (rxq->rx_buf_size + size > PAGE_SIZE) 15238c2ecf20Sopenharmony_ci rxq->rx_buf_size = PAGE_SIZE - size; 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci /* Segment size to split a page in multiple equal parts, 15268c2ecf20Sopenharmony_ci * unless XDP is used in which case we'd use the entire page. 15278c2ecf20Sopenharmony_ci */ 15288c2ecf20Sopenharmony_ci if (!edev->xdp_prog) { 15298c2ecf20Sopenharmony_ci size = size + rxq->rx_buf_size; 15308c2ecf20Sopenharmony_ci rxq->rx_buf_seg_size = roundup_pow_of_two(size); 15318c2ecf20Sopenharmony_ci } else { 15328c2ecf20Sopenharmony_ci rxq->rx_buf_seg_size = PAGE_SIZE; 15338c2ecf20Sopenharmony_ci edev->ndev->features &= ~NETIF_F_GRO_HW; 15348c2ecf20Sopenharmony_ci } 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci /* Allocate the parallel driver ring for Rx buffers */ 15378c2ecf20Sopenharmony_ci size = sizeof(*rxq->sw_rx_ring) * RX_RING_SIZE; 15388c2ecf20Sopenharmony_ci rxq->sw_rx_ring = kzalloc(size, GFP_KERNEL); 15398c2ecf20Sopenharmony_ci if (!rxq->sw_rx_ring) { 15408c2ecf20Sopenharmony_ci DP_ERR(edev, "Rx buffers ring allocation failed\n"); 15418c2ecf20Sopenharmony_ci rc = -ENOMEM; 15428c2ecf20Sopenharmony_ci goto err; 15438c2ecf20Sopenharmony_ci } 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci /* Allocate FW Rx ring */ 15468c2ecf20Sopenharmony_ci params.mode = QED_CHAIN_MODE_NEXT_PTR; 15478c2ecf20Sopenharmony_ci params.intended_use = QED_CHAIN_USE_TO_CONSUME_PRODUCE; 15488c2ecf20Sopenharmony_ci params.elem_size = sizeof(struct eth_rx_bd); 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci rc = edev->ops->common->chain_alloc(cdev, &rxq->rx_bd_ring, ¶ms); 15518c2ecf20Sopenharmony_ci if (rc) 15528c2ecf20Sopenharmony_ci goto err; 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci /* Allocate FW completion ring */ 15558c2ecf20Sopenharmony_ci params.mode = QED_CHAIN_MODE_PBL; 15568c2ecf20Sopenharmony_ci params.intended_use = QED_CHAIN_USE_TO_CONSUME; 15578c2ecf20Sopenharmony_ci params.elem_size = sizeof(union eth_rx_cqe); 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci rc = edev->ops->common->chain_alloc(cdev, &rxq->rx_comp_ring, ¶ms); 15608c2ecf20Sopenharmony_ci if (rc) 15618c2ecf20Sopenharmony_ci goto err; 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci /* Allocate buffers for the Rx ring */ 15648c2ecf20Sopenharmony_ci rxq->filled_buffers = 0; 15658c2ecf20Sopenharmony_ci for (i = 0; i < rxq->num_rx_buffers; i++) { 15668c2ecf20Sopenharmony_ci rc = qede_alloc_rx_buffer(rxq, false); 15678c2ecf20Sopenharmony_ci if (rc) { 15688c2ecf20Sopenharmony_ci DP_ERR(edev, 15698c2ecf20Sopenharmony_ci "Rx buffers allocation failed at index %d\n", i); 15708c2ecf20Sopenharmony_ci goto err; 15718c2ecf20Sopenharmony_ci } 15728c2ecf20Sopenharmony_ci } 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci edev->gro_disable = !(edev->ndev->features & NETIF_F_GRO_HW); 15758c2ecf20Sopenharmony_ci if (!edev->gro_disable) 15768c2ecf20Sopenharmony_ci qede_set_tpa_param(rxq); 15778c2ecf20Sopenharmony_cierr: 15788c2ecf20Sopenharmony_ci return rc; 15798c2ecf20Sopenharmony_ci} 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_cistatic void qede_free_mem_txq(struct qede_dev *edev, struct qede_tx_queue *txq) 15828c2ecf20Sopenharmony_ci{ 15838c2ecf20Sopenharmony_ci /* Free the parallel SW ring */ 15848c2ecf20Sopenharmony_ci if (txq->is_xdp) 15858c2ecf20Sopenharmony_ci kfree(txq->sw_tx_ring.xdp); 15868c2ecf20Sopenharmony_ci else 15878c2ecf20Sopenharmony_ci kfree(txq->sw_tx_ring.skbs); 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci /* Free the real RQ ring used by FW */ 15908c2ecf20Sopenharmony_ci edev->ops->common->chain_free(edev->cdev, &txq->tx_pbl); 15918c2ecf20Sopenharmony_ci} 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci/* This function allocates all memory needed per Tx queue */ 15948c2ecf20Sopenharmony_cistatic int qede_alloc_mem_txq(struct qede_dev *edev, struct qede_tx_queue *txq) 15958c2ecf20Sopenharmony_ci{ 15968c2ecf20Sopenharmony_ci struct qed_chain_init_params params = { 15978c2ecf20Sopenharmony_ci .mode = QED_CHAIN_MODE_PBL, 15988c2ecf20Sopenharmony_ci .intended_use = QED_CHAIN_USE_TO_CONSUME_PRODUCE, 15998c2ecf20Sopenharmony_ci .cnt_type = QED_CHAIN_CNT_TYPE_U16, 16008c2ecf20Sopenharmony_ci .num_elems = edev->q_num_tx_buffers, 16018c2ecf20Sopenharmony_ci .elem_size = sizeof(union eth_tx_bd_types), 16028c2ecf20Sopenharmony_ci }; 16038c2ecf20Sopenharmony_ci int size, rc; 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci txq->num_tx_buffers = edev->q_num_tx_buffers; 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci /* Allocate the parallel driver ring for Tx buffers */ 16088c2ecf20Sopenharmony_ci if (txq->is_xdp) { 16098c2ecf20Sopenharmony_ci size = sizeof(*txq->sw_tx_ring.xdp) * txq->num_tx_buffers; 16108c2ecf20Sopenharmony_ci txq->sw_tx_ring.xdp = kzalloc(size, GFP_KERNEL); 16118c2ecf20Sopenharmony_ci if (!txq->sw_tx_ring.xdp) 16128c2ecf20Sopenharmony_ci goto err; 16138c2ecf20Sopenharmony_ci } else { 16148c2ecf20Sopenharmony_ci size = sizeof(*txq->sw_tx_ring.skbs) * txq->num_tx_buffers; 16158c2ecf20Sopenharmony_ci txq->sw_tx_ring.skbs = kzalloc(size, GFP_KERNEL); 16168c2ecf20Sopenharmony_ci if (!txq->sw_tx_ring.skbs) 16178c2ecf20Sopenharmony_ci goto err; 16188c2ecf20Sopenharmony_ci } 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci rc = edev->ops->common->chain_alloc(edev->cdev, &txq->tx_pbl, ¶ms); 16218c2ecf20Sopenharmony_ci if (rc) 16228c2ecf20Sopenharmony_ci goto err; 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci return 0; 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_cierr: 16278c2ecf20Sopenharmony_ci qede_free_mem_txq(edev, txq); 16288c2ecf20Sopenharmony_ci return -ENOMEM; 16298c2ecf20Sopenharmony_ci} 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci/* This function frees all memory of a single fp */ 16328c2ecf20Sopenharmony_cistatic void qede_free_mem_fp(struct qede_dev *edev, struct qede_fastpath *fp) 16338c2ecf20Sopenharmony_ci{ 16348c2ecf20Sopenharmony_ci qede_free_mem_sb(edev, fp->sb_info, fp->id); 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_RX) 16378c2ecf20Sopenharmony_ci qede_free_mem_rxq(edev, fp->rxq); 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_XDP) 16408c2ecf20Sopenharmony_ci qede_free_mem_txq(edev, fp->xdp_tx); 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_TX) { 16438c2ecf20Sopenharmony_ci int cos; 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci for_each_cos_in_txq(edev, cos) 16468c2ecf20Sopenharmony_ci qede_free_mem_txq(edev, &fp->txq[cos]); 16478c2ecf20Sopenharmony_ci } 16488c2ecf20Sopenharmony_ci} 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci/* This function allocates all memory needed for a single fp (i.e. an entity 16518c2ecf20Sopenharmony_ci * which contains status block, one rx queue and/or multiple per-TC tx queues. 16528c2ecf20Sopenharmony_ci */ 16538c2ecf20Sopenharmony_cistatic int qede_alloc_mem_fp(struct qede_dev *edev, struct qede_fastpath *fp) 16548c2ecf20Sopenharmony_ci{ 16558c2ecf20Sopenharmony_ci int rc = 0; 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci rc = qede_alloc_mem_sb(edev, fp->sb_info, fp->id); 16588c2ecf20Sopenharmony_ci if (rc) 16598c2ecf20Sopenharmony_ci goto out; 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_RX) { 16628c2ecf20Sopenharmony_ci rc = qede_alloc_mem_rxq(edev, fp->rxq); 16638c2ecf20Sopenharmony_ci if (rc) 16648c2ecf20Sopenharmony_ci goto out; 16658c2ecf20Sopenharmony_ci } 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_XDP) { 16688c2ecf20Sopenharmony_ci rc = qede_alloc_mem_txq(edev, fp->xdp_tx); 16698c2ecf20Sopenharmony_ci if (rc) 16708c2ecf20Sopenharmony_ci goto out; 16718c2ecf20Sopenharmony_ci } 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_TX) { 16748c2ecf20Sopenharmony_ci int cos; 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci for_each_cos_in_txq(edev, cos) { 16778c2ecf20Sopenharmony_ci rc = qede_alloc_mem_txq(edev, &fp->txq[cos]); 16788c2ecf20Sopenharmony_ci if (rc) 16798c2ecf20Sopenharmony_ci goto out; 16808c2ecf20Sopenharmony_ci } 16818c2ecf20Sopenharmony_ci } 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ciout: 16848c2ecf20Sopenharmony_ci return rc; 16858c2ecf20Sopenharmony_ci} 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_cistatic void qede_free_mem_load(struct qede_dev *edev) 16888c2ecf20Sopenharmony_ci{ 16898c2ecf20Sopenharmony_ci int i; 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci for_each_queue(i) { 16928c2ecf20Sopenharmony_ci struct qede_fastpath *fp = &edev->fp_array[i]; 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci qede_free_mem_fp(edev, fp); 16958c2ecf20Sopenharmony_ci } 16968c2ecf20Sopenharmony_ci} 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci/* This function allocates all qede memory at NIC load. */ 16998c2ecf20Sopenharmony_cistatic int qede_alloc_mem_load(struct qede_dev *edev) 17008c2ecf20Sopenharmony_ci{ 17018c2ecf20Sopenharmony_ci int rc = 0, queue_id; 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci for (queue_id = 0; queue_id < QEDE_QUEUE_CNT(edev); queue_id++) { 17048c2ecf20Sopenharmony_ci struct qede_fastpath *fp = &edev->fp_array[queue_id]; 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci rc = qede_alloc_mem_fp(edev, fp); 17078c2ecf20Sopenharmony_ci if (rc) { 17088c2ecf20Sopenharmony_ci DP_ERR(edev, 17098c2ecf20Sopenharmony_ci "Failed to allocate memory for fastpath - rss id = %d\n", 17108c2ecf20Sopenharmony_ci queue_id); 17118c2ecf20Sopenharmony_ci qede_free_mem_load(edev); 17128c2ecf20Sopenharmony_ci return rc; 17138c2ecf20Sopenharmony_ci } 17148c2ecf20Sopenharmony_ci } 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci return 0; 17178c2ecf20Sopenharmony_ci} 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_cistatic void qede_empty_tx_queue(struct qede_dev *edev, 17208c2ecf20Sopenharmony_ci struct qede_tx_queue *txq) 17218c2ecf20Sopenharmony_ci{ 17228c2ecf20Sopenharmony_ci unsigned int pkts_compl = 0, bytes_compl = 0; 17238c2ecf20Sopenharmony_ci struct netdev_queue *netdev_txq; 17248c2ecf20Sopenharmony_ci int rc, len = 0; 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ci netdev_txq = netdev_get_tx_queue(edev->ndev, txq->ndev_txq_id); 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci while (qed_chain_get_cons_idx(&txq->tx_pbl) != 17298c2ecf20Sopenharmony_ci qed_chain_get_prod_idx(&txq->tx_pbl)) { 17308c2ecf20Sopenharmony_ci DP_VERBOSE(edev, NETIF_MSG_IFDOWN, 17318c2ecf20Sopenharmony_ci "Freeing a packet on tx queue[%d]: chain_cons 0x%x, chain_prod 0x%x\n", 17328c2ecf20Sopenharmony_ci txq->index, qed_chain_get_cons_idx(&txq->tx_pbl), 17338c2ecf20Sopenharmony_ci qed_chain_get_prod_idx(&txq->tx_pbl)); 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci rc = qede_free_tx_pkt(edev, txq, &len); 17368c2ecf20Sopenharmony_ci if (rc) { 17378c2ecf20Sopenharmony_ci DP_NOTICE(edev, 17388c2ecf20Sopenharmony_ci "Failed to free a packet on tx queue[%d]: chain_cons 0x%x, chain_prod 0x%x\n", 17398c2ecf20Sopenharmony_ci txq->index, 17408c2ecf20Sopenharmony_ci qed_chain_get_cons_idx(&txq->tx_pbl), 17418c2ecf20Sopenharmony_ci qed_chain_get_prod_idx(&txq->tx_pbl)); 17428c2ecf20Sopenharmony_ci break; 17438c2ecf20Sopenharmony_ci } 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci bytes_compl += len; 17468c2ecf20Sopenharmony_ci pkts_compl++; 17478c2ecf20Sopenharmony_ci txq->sw_tx_cons++; 17488c2ecf20Sopenharmony_ci } 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci netdev_tx_completed_queue(netdev_txq, pkts_compl, bytes_compl); 17518c2ecf20Sopenharmony_ci} 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_cistatic void qede_empty_tx_queues(struct qede_dev *edev) 17548c2ecf20Sopenharmony_ci{ 17558c2ecf20Sopenharmony_ci int i; 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_ci for_each_queue(i) 17588c2ecf20Sopenharmony_ci if (edev->fp_array[i].type & QEDE_FASTPATH_TX) { 17598c2ecf20Sopenharmony_ci int cos; 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci for_each_cos_in_txq(edev, cos) { 17628c2ecf20Sopenharmony_ci struct qede_fastpath *fp; 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci fp = &edev->fp_array[i]; 17658c2ecf20Sopenharmony_ci qede_empty_tx_queue(edev, 17668c2ecf20Sopenharmony_ci &fp->txq[cos]); 17678c2ecf20Sopenharmony_ci } 17688c2ecf20Sopenharmony_ci } 17698c2ecf20Sopenharmony_ci} 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci/* This function inits fp content and resets the SB, RXQ and TXQ structures */ 17728c2ecf20Sopenharmony_cistatic void qede_init_fp(struct qede_dev *edev) 17738c2ecf20Sopenharmony_ci{ 17748c2ecf20Sopenharmony_ci int queue_id, rxq_index = 0, txq_index = 0; 17758c2ecf20Sopenharmony_ci struct qede_fastpath *fp; 17768c2ecf20Sopenharmony_ci bool init_xdp = false; 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci for_each_queue(queue_id) { 17798c2ecf20Sopenharmony_ci fp = &edev->fp_array[queue_id]; 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci fp->edev = edev; 17828c2ecf20Sopenharmony_ci fp->id = queue_id; 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_XDP) { 17858c2ecf20Sopenharmony_ci fp->xdp_tx->index = QEDE_TXQ_IDX_TO_XDP(edev, 17868c2ecf20Sopenharmony_ci rxq_index); 17878c2ecf20Sopenharmony_ci fp->xdp_tx->is_xdp = 1; 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci spin_lock_init(&fp->xdp_tx->xdp_tx_lock); 17908c2ecf20Sopenharmony_ci init_xdp = true; 17918c2ecf20Sopenharmony_ci } 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_RX) { 17948c2ecf20Sopenharmony_ci fp->rxq->rxq_id = rxq_index++; 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci /* Determine how to map buffers for this queue */ 17978c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_XDP) 17988c2ecf20Sopenharmony_ci fp->rxq->data_direction = DMA_BIDIRECTIONAL; 17998c2ecf20Sopenharmony_ci else 18008c2ecf20Sopenharmony_ci fp->rxq->data_direction = DMA_FROM_DEVICE; 18018c2ecf20Sopenharmony_ci fp->rxq->dev = &edev->pdev->dev; 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci /* Driver have no error path from here */ 18048c2ecf20Sopenharmony_ci WARN_ON(xdp_rxq_info_reg(&fp->rxq->xdp_rxq, edev->ndev, 18058c2ecf20Sopenharmony_ci fp->rxq->rxq_id) < 0); 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci if (xdp_rxq_info_reg_mem_model(&fp->rxq->xdp_rxq, 18088c2ecf20Sopenharmony_ci MEM_TYPE_PAGE_ORDER0, 18098c2ecf20Sopenharmony_ci NULL)) { 18108c2ecf20Sopenharmony_ci DP_NOTICE(edev, 18118c2ecf20Sopenharmony_ci "Failed to register XDP memory model\n"); 18128c2ecf20Sopenharmony_ci } 18138c2ecf20Sopenharmony_ci } 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_TX) { 18168c2ecf20Sopenharmony_ci int cos; 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci for_each_cos_in_txq(edev, cos) { 18198c2ecf20Sopenharmony_ci struct qede_tx_queue *txq = &fp->txq[cos]; 18208c2ecf20Sopenharmony_ci u16 ndev_tx_id; 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ci txq->cos = cos; 18238c2ecf20Sopenharmony_ci txq->index = txq_index; 18248c2ecf20Sopenharmony_ci ndev_tx_id = QEDE_TXQ_TO_NDEV_TXQ_ID(edev, txq); 18258c2ecf20Sopenharmony_ci txq->ndev_txq_id = ndev_tx_id; 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci if (edev->dev_info.is_legacy) 18288c2ecf20Sopenharmony_ci txq->is_legacy = true; 18298c2ecf20Sopenharmony_ci txq->dev = &edev->pdev->dev; 18308c2ecf20Sopenharmony_ci } 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci txq_index++; 18338c2ecf20Sopenharmony_ci } 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci snprintf(fp->name, sizeof(fp->name), "%s-fp-%d", 18368c2ecf20Sopenharmony_ci edev->ndev->name, queue_id); 18378c2ecf20Sopenharmony_ci } 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci if (init_xdp) { 18408c2ecf20Sopenharmony_ci edev->total_xdp_queues = QEDE_RSS_COUNT(edev); 18418c2ecf20Sopenharmony_ci DP_INFO(edev, "Total XDP queues: %u\n", edev->total_xdp_queues); 18428c2ecf20Sopenharmony_ci } 18438c2ecf20Sopenharmony_ci} 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_cistatic int qede_set_real_num_queues(struct qede_dev *edev) 18468c2ecf20Sopenharmony_ci{ 18478c2ecf20Sopenharmony_ci int rc = 0; 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci rc = netif_set_real_num_tx_queues(edev->ndev, 18508c2ecf20Sopenharmony_ci QEDE_TSS_COUNT(edev) * 18518c2ecf20Sopenharmony_ci edev->dev_info.num_tc); 18528c2ecf20Sopenharmony_ci if (rc) { 18538c2ecf20Sopenharmony_ci DP_NOTICE(edev, "Failed to set real number of Tx queues\n"); 18548c2ecf20Sopenharmony_ci return rc; 18558c2ecf20Sopenharmony_ci } 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci rc = netif_set_real_num_rx_queues(edev->ndev, QEDE_RSS_COUNT(edev)); 18588c2ecf20Sopenharmony_ci if (rc) { 18598c2ecf20Sopenharmony_ci DP_NOTICE(edev, "Failed to set real number of Rx queues\n"); 18608c2ecf20Sopenharmony_ci return rc; 18618c2ecf20Sopenharmony_ci } 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci return 0; 18648c2ecf20Sopenharmony_ci} 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_cistatic void qede_napi_disable_remove(struct qede_dev *edev) 18678c2ecf20Sopenharmony_ci{ 18688c2ecf20Sopenharmony_ci int i; 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci for_each_queue(i) { 18718c2ecf20Sopenharmony_ci napi_disable(&edev->fp_array[i].napi); 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci netif_napi_del(&edev->fp_array[i].napi); 18748c2ecf20Sopenharmony_ci } 18758c2ecf20Sopenharmony_ci} 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_cistatic void qede_napi_add_enable(struct qede_dev *edev) 18788c2ecf20Sopenharmony_ci{ 18798c2ecf20Sopenharmony_ci int i; 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci /* Add NAPI objects */ 18828c2ecf20Sopenharmony_ci for_each_queue(i) { 18838c2ecf20Sopenharmony_ci netif_napi_add(edev->ndev, &edev->fp_array[i].napi, 18848c2ecf20Sopenharmony_ci qede_poll, NAPI_POLL_WEIGHT); 18858c2ecf20Sopenharmony_ci napi_enable(&edev->fp_array[i].napi); 18868c2ecf20Sopenharmony_ci } 18878c2ecf20Sopenharmony_ci} 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_cistatic void qede_sync_free_irqs(struct qede_dev *edev) 18908c2ecf20Sopenharmony_ci{ 18918c2ecf20Sopenharmony_ci int i; 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ci for (i = 0; i < edev->int_info.used_cnt; i++) { 18948c2ecf20Sopenharmony_ci if (edev->int_info.msix_cnt) { 18958c2ecf20Sopenharmony_ci synchronize_irq(edev->int_info.msix[i].vector); 18968c2ecf20Sopenharmony_ci free_irq(edev->int_info.msix[i].vector, 18978c2ecf20Sopenharmony_ci &edev->fp_array[i]); 18988c2ecf20Sopenharmony_ci } else { 18998c2ecf20Sopenharmony_ci edev->ops->common->simd_handler_clean(edev->cdev, i); 19008c2ecf20Sopenharmony_ci } 19018c2ecf20Sopenharmony_ci } 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci edev->int_info.used_cnt = 0; 19048c2ecf20Sopenharmony_ci edev->int_info.msix_cnt = 0; 19058c2ecf20Sopenharmony_ci} 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_cistatic int qede_req_msix_irqs(struct qede_dev *edev) 19088c2ecf20Sopenharmony_ci{ 19098c2ecf20Sopenharmony_ci int i, rc; 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci /* Sanitize number of interrupts == number of prepared RSS queues */ 19128c2ecf20Sopenharmony_ci if (QEDE_QUEUE_CNT(edev) > edev->int_info.msix_cnt) { 19138c2ecf20Sopenharmony_ci DP_ERR(edev, 19148c2ecf20Sopenharmony_ci "Interrupt mismatch: %d RSS queues > %d MSI-x vectors\n", 19158c2ecf20Sopenharmony_ci QEDE_QUEUE_CNT(edev), edev->int_info.msix_cnt); 19168c2ecf20Sopenharmony_ci return -EINVAL; 19178c2ecf20Sopenharmony_ci } 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci for (i = 0; i < QEDE_QUEUE_CNT(edev); i++) { 19208c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 19218c2ecf20Sopenharmony_ci struct qede_fastpath *fp = &edev->fp_array[i]; 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci if (edev->ndev->rx_cpu_rmap && (fp->type & QEDE_FASTPATH_RX)) { 19248c2ecf20Sopenharmony_ci rc = irq_cpu_rmap_add(edev->ndev->rx_cpu_rmap, 19258c2ecf20Sopenharmony_ci edev->int_info.msix[i].vector); 19268c2ecf20Sopenharmony_ci if (rc) { 19278c2ecf20Sopenharmony_ci DP_ERR(edev, "Failed to add CPU rmap\n"); 19288c2ecf20Sopenharmony_ci qede_free_arfs(edev); 19298c2ecf20Sopenharmony_ci } 19308c2ecf20Sopenharmony_ci } 19318c2ecf20Sopenharmony_ci#endif 19328c2ecf20Sopenharmony_ci rc = request_irq(edev->int_info.msix[i].vector, 19338c2ecf20Sopenharmony_ci qede_msix_fp_int, 0, edev->fp_array[i].name, 19348c2ecf20Sopenharmony_ci &edev->fp_array[i]); 19358c2ecf20Sopenharmony_ci if (rc) { 19368c2ecf20Sopenharmony_ci DP_ERR(edev, "Request fp %d irq failed\n", i); 19378c2ecf20Sopenharmony_ci qede_sync_free_irqs(edev); 19388c2ecf20Sopenharmony_ci return rc; 19398c2ecf20Sopenharmony_ci } 19408c2ecf20Sopenharmony_ci DP_VERBOSE(edev, NETIF_MSG_INTR, 19418c2ecf20Sopenharmony_ci "Requested fp irq for %s [entry %d]. Cookie is at %p\n", 19428c2ecf20Sopenharmony_ci edev->fp_array[i].name, i, 19438c2ecf20Sopenharmony_ci &edev->fp_array[i]); 19448c2ecf20Sopenharmony_ci edev->int_info.used_cnt++; 19458c2ecf20Sopenharmony_ci } 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci return 0; 19488c2ecf20Sopenharmony_ci} 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_cistatic void qede_simd_fp_handler(void *cookie) 19518c2ecf20Sopenharmony_ci{ 19528c2ecf20Sopenharmony_ci struct qede_fastpath *fp = (struct qede_fastpath *)cookie; 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci napi_schedule_irqoff(&fp->napi); 19558c2ecf20Sopenharmony_ci} 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_cistatic int qede_setup_irqs(struct qede_dev *edev) 19588c2ecf20Sopenharmony_ci{ 19598c2ecf20Sopenharmony_ci int i, rc = 0; 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci /* Learn Interrupt configuration */ 19628c2ecf20Sopenharmony_ci rc = edev->ops->common->get_fp_int(edev->cdev, &edev->int_info); 19638c2ecf20Sopenharmony_ci if (rc) 19648c2ecf20Sopenharmony_ci return rc; 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci if (edev->int_info.msix_cnt) { 19678c2ecf20Sopenharmony_ci rc = qede_req_msix_irqs(edev); 19688c2ecf20Sopenharmony_ci if (rc) 19698c2ecf20Sopenharmony_ci return rc; 19708c2ecf20Sopenharmony_ci edev->ndev->irq = edev->int_info.msix[0].vector; 19718c2ecf20Sopenharmony_ci } else { 19728c2ecf20Sopenharmony_ci const struct qed_common_ops *ops; 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci /* qed should learn receive the RSS ids and callbacks */ 19758c2ecf20Sopenharmony_ci ops = edev->ops->common; 19768c2ecf20Sopenharmony_ci for (i = 0; i < QEDE_QUEUE_CNT(edev); i++) 19778c2ecf20Sopenharmony_ci ops->simd_handler_config(edev->cdev, 19788c2ecf20Sopenharmony_ci &edev->fp_array[i], i, 19798c2ecf20Sopenharmony_ci qede_simd_fp_handler); 19808c2ecf20Sopenharmony_ci edev->int_info.used_cnt = QEDE_QUEUE_CNT(edev); 19818c2ecf20Sopenharmony_ci } 19828c2ecf20Sopenharmony_ci return 0; 19838c2ecf20Sopenharmony_ci} 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_cistatic int qede_drain_txq(struct qede_dev *edev, 19868c2ecf20Sopenharmony_ci struct qede_tx_queue *txq, bool allow_drain) 19878c2ecf20Sopenharmony_ci{ 19888c2ecf20Sopenharmony_ci int rc, cnt = 1000; 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci while (txq->sw_tx_cons != txq->sw_tx_prod) { 19918c2ecf20Sopenharmony_ci if (!cnt) { 19928c2ecf20Sopenharmony_ci if (allow_drain) { 19938c2ecf20Sopenharmony_ci DP_NOTICE(edev, 19948c2ecf20Sopenharmony_ci "Tx queue[%d] is stuck, requesting MCP to drain\n", 19958c2ecf20Sopenharmony_ci txq->index); 19968c2ecf20Sopenharmony_ci rc = edev->ops->common->drain(edev->cdev); 19978c2ecf20Sopenharmony_ci if (rc) 19988c2ecf20Sopenharmony_ci return rc; 19998c2ecf20Sopenharmony_ci return qede_drain_txq(edev, txq, false); 20008c2ecf20Sopenharmony_ci } 20018c2ecf20Sopenharmony_ci DP_NOTICE(edev, 20028c2ecf20Sopenharmony_ci "Timeout waiting for tx queue[%d]: PROD=%d, CONS=%d\n", 20038c2ecf20Sopenharmony_ci txq->index, txq->sw_tx_prod, 20048c2ecf20Sopenharmony_ci txq->sw_tx_cons); 20058c2ecf20Sopenharmony_ci return -ENODEV; 20068c2ecf20Sopenharmony_ci } 20078c2ecf20Sopenharmony_ci cnt--; 20088c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 20098c2ecf20Sopenharmony_ci barrier(); 20108c2ecf20Sopenharmony_ci } 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci /* FW finished processing, wait for HW to transmit all tx packets */ 20138c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci return 0; 20168c2ecf20Sopenharmony_ci} 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_cistatic int qede_stop_txq(struct qede_dev *edev, 20198c2ecf20Sopenharmony_ci struct qede_tx_queue *txq, int rss_id) 20208c2ecf20Sopenharmony_ci{ 20218c2ecf20Sopenharmony_ci /* delete doorbell from doorbell recovery mechanism */ 20228c2ecf20Sopenharmony_ci edev->ops->common->db_recovery_del(edev->cdev, txq->doorbell_addr, 20238c2ecf20Sopenharmony_ci &txq->tx_db); 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_ci return edev->ops->q_tx_stop(edev->cdev, rss_id, txq->handle); 20268c2ecf20Sopenharmony_ci} 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_cistatic int qede_stop_queues(struct qede_dev *edev) 20298c2ecf20Sopenharmony_ci{ 20308c2ecf20Sopenharmony_ci struct qed_update_vport_params *vport_update_params; 20318c2ecf20Sopenharmony_ci struct qed_dev *cdev = edev->cdev; 20328c2ecf20Sopenharmony_ci struct qede_fastpath *fp; 20338c2ecf20Sopenharmony_ci int rc, i; 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci /* Disable the vport */ 20368c2ecf20Sopenharmony_ci vport_update_params = vzalloc(sizeof(*vport_update_params)); 20378c2ecf20Sopenharmony_ci if (!vport_update_params) 20388c2ecf20Sopenharmony_ci return -ENOMEM; 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci vport_update_params->vport_id = 0; 20418c2ecf20Sopenharmony_ci vport_update_params->update_vport_active_flg = 1; 20428c2ecf20Sopenharmony_ci vport_update_params->vport_active_flg = 0; 20438c2ecf20Sopenharmony_ci vport_update_params->update_rss_flg = 0; 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ci rc = edev->ops->vport_update(cdev, vport_update_params); 20468c2ecf20Sopenharmony_ci vfree(vport_update_params); 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci if (rc) { 20498c2ecf20Sopenharmony_ci DP_ERR(edev, "Failed to update vport\n"); 20508c2ecf20Sopenharmony_ci return rc; 20518c2ecf20Sopenharmony_ci } 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ci /* Flush Tx queues. If needed, request drain from MCP */ 20548c2ecf20Sopenharmony_ci for_each_queue(i) { 20558c2ecf20Sopenharmony_ci fp = &edev->fp_array[i]; 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_TX) { 20588c2ecf20Sopenharmony_ci int cos; 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci for_each_cos_in_txq(edev, cos) { 20618c2ecf20Sopenharmony_ci rc = qede_drain_txq(edev, &fp->txq[cos], true); 20628c2ecf20Sopenharmony_ci if (rc) 20638c2ecf20Sopenharmony_ci return rc; 20648c2ecf20Sopenharmony_ci } 20658c2ecf20Sopenharmony_ci } 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_XDP) { 20688c2ecf20Sopenharmony_ci rc = qede_drain_txq(edev, fp->xdp_tx, true); 20698c2ecf20Sopenharmony_ci if (rc) 20708c2ecf20Sopenharmony_ci return rc; 20718c2ecf20Sopenharmony_ci } 20728c2ecf20Sopenharmony_ci } 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci /* Stop all Queues in reverse order */ 20758c2ecf20Sopenharmony_ci for (i = QEDE_QUEUE_CNT(edev) - 1; i >= 0; i--) { 20768c2ecf20Sopenharmony_ci fp = &edev->fp_array[i]; 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci /* Stop the Tx Queue(s) */ 20798c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_TX) { 20808c2ecf20Sopenharmony_ci int cos; 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci for_each_cos_in_txq(edev, cos) { 20838c2ecf20Sopenharmony_ci rc = qede_stop_txq(edev, &fp->txq[cos], i); 20848c2ecf20Sopenharmony_ci if (rc) 20858c2ecf20Sopenharmony_ci return rc; 20868c2ecf20Sopenharmony_ci } 20878c2ecf20Sopenharmony_ci } 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci /* Stop the Rx Queue */ 20908c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_RX) { 20918c2ecf20Sopenharmony_ci rc = edev->ops->q_rx_stop(cdev, i, fp->rxq->handle); 20928c2ecf20Sopenharmony_ci if (rc) { 20938c2ecf20Sopenharmony_ci DP_ERR(edev, "Failed to stop RXQ #%d\n", i); 20948c2ecf20Sopenharmony_ci return rc; 20958c2ecf20Sopenharmony_ci } 20968c2ecf20Sopenharmony_ci } 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci /* Stop the XDP forwarding queue */ 20998c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_XDP) { 21008c2ecf20Sopenharmony_ci rc = qede_stop_txq(edev, fp->xdp_tx, i); 21018c2ecf20Sopenharmony_ci if (rc) 21028c2ecf20Sopenharmony_ci return rc; 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_ci bpf_prog_put(fp->rxq->xdp_prog); 21058c2ecf20Sopenharmony_ci } 21068c2ecf20Sopenharmony_ci } 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci /* Stop the vport */ 21098c2ecf20Sopenharmony_ci rc = edev->ops->vport_stop(cdev, 0); 21108c2ecf20Sopenharmony_ci if (rc) 21118c2ecf20Sopenharmony_ci DP_ERR(edev, "Failed to stop VPORT\n"); 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_ci return rc; 21148c2ecf20Sopenharmony_ci} 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_cistatic int qede_start_txq(struct qede_dev *edev, 21178c2ecf20Sopenharmony_ci struct qede_fastpath *fp, 21188c2ecf20Sopenharmony_ci struct qede_tx_queue *txq, u8 rss_id, u16 sb_idx) 21198c2ecf20Sopenharmony_ci{ 21208c2ecf20Sopenharmony_ci dma_addr_t phys_table = qed_chain_get_pbl_phys(&txq->tx_pbl); 21218c2ecf20Sopenharmony_ci u32 page_cnt = qed_chain_get_page_cnt(&txq->tx_pbl); 21228c2ecf20Sopenharmony_ci struct qed_queue_start_common_params params; 21238c2ecf20Sopenharmony_ci struct qed_txq_start_ret_params ret_params; 21248c2ecf20Sopenharmony_ci int rc; 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 21278c2ecf20Sopenharmony_ci memset(&ret_params, 0, sizeof(ret_params)); 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci /* Let the XDP queue share the queue-zone with one of the regular txq. 21308c2ecf20Sopenharmony_ci * We don't really care about its coalescing. 21318c2ecf20Sopenharmony_ci */ 21328c2ecf20Sopenharmony_ci if (txq->is_xdp) 21338c2ecf20Sopenharmony_ci params.queue_id = QEDE_TXQ_XDP_TO_IDX(edev, txq); 21348c2ecf20Sopenharmony_ci else 21358c2ecf20Sopenharmony_ci params.queue_id = txq->index; 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci params.p_sb = fp->sb_info; 21388c2ecf20Sopenharmony_ci params.sb_idx = sb_idx; 21398c2ecf20Sopenharmony_ci params.tc = txq->cos; 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci rc = edev->ops->q_tx_start(edev->cdev, rss_id, ¶ms, phys_table, 21428c2ecf20Sopenharmony_ci page_cnt, &ret_params); 21438c2ecf20Sopenharmony_ci if (rc) { 21448c2ecf20Sopenharmony_ci DP_ERR(edev, "Start TXQ #%d failed %d\n", txq->index, rc); 21458c2ecf20Sopenharmony_ci return rc; 21468c2ecf20Sopenharmony_ci } 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci txq->doorbell_addr = ret_params.p_doorbell; 21498c2ecf20Sopenharmony_ci txq->handle = ret_params.p_handle; 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_ci /* Determine the FW consumer address associated */ 21528c2ecf20Sopenharmony_ci txq->hw_cons_ptr = &fp->sb_info->sb_virt->pi_array[sb_idx]; 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci /* Prepare the doorbell parameters */ 21558c2ecf20Sopenharmony_ci SET_FIELD(txq->tx_db.data.params, ETH_DB_DATA_DEST, DB_DEST_XCM); 21568c2ecf20Sopenharmony_ci SET_FIELD(txq->tx_db.data.params, ETH_DB_DATA_AGG_CMD, DB_AGG_CMD_SET); 21578c2ecf20Sopenharmony_ci SET_FIELD(txq->tx_db.data.params, ETH_DB_DATA_AGG_VAL_SEL, 21588c2ecf20Sopenharmony_ci DQ_XCM_ETH_TX_BD_PROD_CMD); 21598c2ecf20Sopenharmony_ci txq->tx_db.data.agg_flags = DQ_XCM_ETH_DQ_CF_CMD; 21608c2ecf20Sopenharmony_ci 21618c2ecf20Sopenharmony_ci /* register doorbell with doorbell recovery mechanism */ 21628c2ecf20Sopenharmony_ci rc = edev->ops->common->db_recovery_add(edev->cdev, txq->doorbell_addr, 21638c2ecf20Sopenharmony_ci &txq->tx_db, DB_REC_WIDTH_32B, 21648c2ecf20Sopenharmony_ci DB_REC_KERNEL); 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_ci return rc; 21678c2ecf20Sopenharmony_ci} 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_cistatic int qede_start_queues(struct qede_dev *edev, bool clear_stats) 21708c2ecf20Sopenharmony_ci{ 21718c2ecf20Sopenharmony_ci int vlan_removal_en = 1; 21728c2ecf20Sopenharmony_ci struct qed_dev *cdev = edev->cdev; 21738c2ecf20Sopenharmony_ci struct qed_dev_info *qed_info = &edev->dev_info.common; 21748c2ecf20Sopenharmony_ci struct qed_update_vport_params *vport_update_params; 21758c2ecf20Sopenharmony_ci struct qed_queue_start_common_params q_params; 21768c2ecf20Sopenharmony_ci struct qed_start_vport_params start = {0}; 21778c2ecf20Sopenharmony_ci int rc, i; 21788c2ecf20Sopenharmony_ci 21798c2ecf20Sopenharmony_ci if (!edev->num_queues) { 21808c2ecf20Sopenharmony_ci DP_ERR(edev, 21818c2ecf20Sopenharmony_ci "Cannot update V-VPORT as active as there are no Rx queues\n"); 21828c2ecf20Sopenharmony_ci return -EINVAL; 21838c2ecf20Sopenharmony_ci } 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ci vport_update_params = vzalloc(sizeof(*vport_update_params)); 21868c2ecf20Sopenharmony_ci if (!vport_update_params) 21878c2ecf20Sopenharmony_ci return -ENOMEM; 21888c2ecf20Sopenharmony_ci 21898c2ecf20Sopenharmony_ci start.handle_ptp_pkts = !!(edev->ptp); 21908c2ecf20Sopenharmony_ci start.gro_enable = !edev->gro_disable; 21918c2ecf20Sopenharmony_ci start.mtu = edev->ndev->mtu; 21928c2ecf20Sopenharmony_ci start.vport_id = 0; 21938c2ecf20Sopenharmony_ci start.drop_ttl0 = true; 21948c2ecf20Sopenharmony_ci start.remove_inner_vlan = vlan_removal_en; 21958c2ecf20Sopenharmony_ci start.clear_stats = clear_stats; 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_ci rc = edev->ops->vport_start(cdev, &start); 21988c2ecf20Sopenharmony_ci 21998c2ecf20Sopenharmony_ci if (rc) { 22008c2ecf20Sopenharmony_ci DP_ERR(edev, "Start V-PORT failed %d\n", rc); 22018c2ecf20Sopenharmony_ci goto out; 22028c2ecf20Sopenharmony_ci } 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ci DP_VERBOSE(edev, NETIF_MSG_IFUP, 22058c2ecf20Sopenharmony_ci "Start vport ramrod passed, vport_id = %d, MTU = %d, vlan_removal_en = %d\n", 22068c2ecf20Sopenharmony_ci start.vport_id, edev->ndev->mtu + 0xe, vlan_removal_en); 22078c2ecf20Sopenharmony_ci 22088c2ecf20Sopenharmony_ci for_each_queue(i) { 22098c2ecf20Sopenharmony_ci struct qede_fastpath *fp = &edev->fp_array[i]; 22108c2ecf20Sopenharmony_ci dma_addr_t p_phys_table; 22118c2ecf20Sopenharmony_ci u32 page_cnt; 22128c2ecf20Sopenharmony_ci 22138c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_RX) { 22148c2ecf20Sopenharmony_ci struct qed_rxq_start_ret_params ret_params; 22158c2ecf20Sopenharmony_ci struct qede_rx_queue *rxq = fp->rxq; 22168c2ecf20Sopenharmony_ci __le16 *val; 22178c2ecf20Sopenharmony_ci 22188c2ecf20Sopenharmony_ci memset(&ret_params, 0, sizeof(ret_params)); 22198c2ecf20Sopenharmony_ci memset(&q_params, 0, sizeof(q_params)); 22208c2ecf20Sopenharmony_ci q_params.queue_id = rxq->rxq_id; 22218c2ecf20Sopenharmony_ci q_params.vport_id = 0; 22228c2ecf20Sopenharmony_ci q_params.p_sb = fp->sb_info; 22238c2ecf20Sopenharmony_ci q_params.sb_idx = RX_PI; 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci p_phys_table = 22268c2ecf20Sopenharmony_ci qed_chain_get_pbl_phys(&rxq->rx_comp_ring); 22278c2ecf20Sopenharmony_ci page_cnt = qed_chain_get_page_cnt(&rxq->rx_comp_ring); 22288c2ecf20Sopenharmony_ci 22298c2ecf20Sopenharmony_ci rc = edev->ops->q_rx_start(cdev, i, &q_params, 22308c2ecf20Sopenharmony_ci rxq->rx_buf_size, 22318c2ecf20Sopenharmony_ci rxq->rx_bd_ring.p_phys_addr, 22328c2ecf20Sopenharmony_ci p_phys_table, 22338c2ecf20Sopenharmony_ci page_cnt, &ret_params); 22348c2ecf20Sopenharmony_ci if (rc) { 22358c2ecf20Sopenharmony_ci DP_ERR(edev, "Start RXQ #%d failed %d\n", i, 22368c2ecf20Sopenharmony_ci rc); 22378c2ecf20Sopenharmony_ci goto out; 22388c2ecf20Sopenharmony_ci } 22398c2ecf20Sopenharmony_ci 22408c2ecf20Sopenharmony_ci /* Use the return parameters */ 22418c2ecf20Sopenharmony_ci rxq->hw_rxq_prod_addr = ret_params.p_prod; 22428c2ecf20Sopenharmony_ci rxq->handle = ret_params.p_handle; 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci val = &fp->sb_info->sb_virt->pi_array[RX_PI]; 22458c2ecf20Sopenharmony_ci rxq->hw_cons_ptr = val; 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_ci qede_update_rx_prod(edev, rxq); 22488c2ecf20Sopenharmony_ci } 22498c2ecf20Sopenharmony_ci 22508c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_XDP) { 22518c2ecf20Sopenharmony_ci rc = qede_start_txq(edev, fp, fp->xdp_tx, i, XDP_PI); 22528c2ecf20Sopenharmony_ci if (rc) 22538c2ecf20Sopenharmony_ci goto out; 22548c2ecf20Sopenharmony_ci 22558c2ecf20Sopenharmony_ci bpf_prog_add(edev->xdp_prog, 1); 22568c2ecf20Sopenharmony_ci fp->rxq->xdp_prog = edev->xdp_prog; 22578c2ecf20Sopenharmony_ci } 22588c2ecf20Sopenharmony_ci 22598c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_TX) { 22608c2ecf20Sopenharmony_ci int cos; 22618c2ecf20Sopenharmony_ci 22628c2ecf20Sopenharmony_ci for_each_cos_in_txq(edev, cos) { 22638c2ecf20Sopenharmony_ci rc = qede_start_txq(edev, fp, &fp->txq[cos], i, 22648c2ecf20Sopenharmony_ci TX_PI(cos)); 22658c2ecf20Sopenharmony_ci if (rc) 22668c2ecf20Sopenharmony_ci goto out; 22678c2ecf20Sopenharmony_ci } 22688c2ecf20Sopenharmony_ci } 22698c2ecf20Sopenharmony_ci } 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ci /* Prepare and send the vport enable */ 22728c2ecf20Sopenharmony_ci vport_update_params->vport_id = start.vport_id; 22738c2ecf20Sopenharmony_ci vport_update_params->update_vport_active_flg = 1; 22748c2ecf20Sopenharmony_ci vport_update_params->vport_active_flg = 1; 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci if ((qed_info->b_inter_pf_switch || pci_num_vf(edev->pdev)) && 22778c2ecf20Sopenharmony_ci qed_info->tx_switching) { 22788c2ecf20Sopenharmony_ci vport_update_params->update_tx_switching_flg = 1; 22798c2ecf20Sopenharmony_ci vport_update_params->tx_switching_flg = 1; 22808c2ecf20Sopenharmony_ci } 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci qede_fill_rss_params(edev, &vport_update_params->rss_params, 22838c2ecf20Sopenharmony_ci &vport_update_params->update_rss_flg); 22848c2ecf20Sopenharmony_ci 22858c2ecf20Sopenharmony_ci rc = edev->ops->vport_update(cdev, vport_update_params); 22868c2ecf20Sopenharmony_ci if (rc) 22878c2ecf20Sopenharmony_ci DP_ERR(edev, "Update V-PORT failed %d\n", rc); 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ciout: 22908c2ecf20Sopenharmony_ci vfree(vport_update_params); 22918c2ecf20Sopenharmony_ci return rc; 22928c2ecf20Sopenharmony_ci} 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_cienum qede_unload_mode { 22958c2ecf20Sopenharmony_ci QEDE_UNLOAD_NORMAL, 22968c2ecf20Sopenharmony_ci QEDE_UNLOAD_RECOVERY, 22978c2ecf20Sopenharmony_ci}; 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_cistatic void qede_unload(struct qede_dev *edev, enum qede_unload_mode mode, 23008c2ecf20Sopenharmony_ci bool is_locked) 23018c2ecf20Sopenharmony_ci{ 23028c2ecf20Sopenharmony_ci struct qed_link_params link_params; 23038c2ecf20Sopenharmony_ci int rc; 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_ci DP_INFO(edev, "Starting qede unload\n"); 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_ci if (!is_locked) 23088c2ecf20Sopenharmony_ci __qede_lock(edev); 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci clear_bit(QEDE_FLAGS_LINK_REQUESTED, &edev->flags); 23118c2ecf20Sopenharmony_ci 23128c2ecf20Sopenharmony_ci if (mode != QEDE_UNLOAD_RECOVERY) 23138c2ecf20Sopenharmony_ci edev->state = QEDE_STATE_CLOSED; 23148c2ecf20Sopenharmony_ci 23158c2ecf20Sopenharmony_ci qede_rdma_dev_event_close(edev); 23168c2ecf20Sopenharmony_ci 23178c2ecf20Sopenharmony_ci /* Close OS Tx */ 23188c2ecf20Sopenharmony_ci netif_tx_disable(edev->ndev); 23198c2ecf20Sopenharmony_ci netif_carrier_off(edev->ndev); 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_ci if (mode != QEDE_UNLOAD_RECOVERY) { 23228c2ecf20Sopenharmony_ci /* Reset the link */ 23238c2ecf20Sopenharmony_ci memset(&link_params, 0, sizeof(link_params)); 23248c2ecf20Sopenharmony_ci link_params.link_up = false; 23258c2ecf20Sopenharmony_ci edev->ops->common->set_link(edev->cdev, &link_params); 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_ci rc = qede_stop_queues(edev); 23288c2ecf20Sopenharmony_ci if (rc) { 23298c2ecf20Sopenharmony_ci qede_sync_free_irqs(edev); 23308c2ecf20Sopenharmony_ci goto out; 23318c2ecf20Sopenharmony_ci } 23328c2ecf20Sopenharmony_ci 23338c2ecf20Sopenharmony_ci DP_INFO(edev, "Stopped Queues\n"); 23348c2ecf20Sopenharmony_ci } 23358c2ecf20Sopenharmony_ci 23368c2ecf20Sopenharmony_ci qede_vlan_mark_nonconfigured(edev); 23378c2ecf20Sopenharmony_ci edev->ops->fastpath_stop(edev->cdev); 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_ci if (edev->dev_info.common.b_arfs_capable) { 23408c2ecf20Sopenharmony_ci qede_poll_for_freeing_arfs_filters(edev); 23418c2ecf20Sopenharmony_ci qede_free_arfs(edev); 23428c2ecf20Sopenharmony_ci } 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci /* Release the interrupts */ 23458c2ecf20Sopenharmony_ci qede_sync_free_irqs(edev); 23468c2ecf20Sopenharmony_ci edev->ops->common->set_fp_int(edev->cdev, 0); 23478c2ecf20Sopenharmony_ci 23488c2ecf20Sopenharmony_ci qede_napi_disable_remove(edev); 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci if (mode == QEDE_UNLOAD_RECOVERY) 23518c2ecf20Sopenharmony_ci qede_empty_tx_queues(edev); 23528c2ecf20Sopenharmony_ci 23538c2ecf20Sopenharmony_ci qede_free_mem_load(edev); 23548c2ecf20Sopenharmony_ci qede_free_fp_array(edev); 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_ciout: 23578c2ecf20Sopenharmony_ci if (!is_locked) 23588c2ecf20Sopenharmony_ci __qede_unlock(edev); 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_ci if (mode != QEDE_UNLOAD_RECOVERY) 23618c2ecf20Sopenharmony_ci DP_NOTICE(edev, "Link is down\n"); 23628c2ecf20Sopenharmony_ci 23638c2ecf20Sopenharmony_ci edev->ptp_skip_txts = 0; 23648c2ecf20Sopenharmony_ci 23658c2ecf20Sopenharmony_ci DP_INFO(edev, "Ending qede unload\n"); 23668c2ecf20Sopenharmony_ci} 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_cienum qede_load_mode { 23698c2ecf20Sopenharmony_ci QEDE_LOAD_NORMAL, 23708c2ecf20Sopenharmony_ci QEDE_LOAD_RELOAD, 23718c2ecf20Sopenharmony_ci QEDE_LOAD_RECOVERY, 23728c2ecf20Sopenharmony_ci}; 23738c2ecf20Sopenharmony_ci 23748c2ecf20Sopenharmony_cistatic int qede_load(struct qede_dev *edev, enum qede_load_mode mode, 23758c2ecf20Sopenharmony_ci bool is_locked) 23768c2ecf20Sopenharmony_ci{ 23778c2ecf20Sopenharmony_ci struct qed_link_params link_params; 23788c2ecf20Sopenharmony_ci u8 num_tc; 23798c2ecf20Sopenharmony_ci int rc; 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_ci DP_INFO(edev, "Starting qede load\n"); 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_ci if (!is_locked) 23848c2ecf20Sopenharmony_ci __qede_lock(edev); 23858c2ecf20Sopenharmony_ci 23868c2ecf20Sopenharmony_ci rc = qede_set_num_queues(edev); 23878c2ecf20Sopenharmony_ci if (rc) 23888c2ecf20Sopenharmony_ci goto out; 23898c2ecf20Sopenharmony_ci 23908c2ecf20Sopenharmony_ci rc = qede_alloc_fp_array(edev); 23918c2ecf20Sopenharmony_ci if (rc) 23928c2ecf20Sopenharmony_ci goto out; 23938c2ecf20Sopenharmony_ci 23948c2ecf20Sopenharmony_ci qede_init_fp(edev); 23958c2ecf20Sopenharmony_ci 23968c2ecf20Sopenharmony_ci rc = qede_alloc_mem_load(edev); 23978c2ecf20Sopenharmony_ci if (rc) 23988c2ecf20Sopenharmony_ci goto err1; 23998c2ecf20Sopenharmony_ci DP_INFO(edev, "Allocated %d Rx, %d Tx queues\n", 24008c2ecf20Sopenharmony_ci QEDE_RSS_COUNT(edev), QEDE_TSS_COUNT(edev)); 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_ci rc = qede_set_real_num_queues(edev); 24038c2ecf20Sopenharmony_ci if (rc) 24048c2ecf20Sopenharmony_ci goto err2; 24058c2ecf20Sopenharmony_ci 24068c2ecf20Sopenharmony_ci if (qede_alloc_arfs(edev)) { 24078c2ecf20Sopenharmony_ci edev->ndev->features &= ~NETIF_F_NTUPLE; 24088c2ecf20Sopenharmony_ci edev->dev_info.common.b_arfs_capable = false; 24098c2ecf20Sopenharmony_ci } 24108c2ecf20Sopenharmony_ci 24118c2ecf20Sopenharmony_ci qede_napi_add_enable(edev); 24128c2ecf20Sopenharmony_ci DP_INFO(edev, "Napi added and enabled\n"); 24138c2ecf20Sopenharmony_ci 24148c2ecf20Sopenharmony_ci rc = qede_setup_irqs(edev); 24158c2ecf20Sopenharmony_ci if (rc) 24168c2ecf20Sopenharmony_ci goto err3; 24178c2ecf20Sopenharmony_ci DP_INFO(edev, "Setup IRQs succeeded\n"); 24188c2ecf20Sopenharmony_ci 24198c2ecf20Sopenharmony_ci rc = qede_start_queues(edev, mode != QEDE_LOAD_RELOAD); 24208c2ecf20Sopenharmony_ci if (rc) 24218c2ecf20Sopenharmony_ci goto err4; 24228c2ecf20Sopenharmony_ci DP_INFO(edev, "Start VPORT, RXQ and TXQ succeeded\n"); 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_ci num_tc = netdev_get_num_tc(edev->ndev); 24258c2ecf20Sopenharmony_ci num_tc = num_tc ? num_tc : edev->dev_info.num_tc; 24268c2ecf20Sopenharmony_ci qede_setup_tc(edev->ndev, num_tc); 24278c2ecf20Sopenharmony_ci 24288c2ecf20Sopenharmony_ci /* Program un-configured VLANs */ 24298c2ecf20Sopenharmony_ci qede_configure_vlan_filters(edev); 24308c2ecf20Sopenharmony_ci 24318c2ecf20Sopenharmony_ci set_bit(QEDE_FLAGS_LINK_REQUESTED, &edev->flags); 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_ci /* Ask for link-up using current configuration */ 24348c2ecf20Sopenharmony_ci memset(&link_params, 0, sizeof(link_params)); 24358c2ecf20Sopenharmony_ci link_params.link_up = true; 24368c2ecf20Sopenharmony_ci edev->ops->common->set_link(edev->cdev, &link_params); 24378c2ecf20Sopenharmony_ci 24388c2ecf20Sopenharmony_ci edev->state = QEDE_STATE_OPEN; 24398c2ecf20Sopenharmony_ci 24408c2ecf20Sopenharmony_ci DP_INFO(edev, "Ending successfully qede load\n"); 24418c2ecf20Sopenharmony_ci 24428c2ecf20Sopenharmony_ci goto out; 24438c2ecf20Sopenharmony_cierr4: 24448c2ecf20Sopenharmony_ci qede_sync_free_irqs(edev); 24458c2ecf20Sopenharmony_cierr3: 24468c2ecf20Sopenharmony_ci qede_napi_disable_remove(edev); 24478c2ecf20Sopenharmony_cierr2: 24488c2ecf20Sopenharmony_ci qede_free_mem_load(edev); 24498c2ecf20Sopenharmony_cierr1: 24508c2ecf20Sopenharmony_ci edev->ops->common->set_fp_int(edev->cdev, 0); 24518c2ecf20Sopenharmony_ci qede_free_fp_array(edev); 24528c2ecf20Sopenharmony_ci edev->num_queues = 0; 24538c2ecf20Sopenharmony_ci edev->fp_num_tx = 0; 24548c2ecf20Sopenharmony_ci edev->fp_num_rx = 0; 24558c2ecf20Sopenharmony_ciout: 24568c2ecf20Sopenharmony_ci if (!is_locked) 24578c2ecf20Sopenharmony_ci __qede_unlock(edev); 24588c2ecf20Sopenharmony_ci 24598c2ecf20Sopenharmony_ci return rc; 24608c2ecf20Sopenharmony_ci} 24618c2ecf20Sopenharmony_ci 24628c2ecf20Sopenharmony_ci/* 'func' should be able to run between unload and reload assuming interface 24638c2ecf20Sopenharmony_ci * is actually running, or afterwards in case it's currently DOWN. 24648c2ecf20Sopenharmony_ci */ 24658c2ecf20Sopenharmony_civoid qede_reload(struct qede_dev *edev, 24668c2ecf20Sopenharmony_ci struct qede_reload_args *args, bool is_locked) 24678c2ecf20Sopenharmony_ci{ 24688c2ecf20Sopenharmony_ci if (!is_locked) 24698c2ecf20Sopenharmony_ci __qede_lock(edev); 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_ci /* Since qede_lock is held, internal state wouldn't change even 24728c2ecf20Sopenharmony_ci * if netdev state would start transitioning. Check whether current 24738c2ecf20Sopenharmony_ci * internal configuration indicates device is up, then reload. 24748c2ecf20Sopenharmony_ci */ 24758c2ecf20Sopenharmony_ci if (edev->state == QEDE_STATE_OPEN) { 24768c2ecf20Sopenharmony_ci qede_unload(edev, QEDE_UNLOAD_NORMAL, true); 24778c2ecf20Sopenharmony_ci if (args) 24788c2ecf20Sopenharmony_ci args->func(edev, args); 24798c2ecf20Sopenharmony_ci qede_load(edev, QEDE_LOAD_RELOAD, true); 24808c2ecf20Sopenharmony_ci 24818c2ecf20Sopenharmony_ci /* Since no one is going to do it for us, re-configure */ 24828c2ecf20Sopenharmony_ci qede_config_rx_mode(edev->ndev); 24838c2ecf20Sopenharmony_ci } else if (args) { 24848c2ecf20Sopenharmony_ci args->func(edev, args); 24858c2ecf20Sopenharmony_ci } 24868c2ecf20Sopenharmony_ci 24878c2ecf20Sopenharmony_ci if (!is_locked) 24888c2ecf20Sopenharmony_ci __qede_unlock(edev); 24898c2ecf20Sopenharmony_ci} 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_ci/* called with rtnl_lock */ 24928c2ecf20Sopenharmony_cistatic int qede_open(struct net_device *ndev) 24938c2ecf20Sopenharmony_ci{ 24948c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(ndev); 24958c2ecf20Sopenharmony_ci int rc; 24968c2ecf20Sopenharmony_ci 24978c2ecf20Sopenharmony_ci netif_carrier_off(ndev); 24988c2ecf20Sopenharmony_ci 24998c2ecf20Sopenharmony_ci edev->ops->common->set_power_state(edev->cdev, PCI_D0); 25008c2ecf20Sopenharmony_ci 25018c2ecf20Sopenharmony_ci rc = qede_load(edev, QEDE_LOAD_NORMAL, false); 25028c2ecf20Sopenharmony_ci if (rc) 25038c2ecf20Sopenharmony_ci return rc; 25048c2ecf20Sopenharmony_ci 25058c2ecf20Sopenharmony_ci udp_tunnel_nic_reset_ntf(ndev); 25068c2ecf20Sopenharmony_ci 25078c2ecf20Sopenharmony_ci edev->ops->common->update_drv_state(edev->cdev, true); 25088c2ecf20Sopenharmony_ci 25098c2ecf20Sopenharmony_ci return 0; 25108c2ecf20Sopenharmony_ci} 25118c2ecf20Sopenharmony_ci 25128c2ecf20Sopenharmony_cistatic int qede_close(struct net_device *ndev) 25138c2ecf20Sopenharmony_ci{ 25148c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(ndev); 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci qede_unload(edev, QEDE_UNLOAD_NORMAL, false); 25178c2ecf20Sopenharmony_ci 25188c2ecf20Sopenharmony_ci if (edev->cdev) 25198c2ecf20Sopenharmony_ci edev->ops->common->update_drv_state(edev->cdev, false); 25208c2ecf20Sopenharmony_ci 25218c2ecf20Sopenharmony_ci return 0; 25228c2ecf20Sopenharmony_ci} 25238c2ecf20Sopenharmony_ci 25248c2ecf20Sopenharmony_cistatic void qede_link_update(void *dev, struct qed_link_output *link) 25258c2ecf20Sopenharmony_ci{ 25268c2ecf20Sopenharmony_ci struct qede_dev *edev = dev; 25278c2ecf20Sopenharmony_ci 25288c2ecf20Sopenharmony_ci if (!test_bit(QEDE_FLAGS_LINK_REQUESTED, &edev->flags)) { 25298c2ecf20Sopenharmony_ci DP_VERBOSE(edev, NETIF_MSG_LINK, "Interface is not ready\n"); 25308c2ecf20Sopenharmony_ci return; 25318c2ecf20Sopenharmony_ci } 25328c2ecf20Sopenharmony_ci 25338c2ecf20Sopenharmony_ci if (link->link_up) { 25348c2ecf20Sopenharmony_ci if (!netif_carrier_ok(edev->ndev)) { 25358c2ecf20Sopenharmony_ci DP_NOTICE(edev, "Link is up\n"); 25368c2ecf20Sopenharmony_ci netif_tx_start_all_queues(edev->ndev); 25378c2ecf20Sopenharmony_ci netif_carrier_on(edev->ndev); 25388c2ecf20Sopenharmony_ci qede_rdma_dev_event_open(edev); 25398c2ecf20Sopenharmony_ci } 25408c2ecf20Sopenharmony_ci } else { 25418c2ecf20Sopenharmony_ci if (netif_carrier_ok(edev->ndev)) { 25428c2ecf20Sopenharmony_ci DP_NOTICE(edev, "Link is down\n"); 25438c2ecf20Sopenharmony_ci netif_tx_disable(edev->ndev); 25448c2ecf20Sopenharmony_ci netif_carrier_off(edev->ndev); 25458c2ecf20Sopenharmony_ci qede_rdma_dev_event_close(edev); 25468c2ecf20Sopenharmony_ci } 25478c2ecf20Sopenharmony_ci } 25488c2ecf20Sopenharmony_ci} 25498c2ecf20Sopenharmony_ci 25508c2ecf20Sopenharmony_cistatic void qede_schedule_recovery_handler(void *dev) 25518c2ecf20Sopenharmony_ci{ 25528c2ecf20Sopenharmony_ci struct qede_dev *edev = dev; 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_ci if (edev->state == QEDE_STATE_RECOVERY) { 25558c2ecf20Sopenharmony_ci DP_NOTICE(edev, 25568c2ecf20Sopenharmony_ci "Avoid scheduling a recovery handling since already in recovery state\n"); 25578c2ecf20Sopenharmony_ci return; 25588c2ecf20Sopenharmony_ci } 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_ci set_bit(QEDE_SP_RECOVERY, &edev->sp_flags); 25618c2ecf20Sopenharmony_ci schedule_delayed_work(&edev->sp_task, 0); 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ci DP_INFO(edev, "Scheduled a recovery handler\n"); 25648c2ecf20Sopenharmony_ci} 25658c2ecf20Sopenharmony_ci 25668c2ecf20Sopenharmony_cistatic void qede_recovery_failed(struct qede_dev *edev) 25678c2ecf20Sopenharmony_ci{ 25688c2ecf20Sopenharmony_ci netdev_err(edev->ndev, "Recovery handling has failed. Power cycle is needed.\n"); 25698c2ecf20Sopenharmony_ci 25708c2ecf20Sopenharmony_ci netif_device_detach(edev->ndev); 25718c2ecf20Sopenharmony_ci 25728c2ecf20Sopenharmony_ci if (edev->cdev) 25738c2ecf20Sopenharmony_ci edev->ops->common->set_power_state(edev->cdev, PCI_D3hot); 25748c2ecf20Sopenharmony_ci} 25758c2ecf20Sopenharmony_ci 25768c2ecf20Sopenharmony_cistatic void qede_recovery_handler(struct qede_dev *edev) 25778c2ecf20Sopenharmony_ci{ 25788c2ecf20Sopenharmony_ci u32 curr_state = edev->state; 25798c2ecf20Sopenharmony_ci int rc; 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ci DP_NOTICE(edev, "Starting a recovery process\n"); 25828c2ecf20Sopenharmony_ci 25838c2ecf20Sopenharmony_ci /* No need to acquire first the qede_lock since is done by qede_sp_task 25848c2ecf20Sopenharmony_ci * before calling this function. 25858c2ecf20Sopenharmony_ci */ 25868c2ecf20Sopenharmony_ci edev->state = QEDE_STATE_RECOVERY; 25878c2ecf20Sopenharmony_ci 25888c2ecf20Sopenharmony_ci edev->ops->common->recovery_prolog(edev->cdev); 25898c2ecf20Sopenharmony_ci 25908c2ecf20Sopenharmony_ci if (curr_state == QEDE_STATE_OPEN) 25918c2ecf20Sopenharmony_ci qede_unload(edev, QEDE_UNLOAD_RECOVERY, true); 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_ci __qede_remove(edev->pdev, QEDE_REMOVE_RECOVERY); 25948c2ecf20Sopenharmony_ci 25958c2ecf20Sopenharmony_ci rc = __qede_probe(edev->pdev, edev->dp_module, edev->dp_level, 25968c2ecf20Sopenharmony_ci IS_VF(edev), QEDE_PROBE_RECOVERY); 25978c2ecf20Sopenharmony_ci if (rc) { 25988c2ecf20Sopenharmony_ci edev->cdev = NULL; 25998c2ecf20Sopenharmony_ci goto err; 26008c2ecf20Sopenharmony_ci } 26018c2ecf20Sopenharmony_ci 26028c2ecf20Sopenharmony_ci if (curr_state == QEDE_STATE_OPEN) { 26038c2ecf20Sopenharmony_ci rc = qede_load(edev, QEDE_LOAD_RECOVERY, true); 26048c2ecf20Sopenharmony_ci if (rc) 26058c2ecf20Sopenharmony_ci goto err; 26068c2ecf20Sopenharmony_ci 26078c2ecf20Sopenharmony_ci qede_config_rx_mode(edev->ndev); 26088c2ecf20Sopenharmony_ci udp_tunnel_nic_reset_ntf(edev->ndev); 26098c2ecf20Sopenharmony_ci } 26108c2ecf20Sopenharmony_ci 26118c2ecf20Sopenharmony_ci edev->state = curr_state; 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_ci DP_NOTICE(edev, "Recovery handling is done\n"); 26148c2ecf20Sopenharmony_ci 26158c2ecf20Sopenharmony_ci return; 26168c2ecf20Sopenharmony_ci 26178c2ecf20Sopenharmony_cierr: 26188c2ecf20Sopenharmony_ci qede_recovery_failed(edev); 26198c2ecf20Sopenharmony_ci} 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_cistatic void qede_atomic_hw_err_handler(struct qede_dev *edev) 26228c2ecf20Sopenharmony_ci{ 26238c2ecf20Sopenharmony_ci struct qed_dev *cdev = edev->cdev; 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_ci DP_NOTICE(edev, 26268c2ecf20Sopenharmony_ci "Generic non-sleepable HW error handling started - err_flags 0x%lx\n", 26278c2ecf20Sopenharmony_ci edev->err_flags); 26288c2ecf20Sopenharmony_ci 26298c2ecf20Sopenharmony_ci /* Get a call trace of the flow that led to the error */ 26308c2ecf20Sopenharmony_ci WARN_ON(test_bit(QEDE_ERR_WARN, &edev->err_flags)); 26318c2ecf20Sopenharmony_ci 26328c2ecf20Sopenharmony_ci /* Prevent HW attentions from being reasserted */ 26338c2ecf20Sopenharmony_ci if (test_bit(QEDE_ERR_ATTN_CLR_EN, &edev->err_flags)) 26348c2ecf20Sopenharmony_ci edev->ops->common->attn_clr_enable(cdev, true); 26358c2ecf20Sopenharmony_ci 26368c2ecf20Sopenharmony_ci DP_NOTICE(edev, "Generic non-sleepable HW error handling is done\n"); 26378c2ecf20Sopenharmony_ci} 26388c2ecf20Sopenharmony_ci 26398c2ecf20Sopenharmony_cistatic void qede_generic_hw_err_handler(struct qede_dev *edev) 26408c2ecf20Sopenharmony_ci{ 26418c2ecf20Sopenharmony_ci DP_NOTICE(edev, 26428c2ecf20Sopenharmony_ci "Generic sleepable HW error handling started - err_flags 0x%lx\n", 26438c2ecf20Sopenharmony_ci edev->err_flags); 26448c2ecf20Sopenharmony_ci 26458c2ecf20Sopenharmony_ci if (edev->devlink) 26468c2ecf20Sopenharmony_ci edev->ops->common->report_fatal_error(edev->devlink, edev->last_err_type); 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_ci clear_bit(QEDE_ERR_IS_HANDLED, &edev->err_flags); 26498c2ecf20Sopenharmony_ci 26508c2ecf20Sopenharmony_ci DP_NOTICE(edev, "Generic sleepable HW error handling is done\n"); 26518c2ecf20Sopenharmony_ci} 26528c2ecf20Sopenharmony_ci 26538c2ecf20Sopenharmony_cistatic void qede_set_hw_err_flags(struct qede_dev *edev, 26548c2ecf20Sopenharmony_ci enum qed_hw_err_type err_type) 26558c2ecf20Sopenharmony_ci{ 26568c2ecf20Sopenharmony_ci unsigned long err_flags = 0; 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_ci switch (err_type) { 26598c2ecf20Sopenharmony_ci case QED_HW_ERR_DMAE_FAIL: 26608c2ecf20Sopenharmony_ci set_bit(QEDE_ERR_WARN, &err_flags); 26618c2ecf20Sopenharmony_ci fallthrough; 26628c2ecf20Sopenharmony_ci case QED_HW_ERR_MFW_RESP_FAIL: 26638c2ecf20Sopenharmony_ci case QED_HW_ERR_HW_ATTN: 26648c2ecf20Sopenharmony_ci case QED_HW_ERR_RAMROD_FAIL: 26658c2ecf20Sopenharmony_ci case QED_HW_ERR_FW_ASSERT: 26668c2ecf20Sopenharmony_ci set_bit(QEDE_ERR_ATTN_CLR_EN, &err_flags); 26678c2ecf20Sopenharmony_ci set_bit(QEDE_ERR_GET_DBG_INFO, &err_flags); 26688c2ecf20Sopenharmony_ci break; 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_ci default: 26718c2ecf20Sopenharmony_ci DP_NOTICE(edev, "Unexpected HW error [%d]\n", err_type); 26728c2ecf20Sopenharmony_ci break; 26738c2ecf20Sopenharmony_ci } 26748c2ecf20Sopenharmony_ci 26758c2ecf20Sopenharmony_ci edev->err_flags |= err_flags; 26768c2ecf20Sopenharmony_ci} 26778c2ecf20Sopenharmony_ci 26788c2ecf20Sopenharmony_cistatic void qede_schedule_hw_err_handler(void *dev, 26798c2ecf20Sopenharmony_ci enum qed_hw_err_type err_type) 26808c2ecf20Sopenharmony_ci{ 26818c2ecf20Sopenharmony_ci struct qede_dev *edev = dev; 26828c2ecf20Sopenharmony_ci 26838c2ecf20Sopenharmony_ci /* Fan failure cannot be masked by handling of another HW error or by a 26848c2ecf20Sopenharmony_ci * concurrent recovery process. 26858c2ecf20Sopenharmony_ci */ 26868c2ecf20Sopenharmony_ci if ((test_and_set_bit(QEDE_ERR_IS_HANDLED, &edev->err_flags) || 26878c2ecf20Sopenharmony_ci edev->state == QEDE_STATE_RECOVERY) && 26888c2ecf20Sopenharmony_ci err_type != QED_HW_ERR_FAN_FAIL) { 26898c2ecf20Sopenharmony_ci DP_INFO(edev, 26908c2ecf20Sopenharmony_ci "Avoid scheduling an error handling while another HW error is being handled\n"); 26918c2ecf20Sopenharmony_ci return; 26928c2ecf20Sopenharmony_ci } 26938c2ecf20Sopenharmony_ci 26948c2ecf20Sopenharmony_ci if (err_type >= QED_HW_ERR_LAST) { 26958c2ecf20Sopenharmony_ci DP_NOTICE(edev, "Unknown HW error [%d]\n", err_type); 26968c2ecf20Sopenharmony_ci clear_bit(QEDE_ERR_IS_HANDLED, &edev->err_flags); 26978c2ecf20Sopenharmony_ci return; 26988c2ecf20Sopenharmony_ci } 26998c2ecf20Sopenharmony_ci 27008c2ecf20Sopenharmony_ci edev->last_err_type = err_type; 27018c2ecf20Sopenharmony_ci qede_set_hw_err_flags(edev, err_type); 27028c2ecf20Sopenharmony_ci qede_atomic_hw_err_handler(edev); 27038c2ecf20Sopenharmony_ci set_bit(QEDE_SP_HW_ERR, &edev->sp_flags); 27048c2ecf20Sopenharmony_ci schedule_delayed_work(&edev->sp_task, 0); 27058c2ecf20Sopenharmony_ci 27068c2ecf20Sopenharmony_ci DP_INFO(edev, "Scheduled a error handler [err_type %d]\n", err_type); 27078c2ecf20Sopenharmony_ci} 27088c2ecf20Sopenharmony_ci 27098c2ecf20Sopenharmony_cistatic bool qede_is_txq_full(struct qede_dev *edev, struct qede_tx_queue *txq) 27108c2ecf20Sopenharmony_ci{ 27118c2ecf20Sopenharmony_ci struct netdev_queue *netdev_txq; 27128c2ecf20Sopenharmony_ci 27138c2ecf20Sopenharmony_ci netdev_txq = netdev_get_tx_queue(edev->ndev, txq->ndev_txq_id); 27148c2ecf20Sopenharmony_ci if (netif_xmit_stopped(netdev_txq)) 27158c2ecf20Sopenharmony_ci return true; 27168c2ecf20Sopenharmony_ci 27178c2ecf20Sopenharmony_ci return false; 27188c2ecf20Sopenharmony_ci} 27198c2ecf20Sopenharmony_ci 27208c2ecf20Sopenharmony_cistatic void qede_get_generic_tlv_data(void *dev, struct qed_generic_tlvs *data) 27218c2ecf20Sopenharmony_ci{ 27228c2ecf20Sopenharmony_ci struct qede_dev *edev = dev; 27238c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 27248c2ecf20Sopenharmony_ci int i; 27258c2ecf20Sopenharmony_ci 27268c2ecf20Sopenharmony_ci if (edev->ndev->features & NETIF_F_IP_CSUM) 27278c2ecf20Sopenharmony_ci data->feat_flags |= QED_TLV_IP_CSUM; 27288c2ecf20Sopenharmony_ci if (edev->ndev->features & NETIF_F_TSO) 27298c2ecf20Sopenharmony_ci data->feat_flags |= QED_TLV_LSO; 27308c2ecf20Sopenharmony_ci 27318c2ecf20Sopenharmony_ci ether_addr_copy(data->mac[0], edev->ndev->dev_addr); 27328c2ecf20Sopenharmony_ci eth_zero_addr(data->mac[1]); 27338c2ecf20Sopenharmony_ci eth_zero_addr(data->mac[2]); 27348c2ecf20Sopenharmony_ci /* Copy the first two UC macs */ 27358c2ecf20Sopenharmony_ci netif_addr_lock_bh(edev->ndev); 27368c2ecf20Sopenharmony_ci i = 1; 27378c2ecf20Sopenharmony_ci netdev_for_each_uc_addr(ha, edev->ndev) { 27388c2ecf20Sopenharmony_ci ether_addr_copy(data->mac[i++], ha->addr); 27398c2ecf20Sopenharmony_ci if (i == QED_TLV_MAC_COUNT) 27408c2ecf20Sopenharmony_ci break; 27418c2ecf20Sopenharmony_ci } 27428c2ecf20Sopenharmony_ci 27438c2ecf20Sopenharmony_ci netif_addr_unlock_bh(edev->ndev); 27448c2ecf20Sopenharmony_ci} 27458c2ecf20Sopenharmony_ci 27468c2ecf20Sopenharmony_cistatic void qede_get_eth_tlv_data(void *dev, void *data) 27478c2ecf20Sopenharmony_ci{ 27488c2ecf20Sopenharmony_ci struct qed_mfw_tlv_eth *etlv = data; 27498c2ecf20Sopenharmony_ci struct qede_dev *edev = dev; 27508c2ecf20Sopenharmony_ci struct qede_fastpath *fp; 27518c2ecf20Sopenharmony_ci int i; 27528c2ecf20Sopenharmony_ci 27538c2ecf20Sopenharmony_ci etlv->lso_maxoff_size = 0XFFFF; 27548c2ecf20Sopenharmony_ci etlv->lso_maxoff_size_set = true; 27558c2ecf20Sopenharmony_ci etlv->lso_minseg_size = (u16)ETH_TX_LSO_WINDOW_MIN_LEN; 27568c2ecf20Sopenharmony_ci etlv->lso_minseg_size_set = true; 27578c2ecf20Sopenharmony_ci etlv->prom_mode = !!(edev->ndev->flags & IFF_PROMISC); 27588c2ecf20Sopenharmony_ci etlv->prom_mode_set = true; 27598c2ecf20Sopenharmony_ci etlv->tx_descr_size = QEDE_TSS_COUNT(edev); 27608c2ecf20Sopenharmony_ci etlv->tx_descr_size_set = true; 27618c2ecf20Sopenharmony_ci etlv->rx_descr_size = QEDE_RSS_COUNT(edev); 27628c2ecf20Sopenharmony_ci etlv->rx_descr_size_set = true; 27638c2ecf20Sopenharmony_ci etlv->iov_offload = QED_MFW_TLV_IOV_OFFLOAD_VEB; 27648c2ecf20Sopenharmony_ci etlv->iov_offload_set = true; 27658c2ecf20Sopenharmony_ci 27668c2ecf20Sopenharmony_ci /* Fill information regarding queues; Should be done under the qede 27678c2ecf20Sopenharmony_ci * lock to guarantee those don't change beneath our feet. 27688c2ecf20Sopenharmony_ci */ 27698c2ecf20Sopenharmony_ci etlv->txqs_empty = true; 27708c2ecf20Sopenharmony_ci etlv->rxqs_empty = true; 27718c2ecf20Sopenharmony_ci etlv->num_txqs_full = 0; 27728c2ecf20Sopenharmony_ci etlv->num_rxqs_full = 0; 27738c2ecf20Sopenharmony_ci 27748c2ecf20Sopenharmony_ci __qede_lock(edev); 27758c2ecf20Sopenharmony_ci for_each_queue(i) { 27768c2ecf20Sopenharmony_ci fp = &edev->fp_array[i]; 27778c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_TX) { 27788c2ecf20Sopenharmony_ci struct qede_tx_queue *txq = QEDE_FP_TC0_TXQ(fp); 27798c2ecf20Sopenharmony_ci 27808c2ecf20Sopenharmony_ci if (txq->sw_tx_cons != txq->sw_tx_prod) 27818c2ecf20Sopenharmony_ci etlv->txqs_empty = false; 27828c2ecf20Sopenharmony_ci if (qede_is_txq_full(edev, txq)) 27838c2ecf20Sopenharmony_ci etlv->num_txqs_full++; 27848c2ecf20Sopenharmony_ci } 27858c2ecf20Sopenharmony_ci if (fp->type & QEDE_FASTPATH_RX) { 27868c2ecf20Sopenharmony_ci if (qede_has_rx_work(fp->rxq)) 27878c2ecf20Sopenharmony_ci etlv->rxqs_empty = false; 27888c2ecf20Sopenharmony_ci 27898c2ecf20Sopenharmony_ci /* This one is a bit tricky; Firmware might stop 27908c2ecf20Sopenharmony_ci * placing packets if ring is not yet full. 27918c2ecf20Sopenharmony_ci * Give an approximation. 27928c2ecf20Sopenharmony_ci */ 27938c2ecf20Sopenharmony_ci if (le16_to_cpu(*fp->rxq->hw_cons_ptr) - 27948c2ecf20Sopenharmony_ci qed_chain_get_cons_idx(&fp->rxq->rx_comp_ring) > 27958c2ecf20Sopenharmony_ci RX_RING_SIZE - 100) 27968c2ecf20Sopenharmony_ci etlv->num_rxqs_full++; 27978c2ecf20Sopenharmony_ci } 27988c2ecf20Sopenharmony_ci } 27998c2ecf20Sopenharmony_ci __qede_unlock(edev); 28008c2ecf20Sopenharmony_ci 28018c2ecf20Sopenharmony_ci etlv->txqs_empty_set = true; 28028c2ecf20Sopenharmony_ci etlv->rxqs_empty_set = true; 28038c2ecf20Sopenharmony_ci etlv->num_txqs_full_set = true; 28048c2ecf20Sopenharmony_ci etlv->num_rxqs_full_set = true; 28058c2ecf20Sopenharmony_ci} 28068c2ecf20Sopenharmony_ci 28078c2ecf20Sopenharmony_ci/** 28088c2ecf20Sopenharmony_ci * qede_io_error_detected - called when PCI error is detected 28098c2ecf20Sopenharmony_ci * @pdev: Pointer to PCI device 28108c2ecf20Sopenharmony_ci * @state: The current pci connection state 28118c2ecf20Sopenharmony_ci * 28128c2ecf20Sopenharmony_ci * This function is called after a PCI bus error affecting 28138c2ecf20Sopenharmony_ci * this device has been detected. 28148c2ecf20Sopenharmony_ci */ 28158c2ecf20Sopenharmony_cistatic pci_ers_result_t 28168c2ecf20Sopenharmony_ciqede_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) 28178c2ecf20Sopenharmony_ci{ 28188c2ecf20Sopenharmony_ci struct net_device *dev = pci_get_drvdata(pdev); 28198c2ecf20Sopenharmony_ci struct qede_dev *edev = netdev_priv(dev); 28208c2ecf20Sopenharmony_ci 28218c2ecf20Sopenharmony_ci if (!edev) 28228c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_NONE; 28238c2ecf20Sopenharmony_ci 28248c2ecf20Sopenharmony_ci DP_NOTICE(edev, "IO error detected [%d]\n", state); 28258c2ecf20Sopenharmony_ci 28268c2ecf20Sopenharmony_ci __qede_lock(edev); 28278c2ecf20Sopenharmony_ci if (edev->state == QEDE_STATE_RECOVERY) { 28288c2ecf20Sopenharmony_ci DP_NOTICE(edev, "Device already in the recovery state\n"); 28298c2ecf20Sopenharmony_ci __qede_unlock(edev); 28308c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_NONE; 28318c2ecf20Sopenharmony_ci } 28328c2ecf20Sopenharmony_ci 28338c2ecf20Sopenharmony_ci /* PF handles the recovery of its VFs */ 28348c2ecf20Sopenharmony_ci if (IS_VF(edev)) { 28358c2ecf20Sopenharmony_ci DP_VERBOSE(edev, QED_MSG_IOV, 28368c2ecf20Sopenharmony_ci "VF recovery is handled by its PF\n"); 28378c2ecf20Sopenharmony_ci __qede_unlock(edev); 28388c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_RECOVERED; 28398c2ecf20Sopenharmony_ci } 28408c2ecf20Sopenharmony_ci 28418c2ecf20Sopenharmony_ci /* Close OS Tx */ 28428c2ecf20Sopenharmony_ci netif_tx_disable(edev->ndev); 28438c2ecf20Sopenharmony_ci netif_carrier_off(edev->ndev); 28448c2ecf20Sopenharmony_ci 28458c2ecf20Sopenharmony_ci set_bit(QEDE_SP_AER, &edev->sp_flags); 28468c2ecf20Sopenharmony_ci schedule_delayed_work(&edev->sp_task, 0); 28478c2ecf20Sopenharmony_ci 28488c2ecf20Sopenharmony_ci __qede_unlock(edev); 28498c2ecf20Sopenharmony_ci 28508c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_CAN_RECOVER; 28518c2ecf20Sopenharmony_ci} 2852