1d89f4990SChaoyong He /* SPDX-License-Identifier: BSD-3-Clause 2d89f4990SChaoyong He * Copyright (c) 2023 Corigine, Inc. 3d89f4990SChaoyong He * All rights reserved. 4d89f4990SChaoyong He */ 5d89f4990SChaoyong He 6d89f4990SChaoyong He #include "nfp_vdpa_core.h" 7d89f4990SChaoyong He 8b47a0373SChaoyong He #include <nfp_common.h> 9d89f4990SChaoyong He #include <rte_vhost.h> 10d89f4990SChaoyong He 11d89f4990SChaoyong He #include "nfp_vdpa_log.h" 12d89f4990SChaoyong He 13d89f4990SChaoyong He /* Available and used descs are in same order */ 14d89f4990SChaoyong He #ifndef VIRTIO_F_IN_ORDER 15d89f4990SChaoyong He #define VIRTIO_F_IN_ORDER 35 16d89f4990SChaoyong He #endif 17d89f4990SChaoyong He 1876ea5ebeSChaoyong He #define NFP_QCP_NOTIFY_MAX_ADD 0x7f 1976ea5ebeSChaoyong He 2076ea5ebeSChaoyong He enum nfp_qcp_notify_ptr { 2176ea5ebeSChaoyong He NFP_QCP_NOTIFY_WRITE_PTR = 0, 2276ea5ebeSChaoyong He NFP_QCP_NOTIFY_READ_PTR 2376ea5ebeSChaoyong He }; 2476ea5ebeSChaoyong He 2576ea5ebeSChaoyong He /** 2676ea5ebeSChaoyong He * Add the value to the selected pointer of a queue 2776ea5ebeSChaoyong He * 2876ea5ebeSChaoyong He * @param queue 2976ea5ebeSChaoyong He * Base address for queue structure 3076ea5ebeSChaoyong He * @param ptr 3176ea5ebeSChaoyong He * Add to the Read or Write pointer 3276ea5ebeSChaoyong He * @param val 3376ea5ebeSChaoyong He * Value to add to the queue pointer 3476ea5ebeSChaoyong He */ 3576ea5ebeSChaoyong He static inline void 3676ea5ebeSChaoyong He nfp_qcp_notify_ptr_add(uint8_t *q, 3776ea5ebeSChaoyong He enum nfp_qcp_notify_ptr ptr, 3876ea5ebeSChaoyong He uint32_t val) 3976ea5ebeSChaoyong He { 4076ea5ebeSChaoyong He uint32_t off; 4176ea5ebeSChaoyong He 4276ea5ebeSChaoyong He if (ptr == NFP_QCP_NOTIFY_WRITE_PTR) 4376ea5ebeSChaoyong He off = NFP_QCP_QUEUE_ADD_RPTR; 4476ea5ebeSChaoyong He else 4576ea5ebeSChaoyong He off = NFP_QCP_QUEUE_ADD_WPTR; 4676ea5ebeSChaoyong He 4776ea5ebeSChaoyong He for (; val > NFP_QCP_NOTIFY_MAX_ADD; val -= NFP_QCP_NOTIFY_MAX_ADD) 4876ea5ebeSChaoyong He nn_writel(rte_cpu_to_le_32(NFP_QCP_NOTIFY_MAX_ADD), q + off); 4976ea5ebeSChaoyong He 5076ea5ebeSChaoyong He nn_writel(rte_cpu_to_le_32(val), q + off); 5176ea5ebeSChaoyong He } 5276ea5ebeSChaoyong He 53d89f4990SChaoyong He int 54d89f4990SChaoyong He nfp_vdpa_hw_init(struct nfp_vdpa_hw *vdpa_hw, 55d89f4990SChaoyong He struct rte_pci_device *pci_dev) 56d89f4990SChaoyong He { 57d89f4990SChaoyong He uint32_t queue; 58fc470d5eSXinying Yu uint8_t *tx_bar; 59fc470d5eSXinying Yu uint32_t start_q; 60d89f4990SChaoyong He struct nfp_hw *hw; 61fc470d5eSXinying Yu uint32_t tx_bar_off; 62d89f4990SChaoyong He uint8_t *notify_base; 63d89f4990SChaoyong He 64d89f4990SChaoyong He hw = &vdpa_hw->super; 65d89f4990SChaoyong He hw->ctrl_bar = pci_dev->mem_resource[0].addr; 66d89f4990SChaoyong He if (hw->ctrl_bar == NULL) { 67f6272c7aSZerun Fu DRV_CORE_LOG(ERR, "The hw->ctrl_bar is NULL. BAR0 not configured."); 68d89f4990SChaoyong He return -ENODEV; 69d89f4990SChaoyong He } 70d89f4990SChaoyong He 71d89f4990SChaoyong He notify_base = hw->ctrl_bar + NFP_VDPA_NOTIFY_ADDR_BASE; 72d89f4990SChaoyong He for (queue = 0; queue < NFP_VDPA_MAX_QUEUES; queue++) { 73d89f4990SChaoyong He uint32_t idx = queue * 2; 74d89f4990SChaoyong He 75d89f4990SChaoyong He /* RX */ 76d89f4990SChaoyong He vdpa_hw->notify_addr[idx] = notify_base; 77d89f4990SChaoyong He notify_base += NFP_VDPA_NOTIFY_ADDR_INTERVAL; 78d89f4990SChaoyong He /* TX */ 79d89f4990SChaoyong He vdpa_hw->notify_addr[idx + 1] = notify_base; 80d89f4990SChaoyong He notify_base += NFP_VDPA_NOTIFY_ADDR_INTERVAL; 81d89f4990SChaoyong He 82d89f4990SChaoyong He vdpa_hw->notify_region = queue; 83*b6de4353SZerun Fu DRV_CORE_LOG(DEBUG, "The notify_addr[%d] at %p, notify_addr[%d] at %p.", 84d89f4990SChaoyong He idx, vdpa_hw->notify_addr[idx], 85d89f4990SChaoyong He idx + 1, vdpa_hw->notify_addr[idx + 1]); 86d89f4990SChaoyong He } 87d89f4990SChaoyong He 88fc470d5eSXinying Yu /* NFP vDPA cfg queue setup */ 89fc470d5eSXinying Yu start_q = nn_cfg_readl(hw, NFP_NET_CFG_START_TXQ); 90fc470d5eSXinying Yu tx_bar_off = start_q * NFP_QCP_QUEUE_ADDR_SZ; 91fc470d5eSXinying Yu tx_bar = (uint8_t *)pci_dev->mem_resource[2].addr + tx_bar_off; 92fc470d5eSXinying Yu hw->qcp_cfg = tx_bar + NFP_QCP_QUEUE_ADDR_SZ; 93fc470d5eSXinying Yu 9494fde3a7SXinying Yu vdpa_hw->sw_lm = true; 9594fde3a7SXinying Yu 96d89f4990SChaoyong He vdpa_hw->features = (1ULL << VIRTIO_F_VERSION_1) | 97d89f4990SChaoyong He (1ULL << VIRTIO_F_IN_ORDER) | 98adec2a5cSXinying Yu (1ULL << VHOST_F_LOG_ALL) | 99d89f4990SChaoyong He (1ULL << VHOST_USER_F_PROTOCOL_FEATURES); 100d89f4990SChaoyong He 101d89f4990SChaoyong He return 0; 102d89f4990SChaoyong He } 103b47a0373SChaoyong He 1049725f326SXinying Yu static void 1059725f326SXinying Yu nfp_vdpa_hw_queue_init(struct nfp_vdpa_hw *vdpa_hw) 1069725f326SXinying Yu { 1079725f326SXinying Yu /* Distribute ring information to firmware */ 1089725f326SXinying Yu nn_cfg_writel(&vdpa_hw->super, NFP_NET_CFG_TX_USED_INDEX, 1099725f326SXinying Yu vdpa_hw->vring[1].last_used_idx); 1109725f326SXinying Yu nn_cfg_writel(&vdpa_hw->super, NFP_NET_CFG_RX_USED_INDEX, 1119725f326SXinying Yu vdpa_hw->vring[0].last_used_idx); 1129725f326SXinying Yu } 1139725f326SXinying Yu 114b47a0373SChaoyong He static uint32_t 115b47a0373SChaoyong He nfp_vdpa_check_offloads(void) 116b47a0373SChaoyong He { 117d1498272SXinying Yu return NFP_NET_CFG_CTRL_VIRTIO | 118b47a0373SChaoyong He NFP_NET_CFG_CTRL_IN_ORDER; 119b47a0373SChaoyong He } 120b47a0373SChaoyong He 1217bd25583SXinying Yu static int 1227bd25583SXinying Yu nfp_vdpa_vf_config(struct nfp_hw *hw, 123e6ac31e0SXinying Yu int vid, 124e6ac31e0SXinying Yu bool relay) 125b47a0373SChaoyong He { 126b47a0373SChaoyong He int ret; 127b47a0373SChaoyong He uint32_t update; 128b47a0373SChaoyong He uint32_t new_ctrl; 129d1498272SXinying Yu uint32_t new_ext_ctrl; 130b47a0373SChaoyong He struct timespec wait_tst; 131b47a0373SChaoyong He uint8_t mac_addr[RTE_ETHER_ADDR_LEN]; 132b47a0373SChaoyong He 133b47a0373SChaoyong He nn_cfg_writel(hw, NFP_NET_CFG_MTU, 9216); 134b47a0373SChaoyong He nn_cfg_writel(hw, NFP_NET_CFG_FLBUFSZ, 10240); 135b47a0373SChaoyong He 136b47a0373SChaoyong He /* TODO: Temporary set MAC to fixed value fe:1b:ac:05:a5:22 */ 137b47a0373SChaoyong He mac_addr[0] = 0xfe; 138b47a0373SChaoyong He mac_addr[1] = 0x1b; 139b47a0373SChaoyong He mac_addr[2] = 0xac; 140b47a0373SChaoyong He mac_addr[3] = 0x05; 141b47a0373SChaoyong He mac_addr[4] = 0xa5; 142b47a0373SChaoyong He mac_addr[5] = (0x22 + vid); 143b47a0373SChaoyong He 144b47a0373SChaoyong He /* Writing new MAC to the specific port BAR address */ 145b47a0373SChaoyong He nfp_write_mac(hw, (uint8_t *)mac_addr); 146b47a0373SChaoyong He 147d1498272SXinying Yu new_ext_ctrl = nfp_vdpa_check_offloads(); 148e6ac31e0SXinying Yu if (relay) 149e6ac31e0SXinying Yu new_ext_ctrl |= NFP_NET_CFG_CTRL_LM_RELAY; 150e6ac31e0SXinying Yu else 151e6ac31e0SXinying Yu new_ext_ctrl |= NFP_NET_CFG_CTRL_SWLM; 152d1498272SXinying Yu 153d1498272SXinying Yu update = NFP_NET_CFG_UPDATE_GEN; 154d1498272SXinying Yu ret = nfp_ext_reconfig(hw, new_ext_ctrl, update); 155d1498272SXinying Yu if (ret != 0) 156d1498272SXinying Yu return -EIO; 157d1498272SXinying Yu 158d1498272SXinying Yu hw->ctrl_ext = new_ext_ctrl; 159d1498272SXinying Yu 160b47a0373SChaoyong He /* Enable device */ 161d1498272SXinying Yu new_ctrl = NFP_NET_CFG_CTRL_ENABLE; 162b47a0373SChaoyong He 163b47a0373SChaoyong He /* Signal the NIC about the change */ 164b47a0373SChaoyong He update = NFP_NET_CFG_UPDATE_MACADDR | 165b47a0373SChaoyong He NFP_NET_CFG_UPDATE_GEN | 166b47a0373SChaoyong He NFP_NET_CFG_UPDATE_RING; 167b47a0373SChaoyong He 168e6ac31e0SXinying Yu if (relay) { 169e6ac31e0SXinying Yu update |= NFP_NET_CFG_UPDATE_MSIX; 170e6ac31e0SXinying Yu 171e6ac31e0SXinying Yu /* Enable misx interrupt for vdpa relay */ 172e6ac31e0SXinying Yu new_ctrl |= NFP_NET_CFG_CTRL_MSIX_TX_OFF; 173e6ac31e0SXinying Yu 174e6ac31e0SXinying Yu nn_cfg_writeb(hw, NFP_NET_CFG_RXR_VEC(0), 1); 175e6ac31e0SXinying Yu } 176e6ac31e0SXinying Yu 177b47a0373SChaoyong He ret = nfp_reconfig(hw, new_ctrl, update); 178b47a0373SChaoyong He if (ret < 0) 179b47a0373SChaoyong He return -EIO; 180b47a0373SChaoyong He 181b47a0373SChaoyong He hw->ctrl = new_ctrl; 182b47a0373SChaoyong He 183b47a0373SChaoyong He DRV_CORE_LOG(DEBUG, "Enabling the device, sleep 1 seconds..."); 184b47a0373SChaoyong He wait_tst.tv_sec = 1; 185b47a0373SChaoyong He wait_tst.tv_nsec = 0; 186b47a0373SChaoyong He nanosleep(&wait_tst, 0); 187b47a0373SChaoyong He 188b47a0373SChaoyong He return 0; 189b47a0373SChaoyong He } 190b47a0373SChaoyong He 1917bd25583SXinying Yu static void 192e6ac31e0SXinying Yu nfp_vdpa_queue_config(struct nfp_vdpa_hw *vdpa_hw, 193e6ac31e0SXinying Yu bool relay) 1947bd25583SXinying Yu { 1957bd25583SXinying Yu struct nfp_hw *hw = &vdpa_hw->super; 1967bd25583SXinying Yu 197e6ac31e0SXinying Yu if (!relay) { 1987bd25583SXinying Yu nn_cfg_writeq(hw, NFP_NET_CFG_TXR_ADDR(0), vdpa_hw->vring[1].desc); 1997bd25583SXinying Yu nn_cfg_writeb(hw, NFP_NET_CFG_TXR_SZ(0), 2007bd25583SXinying Yu rte_log2_u32(vdpa_hw->vring[1].size)); 2017bd25583SXinying Yu nn_cfg_writeq(hw, NFP_NET_CFG_TXR_ADDR(1), vdpa_hw->vring[1].avail); 2027bd25583SXinying Yu nn_cfg_writeq(hw, NFP_NET_CFG_TXR_ADDR(2), vdpa_hw->vring[1].used); 2037bd25583SXinying Yu 2047bd25583SXinying Yu nn_cfg_writeq(hw, NFP_NET_CFG_RXR_ADDR(0), vdpa_hw->vring[0].desc); 2057bd25583SXinying Yu nn_cfg_writeb(hw, NFP_NET_CFG_RXR_SZ(0), 2067bd25583SXinying Yu rte_log2_u32(vdpa_hw->vring[0].size)); 2077bd25583SXinying Yu nn_cfg_writeq(hw, NFP_NET_CFG_RXR_ADDR(1), vdpa_hw->vring[0].avail); 208e6ac31e0SXinying Yu } 209e6ac31e0SXinying Yu 2107bd25583SXinying Yu nn_cfg_writeq(hw, NFP_NET_CFG_RXR_ADDR(2), vdpa_hw->vring[0].used); 2117bd25583SXinying Yu 2129725f326SXinying Yu if (!relay) 2139725f326SXinying Yu nfp_vdpa_hw_queue_init(vdpa_hw); 2149725f326SXinying Yu 2157bd25583SXinying Yu rte_wmb(); 2167bd25583SXinying Yu } 2177bd25583SXinying Yu 2187bd25583SXinying Yu int 2197bd25583SXinying Yu nfp_vdpa_hw_start(struct nfp_vdpa_hw *vdpa_hw, 2207bd25583SXinying Yu int vid) 2217bd25583SXinying Yu { 2227bd25583SXinying Yu struct nfp_hw *hw = &vdpa_hw->super; 2237bd25583SXinying Yu 224e6ac31e0SXinying Yu nfp_vdpa_queue_config(vdpa_hw, false); 2257bd25583SXinying Yu 2267bd25583SXinying Yu nfp_disable_queues(hw); 2277bd25583SXinying Yu nfp_enable_queues(hw, NFP_VDPA_MAX_QUEUES, NFP_VDPA_MAX_QUEUES); 2287bd25583SXinying Yu 229e6ac31e0SXinying Yu return nfp_vdpa_vf_config(hw, vid, false); 230e6ac31e0SXinying Yu } 231e6ac31e0SXinying Yu 232e6ac31e0SXinying Yu int 233e6ac31e0SXinying Yu nfp_vdpa_relay_hw_start(struct nfp_vdpa_hw *vdpa_hw, 234e6ac31e0SXinying Yu int vid) 235e6ac31e0SXinying Yu { 236e6ac31e0SXinying Yu struct nfp_hw *hw = &vdpa_hw->super; 237e6ac31e0SXinying Yu 238e6ac31e0SXinying Yu nfp_vdpa_queue_config(vdpa_hw, true); 239e6ac31e0SXinying Yu 240e6ac31e0SXinying Yu return nfp_vdpa_vf_config(hw, vid, true); 2417bd25583SXinying Yu } 2427bd25583SXinying Yu 243b47a0373SChaoyong He void 244b47a0373SChaoyong He nfp_vdpa_hw_stop(struct nfp_vdpa_hw *vdpa_hw) 245b47a0373SChaoyong He { 246b47a0373SChaoyong He nfp_disable_queues(&vdpa_hw->super); 247b47a0373SChaoyong He } 24876ea5ebeSChaoyong He 24976ea5ebeSChaoyong He /* 25076ea5ebeSChaoyong He * This offset is used for mmaping the notify area. It implies it needs 25176ea5ebeSChaoyong He * to be a multiple of PAGE_SIZE. 25276ea5ebeSChaoyong He * For debugging, using notify region 0 with an offset of 4K. This should 25376ea5ebeSChaoyong He * point to the conf bar. 25476ea5ebeSChaoyong He */ 25576ea5ebeSChaoyong He uint64_t 25676ea5ebeSChaoyong He nfp_vdpa_get_queue_notify_offset(struct nfp_vdpa_hw *vdpa_hw __rte_unused, 25776ea5ebeSChaoyong He int qid) 25876ea5ebeSChaoyong He { 259b7f656e3SChaoyong He return NFP_VDPA_NOTIFY_ADDR_BASE + ((uint64_t)qid * NFP_VDPA_NOTIFY_ADDR_INTERVAL); 26076ea5ebeSChaoyong He } 26176ea5ebeSChaoyong He 26276ea5ebeSChaoyong He /* 26376ea5ebeSChaoyong He * With just one queue the increment is 0, which does not 26476ea5ebeSChaoyong He * incremente the counter but will raise a queue event due 26576ea5ebeSChaoyong He * to queue configured for watermark events. 26676ea5ebeSChaoyong He */ 26776ea5ebeSChaoyong He void 26876ea5ebeSChaoyong He nfp_vdpa_notify_queue(struct nfp_vdpa_hw *vdpa_hw, 26976ea5ebeSChaoyong He uint16_t qid) 27076ea5ebeSChaoyong He { 27176ea5ebeSChaoyong He nfp_qcp_notify_ptr_add(vdpa_hw->notify_addr[qid], 27276ea5ebeSChaoyong He NFP_QCP_NOTIFY_WRITE_PTR, qid); 27376ea5ebeSChaoyong He } 27402fe8366SXinying Yu 27502fe8366SXinying Yu void nfp_vdpa_irq_unmask(struct nfp_vdpa_hw *vdpa_hw) 27602fe8366SXinying Yu { 27702fe8366SXinying Yu struct nfp_hw *hw = &vdpa_hw->super; 27802fe8366SXinying Yu 27902fe8366SXinying Yu /* Make sure all updates are written before un-masking */ 28002fe8366SXinying Yu rte_wmb(); 28102fe8366SXinying Yu nn_cfg_writeb(hw, NFP_NET_CFG_ICR(1), NFP_NET_CFG_ICR_UNMASKED); 28202fe8366SXinying Yu } 283