1503ac807SChaoyong He /* SPDX-License-Identifier: BSD-3-Clause 2503ac807SChaoyong He * Copyright (c) 2023 Corigine, Inc. 3503ac807SChaoyong He * All rights reserved. 4503ac807SChaoyong He */ 5503ac807SChaoyong He 6503ac807SChaoyong He #include "nfp_common.h" 7503ac807SChaoyong He 8503ac807SChaoyong He #include "nfp_common_log.h" 9503ac807SChaoyong He 10503ac807SChaoyong He /* 11503ac807SChaoyong He * This is used by the reconfig protocol. It sets the maximum time waiting in 12503ac807SChaoyong He * milliseconds before a reconfig timeout happens. 13503ac807SChaoyong He */ 14503ac807SChaoyong He #define NFP_NET_POLL_TIMEOUT 5000 15503ac807SChaoyong He 16503ac807SChaoyong He int 17503ac807SChaoyong He nfp_reconfig_real(struct nfp_hw *hw, 18503ac807SChaoyong He uint32_t update) 19503ac807SChaoyong He { 20503ac807SChaoyong He uint32_t cnt; 21503ac807SChaoyong He uint32_t new; 22503ac807SChaoyong He struct timespec wait; 23503ac807SChaoyong He 24503ac807SChaoyong He PMD_DRV_LOG(DEBUG, "Writing to the configuration queue (%p)...", 25503ac807SChaoyong He hw->qcp_cfg); 26503ac807SChaoyong He 27503ac807SChaoyong He if (hw->qcp_cfg == NULL) { 28*b6de4353SZerun Fu PMD_DRV_LOG(ERR, "Bad configuration queue pointer."); 29503ac807SChaoyong He return -ENXIO; 30503ac807SChaoyong He } 31503ac807SChaoyong He 32503ac807SChaoyong He nfp_qcp_ptr_add(hw->qcp_cfg, NFP_QCP_WRITE_PTR, 1); 33503ac807SChaoyong He 34503ac807SChaoyong He wait.tv_sec = 0; 35503ac807SChaoyong He wait.tv_nsec = 1000000; /* 1ms */ 36503ac807SChaoyong He 37503ac807SChaoyong He PMD_DRV_LOG(DEBUG, "Polling for update ack..."); 38503ac807SChaoyong He 39503ac807SChaoyong He /* Poll update field, waiting for NFP to ack the config */ 40503ac807SChaoyong He for (cnt = 0; ; cnt++) { 41503ac807SChaoyong He new = nn_cfg_readl(hw, NFP_NET_CFG_UPDATE); 42503ac807SChaoyong He if (new == 0) 43503ac807SChaoyong He break; 44503ac807SChaoyong He 45503ac807SChaoyong He if ((new & NFP_NET_CFG_UPDATE_ERR) != 0) { 46*b6de4353SZerun Fu PMD_DRV_LOG(ERR, "Reconfig error: %#08x.", new); 47503ac807SChaoyong He return -1; 48503ac807SChaoyong He } 49503ac807SChaoyong He 50503ac807SChaoyong He if (cnt >= NFP_NET_POLL_TIMEOUT) { 51*b6de4353SZerun Fu PMD_DRV_LOG(ERR, "Reconfig timeout for %#08x after %u ms.", 52503ac807SChaoyong He update, cnt); 53503ac807SChaoyong He return -EIO; 54503ac807SChaoyong He } 55503ac807SChaoyong He 56503ac807SChaoyong He nanosleep(&wait, 0); /* waiting for a 1ms */ 57503ac807SChaoyong He } 58503ac807SChaoyong He 59*b6de4353SZerun Fu PMD_DRV_LOG(DEBUG, "Ack DONE."); 60503ac807SChaoyong He return 0; 61503ac807SChaoyong He } 62503ac807SChaoyong He 63503ac807SChaoyong He /** 64503ac807SChaoyong He * Reconfigure the NIC. 65503ac807SChaoyong He * 66503ac807SChaoyong He * Write the update word to the BAR and ping the reconfig queue. Then poll 67503ac807SChaoyong He * until the firmware has acknowledged the update by zeroing the update word. 68503ac807SChaoyong He * 69503ac807SChaoyong He * @param hw 70503ac807SChaoyong He * Device to reconfigure. 71503ac807SChaoyong He * @param ctrl 72503ac807SChaoyong He * The value for the ctrl field in the BAR config. 73503ac807SChaoyong He * @param update 74503ac807SChaoyong He * The value for the update field in the BAR config. 75503ac807SChaoyong He * 76503ac807SChaoyong He * @return 77503ac807SChaoyong He * - (0) if OK to reconfigure the device. 78503ac807SChaoyong He * - (-EIO) if I/O err and fail to reconfigure the device. 79503ac807SChaoyong He */ 80503ac807SChaoyong He int 81503ac807SChaoyong He nfp_reconfig(struct nfp_hw *hw, 82503ac807SChaoyong He uint32_t ctrl, 83503ac807SChaoyong He uint32_t update) 84503ac807SChaoyong He { 85503ac807SChaoyong He int ret; 86503ac807SChaoyong He 87503ac807SChaoyong He rte_spinlock_lock(&hw->reconfig_lock); 88503ac807SChaoyong He 89503ac807SChaoyong He nn_cfg_writel(hw, NFP_NET_CFG_CTRL, ctrl); 90503ac807SChaoyong He nn_cfg_writel(hw, NFP_NET_CFG_UPDATE, update); 91503ac807SChaoyong He 92503ac807SChaoyong He rte_wmb(); 93503ac807SChaoyong He 94503ac807SChaoyong He ret = nfp_reconfig_real(hw, update); 95503ac807SChaoyong He 96503ac807SChaoyong He rte_spinlock_unlock(&hw->reconfig_lock); 97503ac807SChaoyong He 98503ac807SChaoyong He if (ret != 0) { 99*b6de4353SZerun Fu PMD_DRV_LOG(ERR, "Error NFP reconfig: ctrl=%#08x update=%#08x.", 100503ac807SChaoyong He ctrl, update); 101503ac807SChaoyong He return -EIO; 102503ac807SChaoyong He } 103503ac807SChaoyong He 104503ac807SChaoyong He return 0; 105503ac807SChaoyong He } 106503ac807SChaoyong He 107503ac807SChaoyong He /** 108503ac807SChaoyong He * Reconfigure the NIC for the extend ctrl BAR. 109503ac807SChaoyong He * 110503ac807SChaoyong He * Write the update word to the BAR and ping the reconfig queue. Then poll 111503ac807SChaoyong He * until the firmware has acknowledged the update by zeroing the update word. 112503ac807SChaoyong He * 113503ac807SChaoyong He * @param hw 114503ac807SChaoyong He * Device to reconfigure. 115503ac807SChaoyong He * @param ctrl_ext 116503ac807SChaoyong He * The value for the first word of extend ctrl field in the BAR config. 117503ac807SChaoyong He * @param update 118503ac807SChaoyong He * The value for the update field in the BAR config. 119503ac807SChaoyong He * 120503ac807SChaoyong He * @return 121503ac807SChaoyong He * - (0) if OK to reconfigure the device. 122503ac807SChaoyong He * - (-EIO) if I/O err and fail to reconfigure the device. 123503ac807SChaoyong He */ 124503ac807SChaoyong He int 125503ac807SChaoyong He nfp_ext_reconfig(struct nfp_hw *hw, 126503ac807SChaoyong He uint32_t ctrl_ext, 127503ac807SChaoyong He uint32_t update) 128503ac807SChaoyong He { 129503ac807SChaoyong He int ret; 130503ac807SChaoyong He 131503ac807SChaoyong He rte_spinlock_lock(&hw->reconfig_lock); 132503ac807SChaoyong He 133503ac807SChaoyong He nn_cfg_writel(hw, NFP_NET_CFG_CTRL_WORD1, ctrl_ext); 134503ac807SChaoyong He nn_cfg_writel(hw, NFP_NET_CFG_UPDATE, update); 135503ac807SChaoyong He 136503ac807SChaoyong He rte_wmb(); 137503ac807SChaoyong He 138503ac807SChaoyong He ret = nfp_reconfig_real(hw, update); 139503ac807SChaoyong He 140503ac807SChaoyong He rte_spinlock_unlock(&hw->reconfig_lock); 141503ac807SChaoyong He 142503ac807SChaoyong He if (ret != 0) { 143*b6de4353SZerun Fu PMD_DRV_LOG(ERR, "Error NFP ext reconfig: ctrl_ext=%#08x update=%#08x.", 144503ac807SChaoyong He ctrl_ext, update); 145503ac807SChaoyong He return -EIO; 146503ac807SChaoyong He } 147503ac807SChaoyong He 148503ac807SChaoyong He return 0; 149503ac807SChaoyong He } 150503ac807SChaoyong He 151503ac807SChaoyong He void 152503ac807SChaoyong He nfp_read_mac(struct nfp_hw *hw) 153503ac807SChaoyong He { 154503ac807SChaoyong He uint32_t tmp; 155503ac807SChaoyong He 156503ac807SChaoyong He tmp = rte_be_to_cpu_32(nn_cfg_readl(hw, NFP_NET_CFG_MACADDR)); 157503ac807SChaoyong He memcpy(&hw->mac_addr.addr_bytes[0], &tmp, 4); 158503ac807SChaoyong He 159503ac807SChaoyong He tmp = rte_be_to_cpu_32(nn_cfg_readl(hw, NFP_NET_CFG_MACADDR + 4)); 160503ac807SChaoyong He memcpy(&hw->mac_addr.addr_bytes[4], &tmp, 2); 161503ac807SChaoyong He } 162503ac807SChaoyong He 163503ac807SChaoyong He void 164503ac807SChaoyong He nfp_write_mac(struct nfp_hw *hw, 165503ac807SChaoyong He uint8_t *mac) 166503ac807SChaoyong He { 167503ac807SChaoyong He uint32_t mac0; 168503ac807SChaoyong He uint16_t mac1; 169503ac807SChaoyong He 170503ac807SChaoyong He mac0 = *(uint32_t *)mac; 171503ac807SChaoyong He nn_writel(rte_cpu_to_be_32(mac0), hw->ctrl_bar + NFP_NET_CFG_MACADDR); 172503ac807SChaoyong He 173503ac807SChaoyong He mac += 4; 174503ac807SChaoyong He mac1 = *(uint16_t *)mac; 175503ac807SChaoyong He nn_writew(rte_cpu_to_be_16(mac1), 176503ac807SChaoyong He hw->ctrl_bar + NFP_NET_CFG_MACADDR + 6); 177503ac807SChaoyong He } 17887f5b35bSChaoyong He 17987f5b35bSChaoyong He void 18087f5b35bSChaoyong He nfp_enable_queues(struct nfp_hw *hw, 18187f5b35bSChaoyong He uint16_t nb_rx_queues, 18287f5b35bSChaoyong He uint16_t nb_tx_queues) 18387f5b35bSChaoyong He { 18487f5b35bSChaoyong He int i; 18587f5b35bSChaoyong He uint64_t enabled_queues; 18687f5b35bSChaoyong He 18787f5b35bSChaoyong He /* Enabling the required TX queues in the device */ 18887f5b35bSChaoyong He enabled_queues = 0; 18987f5b35bSChaoyong He for (i = 0; i < nb_tx_queues; i++) 1901b17d99fSChaoyong He enabled_queues |= (1ULL << i); 19187f5b35bSChaoyong He 19287f5b35bSChaoyong He nn_cfg_writeq(hw, NFP_NET_CFG_TXRS_ENABLE, enabled_queues); 19387f5b35bSChaoyong He 19487f5b35bSChaoyong He /* Enabling the required RX queues in the device */ 19587f5b35bSChaoyong He enabled_queues = 0; 19687f5b35bSChaoyong He for (i = 0; i < nb_rx_queues; i++) 1971b17d99fSChaoyong He enabled_queues |= (1ULL << i); 19887f5b35bSChaoyong He 19987f5b35bSChaoyong He nn_cfg_writeq(hw, NFP_NET_CFG_RXRS_ENABLE, enabled_queues); 20087f5b35bSChaoyong He } 20187f5b35bSChaoyong He 20287f5b35bSChaoyong He void 20387f5b35bSChaoyong He nfp_disable_queues(struct nfp_hw *hw) 20487f5b35bSChaoyong He { 20587f5b35bSChaoyong He int ret; 20687f5b35bSChaoyong He uint32_t update; 20787f5b35bSChaoyong He uint32_t new_ctrl; 20887f5b35bSChaoyong He 20987f5b35bSChaoyong He nn_cfg_writeq(hw, NFP_NET_CFG_TXRS_ENABLE, 0); 21087f5b35bSChaoyong He nn_cfg_writeq(hw, NFP_NET_CFG_RXRS_ENABLE, 0); 21187f5b35bSChaoyong He 21287f5b35bSChaoyong He new_ctrl = hw->ctrl & ~NFP_NET_CFG_CTRL_ENABLE; 21387f5b35bSChaoyong He update = NFP_NET_CFG_UPDATE_GEN | 21487f5b35bSChaoyong He NFP_NET_CFG_UPDATE_RING | 21587f5b35bSChaoyong He NFP_NET_CFG_UPDATE_MSIX; 21687f5b35bSChaoyong He 21787f5b35bSChaoyong He if ((hw->cap & NFP_NET_CFG_CTRL_RINGCFG) != 0) 21887f5b35bSChaoyong He new_ctrl &= ~NFP_NET_CFG_CTRL_RINGCFG; 21987f5b35bSChaoyong He 22087f5b35bSChaoyong He /* If an error when reconfig we avoid to change hw state */ 22187f5b35bSChaoyong He ret = nfp_reconfig(hw, new_ctrl, update); 22287f5b35bSChaoyong He if (ret < 0) 22387f5b35bSChaoyong He return; 22487f5b35bSChaoyong He 22587f5b35bSChaoyong He hw->ctrl = new_ctrl; 22687f5b35bSChaoyong He } 227