1646ea79cSHeinrich Kuhn /* SPDX-License-Identifier: BSD-3-Clause 2646ea79cSHeinrich Kuhn * Copyright (c) 2014-2021 Netronome Systems, Inc. 3646ea79cSHeinrich Kuhn * All rights reserved. 4646ea79cSHeinrich Kuhn * 5646ea79cSHeinrich Kuhn * Small portions derived from code Copyright(c) 2010-2015 Intel Corporation. 6646ea79cSHeinrich Kuhn */ 7646ea79cSHeinrich Kuhn 88ba461d1SPeng Zhang #include <unistd.h> 98ba461d1SPeng Zhang 105a95b024SChaoyong He #include <eal_firmware.h> 11851f03e1SHeinrich Kuhn #include <rte_alarm.h> 12646ea79cSHeinrich Kuhn 135a95b024SChaoyong He #include "flower/nfp_flower.h" 145a95b024SChaoyong He #include "nfd3/nfp_nfd3.h" 155a95b024SChaoyong He #include "nfdk/nfp_nfdk.h" 16646ea79cSHeinrich Kuhn #include "nfpcore/nfp_cpp.h" 17646ea79cSHeinrich Kuhn #include "nfpcore/nfp_hwinfo.h" 18646ea79cSHeinrich Kuhn #include "nfpcore/nfp_rtsym.h" 19646ea79cSHeinrich Kuhn #include "nfpcore/nfp_nsp.h" 20796f1aecSChaoyong He #include "nfpcore/nfp6000_pcie.h" 218ba461d1SPeng Zhang #include "nfpcore/nfp_resource.h" 22646ea79cSHeinrich Kuhn 23646ea79cSHeinrich Kuhn #include "nfp_cpp_bridge.h" 2454713740SChang Miao #include "nfp_ipsec.h" 255a95b024SChaoyong He #include "nfp_logs.h" 268153bc6fSChaoyong He #include "nfp_net_flow.h" 27b1880421SChaoyong He 28*c7a6970fSZerun Fu /* 64-bit per app capabilities */ 29*c7a6970fSZerun Fu #define NFP_NET_APP_CAP_SP_INDIFF RTE_BIT64(0) /* Indifferent to port speed */ 30*c7a6970fSZerun Fu 31d505ee1dSChaoyong He #define NFP_PF_DRIVER_NAME net_nfp_pf 32d505ee1dSChaoyong He 33a243128bSChaoyong He static void 34f4d24fe9SChaoyong He nfp_net_pf_read_mac(struct nfp_app_fw_nic *app_fw_nic, 358ceb85c3SChaoyong He uint16_t port) 36646ea79cSHeinrich Kuhn { 3749952141SChaoyong He struct nfp_net_hw *hw; 38646ea79cSHeinrich Kuhn struct nfp_eth_table *nfp_eth_table; 39646ea79cSHeinrich Kuhn 40646ea79cSHeinrich Kuhn /* Grab a pointer to the correct physical port */ 41968ec1c3SChaoyong He hw = app_fw_nic->ports[port]; 42646ea79cSHeinrich Kuhn 43a243128bSChaoyong He nfp_eth_table = app_fw_nic->pf_dev->nfp_eth_table; 44646ea79cSHeinrich Kuhn 45ef759759SChaoyong He rte_ether_addr_copy(&nfp_eth_table->ports[port].mac_addr, &hw->super.mac_addr); 46646ea79cSHeinrich Kuhn } 47646ea79cSHeinrich Kuhn 48646ea79cSHeinrich Kuhn static int 49646ea79cSHeinrich Kuhn nfp_net_start(struct rte_eth_dev *dev) 50646ea79cSHeinrich Kuhn { 5149952141SChaoyong He int ret; 5249952141SChaoyong He uint16_t i; 5372d1dea6SChaoyong He struct nfp_hw *hw; 5449952141SChaoyong He uint32_t new_ctrl; 55acb6bebfSChaoyong He struct nfp_cpp *cpp; 5649952141SChaoyong He uint32_t update = 0; 572e7c3612SQin Ke uint32_t cap_extend; 5849952141SChaoyong He uint32_t intr_vector; 5949952141SChaoyong He uint32_t ctrl_extend = 0; 6072d1dea6SChaoyong He struct nfp_net_hw *net_hw; 61646ea79cSHeinrich Kuhn struct nfp_pf_dev *pf_dev; 62646ea79cSHeinrich Kuhn struct rte_eth_rxmode *rxmode; 6349952141SChaoyong He struct nfp_app_fw_nic *app_fw_nic; 6449952141SChaoyong He struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev); 6549952141SChaoyong He struct rte_intr_handle *intr_handle = pci_dev->intr_handle; 66646ea79cSHeinrich Kuhn 679d723baaSChaoyong He net_hw = dev->data->dev_private; 6865f6915dSChaoyong He pf_dev = net_hw->pf_dev; 69968ec1c3SChaoyong He app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(pf_dev->app_fw_priv); 7072d1dea6SChaoyong He hw = &net_hw->super; 71646ea79cSHeinrich Kuhn 72646ea79cSHeinrich Kuhn /* Disabling queues just in case... */ 73646ea79cSHeinrich Kuhn nfp_net_disable_queues(dev); 74646ea79cSHeinrich Kuhn 75646ea79cSHeinrich Kuhn /* Enabling the required queues in the device */ 76646ea79cSHeinrich Kuhn nfp_net_enable_queues(dev); 77646ea79cSHeinrich Kuhn 7840688372SChaoyong He /* Check and configure queue intr-vector mapping */ 79646ea79cSHeinrich Kuhn if (dev->data->dev_conf.intr_conf.rxq != 0) { 80968ec1c3SChaoyong He if (app_fw_nic->multiport) { 81646ea79cSHeinrich Kuhn PMD_INIT_LOG(ERR, "PMD rx interrupt is not supported " 82646ea79cSHeinrich Kuhn "with NFP multiport PF"); 83646ea79cSHeinrich Kuhn return -EINVAL; 84646ea79cSHeinrich Kuhn } 85b0c496abSChaoyong He 86f4d24fe9SChaoyong He if (rte_intr_type_get(intr_handle) == RTE_INTR_HANDLE_UIO) { 87646ea79cSHeinrich Kuhn /* 88646ea79cSHeinrich Kuhn * Better not to share LSC with RX interrupts. 8940688372SChaoyong He * Unregistering LSC interrupt handler. 90646ea79cSHeinrich Kuhn */ 91e7978635SChaoyong He rte_intr_callback_unregister(intr_handle, 92646ea79cSHeinrich Kuhn nfp_net_dev_interrupt_handler, (void *)dev); 93646ea79cSHeinrich Kuhn 94646ea79cSHeinrich Kuhn if (dev->data->nb_rx_queues > 1) { 95646ea79cSHeinrich Kuhn PMD_INIT_LOG(ERR, "PMD rx interrupt only " 96646ea79cSHeinrich Kuhn "supports 1 queue with UIO"); 97646ea79cSHeinrich Kuhn return -EIO; 98646ea79cSHeinrich Kuhn } 99646ea79cSHeinrich Kuhn } 100b0c496abSChaoyong He 101646ea79cSHeinrich Kuhn intr_vector = dev->data->nb_rx_queues; 102c01e5c0cSChaoyong He if (rte_intr_efd_enable(intr_handle, intr_vector) != 0) 103646ea79cSHeinrich Kuhn return -1; 104646ea79cSHeinrich Kuhn 105646ea79cSHeinrich Kuhn nfp_configure_rx_interrupt(dev, intr_handle); 106646ea79cSHeinrich Kuhn update = NFP_NET_CFG_UPDATE_MSIX; 107646ea79cSHeinrich Kuhn } 108646ea79cSHeinrich Kuhn 109dbad6f64SPeng Zhang /* Checking MTU set */ 11072d1dea6SChaoyong He if (dev->data->mtu > net_hw->flbufsz) { 111dbad6f64SPeng Zhang PMD_INIT_LOG(ERR, "MTU (%u) can't be larger than the current NFP_FRAME_SIZE (%u)", 11272d1dea6SChaoyong He dev->data->mtu, net_hw->flbufsz); 113dbad6f64SPeng Zhang return -ERANGE; 114dbad6f64SPeng Zhang } 115dbad6f64SPeng Zhang 116646ea79cSHeinrich Kuhn rte_intr_enable(intr_handle); 117646ea79cSHeinrich Kuhn 118646ea79cSHeinrich Kuhn new_ctrl = nfp_check_offloads(dev); 119646ea79cSHeinrich Kuhn 120646ea79cSHeinrich Kuhn /* Writing configuration parameters in the device */ 12172d1dea6SChaoyong He nfp_net_params_setup(net_hw); 122646ea79cSHeinrich Kuhn 123c4de52ecSChaoyong He rxmode = &dev->data->dev_conf.rxmode; 124c01e5c0cSChaoyong He if ((rxmode->mq_mode & RTE_ETH_MQ_RX_RSS) != 0) { 125646ea79cSHeinrich Kuhn nfp_net_rss_config_default(dev); 126646ea79cSHeinrich Kuhn update |= NFP_NET_CFG_UPDATE_RSS; 12772d1dea6SChaoyong He new_ctrl |= nfp_net_cfg_ctrl_rss(hw->cap); 128646ea79cSHeinrich Kuhn } 129646ea79cSHeinrich Kuhn 130646ea79cSHeinrich Kuhn /* Enable device */ 131646ea79cSHeinrich Kuhn new_ctrl |= NFP_NET_CFG_CTRL_ENABLE; 132646ea79cSHeinrich Kuhn 133646ea79cSHeinrich Kuhn update |= NFP_NET_CFG_UPDATE_GEN | NFP_NET_CFG_UPDATE_RING; 134646ea79cSHeinrich Kuhn 135c55abf61SChaoyong He /* Enable vxlan */ 13672d1dea6SChaoyong He if ((hw->cap & NFP_NET_CFG_CTRL_VXLAN) != 0) { 137c55abf61SChaoyong He new_ctrl |= NFP_NET_CFG_CTRL_VXLAN; 138c55abf61SChaoyong He update |= NFP_NET_CFG_UPDATE_VXLAN; 139c925a157SFei Qin } 140c55abf61SChaoyong He 14172d1dea6SChaoyong He if ((hw->cap & NFP_NET_CFG_CTRL_RINGCFG) != 0) 142646ea79cSHeinrich Kuhn new_ctrl |= NFP_NET_CFG_CTRL_RINGCFG; 143646ea79cSHeinrich Kuhn 14472d1dea6SChaoyong He if (nfp_reconfig(hw, new_ctrl, update) != 0) 145646ea79cSHeinrich Kuhn return -EIO; 146646ea79cSHeinrich Kuhn 1471e80c074SChaoyong He hw->ctrl = new_ctrl; 1481e80c074SChaoyong He 1492e7c3612SQin Ke /* Enable packet type offload by extend ctrl word1. */ 15072d1dea6SChaoyong He cap_extend = hw->cap_ext; 1512e7c3612SQin Ke if ((cap_extend & NFP_NET_CFG_CTRL_PKT_TYPE) != 0) 1522e7c3612SQin Ke ctrl_extend = NFP_NET_CFG_CTRL_PKT_TYPE; 1532e7c3612SQin Ke 15454713740SChang Miao if ((cap_extend & NFP_NET_CFG_CTRL_IPSEC) != 0) 15554713740SChang Miao ctrl_extend |= NFP_NET_CFG_CTRL_IPSEC_SM_LOOKUP 15654713740SChang Miao | NFP_NET_CFG_CTRL_IPSEC_LM_LOOKUP; 15754713740SChang Miao 1588153bc6fSChaoyong He /* Enable flow steer by extend ctrl word1. */ 1598153bc6fSChaoyong He if ((cap_extend & NFP_NET_CFG_CTRL_FLOW_STEER) != 0) 1608153bc6fSChaoyong He ctrl_extend |= NFP_NET_CFG_CTRL_FLOW_STEER; 1618153bc6fSChaoyong He 1622e7c3612SQin Ke update = NFP_NET_CFG_UPDATE_GEN; 16372d1dea6SChaoyong He if (nfp_ext_reconfig(hw, ctrl_extend, update) != 0) 1642e7c3612SQin Ke return -EIO; 1652e7c3612SQin Ke 16672d1dea6SChaoyong He hw->ctrl_ext = ctrl_extend; 167b4b6988aSChaoyong He 168646ea79cSHeinrich Kuhn /* 169646ea79cSHeinrich Kuhn * Allocating rte mbufs for configured rx queues. 17040688372SChaoyong He * This requires queues being enabled before. 171646ea79cSHeinrich Kuhn */ 172c01e5c0cSChaoyong He if (nfp_net_rx_freelist_setup(dev) != 0) { 173646ea79cSHeinrich Kuhn ret = -ENOMEM; 174646ea79cSHeinrich Kuhn goto error; 175646ea79cSHeinrich Kuhn } 176646ea79cSHeinrich Kuhn 177646ea79cSHeinrich Kuhn if (rte_eal_process_type() == RTE_PROC_PRIMARY) 178acb6bebfSChaoyong He cpp = net_hw->cpp; 179646ea79cSHeinrich Kuhn else 180acb6bebfSChaoyong He cpp = ((struct nfp_pf_dev *)(dev->process_private))->cpp; 181acb6bebfSChaoyong He 182acb6bebfSChaoyong He /* Configure the physical port up */ 183acb6bebfSChaoyong He nfp_eth_set_configured(cpp, net_hw->nfp_idx, 1); 184646ea79cSHeinrich Kuhn 185c46216e7SJie Hai for (i = 0; i < dev->data->nb_rx_queues; i++) 186c46216e7SJie Hai dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED; 187c46216e7SJie Hai for (i = 0; i < dev->data->nb_tx_queues; i++) 188c46216e7SJie Hai dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED; 189c46216e7SJie Hai 190646ea79cSHeinrich Kuhn return 0; 191646ea79cSHeinrich Kuhn 192646ea79cSHeinrich Kuhn error: 193646ea79cSHeinrich Kuhn /* 194646ea79cSHeinrich Kuhn * An error returned by this function should mean the app 195646ea79cSHeinrich Kuhn * exiting and then the system releasing all the memory 196646ea79cSHeinrich Kuhn * allocated even memory coming from hugepages. 197646ea79cSHeinrich Kuhn * 198646ea79cSHeinrich Kuhn * The device could be enabled at this point with some queues 199646ea79cSHeinrich Kuhn * ready for getting packets. This is true if the call to 200646ea79cSHeinrich Kuhn * nfp_net_rx_freelist_setup() succeeds for some queues but 201646ea79cSHeinrich Kuhn * fails for subsequent queues. 202646ea79cSHeinrich Kuhn * 203646ea79cSHeinrich Kuhn * This should make the app exiting but better if we tell the 204646ea79cSHeinrich Kuhn * device first. 205646ea79cSHeinrich Kuhn */ 206646ea79cSHeinrich Kuhn nfp_net_disable_queues(dev); 207646ea79cSHeinrich Kuhn 208646ea79cSHeinrich Kuhn return ret; 209646ea79cSHeinrich Kuhn } 210646ea79cSHeinrich Kuhn 211646ea79cSHeinrich Kuhn /* Set the link up. */ 212646ea79cSHeinrich Kuhn static int 213646ea79cSHeinrich Kuhn nfp_net_set_link_up(struct rte_eth_dev *dev) 214646ea79cSHeinrich Kuhn { 215acb6bebfSChaoyong He struct nfp_cpp *cpp; 216646ea79cSHeinrich Kuhn struct nfp_net_hw *hw; 217646ea79cSHeinrich Kuhn 2189d723baaSChaoyong He hw = dev->data->dev_private; 219646ea79cSHeinrich Kuhn 220646ea79cSHeinrich Kuhn if (rte_eal_process_type() == RTE_PROC_PRIMARY) 221acb6bebfSChaoyong He cpp = hw->cpp; 222646ea79cSHeinrich Kuhn else 223acb6bebfSChaoyong He cpp = ((struct nfp_pf_dev *)(dev->process_private))->cpp; 224acb6bebfSChaoyong He 225acb6bebfSChaoyong He return nfp_eth_set_configured(cpp, hw->nfp_idx, 1); 226646ea79cSHeinrich Kuhn } 227646ea79cSHeinrich Kuhn 228646ea79cSHeinrich Kuhn /* Set the link down. */ 229646ea79cSHeinrich Kuhn static int 230646ea79cSHeinrich Kuhn nfp_net_set_link_down(struct rte_eth_dev *dev) 231646ea79cSHeinrich Kuhn { 232acb6bebfSChaoyong He struct nfp_cpp *cpp; 233646ea79cSHeinrich Kuhn struct nfp_net_hw *hw; 234646ea79cSHeinrich Kuhn 2359d723baaSChaoyong He hw = dev->data->dev_private; 236646ea79cSHeinrich Kuhn 237646ea79cSHeinrich Kuhn if (rte_eal_process_type() == RTE_PROC_PRIMARY) 238acb6bebfSChaoyong He cpp = hw->cpp; 239646ea79cSHeinrich Kuhn else 240acb6bebfSChaoyong He cpp = ((struct nfp_pf_dev *)(dev->process_private))->cpp; 241acb6bebfSChaoyong He 242acb6bebfSChaoyong He return nfp_eth_set_configured(cpp, hw->nfp_idx, 0); 243646ea79cSHeinrich Kuhn } 244646ea79cSHeinrich Kuhn 2453b00109dSPeng Zhang static uint8_t 2463b00109dSPeng Zhang nfp_function_id_get(const struct nfp_pf_dev *pf_dev, 2473b00109dSPeng Zhang uint8_t phy_port) 2483b00109dSPeng Zhang { 2493b00109dSPeng Zhang if (pf_dev->multi_pf.enabled) 2503b00109dSPeng Zhang return pf_dev->multi_pf.function_id; 2513b00109dSPeng Zhang 2523b00109dSPeng Zhang return phy_port; 2533b00109dSPeng Zhang } 2543b00109dSPeng Zhang 2558ba461d1SPeng Zhang static void 2568ba461d1SPeng Zhang nfp_net_beat_timer(void *arg) 2578ba461d1SPeng Zhang { 2588ba461d1SPeng Zhang uint64_t cur_sec; 2598ba461d1SPeng Zhang struct nfp_multi_pf *multi_pf = arg; 2608ba461d1SPeng Zhang 2618ba461d1SPeng Zhang cur_sec = rte_rdtsc(); 2628ba461d1SPeng Zhang nn_writeq(cur_sec, multi_pf->beat_addr + NFP_BEAT_OFFSET(multi_pf->function_id)); 2638ba461d1SPeng Zhang 2648ba461d1SPeng Zhang /* Beat once per second. */ 2658ba461d1SPeng Zhang if (rte_eal_alarm_set(1000 * 1000, nfp_net_beat_timer, 2668ba461d1SPeng Zhang (void *)multi_pf) < 0) { 2678ba461d1SPeng Zhang PMD_DRV_LOG(ERR, "Error setting alarm"); 2688ba461d1SPeng Zhang } 2698ba461d1SPeng Zhang } 2708ba461d1SPeng Zhang 2718ba461d1SPeng Zhang static int 2728ba461d1SPeng Zhang nfp_net_keepalive_init(struct nfp_cpp *cpp, 2738ba461d1SPeng Zhang struct nfp_multi_pf *multi_pf) 2748ba461d1SPeng Zhang { 2758ba461d1SPeng Zhang uint8_t *base; 2768ba461d1SPeng Zhang uint64_t addr; 2778ba461d1SPeng Zhang uint32_t size; 2788ba461d1SPeng Zhang uint32_t cpp_id; 2798ba461d1SPeng Zhang struct nfp_resource *res; 2808ba461d1SPeng Zhang 2818ba461d1SPeng Zhang res = nfp_resource_acquire(cpp, NFP_RESOURCE_KEEPALIVE); 2828ba461d1SPeng Zhang if (res == NULL) 2838ba461d1SPeng Zhang return -EIO; 2848ba461d1SPeng Zhang 2858ba461d1SPeng Zhang cpp_id = nfp_resource_cpp_id(res); 2868ba461d1SPeng Zhang addr = nfp_resource_address(res); 2878ba461d1SPeng Zhang size = nfp_resource_size(res); 2888ba461d1SPeng Zhang 2898ba461d1SPeng Zhang nfp_resource_release(res); 2908ba461d1SPeng Zhang 2918ba461d1SPeng Zhang /* Allocate a fixed area for keepalive. */ 2928ba461d1SPeng Zhang base = nfp_cpp_map_area(cpp, cpp_id, addr, size, &multi_pf->beat_area); 2938ba461d1SPeng Zhang if (base == NULL) { 2948ba461d1SPeng Zhang PMD_DRV_LOG(ERR, "Failed to map area for keepalive."); 2958ba461d1SPeng Zhang return -EIO; 2968ba461d1SPeng Zhang } 2978ba461d1SPeng Zhang 2988ba461d1SPeng Zhang multi_pf->beat_addr = base; 2998ba461d1SPeng Zhang 3008ba461d1SPeng Zhang return 0; 3018ba461d1SPeng Zhang } 3028ba461d1SPeng Zhang 3038ba461d1SPeng Zhang static void 3048ba461d1SPeng Zhang nfp_net_keepalive_uninit(struct nfp_multi_pf *multi_pf) 3058ba461d1SPeng Zhang { 3068ba461d1SPeng Zhang nfp_cpp_area_release_free(multi_pf->beat_area); 3078ba461d1SPeng Zhang } 3088ba461d1SPeng Zhang 3098ba461d1SPeng Zhang static int 3108ba461d1SPeng Zhang nfp_net_keepalive_start(struct nfp_multi_pf *multi_pf) 3118ba461d1SPeng Zhang { 3128ba461d1SPeng Zhang if (rte_eal_alarm_set(1000 * 1000, nfp_net_beat_timer, 3138ba461d1SPeng Zhang (void *)multi_pf) < 0) { 3148ba461d1SPeng Zhang PMD_DRV_LOG(ERR, "Error setting alarm"); 3158ba461d1SPeng Zhang return -EIO; 3168ba461d1SPeng Zhang } 3178ba461d1SPeng Zhang 3188ba461d1SPeng Zhang return 0; 3198ba461d1SPeng Zhang } 3208ba461d1SPeng Zhang 3218ba461d1SPeng Zhang static void 3228ba461d1SPeng Zhang nfp_net_keepalive_stop(struct nfp_multi_pf *multi_pf) 3238ba461d1SPeng Zhang { 3248ba461d1SPeng Zhang /* Cancel keepalive for multiple PF setup */ 3258ba461d1SPeng Zhang rte_eal_alarm_cancel(nfp_net_beat_timer, (void *)multi_pf); 3268ba461d1SPeng Zhang } 3278ba461d1SPeng Zhang 3288b8f116bSChaoyong He static void 3298b8f116bSChaoyong He nfp_net_uninit(struct rte_eth_dev *eth_dev) 3308b8f116bSChaoyong He { 3318b8f116bSChaoyong He struct nfp_net_hw *net_hw; 3328b8f116bSChaoyong He 3338b8f116bSChaoyong He net_hw = eth_dev->data->dev_private; 3348153bc6fSChaoyong He 3358153bc6fSChaoyong He if ((net_hw->super.cap_ext & NFP_NET_CFG_CTRL_FLOW_STEER) != 0) 3368153bc6fSChaoyong He nfp_net_flow_priv_uninit(net_hw->pf_dev, net_hw->idx); 3378153bc6fSChaoyong He 3388b8f116bSChaoyong He rte_free(net_hw->eth_xstats_base); 3398b8f116bSChaoyong He nfp_ipsec_uninit(eth_dev); 3408b8f116bSChaoyong He if (net_hw->mac_stats_area != NULL) 3418b8f116bSChaoyong He nfp_cpp_area_release_free(net_hw->mac_stats_area); 3428b8f116bSChaoyong He } 3438b8f116bSChaoyong He 34466d5f53dSChaoyong He static void 34566d5f53dSChaoyong He nfp_cleanup_port_app_fw_nic(struct nfp_pf_dev *pf_dev, 34666d5f53dSChaoyong He uint8_t id) 34766d5f53dSChaoyong He { 34866d5f53dSChaoyong He struct rte_eth_dev *eth_dev; 34966d5f53dSChaoyong He struct nfp_app_fw_nic *app_fw_nic; 35066d5f53dSChaoyong He 35166d5f53dSChaoyong He app_fw_nic = pf_dev->app_fw_priv; 35266d5f53dSChaoyong He if (app_fw_nic->ports[id] != NULL) { 35366d5f53dSChaoyong He eth_dev = app_fw_nic->ports[id]->eth_dev; 35466d5f53dSChaoyong He if (eth_dev != NULL) 35566d5f53dSChaoyong He nfp_net_uninit(eth_dev); 35666d5f53dSChaoyong He 35766d5f53dSChaoyong He app_fw_nic->ports[id] = NULL; 35866d5f53dSChaoyong He } 35966d5f53dSChaoyong He } 36066d5f53dSChaoyong He 36166d5f53dSChaoyong He static void 36266d5f53dSChaoyong He nfp_uninit_app_fw_nic(struct nfp_pf_dev *pf_dev) 36366d5f53dSChaoyong He { 36466d5f53dSChaoyong He nfp_cpp_area_release_free(pf_dev->ctrl_area); 36566d5f53dSChaoyong He rte_free(pf_dev->app_fw_priv); 36666d5f53dSChaoyong He } 36766d5f53dSChaoyong He 36866d5f53dSChaoyong He void 36966d5f53dSChaoyong He nfp_pf_uninit(struct nfp_pf_dev *pf_dev) 37066d5f53dSChaoyong He { 37166d5f53dSChaoyong He nfp_cpp_area_release_free(pf_dev->qc_area); 37266d5f53dSChaoyong He free(pf_dev->sym_tbl); 37366d5f53dSChaoyong He if (pf_dev->multi_pf.enabled) { 37466d5f53dSChaoyong He nfp_net_keepalive_stop(&pf_dev->multi_pf); 37566d5f53dSChaoyong He nfp_net_keepalive_uninit(&pf_dev->multi_pf); 37666d5f53dSChaoyong He } 37766d5f53dSChaoyong He free(pf_dev->nfp_eth_table); 37866d5f53dSChaoyong He free(pf_dev->hwinfo); 37966d5f53dSChaoyong He nfp_cpp_free(pf_dev->cpp); 38066d5f53dSChaoyong He rte_free(pf_dev); 38166d5f53dSChaoyong He } 38266d5f53dSChaoyong He 38366d5f53dSChaoyong He static int 38466d5f53dSChaoyong He nfp_pf_secondary_uninit(struct nfp_pf_dev *pf_dev) 38566d5f53dSChaoyong He { 38666d5f53dSChaoyong He free(pf_dev->sym_tbl); 38766d5f53dSChaoyong He nfp_cpp_free(pf_dev->cpp); 38866d5f53dSChaoyong He rte_free(pf_dev); 38966d5f53dSChaoyong He 39066d5f53dSChaoyong He return 0; 39166d5f53dSChaoyong He } 39266d5f53dSChaoyong He 393646ea79cSHeinrich Kuhn /* Reset and stop device. The device can not be restarted. */ 394646ea79cSHeinrich Kuhn static int 395646ea79cSHeinrich Kuhn nfp_net_close(struct rte_eth_dev *dev) 396646ea79cSHeinrich Kuhn { 3978ceb85c3SChaoyong He uint8_t i; 3983b00109dSPeng Zhang uint8_t id; 39949952141SChaoyong He struct nfp_net_hw *hw; 40049952141SChaoyong He struct nfp_pf_dev *pf_dev; 40149952141SChaoyong He struct rte_pci_device *pci_dev; 40249952141SChaoyong He struct nfp_app_fw_nic *app_fw_nic; 403646ea79cSHeinrich Kuhn 40466d5f53dSChaoyong He /* 40566d5f53dSChaoyong He * In secondary process, a released eth device can be found by its name 40666d5f53dSChaoyong He * in shared memory. 40766d5f53dSChaoyong He * If the state of the eth device is RTE_ETH_DEV_UNUSED, it means the 40866d5f53dSChaoyong He * eth device has been released. 40966d5f53dSChaoyong He */ 41066d5f53dSChaoyong He if (rte_eal_process_type() == RTE_PROC_SECONDARY) { 41166d5f53dSChaoyong He if (dev->state == RTE_ETH_DEV_UNUSED) 412646ea79cSHeinrich Kuhn return 0; 413646ea79cSHeinrich Kuhn 41466d5f53dSChaoyong He nfp_pf_secondary_uninit(dev->process_private); 41566d5f53dSChaoyong He return 0; 41666d5f53dSChaoyong He } 41766d5f53dSChaoyong He 4189d723baaSChaoyong He hw = dev->data->dev_private; 41965f6915dSChaoyong He pf_dev = hw->pf_dev; 420646ea79cSHeinrich Kuhn pci_dev = RTE_ETH_DEV_TO_PCI(dev); 421968ec1c3SChaoyong He app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(pf_dev->app_fw_priv); 422646ea79cSHeinrich Kuhn 423646ea79cSHeinrich Kuhn /* 424646ea79cSHeinrich Kuhn * We assume that the DPDK application is stopping all the 425646ea79cSHeinrich Kuhn * threads/queues before calling the device close function. 426646ea79cSHeinrich Kuhn */ 427646ea79cSHeinrich Kuhn nfp_net_disable_queues(dev); 428646ea79cSHeinrich Kuhn 429646ea79cSHeinrich Kuhn /* Clear queues */ 4301c8d02bbSJin Liu nfp_net_close_tx_queue(dev); 4311c8d02bbSJin Liu nfp_net_close_rx_queue(dev); 432646ea79cSHeinrich Kuhn 433851f03e1SHeinrich Kuhn /* Cancel possible impending LSC work here before releasing the port */ 434f4d24fe9SChaoyong He rte_eal_alarm_cancel(nfp_net_dev_interrupt_delayed_handler, (void *)dev); 435851f03e1SHeinrich Kuhn 436646ea79cSHeinrich Kuhn /* Only free PF resources after all physical ports have been closed */ 437646ea79cSHeinrich Kuhn /* Mark this port as unused and free device priv resources */ 438f58bde00SChaoyong He nn_cfg_writeb(&hw->super, NFP_NET_CFG_LSC, 0xff); 43966d5f53dSChaoyong He 44066d5f53dSChaoyong He if (pf_dev->app_fw_id != NFP_APP_FW_CORE_NIC) 44166d5f53dSChaoyong He return -EINVAL; 44266d5f53dSChaoyong He 44366d5f53dSChaoyong He nfp_cleanup_port_app_fw_nic(pf_dev, hw->idx); 444646ea79cSHeinrich Kuhn 445968ec1c3SChaoyong He for (i = 0; i < app_fw_nic->total_phyports; i++) { 4463b00109dSPeng Zhang id = nfp_function_id_get(pf_dev, i); 4473b00109dSPeng Zhang 448646ea79cSHeinrich Kuhn /* Check to see if ports are still in use */ 4493b00109dSPeng Zhang if (app_fw_nic->ports[id] != NULL) 450646ea79cSHeinrich Kuhn return 0; 451646ea79cSHeinrich Kuhn } 452646ea79cSHeinrich Kuhn 45366d5f53dSChaoyong He /* Enable in nfp_net_start() */ 454d61138d4SHarman Kalra rte_intr_disable(pci_dev->intr_handle); 455646ea79cSHeinrich Kuhn 45666d5f53dSChaoyong He /* Register in nfp_net_init() */ 457d61138d4SHarman Kalra rte_intr_callback_unregister(pci_dev->intr_handle, 458a6189a67SJin Liu nfp_net_dev_interrupt_handler, (void *)dev); 459646ea79cSHeinrich Kuhn 46066d5f53dSChaoyong He nfp_uninit_app_fw_nic(pf_dev); 46166d5f53dSChaoyong He nfp_pf_uninit(pf_dev); 46266d5f53dSChaoyong He 463646ea79cSHeinrich Kuhn return 0; 464646ea79cSHeinrich Kuhn } 465646ea79cSHeinrich Kuhn 466c55abf61SChaoyong He static int 467c55abf61SChaoyong He nfp_net_find_vxlan_idx(struct nfp_net_hw *hw, 468c55abf61SChaoyong He uint16_t port, 469c55abf61SChaoyong He uint32_t *idx) 470c55abf61SChaoyong He { 471c55abf61SChaoyong He uint32_t i; 472c55abf61SChaoyong He int free_idx = -1; 473c55abf61SChaoyong He 474c55abf61SChaoyong He for (i = 0; i < NFP_NET_N_VXLAN_PORTS; i++) { 475c55abf61SChaoyong He if (hw->vxlan_ports[i] == port) { 476c55abf61SChaoyong He free_idx = i; 477c55abf61SChaoyong He break; 478c55abf61SChaoyong He } 479c55abf61SChaoyong He 480c55abf61SChaoyong He if (hw->vxlan_usecnt[i] == 0) { 481c55abf61SChaoyong He free_idx = i; 482c55abf61SChaoyong He break; 483c55abf61SChaoyong He } 484c55abf61SChaoyong He } 485c55abf61SChaoyong He 486c55abf61SChaoyong He if (free_idx == -1) 487c55abf61SChaoyong He return -EINVAL; 488c55abf61SChaoyong He 489c55abf61SChaoyong He *idx = free_idx; 490c55abf61SChaoyong He 491c55abf61SChaoyong He return 0; 492c55abf61SChaoyong He } 493c55abf61SChaoyong He 494c55abf61SChaoyong He static int 495c55abf61SChaoyong He nfp_udp_tunnel_port_add(struct rte_eth_dev *dev, 496c55abf61SChaoyong He struct rte_eth_udp_tunnel *tunnel_udp) 497c55abf61SChaoyong He { 498c55abf61SChaoyong He int ret; 499c55abf61SChaoyong He uint32_t idx; 500c55abf61SChaoyong He uint16_t vxlan_port; 501c55abf61SChaoyong He struct nfp_net_hw *hw; 502c55abf61SChaoyong He enum rte_eth_tunnel_type tnl_type; 503c55abf61SChaoyong He 5049d723baaSChaoyong He hw = dev->data->dev_private; 505c55abf61SChaoyong He vxlan_port = tunnel_udp->udp_port; 506c55abf61SChaoyong He tnl_type = tunnel_udp->prot_type; 507c55abf61SChaoyong He 508c55abf61SChaoyong He if (tnl_type != RTE_ETH_TUNNEL_TYPE_VXLAN) { 509c55abf61SChaoyong He PMD_DRV_LOG(ERR, "Not VXLAN tunnel"); 510c55abf61SChaoyong He return -ENOTSUP; 511c55abf61SChaoyong He } 512c55abf61SChaoyong He 513c55abf61SChaoyong He ret = nfp_net_find_vxlan_idx(hw, vxlan_port, &idx); 514c55abf61SChaoyong He if (ret != 0) { 515c55abf61SChaoyong He PMD_DRV_LOG(ERR, "Failed find valid vxlan idx"); 516c55abf61SChaoyong He return -EINVAL; 517c55abf61SChaoyong He } 518c55abf61SChaoyong He 519c55abf61SChaoyong He if (hw->vxlan_usecnt[idx] == 0) { 520c55abf61SChaoyong He ret = nfp_net_set_vxlan_port(hw, idx, vxlan_port); 521c55abf61SChaoyong He if (ret != 0) { 522c55abf61SChaoyong He PMD_DRV_LOG(ERR, "Failed set vxlan port"); 523c55abf61SChaoyong He return -EINVAL; 524c55abf61SChaoyong He } 525c55abf61SChaoyong He } 526c55abf61SChaoyong He 527c55abf61SChaoyong He hw->vxlan_usecnt[idx]++; 528c55abf61SChaoyong He 529c55abf61SChaoyong He return 0; 530c55abf61SChaoyong He } 531c55abf61SChaoyong He 532c55abf61SChaoyong He static int 533c55abf61SChaoyong He nfp_udp_tunnel_port_del(struct rte_eth_dev *dev, 534c55abf61SChaoyong He struct rte_eth_udp_tunnel *tunnel_udp) 535c55abf61SChaoyong He { 536c55abf61SChaoyong He int ret; 537c55abf61SChaoyong He uint32_t idx; 538c55abf61SChaoyong He uint16_t vxlan_port; 539c55abf61SChaoyong He struct nfp_net_hw *hw; 540c55abf61SChaoyong He enum rte_eth_tunnel_type tnl_type; 541c55abf61SChaoyong He 5429d723baaSChaoyong He hw = dev->data->dev_private; 543c55abf61SChaoyong He vxlan_port = tunnel_udp->udp_port; 544c55abf61SChaoyong He tnl_type = tunnel_udp->prot_type; 545c55abf61SChaoyong He 546c55abf61SChaoyong He if (tnl_type != RTE_ETH_TUNNEL_TYPE_VXLAN) { 547c55abf61SChaoyong He PMD_DRV_LOG(ERR, "Not VXLAN tunnel"); 548c55abf61SChaoyong He return -ENOTSUP; 549c55abf61SChaoyong He } 550c55abf61SChaoyong He 551c55abf61SChaoyong He ret = nfp_net_find_vxlan_idx(hw, vxlan_port, &idx); 552c55abf61SChaoyong He if (ret != 0 || hw->vxlan_usecnt[idx] == 0) { 553c55abf61SChaoyong He PMD_DRV_LOG(ERR, "Failed find valid vxlan idx"); 554c55abf61SChaoyong He return -EINVAL; 555c55abf61SChaoyong He } 556c55abf61SChaoyong He 557c55abf61SChaoyong He hw->vxlan_usecnt[idx]--; 558c55abf61SChaoyong He 559c55abf61SChaoyong He if (hw->vxlan_usecnt[idx] == 0) { 560c55abf61SChaoyong He ret = nfp_net_set_vxlan_port(hw, idx, 0); 561c55abf61SChaoyong He if (ret != 0) { 562c55abf61SChaoyong He PMD_DRV_LOG(ERR, "Failed set vxlan port"); 563c55abf61SChaoyong He return -EINVAL; 564c55abf61SChaoyong He } 565c55abf61SChaoyong He } 566c55abf61SChaoyong He 567c55abf61SChaoyong He return 0; 568c55abf61SChaoyong He } 569c55abf61SChaoyong He 570646ea79cSHeinrich Kuhn /* Initialise and register driver with DPDK Application */ 5718d961320SJin Liu static const struct eth_dev_ops nfp_net_eth_dev_ops = { 572646ea79cSHeinrich Kuhn .dev_configure = nfp_net_configure, 573646ea79cSHeinrich Kuhn .dev_start = nfp_net_start, 574646ea79cSHeinrich Kuhn .dev_stop = nfp_net_stop, 575646ea79cSHeinrich Kuhn .dev_set_link_up = nfp_net_set_link_up, 576646ea79cSHeinrich Kuhn .dev_set_link_down = nfp_net_set_link_down, 577646ea79cSHeinrich Kuhn .dev_close = nfp_net_close, 578646ea79cSHeinrich Kuhn .promiscuous_enable = nfp_net_promisc_enable, 579646ea79cSHeinrich Kuhn .promiscuous_disable = nfp_net_promisc_disable, 5804a86c36bSQin Ke .allmulticast_enable = nfp_net_allmulticast_enable, 5814a86c36bSQin Ke .allmulticast_disable = nfp_net_allmulticast_disable, 582646ea79cSHeinrich Kuhn .link_update = nfp_net_link_update, 583646ea79cSHeinrich Kuhn .stats_get = nfp_net_stats_get, 584646ea79cSHeinrich Kuhn .stats_reset = nfp_net_stats_reset, 585f26e8239SJames Hershaw .xstats_get = nfp_net_xstats_get, 586f26e8239SJames Hershaw .xstats_reset = nfp_net_xstats_reset, 587f26e8239SJames Hershaw .xstats_get_names = nfp_net_xstats_get_names, 588f26e8239SJames Hershaw .xstats_get_by_id = nfp_net_xstats_get_by_id, 589f26e8239SJames Hershaw .xstats_get_names_by_id = nfp_net_xstats_get_names_by_id, 590646ea79cSHeinrich Kuhn .dev_infos_get = nfp_net_infos_get, 591646ea79cSHeinrich Kuhn .dev_supported_ptypes_get = nfp_net_supported_ptypes_get, 592646ea79cSHeinrich Kuhn .mtu_set = nfp_net_dev_mtu_set, 5930a94d6bcSJin Liu .mac_addr_set = nfp_net_set_mac_addr, 594646ea79cSHeinrich Kuhn .vlan_offload_set = nfp_net_vlan_offload_set, 595646ea79cSHeinrich Kuhn .reta_update = nfp_net_reta_update, 596646ea79cSHeinrich Kuhn .reta_query = nfp_net_reta_query, 597646ea79cSHeinrich Kuhn .rss_hash_update = nfp_net_rss_hash_update, 598646ea79cSHeinrich Kuhn .rss_hash_conf_get = nfp_net_rss_hash_conf_get, 599646ea79cSHeinrich Kuhn .rx_queue_setup = nfp_net_rx_queue_setup, 600646ea79cSHeinrich Kuhn .rx_queue_release = nfp_net_rx_queue_release, 6018d961320SJin Liu .tx_queue_setup = nfp_net_tx_queue_setup, 60252ddc4c2SJin Liu .tx_queue_release = nfp_net_tx_queue_release, 60352ddc4c2SJin Liu .rx_queue_intr_enable = nfp_rx_queue_intr_enable, 60452ddc4c2SJin Liu .rx_queue_intr_disable = nfp_rx_queue_intr_disable, 605c55abf61SChaoyong He .udp_tunnel_port_add = nfp_udp_tunnel_port_add, 606c55abf61SChaoyong He .udp_tunnel_port_del = nfp_udp_tunnel_port_del, 607128c8ad9SChaoyong He .fw_version_get = nfp_net_firmware_version_get, 60851d15e82SZerun Fu .flow_ctrl_get = nfp_net_flow_ctrl_get, 60968aa3537SZerun Fu .flow_ctrl_set = nfp_net_flow_ctrl_set, 6100b9079d2SChaoyong He .flow_ops_get = nfp_net_flow_ops_get, 61152ddc4c2SJin Liu }; 61252ddc4c2SJin Liu 613ee8ca64eSChaoyong He static inline void 614ee8ca64eSChaoyong He nfp_net_ethdev_ops_mount(struct nfp_net_hw *hw, 615ee8ca64eSChaoyong He struct rte_eth_dev *eth_dev) 616266470b2SJin Liu { 617ee8ca64eSChaoyong He if (hw->ver.extend == NFP_NET_CFG_VERSION_DP_NFD3) 618ee8ca64eSChaoyong He eth_dev->tx_pkt_burst = nfp_net_nfd3_xmit_pkts; 619ee8ca64eSChaoyong He else 620ee8ca64eSChaoyong He eth_dev->tx_pkt_burst = nfp_net_nfdk_xmit_pkts; 621266470b2SJin Liu 6228d961320SJin Liu eth_dev->dev_ops = &nfp_net_eth_dev_ops; 623266470b2SJin Liu eth_dev->rx_queue_count = nfp_net_rx_queue_count; 624266470b2SJin Liu eth_dev->rx_pkt_burst = &nfp_net_recv_pkts; 625266470b2SJin Liu } 626266470b2SJin Liu 627646ea79cSHeinrich Kuhn static int 628646ea79cSHeinrich Kuhn nfp_net_init(struct rte_eth_dev *eth_dev) 629646ea79cSHeinrich Kuhn { 63049952141SChaoyong He int err; 63149952141SChaoyong He uint16_t port; 6320314a8ffSChaoyong He uint64_t rx_base; 6330314a8ffSChaoyong He uint64_t tx_base; 6344a9bb682SChaoyong He struct nfp_hw *hw; 6354a9bb682SChaoyong He struct nfp_net_hw *net_hw; 63649952141SChaoyong He struct nfp_pf_dev *pf_dev; 63749952141SChaoyong He struct rte_pci_device *pci_dev; 63849952141SChaoyong He struct nfp_app_fw_nic *app_fw_nic; 639646ea79cSHeinrich Kuhn 640646ea79cSHeinrich Kuhn pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev); 64165f6915dSChaoyong He net_hw = eth_dev->data->dev_private; 642646ea79cSHeinrich Kuhn 643646ea79cSHeinrich Kuhn /* Use backpointer here to the PF of this eth_dev */ 64465f6915dSChaoyong He pf_dev = net_hw->pf_dev; 645646ea79cSHeinrich Kuhn 646968ec1c3SChaoyong He /* Use backpointer to the CoreNIC app struct */ 647968ec1c3SChaoyong He app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(pf_dev->app_fw_priv); 648968ec1c3SChaoyong He 649646ea79cSHeinrich Kuhn port = ((struct nfp_net_hw *)eth_dev->data->dev_private)->idx; 6508ceb85c3SChaoyong He if (port > 7) { 651646ea79cSHeinrich Kuhn PMD_DRV_LOG(ERR, "Port value is wrong"); 652646ea79cSHeinrich Kuhn return -ENODEV; 653646ea79cSHeinrich Kuhn } 654646ea79cSHeinrich Kuhn 6554a9bb682SChaoyong He hw = &net_hw->super; 656646ea79cSHeinrich Kuhn 657030b2b19SChaoyong He PMD_INIT_LOG(DEBUG, "Working with physical port number: %hu, " 6584a9bb682SChaoyong He "NFP internal port number: %d", port, net_hw->nfp_idx); 659646ea79cSHeinrich Kuhn 660646ea79cSHeinrich Kuhn rte_eth_copy_pci_info(eth_dev, pci_dev); 661646ea79cSHeinrich Kuhn 6628ad2cc8fSPeng Zhang if (port == 0 || pf_dev->multi_pf.enabled) { 663f26e8239SJames Hershaw uint32_t min_size; 664f26e8239SJames Hershaw 6654a9bb682SChaoyong He hw->ctrl_bar = pf_dev->ctrl_bar; 6664a9bb682SChaoyong He min_size = NFP_MAC_STATS_SIZE * net_hw->pf_dev->nfp_eth_table->max_index; 6674a9bb682SChaoyong He net_hw->mac_stats_bar = nfp_rtsym_map(net_hw->pf_dev->sym_tbl, "_mac_stats", 6684a9bb682SChaoyong He min_size, &net_hw->mac_stats_area); 6694a9bb682SChaoyong He if (net_hw->mac_stats_bar == NULL) { 670f26e8239SJames Hershaw PMD_INIT_LOG(ERR, "nfp_rtsym_map fails for _mac_stats_bar"); 671f26e8239SJames Hershaw return -EIO; 672f26e8239SJames Hershaw } 673b0c496abSChaoyong He 6744a9bb682SChaoyong He net_hw->mac_stats = net_hw->mac_stats_bar; 675646ea79cSHeinrich Kuhn } else { 676a6189a67SJin Liu /* Use port offset in pf ctrl_bar for this ports control bar */ 6774a9bb682SChaoyong He hw->ctrl_bar = pf_dev->ctrl_bar + (port * NFP_NET_CFG_BAR_SZ); 6784a9bb682SChaoyong He net_hw->mac_stats = app_fw_nic->ports[0]->mac_stats_bar + 6794a9bb682SChaoyong He (net_hw->nfp_idx * NFP_MAC_STATS_SIZE); 680646ea79cSHeinrich Kuhn } 681646ea79cSHeinrich Kuhn 6824a9bb682SChaoyong He PMD_INIT_LOG(DEBUG, "ctrl bar: %p", hw->ctrl_bar); 6834a9bb682SChaoyong He PMD_INIT_LOG(DEBUG, "MAC stats: %p", net_hw->mac_stats); 684646ea79cSHeinrich Kuhn 6854a9bb682SChaoyong He err = nfp_net_common_init(pci_dev, net_hw); 686cd4397ebSPeng Zhang if (err != 0) 68736994566SChaoyong He goto free_area; 688fd392f84SPeng Zhang 689eecdfcc1SShihong Wang err = nfp_net_tlv_caps_parse(eth_dev); 690eecdfcc1SShihong Wang if (err != 0) { 691eecdfcc1SShihong Wang PMD_INIT_LOG(ERR, "Failed to parser TLV caps"); 692eecdfcc1SShihong Wang return err; 69336994566SChaoyong He goto free_area; 694eecdfcc1SShihong Wang } 695eecdfcc1SShihong Wang 69654713740SChang Miao err = nfp_ipsec_init(eth_dev); 69754713740SChang Miao if (err != 0) { 69854713740SChang Miao PMD_INIT_LOG(ERR, "Failed to init IPsec module"); 69936994566SChaoyong He goto free_area; 70054713740SChang Miao } 70154713740SChang Miao 7024a9bb682SChaoyong He nfp_net_ethdev_ops_mount(net_hw, eth_dev); 703266470b2SJin Liu 7044a9bb682SChaoyong He net_hw->eth_xstats_base = rte_malloc("rte_eth_xstat", sizeof(struct rte_eth_xstat) * 705f26e8239SJames Hershaw nfp_net_xstats_size(eth_dev), 0); 7064a9bb682SChaoyong He if (net_hw->eth_xstats_base == NULL) { 707f26e8239SJames Hershaw PMD_INIT_LOG(ERR, "no memory for xstats base values on device %s!", 708f26e8239SJames Hershaw pci_dev->device.name); 70936994566SChaoyong He err = -ENOMEM; 71036994566SChaoyong He goto ipsec_exit; 711f26e8239SJames Hershaw } 712f26e8239SJames Hershaw 713646ea79cSHeinrich Kuhn /* Work out where in the BAR the queues start. */ 7144a9bb682SChaoyong He tx_base = nn_cfg_readl(hw, NFP_NET_CFG_START_TXQ); 7154a9bb682SChaoyong He rx_base = nn_cfg_readl(hw, NFP_NET_CFG_START_RXQ); 716646ea79cSHeinrich Kuhn 7174a9bb682SChaoyong He net_hw->tx_bar = pf_dev->qc_bar + tx_base * NFP_QCP_QUEUE_ADDR_SZ; 7184a9bb682SChaoyong He net_hw->rx_bar = pf_dev->qc_bar + rx_base * NFP_QCP_QUEUE_ADDR_SZ; 7194a9bb682SChaoyong He eth_dev->data->dev_private = net_hw; 720646ea79cSHeinrich Kuhn 721646ea79cSHeinrich Kuhn PMD_INIT_LOG(DEBUG, "ctrl_bar: %p, tx_bar: %p, rx_bar: %p", 7224a9bb682SChaoyong He hw->ctrl_bar, net_hw->tx_bar, net_hw->rx_bar); 723646ea79cSHeinrich Kuhn 7244a9bb682SChaoyong He nfp_net_cfg_queue_setup(net_hw); 7254a9bb682SChaoyong He net_hw->mtu = RTE_ETHER_MTU; 726646ea79cSHeinrich Kuhn 727646ea79cSHeinrich Kuhn /* VLAN insertion is incompatible with LSOv2 */ 7284a9bb682SChaoyong He if ((hw->cap & NFP_NET_CFG_CTRL_LSO2) != 0) 7294a9bb682SChaoyong He hw->cap &= ~NFP_NET_CFG_CTRL_TXVLAN; 730646ea79cSHeinrich Kuhn 7314a9bb682SChaoyong He nfp_net_log_device_information(net_hw); 732646ea79cSHeinrich Kuhn 733646ea79cSHeinrich Kuhn /* Initializing spinlock for reconfigs */ 7344a9bb682SChaoyong He rte_spinlock_init(&hw->reconfig_lock); 735646ea79cSHeinrich Kuhn 736646ea79cSHeinrich Kuhn /* Allocating memory for mac addr */ 737f4d24fe9SChaoyong He eth_dev->data->mac_addrs = rte_zmalloc("mac_addr", RTE_ETHER_ADDR_LEN, 0); 738646ea79cSHeinrich Kuhn if (eth_dev->data->mac_addrs == NULL) { 739646ea79cSHeinrich Kuhn PMD_INIT_LOG(ERR, "Failed to space for MAC address"); 74036994566SChaoyong He err = -ENOMEM; 74136994566SChaoyong He goto xstats_free; 742646ea79cSHeinrich Kuhn } 743646ea79cSHeinrich Kuhn 744968ec1c3SChaoyong He nfp_net_pf_read_mac(app_fw_nic, port); 745503ac807SChaoyong He nfp_write_mac(hw, &hw->mac_addr.addr_bytes[0]); 746646ea79cSHeinrich Kuhn 7474a9bb682SChaoyong He if (rte_is_valid_assigned_ether_addr(&hw->mac_addr) == 0) { 748a6189a67SJin Liu PMD_INIT_LOG(INFO, "Using random mac address for port %d", port); 749646ea79cSHeinrich Kuhn /* Using random mac addresses for VFs */ 7504a9bb682SChaoyong He rte_eth_random_addr(&hw->mac_addr.addr_bytes[0]); 751503ac807SChaoyong He nfp_write_mac(hw, &hw->mac_addr.addr_bytes[0]); 752646ea79cSHeinrich Kuhn } 753646ea79cSHeinrich Kuhn 754646ea79cSHeinrich Kuhn /* Copying mac address to DPDK eth_dev struct */ 7554a9bb682SChaoyong He rte_ether_addr_copy(&hw->mac_addr, eth_dev->data->mac_addrs); 756646ea79cSHeinrich Kuhn 7574a9bb682SChaoyong He if ((hw->cap & NFP_NET_CFG_CTRL_LIVE_ADDR) == 0) 758646ea79cSHeinrich Kuhn eth_dev->data->dev_flags |= RTE_ETH_DEV_NOLIVE_MAC_ADDR; 759646ea79cSHeinrich Kuhn 760646ea79cSHeinrich Kuhn eth_dev->data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS; 761646ea79cSHeinrich Kuhn 762030b2b19SChaoyong He PMD_INIT_LOG(INFO, "port %d VendorID=%#x DeviceID=%#x " 763c2c4f87bSAman Deep Singh "mac=" RTE_ETHER_ADDR_PRT_FMT, 764646ea79cSHeinrich Kuhn eth_dev->data->port_id, pci_dev->id.vendor_id, 765646ea79cSHeinrich Kuhn pci_dev->id.device_id, 7664a9bb682SChaoyong He RTE_ETHER_ADDR_BYTES(&hw->mac_addr)); 767646ea79cSHeinrich Kuhn 768646ea79cSHeinrich Kuhn /* Registering LSC interrupt handler */ 769d61138d4SHarman Kalra rte_intr_callback_register(pci_dev->intr_handle, 770a6189a67SJin Liu nfp_net_dev_interrupt_handler, (void *)eth_dev); 771646ea79cSHeinrich Kuhn /* Telling the firmware about the LSC interrupt entry */ 7724a9bb682SChaoyong He nn_cfg_writeb(hw, NFP_NET_CFG_LSC, NFP_NET_IRQ_LSC_IDX); 77394d0631aSPeng Zhang /* Unmask the LSC interrupt */ 77494d0631aSPeng Zhang nfp_net_irq_unmask(eth_dev); 775646ea79cSHeinrich Kuhn /* Recording current stats counters values */ 776646ea79cSHeinrich Kuhn nfp_net_stats_reset(eth_dev); 777646ea79cSHeinrich Kuhn 7788153bc6fSChaoyong He if ((hw->cap_ext & NFP_NET_CFG_CTRL_FLOW_STEER) != 0) { 7798153bc6fSChaoyong He err = nfp_net_flow_priv_init(pf_dev, port); 7808153bc6fSChaoyong He if (err != 0) { 7818153bc6fSChaoyong He PMD_INIT_LOG(ERR, "Init net flow priv failed"); 7828153bc6fSChaoyong He goto xstats_free; 7838153bc6fSChaoyong He } 7848153bc6fSChaoyong He } 7858153bc6fSChaoyong He 786646ea79cSHeinrich Kuhn return 0; 78736994566SChaoyong He 78836994566SChaoyong He xstats_free: 78936994566SChaoyong He rte_free(net_hw->eth_xstats_base); 79036994566SChaoyong He ipsec_exit: 79136994566SChaoyong He nfp_ipsec_uninit(eth_dev); 79236994566SChaoyong He free_area: 79336994566SChaoyong He if (net_hw->mac_stats_area != NULL) 79436994566SChaoyong He nfp_cpp_area_release_free(net_hw->mac_stats_area); 79536994566SChaoyong He 79636994566SChaoyong He return err; 797646ea79cSHeinrich Kuhn } 798646ea79cSHeinrich Kuhn 799646ea79cSHeinrich Kuhn #define DEFAULT_FW_PATH "/lib/firmware/netronome" 800646ea79cSHeinrich Kuhn 801646ea79cSHeinrich Kuhn static int 802f4d24fe9SChaoyong He nfp_fw_upload(struct rte_pci_device *dev, 803f4d24fe9SChaoyong He struct nfp_nsp *nsp, 804f4d24fe9SChaoyong He char *card) 805646ea79cSHeinrich Kuhn { 806646ea79cSHeinrich Kuhn void *fw_buf; 807646ea79cSHeinrich Kuhn size_t fsize; 80849952141SChaoyong He char serial[40]; 80949952141SChaoyong He char fw_name[125]; 810ff627b74SChaoyong He uint16_t interface; 811ff627b74SChaoyong He uint32_t cpp_serial_len; 812ff627b74SChaoyong He const uint8_t *cpp_serial; 81349952141SChaoyong He struct nfp_cpp *cpp = nfp_nsp_cpp(nsp); 814ff627b74SChaoyong He 815ff627b74SChaoyong He cpp_serial_len = nfp_cpp_serial(cpp, &cpp_serial); 816ff627b74SChaoyong He if (cpp_serial_len != NFP_SERIAL_LEN) 817ff627b74SChaoyong He return -ERANGE; 818ff627b74SChaoyong He 819ff627b74SChaoyong He interface = nfp_cpp_interface(cpp); 820646ea79cSHeinrich Kuhn 821646ea79cSHeinrich Kuhn /* Looking for firmware file in order of priority */ 822646ea79cSHeinrich Kuhn 823646ea79cSHeinrich Kuhn /* First try to find a firmware image specific for this device */ 824646ea79cSHeinrich Kuhn snprintf(serial, sizeof(serial), 825646ea79cSHeinrich Kuhn "serial-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x", 826ff627b74SChaoyong He cpp_serial[0], cpp_serial[1], cpp_serial[2], cpp_serial[3], 827ff627b74SChaoyong He cpp_serial[4], cpp_serial[5], interface >> 8, interface & 0xff); 828f4d24fe9SChaoyong He snprintf(fw_name, sizeof(fw_name), "%s/%s.nffw", DEFAULT_FW_PATH, serial); 829646ea79cSHeinrich Kuhn 830646ea79cSHeinrich Kuhn PMD_DRV_LOG(DEBUG, "Trying with fw file: %s", fw_name); 831646ea79cSHeinrich Kuhn if (rte_firmware_read(fw_name, &fw_buf, &fsize) == 0) 832646ea79cSHeinrich Kuhn goto load_fw; 833b0c496abSChaoyong He 834646ea79cSHeinrich Kuhn /* Then try the PCI name */ 835646ea79cSHeinrich Kuhn snprintf(fw_name, sizeof(fw_name), "%s/pci-%s.nffw", DEFAULT_FW_PATH, 8363ddb4cc0SPeng Zhang dev->name); 837646ea79cSHeinrich Kuhn 838646ea79cSHeinrich Kuhn PMD_DRV_LOG(DEBUG, "Trying with fw file: %s", fw_name); 839646ea79cSHeinrich Kuhn if (rte_firmware_read(fw_name, &fw_buf, &fsize) == 0) 840646ea79cSHeinrich Kuhn goto load_fw; 841646ea79cSHeinrich Kuhn 842646ea79cSHeinrich Kuhn /* Finally try the card type and media */ 843646ea79cSHeinrich Kuhn snprintf(fw_name, sizeof(fw_name), "%s/%s", DEFAULT_FW_PATH, card); 844646ea79cSHeinrich Kuhn PMD_DRV_LOG(DEBUG, "Trying with fw file: %s", fw_name); 845c01e5c0cSChaoyong He if (rte_firmware_read(fw_name, &fw_buf, &fsize) == 0) 846c01e5c0cSChaoyong He goto load_fw; 847c01e5c0cSChaoyong He 848c01e5c0cSChaoyong He PMD_DRV_LOG(ERR, "Can't find suitable firmware."); 849646ea79cSHeinrich Kuhn return -ENOENT; 850646ea79cSHeinrich Kuhn 851646ea79cSHeinrich Kuhn load_fw: 852646ea79cSHeinrich Kuhn PMD_DRV_LOG(INFO, "Firmware file found at %s with size: %zu", 853646ea79cSHeinrich Kuhn fw_name, fsize); 854646ea79cSHeinrich Kuhn PMD_DRV_LOG(INFO, "Uploading the firmware ..."); 8552e634b03SPeng Zhang if (nfp_nsp_load_fw(nsp, fw_buf, fsize) < 0) { 8562e634b03SPeng Zhang free(fw_buf); 8572e634b03SPeng Zhang PMD_DRV_LOG(ERR, "Firmware load failed."); 8582e634b03SPeng Zhang return -EIO; 8592e634b03SPeng Zhang } 8602e634b03SPeng Zhang 861646ea79cSHeinrich Kuhn PMD_DRV_LOG(INFO, "Done"); 862646ea79cSHeinrich Kuhn 863646ea79cSHeinrich Kuhn free(fw_buf); 864646ea79cSHeinrich Kuhn 865646ea79cSHeinrich Kuhn return 0; 866646ea79cSHeinrich Kuhn } 867646ea79cSHeinrich Kuhn 8683b00109dSPeng Zhang static void 8693b00109dSPeng Zhang nfp_fw_unload(struct nfp_cpp *cpp) 8703b00109dSPeng Zhang { 8713b00109dSPeng Zhang struct nfp_nsp *nsp; 8723b00109dSPeng Zhang 8733b00109dSPeng Zhang nsp = nfp_nsp_open(cpp); 8743b00109dSPeng Zhang if (nsp == NULL) 8753b00109dSPeng Zhang return; 8763b00109dSPeng Zhang 8773b00109dSPeng Zhang nfp_nsp_device_soft_reset(nsp); 8783b00109dSPeng Zhang nfp_nsp_close(nsp); 8793b00109dSPeng Zhang } 8803b00109dSPeng Zhang 881646ea79cSHeinrich Kuhn static int 8828ba461d1SPeng Zhang nfp_fw_reload(struct rte_pci_device *dev, 8838ba461d1SPeng Zhang struct nfp_nsp *nsp, 8848ba461d1SPeng Zhang char *card_desc) 8858ba461d1SPeng Zhang { 8868ba461d1SPeng Zhang int err; 8878ba461d1SPeng Zhang 8888ba461d1SPeng Zhang nfp_nsp_device_soft_reset(nsp); 8898ba461d1SPeng Zhang err = nfp_fw_upload(dev, nsp, card_desc); 8908ba461d1SPeng Zhang if (err != 0) 8918ba461d1SPeng Zhang PMD_DRV_LOG(ERR, "NFP firmware load failed"); 8928ba461d1SPeng Zhang 8938ba461d1SPeng Zhang return err; 8948ba461d1SPeng Zhang } 8958ba461d1SPeng Zhang 8968ba461d1SPeng Zhang static int 8978ba461d1SPeng Zhang nfp_fw_loaded_check_alive(struct rte_pci_device *dev, 8988ba461d1SPeng Zhang struct nfp_nsp *nsp, 8998ba461d1SPeng Zhang char *card_desc, 9008ba461d1SPeng Zhang const struct nfp_dev_info *dev_info, 9018ba461d1SPeng Zhang struct nfp_multi_pf *multi_pf) 9028ba461d1SPeng Zhang { 9038ba461d1SPeng Zhang int offset; 9048ba461d1SPeng Zhang uint32_t i; 9058ba461d1SPeng Zhang uint64_t beat; 9068ba461d1SPeng Zhang uint32_t port_num; 9078ba461d1SPeng Zhang 9088ba461d1SPeng Zhang /* 9098ba461d1SPeng Zhang * If the beats of any other port changed in 3s, 9108ba461d1SPeng Zhang * we should not reload the firmware. 9118ba461d1SPeng Zhang */ 9128ba461d1SPeng Zhang for (port_num = 0; port_num < dev_info->pf_num_per_unit; port_num++) { 9138ba461d1SPeng Zhang if (port_num == multi_pf->function_id) 9148ba461d1SPeng Zhang continue; 9158ba461d1SPeng Zhang 9168ba461d1SPeng Zhang offset = NFP_BEAT_OFFSET(port_num); 9178ba461d1SPeng Zhang beat = nn_readq(multi_pf->beat_addr + offset); 9188ba461d1SPeng Zhang for (i = 0; i < 3; i++) { 9198ba461d1SPeng Zhang sleep(1); 9208ba461d1SPeng Zhang if (nn_readq(multi_pf->beat_addr + offset) != beat) 9218ba461d1SPeng Zhang return 0; 9228ba461d1SPeng Zhang } 9238ba461d1SPeng Zhang } 9248ba461d1SPeng Zhang 9258ba461d1SPeng Zhang return nfp_fw_reload(dev, nsp, card_desc); 9268ba461d1SPeng Zhang } 9278ba461d1SPeng Zhang 9288ba461d1SPeng Zhang static int 9298ba461d1SPeng Zhang nfp_fw_reload_for_multipf(struct rte_pci_device *dev, 9308ba461d1SPeng Zhang struct nfp_nsp *nsp, 9318ba461d1SPeng Zhang char *card_desc, 9328ba461d1SPeng Zhang struct nfp_cpp *cpp, 9338ba461d1SPeng Zhang const struct nfp_dev_info *dev_info, 9348ba461d1SPeng Zhang struct nfp_multi_pf *multi_pf) 9358ba461d1SPeng Zhang { 9368ba461d1SPeng Zhang int err; 9378ba461d1SPeng Zhang 9388ba461d1SPeng Zhang err = nfp_net_keepalive_init(cpp, multi_pf); 9398ba461d1SPeng Zhang if (err != 0) 9408ba461d1SPeng Zhang PMD_DRV_LOG(ERR, "NFP write beat failed"); 9418ba461d1SPeng Zhang 9428ba461d1SPeng Zhang if (nfp_nsp_fw_loaded(nsp)) 9438ba461d1SPeng Zhang err = nfp_fw_loaded_check_alive(dev, nsp, card_desc, dev_info, multi_pf); 9448ba461d1SPeng Zhang else 9458ba461d1SPeng Zhang err = nfp_fw_reload(dev, nsp, card_desc); 9468ba461d1SPeng Zhang if (err != 0) { 9478ba461d1SPeng Zhang nfp_net_keepalive_uninit(multi_pf); 9488ba461d1SPeng Zhang return err; 9498ba461d1SPeng Zhang } 9508ba461d1SPeng Zhang 9518ba461d1SPeng Zhang err = nfp_net_keepalive_start(multi_pf); 9528ba461d1SPeng Zhang if (err != 0) { 9538ba461d1SPeng Zhang nfp_net_keepalive_uninit(multi_pf); 9548ba461d1SPeng Zhang PMD_DRV_LOG(ERR, "NFP write beat failed"); 9558ba461d1SPeng Zhang } 9568ba461d1SPeng Zhang 9578ba461d1SPeng Zhang return err; 9588ba461d1SPeng Zhang } 9598ba461d1SPeng Zhang 9608ba461d1SPeng Zhang static int 961a6189a67SJin Liu nfp_fw_setup(struct rte_pci_device *dev, 962a6189a67SJin Liu struct nfp_cpp *cpp, 963a6189a67SJin Liu struct nfp_eth_table *nfp_eth_table, 9648ba461d1SPeng Zhang struct nfp_hwinfo *hwinfo, 9658ba461d1SPeng Zhang const struct nfp_dev_info *dev_info, 9668ba461d1SPeng Zhang struct nfp_multi_pf *multi_pf) 967646ea79cSHeinrich Kuhn { 96849952141SChaoyong He int err; 96949952141SChaoyong He char card_desc[100]; 970646ea79cSHeinrich Kuhn struct nfp_nsp *nsp; 971646ea79cSHeinrich Kuhn const char *nfp_fw_model; 972646ea79cSHeinrich Kuhn 97306be30d4SPeng Zhang nfp_fw_model = nfp_hwinfo_lookup(hwinfo, "nffw.partno"); 97406be30d4SPeng Zhang if (nfp_fw_model == NULL) 975646ea79cSHeinrich Kuhn nfp_fw_model = nfp_hwinfo_lookup(hwinfo, "assembly.partno"); 976646ea79cSHeinrich Kuhn 977c01e5c0cSChaoyong He if (nfp_fw_model != NULL) { 978646ea79cSHeinrich Kuhn PMD_DRV_LOG(INFO, "firmware model found: %s", nfp_fw_model); 979646ea79cSHeinrich Kuhn } else { 980646ea79cSHeinrich Kuhn PMD_DRV_LOG(ERR, "firmware model NOT found"); 981646ea79cSHeinrich Kuhn return -EIO; 982646ea79cSHeinrich Kuhn } 983646ea79cSHeinrich Kuhn 984646ea79cSHeinrich Kuhn if (nfp_eth_table->count == 0 || nfp_eth_table->count > 8) { 985646ea79cSHeinrich Kuhn PMD_DRV_LOG(ERR, "NFP ethernet table reports wrong ports: %u", 986646ea79cSHeinrich Kuhn nfp_eth_table->count); 987646ea79cSHeinrich Kuhn return -EIO; 988646ea79cSHeinrich Kuhn } 989646ea79cSHeinrich Kuhn 990646ea79cSHeinrich Kuhn PMD_DRV_LOG(INFO, "NFP ethernet port table reports %u ports", 991646ea79cSHeinrich Kuhn nfp_eth_table->count); 992646ea79cSHeinrich Kuhn 993646ea79cSHeinrich Kuhn PMD_DRV_LOG(INFO, "Port speed: %u", nfp_eth_table->ports[0].speed); 994646ea79cSHeinrich Kuhn 995646ea79cSHeinrich Kuhn snprintf(card_desc, sizeof(card_desc), "nic_%s_%dx%d.nffw", 996646ea79cSHeinrich Kuhn nfp_fw_model, nfp_eth_table->count, 997646ea79cSHeinrich Kuhn nfp_eth_table->ports[0].speed / 1000); 998646ea79cSHeinrich Kuhn 999646ea79cSHeinrich Kuhn nsp = nfp_nsp_open(cpp); 1000a6189a67SJin Liu if (nsp == NULL) { 1001646ea79cSHeinrich Kuhn PMD_DRV_LOG(ERR, "NFP error when obtaining NSP handle"); 1002646ea79cSHeinrich Kuhn return -EIO; 1003646ea79cSHeinrich Kuhn } 1004646ea79cSHeinrich Kuhn 10058ba461d1SPeng Zhang if (multi_pf->enabled) 10068ba461d1SPeng Zhang err = nfp_fw_reload_for_multipf(dev, nsp, card_desc, cpp, dev_info, multi_pf); 10078ba461d1SPeng Zhang else 10088ba461d1SPeng Zhang err = nfp_fw_reload(dev, nsp, card_desc); 1009646ea79cSHeinrich Kuhn 1010646ea79cSHeinrich Kuhn nfp_nsp_close(nsp); 1011646ea79cSHeinrich Kuhn return err; 1012646ea79cSHeinrich Kuhn } 1013646ea79cSHeinrich Kuhn 10148ad2cc8fSPeng Zhang static inline bool 1015a508fa23SPeng Zhang nfp_check_multi_pf_from_fw(uint32_t total_vnics) 1016a508fa23SPeng Zhang { 1017a508fa23SPeng Zhang if (total_vnics == 1) 1018a508fa23SPeng Zhang return true; 1019a508fa23SPeng Zhang 1020a508fa23SPeng Zhang return false; 1021a508fa23SPeng Zhang } 1022a508fa23SPeng Zhang 1023a508fa23SPeng Zhang static inline bool 10248ad2cc8fSPeng Zhang nfp_check_multi_pf_from_nsp(struct rte_pci_device *pci_dev, 10258ad2cc8fSPeng Zhang struct nfp_cpp *cpp) 10268ad2cc8fSPeng Zhang { 10278ad2cc8fSPeng Zhang bool flag; 10288ad2cc8fSPeng Zhang struct nfp_nsp *nsp; 10298ad2cc8fSPeng Zhang 10308ad2cc8fSPeng Zhang nsp = nfp_nsp_open(cpp); 10318ad2cc8fSPeng Zhang if (nsp == NULL) { 10328ad2cc8fSPeng Zhang PMD_DRV_LOG(ERR, "NFP error when obtaining NSP handle"); 10338ad2cc8fSPeng Zhang return false; 10348ad2cc8fSPeng Zhang } 10358ad2cc8fSPeng Zhang 10368ad2cc8fSPeng Zhang flag = (nfp_nsp_get_abi_ver_major(nsp) > 0) && 10378ad2cc8fSPeng Zhang (pci_dev->id.device_id == PCI_DEVICE_ID_NFP3800_PF_NIC); 10388ad2cc8fSPeng Zhang 10398ad2cc8fSPeng Zhang nfp_nsp_close(nsp); 10408ad2cc8fSPeng Zhang return flag; 10418ad2cc8fSPeng Zhang } 10428ad2cc8fSPeng Zhang 1043a6189a67SJin Liu static int 104495f978efSPeng Zhang nfp_enable_multi_pf(struct nfp_pf_dev *pf_dev) 104595f978efSPeng Zhang { 104695f978efSPeng Zhang int err = 0; 104795f978efSPeng Zhang uint64_t tx_base; 104895f978efSPeng Zhang uint8_t *ctrl_bar; 104995f978efSPeng Zhang struct nfp_hw *hw; 105095f978efSPeng Zhang uint32_t cap_extend; 105195f978efSPeng Zhang struct nfp_net_hw net_hw; 105295f978efSPeng Zhang struct nfp_cpp_area *area; 105395f978efSPeng Zhang char name[RTE_ETH_NAME_MAX_LEN]; 105495f978efSPeng Zhang 105595f978efSPeng Zhang memset(&net_hw, 0, sizeof(struct nfp_net_hw)); 105695f978efSPeng Zhang 105795f978efSPeng Zhang /* Map the symbol table */ 105895f978efSPeng Zhang snprintf(name, sizeof(name), "_pf%u_net_bar0", 105995f978efSPeng Zhang pf_dev->multi_pf.function_id); 106095f978efSPeng Zhang ctrl_bar = nfp_rtsym_map(pf_dev->sym_tbl, name, NFP_NET_CFG_BAR_SZ, 106195f978efSPeng Zhang &area); 106295f978efSPeng Zhang if (ctrl_bar == NULL) { 106395f978efSPeng Zhang PMD_INIT_LOG(ERR, "Failed to find data vNIC memory symbol"); 106495f978efSPeng Zhang return -ENODEV; 106595f978efSPeng Zhang } 106695f978efSPeng Zhang 106795f978efSPeng Zhang hw = &net_hw.super; 106895f978efSPeng Zhang hw->ctrl_bar = ctrl_bar; 106995f978efSPeng Zhang 107095f978efSPeng Zhang cap_extend = nn_cfg_readl(hw, NFP_NET_CFG_CAP_WORD1); 107195f978efSPeng Zhang if ((cap_extend & NFP_NET_CFG_CTRL_MULTI_PF) == 0) { 107295f978efSPeng Zhang PMD_INIT_LOG(ERR, "Loaded firmware doesn't support multiple PF"); 107395f978efSPeng Zhang err = -EINVAL; 107495f978efSPeng Zhang goto end; 107595f978efSPeng Zhang } 107695f978efSPeng Zhang 107795f978efSPeng Zhang tx_base = nn_cfg_readl(hw, NFP_NET_CFG_START_TXQ); 107895f978efSPeng Zhang net_hw.tx_bar = pf_dev->qc_bar + tx_base * NFP_QCP_QUEUE_ADDR_SZ; 107995f978efSPeng Zhang nfp_net_cfg_queue_setup(&net_hw); 108095f978efSPeng Zhang rte_spinlock_init(&hw->reconfig_lock); 108195f978efSPeng Zhang nfp_ext_reconfig(&net_hw.super, NFP_NET_CFG_CTRL_MULTI_PF, NFP_NET_CFG_UPDATE_GEN); 108295f978efSPeng Zhang end: 108395f978efSPeng Zhang nfp_cpp_area_release_free(area); 108495f978efSPeng Zhang return err; 108595f978efSPeng Zhang } 108695f978efSPeng Zhang 108795f978efSPeng Zhang static int 10880314a8ffSChaoyong He nfp_init_app_fw_nic(struct nfp_pf_dev *pf_dev, 10890314a8ffSChaoyong He const struct nfp_dev_info *dev_info) 1090646ea79cSHeinrich Kuhn { 10918ceb85c3SChaoyong He uint8_t i; 10923b00109dSPeng Zhang uint8_t id; 1093e7978635SChaoyong He int ret = 0; 10948ceb85c3SChaoyong He uint32_t total_vnics; 1095646ea79cSHeinrich Kuhn struct nfp_net_hw *hw; 1096968ec1c3SChaoyong He unsigned int numa_node; 1097646ea79cSHeinrich Kuhn struct rte_eth_dev *eth_dev; 1098968ec1c3SChaoyong He struct nfp_app_fw_nic *app_fw_nic; 1099a6189a67SJin Liu struct nfp_eth_table *nfp_eth_table; 11003b00109dSPeng Zhang char bar_name[RTE_ETH_NAME_MAX_LEN]; 1101646ea79cSHeinrich Kuhn char port_name[RTE_ETH_NAME_MAX_LEN]; 11023b00109dSPeng Zhang char vnic_name[RTE_ETH_NAME_MAX_LEN]; 1103646ea79cSHeinrich Kuhn 1104968ec1c3SChaoyong He nfp_eth_table = pf_dev->nfp_eth_table; 1105968ec1c3SChaoyong He PMD_INIT_LOG(INFO, "Total physical ports: %d", nfp_eth_table->count); 11063b00109dSPeng Zhang id = nfp_function_id_get(pf_dev, 0); 1107968ec1c3SChaoyong He 1108968ec1c3SChaoyong He /* Allocate memory for the CoreNIC app */ 1109968ec1c3SChaoyong He app_fw_nic = rte_zmalloc("nfp_app_fw_nic", sizeof(*app_fw_nic), 0); 1110968ec1c3SChaoyong He if (app_fw_nic == NULL) 1111968ec1c3SChaoyong He return -ENOMEM; 1112968ec1c3SChaoyong He 1113968ec1c3SChaoyong He /* Point the app_fw_priv pointer in the PF to the coreNIC app */ 1114968ec1c3SChaoyong He pf_dev->app_fw_priv = app_fw_nic; 1115968ec1c3SChaoyong He 1116968ec1c3SChaoyong He /* Read the number of vNIC's created for the PF */ 11173b00109dSPeng Zhang snprintf(vnic_name, sizeof(vnic_name), "nfd_cfg_pf%u_num_ports", id); 11183b00109dSPeng Zhang total_vnics = nfp_rtsym_read_le(pf_dev->sym_tbl, vnic_name, &ret); 1119e7978635SChaoyong He if (ret != 0 || total_vnics == 0 || total_vnics > 8) { 11203b00109dSPeng Zhang PMD_INIT_LOG(ERR, "%s symbol with wrong value", vnic_name); 1121968ec1c3SChaoyong He ret = -ENODEV; 1122968ec1c3SChaoyong He goto app_cleanup; 1123968ec1c3SChaoyong He } 1124968ec1c3SChaoyong He 1125a508fa23SPeng Zhang if (pf_dev->multi_pf.enabled) { 1126a508fa23SPeng Zhang if (!nfp_check_multi_pf_from_fw(total_vnics)) { 1127a508fa23SPeng Zhang PMD_INIT_LOG(ERR, "NSP report multipf, but FW report not multipf"); 1128a508fa23SPeng Zhang ret = -ENODEV; 1129a508fa23SPeng Zhang goto app_cleanup; 1130a508fa23SPeng Zhang } 1131a508fa23SPeng Zhang } else { 1132968ec1c3SChaoyong He /* 1133968ec1c3SChaoyong He * For coreNIC the number of vNICs exposed should be the same as the 113440688372SChaoyong He * number of physical ports. 1135968ec1c3SChaoyong He */ 11368ceb85c3SChaoyong He if (total_vnics != nfp_eth_table->count) { 1137968ec1c3SChaoyong He PMD_INIT_LOG(ERR, "Total physical ports do not match number of vNICs"); 1138968ec1c3SChaoyong He ret = -ENODEV; 1139968ec1c3SChaoyong He goto app_cleanup; 1140968ec1c3SChaoyong He } 1141a508fa23SPeng Zhang } 1142968ec1c3SChaoyong He 1143968ec1c3SChaoyong He /* Populate coreNIC app properties */ 1144968ec1c3SChaoyong He app_fw_nic->total_phyports = total_vnics; 1145968ec1c3SChaoyong He app_fw_nic->pf_dev = pf_dev; 1146968ec1c3SChaoyong He if (total_vnics > 1) 1147968ec1c3SChaoyong He app_fw_nic->multiport = true; 1148968ec1c3SChaoyong He 1149968ec1c3SChaoyong He /* Map the symbol table */ 11503b00109dSPeng Zhang snprintf(bar_name, sizeof(bar_name), "_pf%u_net_bar0", id); 11513b00109dSPeng Zhang pf_dev->ctrl_bar = nfp_rtsym_map(pf_dev->sym_tbl, bar_name, 1152d5e9fc86SChaoyong He app_fw_nic->total_phyports * NFP_NET_CFG_BAR_SZ, 1153d5e9fc86SChaoyong He &pf_dev->ctrl_area); 1154968ec1c3SChaoyong He if (pf_dev->ctrl_bar == NULL) { 11553b00109dSPeng Zhang PMD_INIT_LOG(ERR, "nfp_rtsym_map fails for %s", bar_name); 1156968ec1c3SChaoyong He ret = -EIO; 1157968ec1c3SChaoyong He goto app_cleanup; 1158968ec1c3SChaoyong He } 1159968ec1c3SChaoyong He 1160968ec1c3SChaoyong He PMD_INIT_LOG(DEBUG, "ctrl bar: %p", pf_dev->ctrl_bar); 1161968ec1c3SChaoyong He 1162968ec1c3SChaoyong He /* Loop through all physical ports on PF */ 1163968ec1c3SChaoyong He numa_node = rte_socket_id(); 1164968ec1c3SChaoyong He for (i = 0; i < app_fw_nic->total_phyports; i++) { 11653b00109dSPeng Zhang id = nfp_function_id_get(pf_dev, i); 11663b00109dSPeng Zhang snprintf(port_name, sizeof(port_name), "%s_port%u", 11673b00109dSPeng Zhang pf_dev->pci_dev->device.name, id); 1168646ea79cSHeinrich Kuhn 1169646ea79cSHeinrich Kuhn /* Allocate a eth_dev for this phyport */ 1170646ea79cSHeinrich Kuhn eth_dev = rte_eth_dev_allocate(port_name); 1171a6189a67SJin Liu if (eth_dev == NULL) { 1172646ea79cSHeinrich Kuhn ret = -ENODEV; 1173646ea79cSHeinrich Kuhn goto port_cleanup; 1174646ea79cSHeinrich Kuhn } 1175646ea79cSHeinrich Kuhn 1176646ea79cSHeinrich Kuhn /* Allocate memory for this phyport */ 1177f4d24fe9SChaoyong He eth_dev->data->dev_private = rte_zmalloc_socket(port_name, 1178f4d24fe9SChaoyong He sizeof(struct nfp_net_hw), 1179646ea79cSHeinrich Kuhn RTE_CACHE_LINE_SIZE, numa_node); 1180a6189a67SJin Liu if (eth_dev->data->dev_private == NULL) { 1181646ea79cSHeinrich Kuhn ret = -ENOMEM; 1182646ea79cSHeinrich Kuhn rte_eth_dev_release_port(eth_dev); 1183646ea79cSHeinrich Kuhn goto port_cleanup; 1184646ea79cSHeinrich Kuhn } 1185646ea79cSHeinrich Kuhn 11869d723baaSChaoyong He hw = eth_dev->data->dev_private; 1187646ea79cSHeinrich Kuhn 1188646ea79cSHeinrich Kuhn /* Add this device to the PF's array of physical ports */ 11893b00109dSPeng Zhang app_fw_nic->ports[id] = hw; 1190646ea79cSHeinrich Kuhn 11910314a8ffSChaoyong He hw->dev_info = dev_info; 1192646ea79cSHeinrich Kuhn hw->pf_dev = pf_dev; 1193646ea79cSHeinrich Kuhn hw->cpp = pf_dev->cpp; 1194646ea79cSHeinrich Kuhn hw->eth_dev = eth_dev; 11953b00109dSPeng Zhang hw->idx = id; 11963b00109dSPeng Zhang hw->nfp_idx = nfp_eth_table->ports[id].index; 1197646ea79cSHeinrich Kuhn 1198646ea79cSHeinrich Kuhn eth_dev->device = &pf_dev->pci_dev->device; 1199646ea79cSHeinrich Kuhn 120040688372SChaoyong He /* 120140688372SChaoyong He * Ctrl/tx/rx BAR mappings and remaining init happens in 120240688372SChaoyong He * @nfp_net_init() 1203646ea79cSHeinrich Kuhn */ 1204646ea79cSHeinrich Kuhn ret = nfp_net_init(eth_dev); 1205c01e5c0cSChaoyong He if (ret != 0) { 1206646ea79cSHeinrich Kuhn ret = -ENODEV; 1207646ea79cSHeinrich Kuhn goto port_cleanup; 1208646ea79cSHeinrich Kuhn } 1209646ea79cSHeinrich Kuhn 1210646ea79cSHeinrich Kuhn rte_eth_dev_probing_finish(eth_dev); 1211646ea79cSHeinrich Kuhn 1212646ea79cSHeinrich Kuhn } /* End loop, all ports on this PF */ 1213968ec1c3SChaoyong He 1214968ec1c3SChaoyong He return 0; 1215646ea79cSHeinrich Kuhn 1216646ea79cSHeinrich Kuhn port_cleanup: 1217968ec1c3SChaoyong He for (i = 0; i < app_fw_nic->total_phyports; i++) { 12183b00109dSPeng Zhang id = nfp_function_id_get(pf_dev, i); 12198153bc6fSChaoyong He hw = app_fw_nic->ports[id]; 12203b00109dSPeng Zhang 12218153bc6fSChaoyong He if (hw != NULL && hw->eth_dev != NULL) { 12228153bc6fSChaoyong He nfp_net_uninit(hw->eth_dev); 12238153bc6fSChaoyong He rte_eth_dev_release_port(hw->eth_dev); 1224646ea79cSHeinrich Kuhn } 1225646ea79cSHeinrich Kuhn } 12268b8f116bSChaoyong He nfp_cpp_area_release_free(pf_dev->ctrl_area); 1227968ec1c3SChaoyong He app_cleanup: 1228968ec1c3SChaoyong He rte_free(app_fw_nic); 1229a6189a67SJin Liu 1230646ea79cSHeinrich Kuhn return ret; 1231646ea79cSHeinrich Kuhn } 1232646ea79cSHeinrich Kuhn 1233a6189a67SJin Liu static int 1234*c7a6970fSZerun Fu nfp_net_hwinfo_set(uint8_t function_id, 1235*c7a6970fSZerun Fu struct nfp_rtsym_table *sym_tbl, 1236*c7a6970fSZerun Fu struct nfp_cpp *cpp) 1237*c7a6970fSZerun Fu { 1238*c7a6970fSZerun Fu int ret = 0; 1239*c7a6970fSZerun Fu uint64_t app_cap; 1240*c7a6970fSZerun Fu uint8_t sp_indiff; 1241*c7a6970fSZerun Fu struct nfp_nsp *nsp; 1242*c7a6970fSZerun Fu char hw_info[RTE_ETH_NAME_MAX_LEN]; 1243*c7a6970fSZerun Fu char app_cap_name[RTE_ETH_NAME_MAX_LEN]; 1244*c7a6970fSZerun Fu 1245*c7a6970fSZerun Fu /* Read the app capabilities of the firmware loaded */ 1246*c7a6970fSZerun Fu snprintf(app_cap_name, sizeof(app_cap_name), "_pf%u_net_app_cap", function_id); 1247*c7a6970fSZerun Fu app_cap = nfp_rtsym_read_le(sym_tbl, app_cap_name, &ret); 1248*c7a6970fSZerun Fu if (ret != 0) { 1249*c7a6970fSZerun Fu PMD_INIT_LOG(ERR, "Couldn't read app_fw_cap from firmware."); 1250*c7a6970fSZerun Fu return ret; 1251*c7a6970fSZerun Fu } 1252*c7a6970fSZerun Fu 1253*c7a6970fSZerun Fu /* Calculate the value of sp_indiff and write to hw_info */ 1254*c7a6970fSZerun Fu sp_indiff = app_cap & NFP_NET_APP_CAP_SP_INDIFF; 1255*c7a6970fSZerun Fu snprintf(hw_info, sizeof(hw_info), "sp_indiff=%u", sp_indiff); 1256*c7a6970fSZerun Fu 1257*c7a6970fSZerun Fu nsp = nfp_nsp_open(cpp); 1258*c7a6970fSZerun Fu if (nsp == NULL) { 1259*c7a6970fSZerun Fu PMD_INIT_LOG(ERR, "Couldn't get NSP."); 1260*c7a6970fSZerun Fu return -EIO; 1261*c7a6970fSZerun Fu } 1262*c7a6970fSZerun Fu 1263*c7a6970fSZerun Fu ret = nfp_nsp_hwinfo_set(nsp, hw_info, sizeof(hw_info)); 1264*c7a6970fSZerun Fu nfp_nsp_close(nsp); 1265*c7a6970fSZerun Fu if (ret != 0) { 1266*c7a6970fSZerun Fu PMD_INIT_LOG(ERR, "Failed to set parameter to hwinfo."); 1267*c7a6970fSZerun Fu return ret; 1268*c7a6970fSZerun Fu } 1269*c7a6970fSZerun Fu 1270*c7a6970fSZerun Fu return 0; 1271*c7a6970fSZerun Fu } 1272*c7a6970fSZerun Fu 1273*c7a6970fSZerun Fu static int 1274a6189a67SJin Liu nfp_pf_init(struct rte_pci_device *pci_dev) 1275646ea79cSHeinrich Kuhn { 12769e442599SShihong Wang uint32_t i; 12773b00109dSPeng Zhang uint32_t id; 1278e7978635SChaoyong He int ret = 0; 12795c464d6aSJin Liu uint64_t addr; 12803b00109dSPeng Zhang uint32_t index; 1281925c27ecSChaoyong He uint32_t cpp_id; 12823b00109dSPeng Zhang uint8_t function_id; 1283a6189a67SJin Liu struct nfp_cpp *cpp; 1284a6189a67SJin Liu struct nfp_pf_dev *pf_dev; 1285a6189a67SJin Liu struct nfp_hwinfo *hwinfo; 128649952141SChaoyong He enum nfp_app_fw_id app_fw_id; 1287a6189a67SJin Liu char name[RTE_ETH_NAME_MAX_LEN]; 1288a6189a67SJin Liu struct nfp_rtsym_table *sym_tbl; 12893b00109dSPeng Zhang char app_name[RTE_ETH_NAME_MAX_LEN]; 1290a6189a67SJin Liu struct nfp_eth_table *nfp_eth_table; 12910314a8ffSChaoyong He const struct nfp_dev_info *dev_info; 1292646ea79cSHeinrich Kuhn 1293a6189a67SJin Liu if (pci_dev == NULL) 1294a6189a67SJin Liu return -ENODEV; 1295646ea79cSHeinrich Kuhn 129684aaba5aSChaoyong He if (pci_dev->mem_resource[0].addr == NULL) { 129784aaba5aSChaoyong He PMD_INIT_LOG(ERR, "The address of BAR0 is NULL."); 129884aaba5aSChaoyong He return -ENODEV; 129984aaba5aSChaoyong He } 130084aaba5aSChaoyong He 13010314a8ffSChaoyong He dev_info = nfp_dev_info_get(pci_dev->id.device_id); 13020314a8ffSChaoyong He if (dev_info == NULL) { 13030314a8ffSChaoyong He PMD_INIT_LOG(ERR, "Not supported device ID"); 13040314a8ffSChaoyong He return -ENODEV; 13050314a8ffSChaoyong He } 13060314a8ffSChaoyong He 13078ad2cc8fSPeng Zhang /* Allocate memory for the PF "device" */ 13083b00109dSPeng Zhang function_id = (pci_dev->addr.function) & 0x07; 13093b00109dSPeng Zhang snprintf(name, sizeof(name), "nfp_pf%u", function_id); 13108ad2cc8fSPeng Zhang pf_dev = rte_zmalloc(name, sizeof(*pf_dev), 0); 13118ad2cc8fSPeng Zhang if (pf_dev == NULL) { 13128ad2cc8fSPeng Zhang PMD_INIT_LOG(ERR, "Can't allocate memory for the PF device"); 13138ad2cc8fSPeng Zhang return -ENOMEM; 13148ad2cc8fSPeng Zhang } 13158ad2cc8fSPeng Zhang 1316646ea79cSHeinrich Kuhn /* 1317646ea79cSHeinrich Kuhn * When device bound to UIO, the device could be used, by mistake, 1318646ea79cSHeinrich Kuhn * by two DPDK apps, and the UIO driver does not avoid it. This 1319646ea79cSHeinrich Kuhn * could lead to a serious problem when configuring the NFP CPP 1320646ea79cSHeinrich Kuhn * interface. Here we avoid this telling to the CPP init code to 1321646ea79cSHeinrich Kuhn * use a lock file if UIO is being used. 1322646ea79cSHeinrich Kuhn */ 1323646ea79cSHeinrich Kuhn if (pci_dev->kdrv == RTE_PCI_KDRV_VFIO) 13241fbe51cdSChaoyong He cpp = nfp_cpp_from_nfp6000_pcie(pci_dev, dev_info, false); 1325646ea79cSHeinrich Kuhn else 13261fbe51cdSChaoyong He cpp = nfp_cpp_from_nfp6000_pcie(pci_dev, dev_info, true); 1327646ea79cSHeinrich Kuhn 1328a6189a67SJin Liu if (cpp == NULL) { 1329646ea79cSHeinrich Kuhn PMD_INIT_LOG(ERR, "A CPP handle can not be obtained"); 13308ad2cc8fSPeng Zhang ret = -EIO; 13318ad2cc8fSPeng Zhang goto pf_cleanup; 1332646ea79cSHeinrich Kuhn } 1333646ea79cSHeinrich Kuhn 1334646ea79cSHeinrich Kuhn hwinfo = nfp_hwinfo_read(cpp); 1335a6189a67SJin Liu if (hwinfo == NULL) { 1336646ea79cSHeinrich Kuhn PMD_INIT_LOG(ERR, "Error reading hwinfo table"); 1337646ea79cSHeinrich Kuhn ret = -EIO; 1338968ec1c3SChaoyong He goto cpp_cleanup; 1339646ea79cSHeinrich Kuhn } 1340646ea79cSHeinrich Kuhn 1341968ec1c3SChaoyong He /* Read the number of physical ports from hardware */ 1342646ea79cSHeinrich Kuhn nfp_eth_table = nfp_eth_read_ports(cpp); 1343a6189a67SJin Liu if (nfp_eth_table == NULL) { 1344646ea79cSHeinrich Kuhn PMD_INIT_LOG(ERR, "Error reading NFP ethernet table"); 1345646ea79cSHeinrich Kuhn ret = -EIO; 1346646ea79cSHeinrich Kuhn goto hwinfo_cleanup; 1347646ea79cSHeinrich Kuhn } 1348646ea79cSHeinrich Kuhn 13498ad2cc8fSPeng Zhang pf_dev->multi_pf.enabled = nfp_check_multi_pf_from_nsp(pci_dev, cpp); 13503b00109dSPeng Zhang pf_dev->multi_pf.function_id = function_id; 13518ad2cc8fSPeng Zhang 13529e442599SShihong Wang /* Force the physical port down to clear the possible DMA error */ 13533b00109dSPeng Zhang for (i = 0; i < nfp_eth_table->count; i++) { 13543b00109dSPeng Zhang id = nfp_function_id_get(pf_dev, i); 13553b00109dSPeng Zhang index = nfp_eth_table->ports[id].index; 13563b00109dSPeng Zhang nfp_eth_set_configured(cpp, index, 0); 13573b00109dSPeng Zhang } 13589e442599SShihong Wang 13598ba461d1SPeng Zhang if (nfp_fw_setup(pci_dev, cpp, nfp_eth_table, hwinfo, 13608ba461d1SPeng Zhang dev_info, &pf_dev->multi_pf) != 0) { 1361646ea79cSHeinrich Kuhn PMD_INIT_LOG(ERR, "Error when uploading firmware"); 1362646ea79cSHeinrich Kuhn ret = -EIO; 1363646ea79cSHeinrich Kuhn goto eth_table_cleanup; 1364646ea79cSHeinrich Kuhn } 1365646ea79cSHeinrich Kuhn 1366646ea79cSHeinrich Kuhn /* Now the symbol table should be there */ 1367646ea79cSHeinrich Kuhn sym_tbl = nfp_rtsym_table_read(cpp); 1368a6189a67SJin Liu if (sym_tbl == NULL) { 1369f4d24fe9SChaoyong He PMD_INIT_LOG(ERR, "Something is wrong with the firmware symbol table"); 1370646ea79cSHeinrich Kuhn ret = -EIO; 13713b00109dSPeng Zhang goto fw_cleanup; 1372646ea79cSHeinrich Kuhn } 1373646ea79cSHeinrich Kuhn 1374968ec1c3SChaoyong He /* Read the app ID of the firmware loaded */ 13753b00109dSPeng Zhang snprintf(app_name, sizeof(app_name), "_pf%u_net_app_id", function_id); 13763b00109dSPeng Zhang app_fw_id = nfp_rtsym_read_le(sym_tbl, app_name, &ret); 1377e7978635SChaoyong He if (ret != 0) { 13783b00109dSPeng Zhang PMD_INIT_LOG(ERR, "Couldn't read %s from firmware", app_name); 1379646ea79cSHeinrich Kuhn ret = -EIO; 1380646ea79cSHeinrich Kuhn goto sym_tbl_cleanup; 1381646ea79cSHeinrich Kuhn } 1382646ea79cSHeinrich Kuhn 1383*c7a6970fSZerun Fu /* Write sp_indiff to hw_info */ 1384*c7a6970fSZerun Fu ret = nfp_net_hwinfo_set(function_id, sym_tbl, cpp); 1385*c7a6970fSZerun Fu if (ret != 0) { 1386*c7a6970fSZerun Fu PMD_INIT_LOG(ERR, "Failed to set hwinfo."); 1387*c7a6970fSZerun Fu ret = -EIO; 1388*c7a6970fSZerun Fu goto sym_tbl_cleanup; 1389*c7a6970fSZerun Fu } 1390*c7a6970fSZerun Fu 1391646ea79cSHeinrich Kuhn /* Populate the newly created PF device */ 1392968ec1c3SChaoyong He pf_dev->app_fw_id = app_fw_id; 1393646ea79cSHeinrich Kuhn pf_dev->cpp = cpp; 1394646ea79cSHeinrich Kuhn pf_dev->hwinfo = hwinfo; 1395646ea79cSHeinrich Kuhn pf_dev->sym_tbl = sym_tbl; 1396646ea79cSHeinrich Kuhn pf_dev->pci_dev = pci_dev; 1397968ec1c3SChaoyong He pf_dev->nfp_eth_table = nfp_eth_table; 1398646ea79cSHeinrich Kuhn 139940688372SChaoyong He /* Configure access to tx/rx vNIC BARs */ 14000314a8ffSChaoyong He addr = nfp_qcp_queue_offset(dev_info, 0); 1401925c27ecSChaoyong He cpp_id = NFP_CPP_ISLAND_ID(0, NFP_CPP_ACTION_RW, 0, 0); 14020314a8ffSChaoyong He 1403711e4559SChaoyong He pf_dev->qc_bar = nfp_cpp_map_area(pf_dev->cpp, cpp_id, 14040314a8ffSChaoyong He addr, dev_info->qc_area_sz, &pf_dev->qc_area); 1405711e4559SChaoyong He if (pf_dev->qc_bar == NULL) { 1406646ea79cSHeinrich Kuhn PMD_INIT_LOG(ERR, "nfp_rtsym_map fails for net.qc"); 1407646ea79cSHeinrich Kuhn ret = -EIO; 14088ad2cc8fSPeng Zhang goto sym_tbl_cleanup; 1409646ea79cSHeinrich Kuhn } 1410646ea79cSHeinrich Kuhn 1411030b2b19SChaoyong He PMD_INIT_LOG(DEBUG, "qc_bar address: %p", pf_dev->qc_bar); 1412646ea79cSHeinrich Kuhn 1413a6189a67SJin Liu /* 1414968ec1c3SChaoyong He * PF initialization has been done at this point. Call app specific 141540688372SChaoyong He * init code now. 1416646ea79cSHeinrich Kuhn */ 1417968ec1c3SChaoyong He switch (pf_dev->app_fw_id) { 1418968ec1c3SChaoyong He case NFP_APP_FW_CORE_NIC: 141995f978efSPeng Zhang if (pf_dev->multi_pf.enabled) { 142095f978efSPeng Zhang ret = nfp_enable_multi_pf(pf_dev); 142195f978efSPeng Zhang if (ret != 0) 142295f978efSPeng Zhang goto hwqueues_cleanup; 142395f978efSPeng Zhang } 142495f978efSPeng Zhang 1425968ec1c3SChaoyong He PMD_INIT_LOG(INFO, "Initializing coreNIC"); 14260314a8ffSChaoyong He ret = nfp_init_app_fw_nic(pf_dev, dev_info); 1427968ec1c3SChaoyong He if (ret != 0) { 1428968ec1c3SChaoyong He PMD_INIT_LOG(ERR, "Could not initialize coreNIC!"); 1429968ec1c3SChaoyong He goto hwqueues_cleanup; 1430968ec1c3SChaoyong He } 1431968ec1c3SChaoyong He break; 1432b1880421SChaoyong He case NFP_APP_FW_FLOWER_NIC: 1433b1880421SChaoyong He PMD_INIT_LOG(INFO, "Initializing Flower"); 14340314a8ffSChaoyong He ret = nfp_init_app_fw_flower(pf_dev, dev_info); 1435b1880421SChaoyong He if (ret != 0) { 1436b1880421SChaoyong He PMD_INIT_LOG(ERR, "Could not initialize Flower!"); 1437b1880421SChaoyong He goto hwqueues_cleanup; 1438b1880421SChaoyong He } 1439b1880421SChaoyong He break; 1440968ec1c3SChaoyong He default: 1441968ec1c3SChaoyong He PMD_INIT_LOG(ERR, "Unsupported Firmware loaded"); 1442968ec1c3SChaoyong He ret = -EINVAL; 1443646ea79cSHeinrich Kuhn goto hwqueues_cleanup; 1444646ea79cSHeinrich Kuhn } 1445646ea79cSHeinrich Kuhn 144640688372SChaoyong He /* Register the CPP bridge service here for primary use */ 1447bab0e6f4SChaoyong He ret = nfp_enable_cpp_service(pf_dev); 1448dee23e6cSChaoyong He if (ret != 0) 1449dee23e6cSChaoyong He PMD_INIT_LOG(INFO, "Enable cpp service failed."); 1450646ea79cSHeinrich Kuhn 1451646ea79cSHeinrich Kuhn return 0; 1452646ea79cSHeinrich Kuhn 1453646ea79cSHeinrich Kuhn hwqueues_cleanup: 1454528812a6SChaoyong He nfp_cpp_area_release_free(pf_dev->qc_area); 1455646ea79cSHeinrich Kuhn sym_tbl_cleanup: 1456646ea79cSHeinrich Kuhn free(sym_tbl); 14573b00109dSPeng Zhang fw_cleanup: 14583b00109dSPeng Zhang nfp_fw_unload(cpp); 14598ba461d1SPeng Zhang nfp_net_keepalive_stop(&pf_dev->multi_pf); 1460528812a6SChaoyong He nfp_net_keepalive_uninit(&pf_dev->multi_pf); 1461646ea79cSHeinrich Kuhn eth_table_cleanup: 1462646ea79cSHeinrich Kuhn free(nfp_eth_table); 1463646ea79cSHeinrich Kuhn hwinfo_cleanup: 1464646ea79cSHeinrich Kuhn free(hwinfo); 1465968ec1c3SChaoyong He cpp_cleanup: 1466968ec1c3SChaoyong He nfp_cpp_free(cpp); 14678ad2cc8fSPeng Zhang pf_cleanup: 14688ad2cc8fSPeng Zhang rte_free(pf_dev); 14697feb8909SChaoyong He 1470646ea79cSHeinrich Kuhn return ret; 1471646ea79cSHeinrich Kuhn } 1472646ea79cSHeinrich Kuhn 1473d5f39e07SChaoyong He static int 1474016141b1SChaoyong He nfp_secondary_init_app_fw_nic(struct nfp_pf_dev *pf_dev) 1475d5f39e07SChaoyong He { 14768ceb85c3SChaoyong He uint32_t i; 1477d5f39e07SChaoyong He int err = 0; 1478d5f39e07SChaoyong He int ret = 0; 14793b00109dSPeng Zhang uint8_t function_id; 14808ceb85c3SChaoyong He uint32_t total_vnics; 1481d5f39e07SChaoyong He struct nfp_net_hw *hw; 14823b00109dSPeng Zhang char pf_name[RTE_ETH_NAME_MAX_LEN]; 1483d5f39e07SChaoyong He 1484d5f39e07SChaoyong He /* Read the number of vNIC's created for the PF */ 14853b00109dSPeng Zhang function_id = (pf_dev->pci_dev->addr.function) & 0x07; 14863b00109dSPeng Zhang snprintf(pf_name, sizeof(pf_name), "nfd_cfg_pf%u_num_ports", function_id); 14873b00109dSPeng Zhang total_vnics = nfp_rtsym_read_le(pf_dev->sym_tbl, pf_name, &err); 14888ceb85c3SChaoyong He if (err != 0 || total_vnics == 0 || total_vnics > 8) { 14893b00109dSPeng Zhang PMD_INIT_LOG(ERR, "%s symbol with wrong value", pf_name); 1490d5f39e07SChaoyong He return -ENODEV; 1491d5f39e07SChaoyong He } 1492d5f39e07SChaoyong He 1493d5f39e07SChaoyong He for (i = 0; i < total_vnics; i++) { 14943b00109dSPeng Zhang uint32_t id = i; 1495d5f39e07SChaoyong He struct rte_eth_dev *eth_dev; 1496d5f39e07SChaoyong He char port_name[RTE_ETH_NAME_MAX_LEN]; 14973b00109dSPeng Zhang 14983b00109dSPeng Zhang if (nfp_check_multi_pf_from_fw(total_vnics)) 14993b00109dSPeng Zhang id = function_id; 15008ceb85c3SChaoyong He snprintf(port_name, sizeof(port_name), "%s_port%u", 15013b00109dSPeng Zhang pf_dev->pci_dev->device.name, id); 1502d5f39e07SChaoyong He 1503d5f39e07SChaoyong He PMD_INIT_LOG(DEBUG, "Secondary attaching to port %s", port_name); 1504d5f39e07SChaoyong He eth_dev = rte_eth_dev_attach_secondary(port_name); 1505d5f39e07SChaoyong He if (eth_dev == NULL) { 1506d5f39e07SChaoyong He PMD_INIT_LOG(ERR, "Secondary process attach to port %s failed", port_name); 1507d5f39e07SChaoyong He ret = -ENODEV; 1508d5f39e07SChaoyong He break; 1509d5f39e07SChaoyong He } 1510d5f39e07SChaoyong He 1511acb6bebfSChaoyong He eth_dev->process_private = pf_dev; 15129d723baaSChaoyong He hw = eth_dev->data->dev_private; 1513ee8ca64eSChaoyong He nfp_net_ethdev_ops_mount(hw, eth_dev); 1514d5f39e07SChaoyong He 1515d5f39e07SChaoyong He rte_eth_dev_probing_finish(eth_dev); 1516d5f39e07SChaoyong He } 1517d5f39e07SChaoyong He 1518d5f39e07SChaoyong He return ret; 1519d5f39e07SChaoyong He } 1520d5f39e07SChaoyong He 1521646ea79cSHeinrich Kuhn /* 1522646ea79cSHeinrich Kuhn * When attaching to the NFP4000/6000 PF on a secondary process there 1523646ea79cSHeinrich Kuhn * is no need to initialise the PF again. Only minimal work is required 152440688372SChaoyong He * here. 1525646ea79cSHeinrich Kuhn */ 1526a6189a67SJin Liu static int 1527a6189a67SJin Liu nfp_pf_secondary_init(struct rte_pci_device *pci_dev) 1528646ea79cSHeinrich Kuhn { 1529968ec1c3SChaoyong He int ret = 0; 1530a6189a67SJin Liu struct nfp_cpp *cpp; 15313b00109dSPeng Zhang uint8_t function_id; 1532016141b1SChaoyong He struct nfp_pf_dev *pf_dev; 1533d5f39e07SChaoyong He enum nfp_app_fw_id app_fw_id; 1534016141b1SChaoyong He char name[RTE_ETH_NAME_MAX_LEN]; 1535a6189a67SJin Liu struct nfp_rtsym_table *sym_tbl; 15360314a8ffSChaoyong He const struct nfp_dev_info *dev_info; 15373b00109dSPeng Zhang char app_name[RTE_ETH_NAME_MAX_LEN]; 1538646ea79cSHeinrich Kuhn 1539a6189a67SJin Liu if (pci_dev == NULL) 1540646ea79cSHeinrich Kuhn return -ENODEV; 1541646ea79cSHeinrich Kuhn 154284aaba5aSChaoyong He if (pci_dev->mem_resource[0].addr == NULL) { 154384aaba5aSChaoyong He PMD_INIT_LOG(ERR, "The address of BAR0 is NULL."); 154484aaba5aSChaoyong He return -ENODEV; 154584aaba5aSChaoyong He } 154684aaba5aSChaoyong He 15470314a8ffSChaoyong He dev_info = nfp_dev_info_get(pci_dev->id.device_id); 15480314a8ffSChaoyong He if (dev_info == NULL) { 15490314a8ffSChaoyong He PMD_INIT_LOG(ERR, "Not supported device ID"); 15500314a8ffSChaoyong He return -ENODEV; 15510314a8ffSChaoyong He } 15520314a8ffSChaoyong He 1553016141b1SChaoyong He /* Allocate memory for the PF "device" */ 1554016141b1SChaoyong He snprintf(name, sizeof(name), "nfp_pf%d", 0); 1555016141b1SChaoyong He pf_dev = rte_zmalloc(name, sizeof(*pf_dev), 0); 1556016141b1SChaoyong He if (pf_dev == NULL) { 1557016141b1SChaoyong He PMD_INIT_LOG(ERR, "Can't allocate memory for the PF device"); 1558016141b1SChaoyong He return -ENOMEM; 1559016141b1SChaoyong He } 1560016141b1SChaoyong He 1561646ea79cSHeinrich Kuhn /* 1562646ea79cSHeinrich Kuhn * When device bound to UIO, the device could be used, by mistake, 1563646ea79cSHeinrich Kuhn * by two DPDK apps, and the UIO driver does not avoid it. This 1564646ea79cSHeinrich Kuhn * could lead to a serious problem when configuring the NFP CPP 1565646ea79cSHeinrich Kuhn * interface. Here we avoid this telling to the CPP init code to 1566646ea79cSHeinrich Kuhn * use a lock file if UIO is being used. 1567646ea79cSHeinrich Kuhn */ 1568646ea79cSHeinrich Kuhn if (pci_dev->kdrv == RTE_PCI_KDRV_VFIO) 15691fbe51cdSChaoyong He cpp = nfp_cpp_from_nfp6000_pcie(pci_dev, dev_info, false); 1570646ea79cSHeinrich Kuhn else 15711fbe51cdSChaoyong He cpp = nfp_cpp_from_nfp6000_pcie(pci_dev, dev_info, true); 1572646ea79cSHeinrich Kuhn 1573a6189a67SJin Liu if (cpp == NULL) { 1574646ea79cSHeinrich Kuhn PMD_INIT_LOG(ERR, "A CPP handle can not be obtained"); 1575016141b1SChaoyong He ret = -EIO; 1576016141b1SChaoyong He goto pf_cleanup; 1577646ea79cSHeinrich Kuhn } 1578646ea79cSHeinrich Kuhn 1579646ea79cSHeinrich Kuhn /* 1580646ea79cSHeinrich Kuhn * We don't have access to the PF created in the primary process 158140688372SChaoyong He * here so we have to read the number of ports from firmware. 1582646ea79cSHeinrich Kuhn */ 1583646ea79cSHeinrich Kuhn sym_tbl = nfp_rtsym_table_read(cpp); 1584a6189a67SJin Liu if (sym_tbl == NULL) { 1585f4d24fe9SChaoyong He PMD_INIT_LOG(ERR, "Something is wrong with the firmware symbol table"); 1586016141b1SChaoyong He ret = -EIO; 1587016141b1SChaoyong He goto pf_cleanup; 1588646ea79cSHeinrich Kuhn } 1589646ea79cSHeinrich Kuhn 1590d5f39e07SChaoyong He /* Read the app ID of the firmware loaded */ 15913b00109dSPeng Zhang function_id = pci_dev->addr.function & 0x7; 15923b00109dSPeng Zhang snprintf(app_name, sizeof(app_name), "_pf%u_net_app_id", function_id); 15933b00109dSPeng Zhang app_fw_id = nfp_rtsym_read_le(sym_tbl, app_name, &ret); 1594e7978635SChaoyong He if (ret != 0) { 15953b00109dSPeng Zhang PMD_INIT_LOG(ERR, "Couldn't read %s from fw", app_name); 1596016141b1SChaoyong He ret = -EIO; 1597968ec1c3SChaoyong He goto sym_tbl_cleanup; 1598968ec1c3SChaoyong He } 1599646ea79cSHeinrich Kuhn 1600016141b1SChaoyong He /* Populate the newly created PF device */ 1601016141b1SChaoyong He pf_dev->app_fw_id = app_fw_id; 1602016141b1SChaoyong He pf_dev->cpp = cpp; 1603016141b1SChaoyong He pf_dev->sym_tbl = sym_tbl; 1604016141b1SChaoyong He pf_dev->pci_dev = pci_dev; 1605016141b1SChaoyong He 1606016141b1SChaoyong He /* Call app specific init code now */ 1607d5f39e07SChaoyong He switch (app_fw_id) { 1608d5f39e07SChaoyong He case NFP_APP_FW_CORE_NIC: 1609d5f39e07SChaoyong He PMD_INIT_LOG(INFO, "Initializing coreNIC"); 1610016141b1SChaoyong He ret = nfp_secondary_init_app_fw_nic(pf_dev); 1611d5f39e07SChaoyong He if (ret != 0) { 1612d5f39e07SChaoyong He PMD_INIT_LOG(ERR, "Could not initialize coreNIC!"); 1613d5f39e07SChaoyong He goto sym_tbl_cleanup; 1614646ea79cSHeinrich Kuhn } 1615d5f39e07SChaoyong He break; 1616b1880421SChaoyong He case NFP_APP_FW_FLOWER_NIC: 1617b1880421SChaoyong He PMD_INIT_LOG(INFO, "Initializing Flower"); 1618016141b1SChaoyong He ret = nfp_secondary_init_app_fw_flower(pf_dev); 1619b1880421SChaoyong He if (ret != 0) { 1620b1880421SChaoyong He PMD_INIT_LOG(ERR, "Could not initialize Flower!"); 1621b1880421SChaoyong He goto sym_tbl_cleanup; 1622b1880421SChaoyong He } 1623b1880421SChaoyong He break; 1624d5f39e07SChaoyong He default: 1625d5f39e07SChaoyong He PMD_INIT_LOG(ERR, "Unsupported Firmware loaded"); 1626d5f39e07SChaoyong He ret = -EINVAL; 1627d5f39e07SChaoyong He goto sym_tbl_cleanup; 1628646ea79cSHeinrich Kuhn } 1629646ea79cSHeinrich Kuhn 1630016141b1SChaoyong He return 0; 1631016141b1SChaoyong He 1632968ec1c3SChaoyong He sym_tbl_cleanup: 1633968ec1c3SChaoyong He free(sym_tbl); 1634016141b1SChaoyong He pf_cleanup: 1635016141b1SChaoyong He rte_free(pf_dev); 1636968ec1c3SChaoyong He 1637968ec1c3SChaoyong He return ret; 1638646ea79cSHeinrich Kuhn } 1639646ea79cSHeinrich Kuhn 1640a6189a67SJin Liu static int 1641a6189a67SJin Liu nfp_pf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, 1642646ea79cSHeinrich Kuhn struct rte_pci_device *dev) 1643646ea79cSHeinrich Kuhn { 1644646ea79cSHeinrich Kuhn if (rte_eal_process_type() == RTE_PROC_PRIMARY) 1645646ea79cSHeinrich Kuhn return nfp_pf_init(dev); 1646646ea79cSHeinrich Kuhn else 1647646ea79cSHeinrich Kuhn return nfp_pf_secondary_init(dev); 1648646ea79cSHeinrich Kuhn } 1649646ea79cSHeinrich Kuhn 1650646ea79cSHeinrich Kuhn static const struct rte_pci_id pci_id_nfp_pf_net_map[] = { 1651646ea79cSHeinrich Kuhn { 1652646ea79cSHeinrich Kuhn RTE_PCI_DEVICE(PCI_VENDOR_ID_NETRONOME, 16535c464d6aSJin Liu PCI_DEVICE_ID_NFP3800_PF_NIC) 16545c464d6aSJin Liu }, 16555c464d6aSJin Liu { 16565c464d6aSJin Liu RTE_PCI_DEVICE(PCI_VENDOR_ID_NETRONOME, 1657646ea79cSHeinrich Kuhn PCI_DEVICE_ID_NFP4000_PF_NIC) 1658646ea79cSHeinrich Kuhn }, 1659646ea79cSHeinrich Kuhn { 1660646ea79cSHeinrich Kuhn RTE_PCI_DEVICE(PCI_VENDOR_ID_NETRONOME, 1661646ea79cSHeinrich Kuhn PCI_DEVICE_ID_NFP6000_PF_NIC) 1662646ea79cSHeinrich Kuhn }, 1663646ea79cSHeinrich Kuhn { 16645aedd4c3SJames Hershaw RTE_PCI_DEVICE(PCI_VENDOR_ID_CORIGINE, 16655aedd4c3SJames Hershaw PCI_DEVICE_ID_NFP3800_PF_NIC) 16665aedd4c3SJames Hershaw }, 16675aedd4c3SJames Hershaw { 16685aedd4c3SJames Hershaw RTE_PCI_DEVICE(PCI_VENDOR_ID_CORIGINE, 16695aedd4c3SJames Hershaw PCI_DEVICE_ID_NFP4000_PF_NIC) 16705aedd4c3SJames Hershaw }, 16715aedd4c3SJames Hershaw { 16725aedd4c3SJames Hershaw RTE_PCI_DEVICE(PCI_VENDOR_ID_CORIGINE, 16735aedd4c3SJames Hershaw PCI_DEVICE_ID_NFP6000_PF_NIC) 16745aedd4c3SJames Hershaw }, 16755aedd4c3SJames Hershaw { 1676646ea79cSHeinrich Kuhn .vendor_id = 0, 1677646ea79cSHeinrich Kuhn }, 1678646ea79cSHeinrich Kuhn }; 1679646ea79cSHeinrich Kuhn 1680a6189a67SJin Liu static int 1681a6189a67SJin Liu nfp_pci_uninit(struct rte_eth_dev *eth_dev) 1682646ea79cSHeinrich Kuhn { 1683646ea79cSHeinrich Kuhn uint16_t port_id; 168449952141SChaoyong He struct rte_pci_device *pci_dev; 1685646ea79cSHeinrich Kuhn 1686646ea79cSHeinrich Kuhn pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev); 1687646ea79cSHeinrich Kuhn 1688646ea79cSHeinrich Kuhn /* Free up all physical ports under PF */ 1689646ea79cSHeinrich Kuhn RTE_ETH_FOREACH_DEV_OF(port_id, &pci_dev->device) 1690646ea79cSHeinrich Kuhn rte_eth_dev_close(port_id); 1691646ea79cSHeinrich Kuhn /* 1692646ea79cSHeinrich Kuhn * Ports can be closed and freed but hotplugging is not 169340688372SChaoyong He * currently supported. 1694646ea79cSHeinrich Kuhn */ 1695646ea79cSHeinrich Kuhn return -ENOTSUP; 1696646ea79cSHeinrich Kuhn } 1697646ea79cSHeinrich Kuhn 1698a6189a67SJin Liu static int 1699a6189a67SJin Liu eth_nfp_pci_remove(struct rte_pci_device *pci_dev) 1700646ea79cSHeinrich Kuhn { 1701646ea79cSHeinrich Kuhn return rte_eth_dev_pci_generic_remove(pci_dev, nfp_pci_uninit); 1702646ea79cSHeinrich Kuhn } 1703646ea79cSHeinrich Kuhn 1704646ea79cSHeinrich Kuhn static struct rte_pci_driver rte_nfp_net_pf_pmd = { 1705646ea79cSHeinrich Kuhn .id_table = pci_id_nfp_pf_net_map, 1706646ea79cSHeinrich Kuhn .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC, 1707646ea79cSHeinrich Kuhn .probe = nfp_pf_pci_probe, 1708646ea79cSHeinrich Kuhn .remove = eth_nfp_pci_remove, 1709646ea79cSHeinrich Kuhn }; 1710646ea79cSHeinrich Kuhn 1711d505ee1dSChaoyong He RTE_PMD_REGISTER_PCI(NFP_PF_DRIVER_NAME, rte_nfp_net_pf_pmd); 1712d505ee1dSChaoyong He RTE_PMD_REGISTER_PCI_TABLE(NFP_PF_DRIVER_NAME, pci_id_nfp_pf_net_map); 1713d505ee1dSChaoyong He RTE_PMD_REGISTER_KMOD_DEP(NFP_PF_DRIVER_NAME, "* igb_uio | uio_pci_generic | vfio"); 1714