xref: /dpdk/drivers/net/octeontx/base/octeontx_pkovf.c (revision aaf4363e1e9e518c034c7ff9938a2faefde9854d)
1*aaf4363eSJerin Jacob /* SPDX-License-Identifier: BSD-3-Clause
2*aaf4363eSJerin Jacob  * Copyright(c) 2017 Cavium, Inc
3445371e8SJerin Jacob  */
4*aaf4363eSJerin Jacob 
5445371e8SJerin Jacob #include <stdbool.h>
6445371e8SJerin Jacob #include <string.h>
7445371e8SJerin Jacob #include <stdio.h>
8445371e8SJerin Jacob 
9445371e8SJerin Jacob #include <rte_eal.h>
10445371e8SJerin Jacob #include <rte_cycles.h>
11445371e8SJerin Jacob #include <rte_malloc.h>
12445371e8SJerin Jacob #include <rte_memory.h>
13c752998bSGaetan Rivet #include <rte_bus_pci.h>
14445371e8SJerin Jacob #include <rte_spinlock.h>
15445371e8SJerin Jacob 
16445371e8SJerin Jacob #include "../octeontx_logs.h"
17445371e8SJerin Jacob #include "octeontx_io.h"
18445371e8SJerin Jacob #include "octeontx_pkovf.h"
19445371e8SJerin Jacob 
20445371e8SJerin Jacob struct octeontx_pko_iomem {
21445371e8SJerin Jacob 	uint8_t		*va;
22df6e0a06SSantosh Shukla 	rte_iova_t	iova;
23445371e8SJerin Jacob 	size_t		size;
24445371e8SJerin Jacob };
25445371e8SJerin Jacob 
26445371e8SJerin Jacob #define PKO_IOMEM_NULL (struct octeontx_pko_iomem){0, 0, 0}
27445371e8SJerin Jacob 
28445371e8SJerin Jacob struct octeontx_pko_fc_ctl_s {
29445371e8SJerin Jacob 	int64_t buf_cnt;
30445371e8SJerin Jacob 	int64_t padding[(PKO_DQ_FC_STRIDE / 8) - 1];
31445371e8SJerin Jacob };
32445371e8SJerin Jacob 
33445371e8SJerin Jacob struct octeontx_pkovf {
34445371e8SJerin Jacob 	uint8_t		*bar0;
35445371e8SJerin Jacob 	uint8_t		*bar2;
36445371e8SJerin Jacob 	uint16_t	domain;
37445371e8SJerin Jacob 	uint16_t	vfid;
38445371e8SJerin Jacob };
39445371e8SJerin Jacob 
40445371e8SJerin Jacob struct octeontx_pko_vf_ctl_s {
41445371e8SJerin Jacob 	rte_spinlock_t lock;
42445371e8SJerin Jacob 
43445371e8SJerin Jacob 	struct octeontx_pko_iomem fc_iomem;
44445371e8SJerin Jacob 	struct octeontx_pko_fc_ctl_s *fc_ctl;
45445371e8SJerin Jacob 	struct octeontx_pkovf pko[PKO_VF_MAX];
46445371e8SJerin Jacob 	struct {
47445371e8SJerin Jacob 		uint64_t chanid;
48445371e8SJerin Jacob 	} dq_map[PKO_VF_MAX * PKO_VF_NUM_DQ];
49445371e8SJerin Jacob };
50445371e8SJerin Jacob 
51445371e8SJerin Jacob static struct octeontx_pko_vf_ctl_s pko_vf_ctl;
52445371e8SJerin Jacob 
53cad78ca2SJerin Jacob static void *
54cad78ca2SJerin Jacob octeontx_pko_dq_vf_bar0(uint16_t txq)
55cad78ca2SJerin Jacob {
56cad78ca2SJerin Jacob 	int vf_ix;
57cad78ca2SJerin Jacob 
58cad78ca2SJerin Jacob 	vf_ix = txq / PKO_VF_NUM_DQ;
59cad78ca2SJerin Jacob 	return pko_vf_ctl.pko[vf_ix].bar0;
60cad78ca2SJerin Jacob }
61cad78ca2SJerin Jacob 
62cad78ca2SJerin Jacob static int
63cad78ca2SJerin Jacob octeontx_pko_dq_gdq(uint16_t txq)
64cad78ca2SJerin Jacob {
65cad78ca2SJerin Jacob 	return txq % PKO_VF_NUM_DQ;
66cad78ca2SJerin Jacob }
67cad78ca2SJerin Jacob 
68cad78ca2SJerin Jacob /**
69cad78ca2SJerin Jacob  * Open a PKO DQ.
70cad78ca2SJerin Jacob  */
71cad78ca2SJerin Jacob static inline
72cad78ca2SJerin Jacob int octeontx_pko_dq_open(uint16_t txq)
73cad78ca2SJerin Jacob {
74cad78ca2SJerin Jacob 	unsigned int reg_off;
75cad78ca2SJerin Jacob 	uint8_t *vf_bar0;
76cad78ca2SJerin Jacob 	uint64_t rtn;
77cad78ca2SJerin Jacob 	int gdq;
78cad78ca2SJerin Jacob 
79cad78ca2SJerin Jacob 	vf_bar0 = octeontx_pko_dq_vf_bar0(txq);
80cad78ca2SJerin Jacob 	gdq = octeontx_pko_dq_gdq(txq);
81cad78ca2SJerin Jacob 
82cad78ca2SJerin Jacob 	if (unlikely(gdq < 0 || vf_bar0 == NULL))
83cad78ca2SJerin Jacob 		return -EINVAL;
84cad78ca2SJerin Jacob 	*(volatile int64_t*)(pko_vf_ctl.fc_ctl + txq) =
85cad78ca2SJerin Jacob 		PKO_DQ_FC_DEPTH_PAGES - PKO_DQ_FC_SKID;
86cad78ca2SJerin Jacob 
87cad78ca2SJerin Jacob 	rte_wmb();
88cad78ca2SJerin Jacob 
89cad78ca2SJerin Jacob 	octeontx_write64(PKO_DQ_FC_DEPTH_PAGES,
90cad78ca2SJerin Jacob 			 vf_bar0 + PKO_VF_DQ_FC_STATUS(gdq));
91cad78ca2SJerin Jacob 
92cad78ca2SJerin Jacob 	/* Set the register to return descriptor (packet) count as DEPTH */
93cad78ca2SJerin Jacob 	/* KIND=1, NCB_QUERY_RSP=0 */
94cad78ca2SJerin Jacob 	octeontx_write64(1ull << PKO_DQ_KIND_BIT,
95cad78ca2SJerin Jacob 				vf_bar0 + PKO_VF_DQ_WM_CTL(gdq));
96cad78ca2SJerin Jacob 	reg_off = PKO_VF_DQ_OP_OPEN(gdq);
97cad78ca2SJerin Jacob 
98cad78ca2SJerin Jacob 	rtn = octeontx_reg_ldadd_u64(vf_bar0 + reg_off, 0);
99cad78ca2SJerin Jacob 
100cad78ca2SJerin Jacob 	/* PKO_DQOP_E::OPEN */
101cad78ca2SJerin Jacob 	if (((rtn >> PKO_DQ_OP_BIT) & 0x3) != 0x1)
102cad78ca2SJerin Jacob 		return -EIO;
103cad78ca2SJerin Jacob 
104cad78ca2SJerin Jacob 	switch (rtn >> PKO_DQ_STATUS_BIT) {
105cad78ca2SJerin Jacob 	case 0xC:	/* DQALREADYCREATED */
106cad78ca2SJerin Jacob 	case 0x0:	/* PASS */
107cad78ca2SJerin Jacob 		break;
108cad78ca2SJerin Jacob 	default:
109cad78ca2SJerin Jacob 		return -EIO;
110cad78ca2SJerin Jacob 	}
111cad78ca2SJerin Jacob 
112cad78ca2SJerin Jacob 	/* DRAIN=0, DRAIN_NULL_LINK=0, SW_XOFF=0 */
113cad78ca2SJerin Jacob 	octeontx_write64(0, vf_bar0 + PKO_VF_DQ_SW_XOFF(gdq));
114cad78ca2SJerin Jacob 
115cad78ca2SJerin Jacob 	return rtn & ((1ull << PKO_DQ_OP_BIT) - 1);
116cad78ca2SJerin Jacob }
117cad78ca2SJerin Jacob 
118cad78ca2SJerin Jacob /**
119cad78ca2SJerin Jacob  * Close a PKO DQ
120cad78ca2SJerin Jacob  * Flush all packets pending.
121cad78ca2SJerin Jacob  */
122cad78ca2SJerin Jacob static inline
123cad78ca2SJerin Jacob int octeontx_pko_dq_close(uint16_t txq)
124cad78ca2SJerin Jacob {
125cad78ca2SJerin Jacob 	unsigned int reg_off;
126cad78ca2SJerin Jacob 	uint8_t *vf_bar0;
127cad78ca2SJerin Jacob 	uint64_t rtn;
128cad78ca2SJerin Jacob 	int res;
129cad78ca2SJerin Jacob 
130cad78ca2SJerin Jacob 	vf_bar0 = octeontx_pko_dq_vf_bar0(txq);
131cad78ca2SJerin Jacob 	res = octeontx_pko_dq_gdq(txq);
132cad78ca2SJerin Jacob 
133cad78ca2SJerin Jacob 	if (unlikely(res < 0 || vf_bar0 == NULL))
134cad78ca2SJerin Jacob 		return -EINVAL;
135cad78ca2SJerin Jacob 
136cad78ca2SJerin Jacob 	reg_off = PKO_VF_DQ_OP_CLOSE(res);
137cad78ca2SJerin Jacob 
138cad78ca2SJerin Jacob 	rtn = octeontx_reg_ldadd_u64(vf_bar0 + reg_off, 0);
139cad78ca2SJerin Jacob 
140cad78ca2SJerin Jacob 	/* PKO_DQOP_E::CLOSE */
141cad78ca2SJerin Jacob 	if (((rtn >> PKO_DQ_OP_BIT) & 0x3) != 0x2)
142cad78ca2SJerin Jacob 		return -EIO;
143cad78ca2SJerin Jacob 
144cad78ca2SJerin Jacob 	switch (rtn >> PKO_DQ_STATUS_BIT) {
145cad78ca2SJerin Jacob 	case 0xD:	/* DQNOTCREATED */
146cad78ca2SJerin Jacob 	case 0x0:	/* PASS */
147cad78ca2SJerin Jacob 		break;
148cad78ca2SJerin Jacob 	default:
149cad78ca2SJerin Jacob 		return -EIO;
150cad78ca2SJerin Jacob 	}
151cad78ca2SJerin Jacob 
152cad78ca2SJerin Jacob 	res = rtn & ((1ull << PKO_DQ_OP_BIT) - 1); /* DEPTH */
153cad78ca2SJerin Jacob 	return res;
154cad78ca2SJerin Jacob }
155cad78ca2SJerin Jacob 
156cad78ca2SJerin Jacob /* Flush all packets pending on a DQ */
157cad78ca2SJerin Jacob static inline
158cad78ca2SJerin Jacob int octeontx_pko_dq_drain(uint16_t txq)
159cad78ca2SJerin Jacob {
160cad78ca2SJerin Jacob 	unsigned int gdq;
161cad78ca2SJerin Jacob 	uint8_t *vf_bar0;
162cad78ca2SJerin Jacob 	uint64_t reg;
163cad78ca2SJerin Jacob 	int res, timo = PKO_DQ_DRAIN_TO;
164cad78ca2SJerin Jacob 
165cad78ca2SJerin Jacob 	vf_bar0 = octeontx_pko_dq_vf_bar0(txq);
166cad78ca2SJerin Jacob 	res = octeontx_pko_dq_gdq(txq);
167cad78ca2SJerin Jacob 	gdq = res;
168cad78ca2SJerin Jacob 
169cad78ca2SJerin Jacob 	 /* DRAIN=1, DRAIN_NULL_LINK=0, SW_XOFF=1 */
170cad78ca2SJerin Jacob 	 octeontx_write64(0x3, vf_bar0 + PKO_VF_DQ_SW_XOFF(gdq));
171cad78ca2SJerin Jacob 	/* Wait until buffers leave DQs */
172cad78ca2SJerin Jacob 	reg = octeontx_read64(vf_bar0 + PKO_VF_DQ_WM_CNT(gdq));
173cad78ca2SJerin Jacob 	while (reg && timo > 0) {
174cad78ca2SJerin Jacob 		rte_delay_us(100);
175cad78ca2SJerin Jacob 		timo--;
176cad78ca2SJerin Jacob 		reg = octeontx_read64(vf_bar0 + PKO_VF_DQ_WM_CNT(gdq));
177cad78ca2SJerin Jacob 	}
178cad78ca2SJerin Jacob 	/* DRAIN=0, DRAIN_NULL_LINK=0, SW_XOFF=0 */
179cad78ca2SJerin Jacob 	octeontx_write64(0, vf_bar0 + PKO_VF_DQ_SW_XOFF(gdq));
180cad78ca2SJerin Jacob 
181cad78ca2SJerin Jacob 	return reg;
182cad78ca2SJerin Jacob }
183cad78ca2SJerin Jacob 
184cad78ca2SJerin Jacob static inline int
185cad78ca2SJerin Jacob octeontx_pko_dq_range_lookup(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid,
186cad78ca2SJerin Jacob 			     unsigned int dq_num, unsigned int dq_from)
187cad78ca2SJerin Jacob {
188cad78ca2SJerin Jacob 	unsigned int dq, dq_cnt;
189cad78ca2SJerin Jacob 	unsigned int dq_base;
190cad78ca2SJerin Jacob 
191cad78ca2SJerin Jacob 	dq_cnt = 0;
192cad78ca2SJerin Jacob 	dq = dq_from;
193cad78ca2SJerin Jacob 	while (dq < RTE_DIM(ctl->dq_map)) {
194cad78ca2SJerin Jacob 		dq_base = dq;
195cad78ca2SJerin Jacob 		dq_cnt = 0;
196cad78ca2SJerin Jacob 		while (ctl->dq_map[dq].chanid == ~chanid &&
197cad78ca2SJerin Jacob 			dq < RTE_DIM(ctl->dq_map)) {
198cad78ca2SJerin Jacob 			dq_cnt++;
199cad78ca2SJerin Jacob 			if (dq_cnt == dq_num)
200cad78ca2SJerin Jacob 				return dq_base;
201cad78ca2SJerin Jacob 			dq++;
202cad78ca2SJerin Jacob 		}
203cad78ca2SJerin Jacob 		dq++;
204cad78ca2SJerin Jacob 	}
205cad78ca2SJerin Jacob 	return -1;
206cad78ca2SJerin Jacob }
207cad78ca2SJerin Jacob 
208cad78ca2SJerin Jacob static inline void
209cad78ca2SJerin Jacob octeontx_pko_dq_range_assign(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid,
210cad78ca2SJerin Jacob 			     unsigned int dq_base, unsigned int dq_num)
211cad78ca2SJerin Jacob {
212cad78ca2SJerin Jacob 	unsigned int dq, dq_cnt;
213cad78ca2SJerin Jacob 
214cad78ca2SJerin Jacob 	dq_cnt = 0;
215cad78ca2SJerin Jacob 	while (dq_cnt < dq_num) {
216cad78ca2SJerin Jacob 		dq = dq_base + dq_cnt;
217cad78ca2SJerin Jacob 
218cad78ca2SJerin Jacob 		octeontx_log_dbg("DQ# %u assigned to CHAN# %" PRIx64 "", dq,
219cad78ca2SJerin Jacob 			chanid);
220cad78ca2SJerin Jacob 
221cad78ca2SJerin Jacob 		ctl->dq_map[dq].chanid = ~chanid;
222cad78ca2SJerin Jacob 		dq_cnt++;
223cad78ca2SJerin Jacob 	}
224cad78ca2SJerin Jacob }
225cad78ca2SJerin Jacob 
226cad78ca2SJerin Jacob static inline int
227cad78ca2SJerin Jacob octeontx_pko_dq_claim(struct octeontx_pko_vf_ctl_s *ctl, unsigned int dq_base,
228cad78ca2SJerin Jacob 		      unsigned int dq_num, uint64_t chanid)
229cad78ca2SJerin Jacob {
230cad78ca2SJerin Jacob 	const uint64_t null_chanid = ~0ull;
231cad78ca2SJerin Jacob 	int dq;
232cad78ca2SJerin Jacob 
233cad78ca2SJerin Jacob 	rte_spinlock_lock(&ctl->lock);
234cad78ca2SJerin Jacob 
235cad78ca2SJerin Jacob 	dq = octeontx_pko_dq_range_lookup(ctl, null_chanid, dq_num, dq_base);
236cad78ca2SJerin Jacob 	if (dq < 0 || (unsigned int)dq != dq_base) {
237cad78ca2SJerin Jacob 		rte_spinlock_unlock(&ctl->lock);
238cad78ca2SJerin Jacob 		return -1;
239cad78ca2SJerin Jacob 	}
240cad78ca2SJerin Jacob 	octeontx_pko_dq_range_assign(ctl, chanid, dq_base, dq_num);
241cad78ca2SJerin Jacob 
242cad78ca2SJerin Jacob 	rte_spinlock_unlock(&ctl->lock);
243cad78ca2SJerin Jacob 
244cad78ca2SJerin Jacob 	return 0;
245cad78ca2SJerin Jacob }
246cad78ca2SJerin Jacob 
247cad78ca2SJerin Jacob static inline int
248cad78ca2SJerin Jacob octeontx_pko_dq_free(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid)
249cad78ca2SJerin Jacob {
250cad78ca2SJerin Jacob 	const uint64_t null_chanid = ~0ull;
251cad78ca2SJerin Jacob 	unsigned int dq = 0, dq_cnt = 0;
252cad78ca2SJerin Jacob 
253cad78ca2SJerin Jacob 	rte_spinlock_lock(&ctl->lock);
254cad78ca2SJerin Jacob 	while (dq < RTE_DIM(ctl->dq_map)) {
255cad78ca2SJerin Jacob 		if (ctl->dq_map[dq].chanid == ~chanid) {
256cad78ca2SJerin Jacob 			ctl->dq_map[dq].chanid = ~null_chanid;
257cad78ca2SJerin Jacob 			dq_cnt++;
258cad78ca2SJerin Jacob 		}
259cad78ca2SJerin Jacob 		dq++;
260cad78ca2SJerin Jacob 	}
261cad78ca2SJerin Jacob 	rte_spinlock_unlock(&ctl->lock);
262cad78ca2SJerin Jacob 
263cad78ca2SJerin Jacob 	return dq_cnt > 0 ? 0 : -EINVAL;
264cad78ca2SJerin Jacob }
265cad78ca2SJerin Jacob 
266cad78ca2SJerin Jacob int
267cad78ca2SJerin Jacob octeontx_pko_channel_open(int dq_base, int dq_num, int chanid)
268cad78ca2SJerin Jacob {
269cad78ca2SJerin Jacob 	struct octeontx_pko_vf_ctl_s *ctl = &pko_vf_ctl;
270cad78ca2SJerin Jacob 	int res;
271cad78ca2SJerin Jacob 
272cad78ca2SJerin Jacob 	res = octeontx_pko_dq_claim(ctl, dq_base, dq_num, chanid);
273cad78ca2SJerin Jacob 	if (res < 0)
274cad78ca2SJerin Jacob 		return -1;
275cad78ca2SJerin Jacob 
276cad78ca2SJerin Jacob 	return 0;
277cad78ca2SJerin Jacob }
278cad78ca2SJerin Jacob 
279cad78ca2SJerin Jacob int
280cad78ca2SJerin Jacob octeontx_pko_channel_close(int chanid)
281cad78ca2SJerin Jacob {
282cad78ca2SJerin Jacob 	struct octeontx_pko_vf_ctl_s *ctl = &pko_vf_ctl;
283cad78ca2SJerin Jacob 	int res;
284cad78ca2SJerin Jacob 
285cad78ca2SJerin Jacob 	res = octeontx_pko_dq_free(ctl, chanid);
286cad78ca2SJerin Jacob 	if (res < 0)
287cad78ca2SJerin Jacob 		return -1;
288cad78ca2SJerin Jacob 
289cad78ca2SJerin Jacob 	return 0;
290cad78ca2SJerin Jacob }
291cad78ca2SJerin Jacob 
292cad78ca2SJerin Jacob static inline int
293cad78ca2SJerin Jacob octeontx_pko_chan_start(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid)
294cad78ca2SJerin Jacob {
295cad78ca2SJerin Jacob 	unsigned int dq_vf;
296cad78ca2SJerin Jacob 	unsigned int dq, dq_cnt;
297cad78ca2SJerin Jacob 
298cad78ca2SJerin Jacob 	dq_cnt = 0;
299cad78ca2SJerin Jacob 	dq = 0;
300cad78ca2SJerin Jacob 	while (dq < RTE_DIM(ctl->dq_map)) {
301cad78ca2SJerin Jacob 		dq_vf = dq / PKO_VF_NUM_DQ;
302cad78ca2SJerin Jacob 
303cad78ca2SJerin Jacob 		if (!ctl->pko[dq_vf].bar0) {
304cad78ca2SJerin Jacob 			dq += PKO_VF_NUM_DQ;
305cad78ca2SJerin Jacob 			continue;
306cad78ca2SJerin Jacob 		}
307cad78ca2SJerin Jacob 
308cad78ca2SJerin Jacob 		if (ctl->dq_map[dq].chanid != ~chanid) {
309cad78ca2SJerin Jacob 			dq++;
310cad78ca2SJerin Jacob 			continue;
311cad78ca2SJerin Jacob 		}
312cad78ca2SJerin Jacob 
313cad78ca2SJerin Jacob 		if (octeontx_pko_dq_open(dq) < 0)
314cad78ca2SJerin Jacob 			break;
315cad78ca2SJerin Jacob 
316cad78ca2SJerin Jacob 		dq_cnt++;
317cad78ca2SJerin Jacob 		dq++;
318cad78ca2SJerin Jacob 	}
319cad78ca2SJerin Jacob 
320cad78ca2SJerin Jacob 	return dq_cnt;
321cad78ca2SJerin Jacob }
322cad78ca2SJerin Jacob 
323cad78ca2SJerin Jacob int
324cad78ca2SJerin Jacob octeontx_pko_channel_start(int chanid)
325cad78ca2SJerin Jacob {
326cad78ca2SJerin Jacob 	struct octeontx_pko_vf_ctl_s *ctl = &pko_vf_ctl;
327cad78ca2SJerin Jacob 	int dq_cnt;
328cad78ca2SJerin Jacob 
329cad78ca2SJerin Jacob 	dq_cnt = octeontx_pko_chan_start(ctl, chanid);
330cad78ca2SJerin Jacob 	if (dq_cnt < 0)
331cad78ca2SJerin Jacob 		return -1;
332cad78ca2SJerin Jacob 
333cad78ca2SJerin Jacob 	return dq_cnt;
334cad78ca2SJerin Jacob }
335cad78ca2SJerin Jacob 
336cad78ca2SJerin Jacob static inline int
337cad78ca2SJerin Jacob octeontx_pko_chan_stop(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid)
338cad78ca2SJerin Jacob {
339cad78ca2SJerin Jacob 	unsigned int dq, dq_cnt, dq_vf;
340cad78ca2SJerin Jacob 	int res;
341cad78ca2SJerin Jacob 
342cad78ca2SJerin Jacob 	dq_cnt = 0;
343cad78ca2SJerin Jacob 	dq = 0;
344cad78ca2SJerin Jacob 	while (dq < RTE_DIM(ctl->dq_map)) {
345cad78ca2SJerin Jacob 		dq_vf = dq / PKO_VF_NUM_DQ;
346cad78ca2SJerin Jacob 
347cad78ca2SJerin Jacob 		if (!ctl->pko[dq_vf].bar0) {
348cad78ca2SJerin Jacob 			dq += PKO_VF_NUM_DQ;
349cad78ca2SJerin Jacob 			continue;
350cad78ca2SJerin Jacob 		}
351cad78ca2SJerin Jacob 
352cad78ca2SJerin Jacob 		if (ctl->dq_map[dq].chanid != ~chanid) {
353cad78ca2SJerin Jacob 			dq++;
354cad78ca2SJerin Jacob 			continue;
355cad78ca2SJerin Jacob 		}
356cad78ca2SJerin Jacob 
357cad78ca2SJerin Jacob 		res = octeontx_pko_dq_drain(dq);
358cad78ca2SJerin Jacob 		if (res > 0)
359cad78ca2SJerin Jacob 			octeontx_log_err("draining DQ%d, buffers left: %x",
360cad78ca2SJerin Jacob 					 dq, res);
361cad78ca2SJerin Jacob 
362cad78ca2SJerin Jacob 		res = octeontx_pko_dq_close(dq);
363cad78ca2SJerin Jacob 		if (res < 0)
364cad78ca2SJerin Jacob 			octeontx_log_err("closing DQ%d failed\n", dq);
365cad78ca2SJerin Jacob 
366cad78ca2SJerin Jacob 		dq_cnt++;
367cad78ca2SJerin Jacob 		dq++;
368cad78ca2SJerin Jacob 	}
369cad78ca2SJerin Jacob 	return dq_cnt;
370cad78ca2SJerin Jacob }
371cad78ca2SJerin Jacob 
372cad78ca2SJerin Jacob int
373cad78ca2SJerin Jacob octeontx_pko_channel_stop(int chanid)
374cad78ca2SJerin Jacob {
375cad78ca2SJerin Jacob 	struct octeontx_pko_vf_ctl_s *ctl = &pko_vf_ctl;
376cad78ca2SJerin Jacob 
377cad78ca2SJerin Jacob 	octeontx_pko_chan_stop(ctl, chanid);
378cad78ca2SJerin Jacob 	return 0;
379cad78ca2SJerin Jacob }
380cad78ca2SJerin Jacob 
3813813a10aSJerin Jacob static inline int
3823813a10aSJerin Jacob octeontx_pko_channel_query(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid,
3833813a10aSJerin Jacob 			   void *out, size_t out_elem_size,
3843813a10aSJerin Jacob 			   size_t dq_num, octeontx_pko_dq_getter_t getter)
3853813a10aSJerin Jacob {
3863813a10aSJerin Jacob 	octeontx_dq_t curr;
3873813a10aSJerin Jacob 	unsigned int dq_vf;
3883813a10aSJerin Jacob 	unsigned int dq;
3893813a10aSJerin Jacob 
3903813a10aSJerin Jacob 	RTE_SET_USED(out_elem_size);
3913813a10aSJerin Jacob 	memset(&curr, 0, sizeof(octeontx_dq_t));
3923813a10aSJerin Jacob 
3933813a10aSJerin Jacob 	dq_vf = dq_num / PKO_VF_NUM_DQ;
3943813a10aSJerin Jacob 	dq = dq_num % PKO_VF_NUM_DQ;
3953813a10aSJerin Jacob 
3963813a10aSJerin Jacob 	if (!ctl->pko[dq_vf].bar0)
3973813a10aSJerin Jacob 		return -EINVAL;
3983813a10aSJerin Jacob 
3993813a10aSJerin Jacob 	if (ctl->dq_map[dq_num].chanid != ~chanid)
4003813a10aSJerin Jacob 		return -EINVAL;
4013813a10aSJerin Jacob 
4023813a10aSJerin Jacob 	uint8_t *iter = (uint8_t *)out;
4033813a10aSJerin Jacob 	curr.lmtline_va = ctl->pko[dq_vf].bar2;
4043813a10aSJerin Jacob 	curr.ioreg_va = (void *)((uintptr_t)ctl->pko[dq_vf].bar0
4053813a10aSJerin Jacob 		+ PKO_VF_DQ_OP_SEND((dq), 0));
4063813a10aSJerin Jacob 	curr.fc_status_va = ctl->fc_ctl + dq;
4073813a10aSJerin Jacob 
4083813a10aSJerin Jacob 	octeontx_log_dbg("lmtline=%p ioreg_va=%p fc_status_va=%p",
4093813a10aSJerin Jacob 			 curr.lmtline_va, curr.ioreg_va,
4103813a10aSJerin Jacob 			 curr.fc_status_va);
4113813a10aSJerin Jacob 
4123813a10aSJerin Jacob 	getter(&curr, (void *)iter);
4133813a10aSJerin Jacob 	return 0;
4143813a10aSJerin Jacob }
4153813a10aSJerin Jacob 
4163813a10aSJerin Jacob int
4173813a10aSJerin Jacob octeontx_pko_channel_query_dqs(int chanid, void *out, size_t out_elem_size,
4183813a10aSJerin Jacob 				size_t dq_num, octeontx_pko_dq_getter_t getter)
4193813a10aSJerin Jacob {
4203813a10aSJerin Jacob 	struct octeontx_pko_vf_ctl_s *ctl = &pko_vf_ctl;
4213813a10aSJerin Jacob 	int dq_cnt;
4223813a10aSJerin Jacob 
4233813a10aSJerin Jacob 	dq_cnt = octeontx_pko_channel_query(ctl, chanid, out, out_elem_size,
4243813a10aSJerin Jacob 						dq_num, getter);
4253813a10aSJerin Jacob 	if (dq_cnt < 0)
4263813a10aSJerin Jacob 		return -1;
4273813a10aSJerin Jacob 
4283813a10aSJerin Jacob 	return dq_cnt;
4293813a10aSJerin Jacob }
4303813a10aSJerin Jacob 
4313813a10aSJerin Jacob int
4323813a10aSJerin Jacob octeontx_pko_vf_count(void)
4333813a10aSJerin Jacob {
4343813a10aSJerin Jacob 	int vf_cnt;
4353813a10aSJerin Jacob 
4363813a10aSJerin Jacob 	vf_cnt = 0;
4373813a10aSJerin Jacob 	while (pko_vf_ctl.pko[vf_cnt].bar0)
4383813a10aSJerin Jacob 		vf_cnt++;
4393813a10aSJerin Jacob 
4403813a10aSJerin Jacob 	return vf_cnt;
4413813a10aSJerin Jacob }
4423813a10aSJerin Jacob 
4433813a10aSJerin Jacob int
4443813a10aSJerin Jacob octeontx_pko_init_fc(const size_t pko_vf_count)
4453813a10aSJerin Jacob {
4463813a10aSJerin Jacob 	int dq_ix;
4473813a10aSJerin Jacob 	uint64_t reg;
4483813a10aSJerin Jacob 	uint8_t *vf_bar0;
4493813a10aSJerin Jacob 	size_t vf_idx;
4503813a10aSJerin Jacob 	size_t fc_mem_size;
4513813a10aSJerin Jacob 
4523813a10aSJerin Jacob 	fc_mem_size = sizeof(struct octeontx_pko_fc_ctl_s) *
4533813a10aSJerin Jacob 			pko_vf_count * PKO_VF_NUM_DQ;
4543813a10aSJerin Jacob 
4553813a10aSJerin Jacob 	pko_vf_ctl.fc_iomem.va = rte_malloc(NULL, fc_mem_size, 128);
4563813a10aSJerin Jacob 	if (unlikely(!pko_vf_ctl.fc_iomem.va)) {
4573813a10aSJerin Jacob 		octeontx_log_err("fc_iomem: not enough memory");
4583813a10aSJerin Jacob 		return -ENOMEM;
4593813a10aSJerin Jacob 	}
4603813a10aSJerin Jacob 
46187cf4c6cSThomas Monjalon 	pko_vf_ctl.fc_iomem.iova = rte_malloc_virt2iova((void *)
4623813a10aSJerin Jacob 							pko_vf_ctl.fc_iomem.va);
4633813a10aSJerin Jacob 	pko_vf_ctl.fc_iomem.size = fc_mem_size;
4643813a10aSJerin Jacob 
4653813a10aSJerin Jacob 	pko_vf_ctl.fc_ctl =
4663813a10aSJerin Jacob 		(struct octeontx_pko_fc_ctl_s *)pko_vf_ctl.fc_iomem.va;
4673813a10aSJerin Jacob 
4683813a10aSJerin Jacob 	/* Configure Flow-Control feature for all DQs of open VFs */
4693813a10aSJerin Jacob 	for (vf_idx = 0; vf_idx < pko_vf_count; vf_idx++) {
4703813a10aSJerin Jacob 		dq_ix = vf_idx * PKO_VF_NUM_DQ;
4713813a10aSJerin Jacob 
4723813a10aSJerin Jacob 		vf_bar0 = pko_vf_ctl.pko[vf_idx].bar0;
4733813a10aSJerin Jacob 
4743813a10aSJerin Jacob 		reg = (pko_vf_ctl.fc_iomem.iova +
4753813a10aSJerin Jacob 			(sizeof(struct octeontx_pko_fc_ctl_s) * dq_ix)) & ~0x7F;
4763813a10aSJerin Jacob 		reg |=			/* BASE */
4773813a10aSJerin Jacob 		    (0x2 << 3) |	/* HYST_BITS */
4783813a10aSJerin Jacob 		    (((PKO_DQ_FC_STRIDE == PKO_DQ_FC_STRIDE_16) ? 1 : 0) << 2) |
4793813a10aSJerin Jacob 		    (0x1 << 0);		/* ENABLE */
4803813a10aSJerin Jacob 
4813813a10aSJerin Jacob 		octeontx_write64(reg, vf_bar0 + PKO_VF_DQ_FC_CONFIG);
4823813a10aSJerin Jacob 
4833813a10aSJerin Jacob 		octeontx_log_dbg("PKO: bar0 %p VF_idx %d DQ_FC_CFG=%" PRIx64 "",
4843813a10aSJerin Jacob 				 vf_bar0, (int)vf_idx, reg);
4853813a10aSJerin Jacob 	}
4863813a10aSJerin Jacob 	return 0;
4873813a10aSJerin Jacob }
4883813a10aSJerin Jacob 
4893813a10aSJerin Jacob void
4903813a10aSJerin Jacob octeontx_pko_fc_free(void)
4913813a10aSJerin Jacob {
4923813a10aSJerin Jacob 	rte_free(pko_vf_ctl.fc_iomem.va);
4933813a10aSJerin Jacob }
4943813a10aSJerin Jacob 
495445371e8SJerin Jacob static void
496445371e8SJerin Jacob octeontx_pkovf_setup(void)
497445371e8SJerin Jacob {
498445371e8SJerin Jacob 	static bool init_once;
499445371e8SJerin Jacob 
500445371e8SJerin Jacob 	if (!init_once) {
501445371e8SJerin Jacob 		unsigned int i;
502445371e8SJerin Jacob 
503445371e8SJerin Jacob 		rte_spinlock_init(&pko_vf_ctl.lock);
504445371e8SJerin Jacob 
505445371e8SJerin Jacob 		pko_vf_ctl.fc_iomem = PKO_IOMEM_NULL;
506445371e8SJerin Jacob 		pko_vf_ctl.fc_ctl = NULL;
507445371e8SJerin Jacob 
508445371e8SJerin Jacob 		for (i = 0; i < PKO_VF_MAX; i++) {
509445371e8SJerin Jacob 			pko_vf_ctl.pko[i].bar0 = NULL;
510445371e8SJerin Jacob 			pko_vf_ctl.pko[i].bar2 = NULL;
511445371e8SJerin Jacob 			pko_vf_ctl.pko[i].domain = ~(uint16_t)0;
512445371e8SJerin Jacob 			pko_vf_ctl.pko[i].vfid = ~(uint16_t)0;
513445371e8SJerin Jacob 		}
514445371e8SJerin Jacob 
515445371e8SJerin Jacob 		for (i = 0; i < (PKO_VF_MAX * PKO_VF_NUM_DQ); i++)
516445371e8SJerin Jacob 			pko_vf_ctl.dq_map[i].chanid = 0;
517445371e8SJerin Jacob 
518445371e8SJerin Jacob 		init_once = true;
519445371e8SJerin Jacob 	}
520445371e8SJerin Jacob }
521445371e8SJerin Jacob 
522445371e8SJerin Jacob /* PKOVF pcie device*/
523445371e8SJerin Jacob static int
524445371e8SJerin Jacob pkovf_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
525445371e8SJerin Jacob {
526445371e8SJerin Jacob 	uint64_t val;
527445371e8SJerin Jacob 	uint16_t vfid;
528445371e8SJerin Jacob 	uint16_t domain;
529445371e8SJerin Jacob 	uint8_t *bar0;
530445371e8SJerin Jacob 	uint8_t *bar2;
531445371e8SJerin Jacob 	struct octeontx_pkovf *res;
532445371e8SJerin Jacob 
533445371e8SJerin Jacob 	RTE_SET_USED(pci_drv);
534445371e8SJerin Jacob 
535445371e8SJerin Jacob 	/* For secondary processes, the primary has done all the work */
536445371e8SJerin Jacob 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
537445371e8SJerin Jacob 		return 0;
538445371e8SJerin Jacob 
539445371e8SJerin Jacob 	if (pci_dev->mem_resource[0].addr == NULL ||
540445371e8SJerin Jacob 	    pci_dev->mem_resource[2].addr == NULL) {
541445371e8SJerin Jacob 		octeontx_log_err("Empty bars %p %p",
542445371e8SJerin Jacob 			pci_dev->mem_resource[0].addr,
543445371e8SJerin Jacob 			pci_dev->mem_resource[2].addr);
544445371e8SJerin Jacob 		return -ENODEV;
545445371e8SJerin Jacob 	}
546445371e8SJerin Jacob 	bar0 = pci_dev->mem_resource[0].addr;
547445371e8SJerin Jacob 	bar2 = pci_dev->mem_resource[2].addr;
548445371e8SJerin Jacob 
549445371e8SJerin Jacob 	octeontx_pkovf_setup();
550445371e8SJerin Jacob 
551445371e8SJerin Jacob 	/* get vfid and domain */
552445371e8SJerin Jacob 	val = octeontx_read64(bar0 + PKO_VF_DQ_FC_CONFIG);
553445371e8SJerin Jacob 	domain = (val >> 7) & 0xffff;
554445371e8SJerin Jacob 	vfid = (val >> 23) & 0xffff;
555445371e8SJerin Jacob 
556445371e8SJerin Jacob 	if (unlikely(vfid >= PKO_VF_MAX)) {
557445371e8SJerin Jacob 		octeontx_log_err("pko: Invalid vfid %d", vfid);
558445371e8SJerin Jacob 		return -EINVAL;
559445371e8SJerin Jacob 	}
560445371e8SJerin Jacob 
561445371e8SJerin Jacob 	res = &pko_vf_ctl.pko[vfid];
562445371e8SJerin Jacob 	res->vfid = vfid;
563445371e8SJerin Jacob 	res->domain = domain;
564445371e8SJerin Jacob 	res->bar0 = bar0;
565445371e8SJerin Jacob 	res->bar2 = bar2;
566445371e8SJerin Jacob 
567445371e8SJerin Jacob 	octeontx_log_dbg("Domain=%d group=%d", res->domain, res->vfid);
568445371e8SJerin Jacob 	return 0;
569445371e8SJerin Jacob }
570445371e8SJerin Jacob 
571445371e8SJerin Jacob #define PCI_VENDOR_ID_CAVIUM               0x177D
572445371e8SJerin Jacob #define PCI_DEVICE_ID_OCTEONTX_PKO_VF      0xA049
573445371e8SJerin Jacob 
574445371e8SJerin Jacob static const struct rte_pci_id pci_pkovf_map[] = {
575445371e8SJerin Jacob 	{
576445371e8SJerin Jacob 		RTE_PCI_DEVICE(PCI_VENDOR_ID_CAVIUM,
577445371e8SJerin Jacob 				PCI_DEVICE_ID_OCTEONTX_PKO_VF)
578445371e8SJerin Jacob 	},
579445371e8SJerin Jacob 	{
580445371e8SJerin Jacob 		.vendor_id = 0,
581445371e8SJerin Jacob 	},
582445371e8SJerin Jacob };
583445371e8SJerin Jacob 
584445371e8SJerin Jacob static struct rte_pci_driver pci_pkovf = {
585445371e8SJerin Jacob 	.id_table = pci_pkovf_map,
586445371e8SJerin Jacob 	.drv_flags = RTE_PCI_DRV_NEED_MAPPING,
587445371e8SJerin Jacob 	.probe = pkovf_probe,
588445371e8SJerin Jacob };
589445371e8SJerin Jacob 
590445371e8SJerin Jacob RTE_PMD_REGISTER_PCI(octeontx_pkovf, pci_pkovf);
591