xref: /dpdk/drivers/vdpa/nfp/nfp_vdpa_core.c (revision b6de43530dfa30cbf6b70857e3835099701063d4)
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