xref: /dpdk/drivers/net/octeontx/base/octeontx_pkovf.c (revision f665790a5dbad7b645ff46f31d65e977324e7bfc)
1aaf4363eSJerin Jacob /* SPDX-License-Identifier: BSD-3-Clause
2aaf4363eSJerin Jacob  * Copyright(c) 2017 Cavium, Inc
3445371e8SJerin Jacob  */
4aaf4363eSJerin 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>
131f37cb2bSDavid Marchand #include <bus_pci_driver.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}
27a6d6f0afSPavan Nikhilesh #define PKO_VALID	0x1
28a6d6f0afSPavan Nikhilesh #define PKO_INUSE	0x2
29445371e8SJerin Jacob 
30445371e8SJerin Jacob struct octeontx_pko_fc_ctl_s {
31445371e8SJerin Jacob 	int64_t buf_cnt;
32445371e8SJerin Jacob 	int64_t padding[(PKO_DQ_FC_STRIDE / 8) - 1];
33445371e8SJerin Jacob };
34445371e8SJerin Jacob 
35445371e8SJerin Jacob struct octeontx_pkovf {
36445371e8SJerin Jacob 	uint8_t		*bar0;
37445371e8SJerin Jacob 	uint8_t		*bar2;
38a6d6f0afSPavan Nikhilesh 	uint8_t		status;
39445371e8SJerin Jacob 	uint16_t	domain;
40445371e8SJerin Jacob 	uint16_t	vfid;
41445371e8SJerin Jacob };
42445371e8SJerin Jacob 
43445371e8SJerin Jacob struct octeontx_pko_vf_ctl_s {
44445371e8SJerin Jacob 	rte_spinlock_t lock;
45a6d6f0afSPavan Nikhilesh 	uint16_t global_domain;
46445371e8SJerin Jacob 	struct octeontx_pko_iomem fc_iomem;
47445371e8SJerin Jacob 	struct octeontx_pko_fc_ctl_s *fc_ctl;
48445371e8SJerin Jacob 	struct octeontx_pkovf pko[PKO_VF_MAX];
49445371e8SJerin Jacob 	struct {
50445371e8SJerin Jacob 		uint64_t chanid;
51445371e8SJerin Jacob 	} dq_map[PKO_VF_MAX * PKO_VF_NUM_DQ];
52445371e8SJerin Jacob };
53445371e8SJerin Jacob 
54445371e8SJerin Jacob static struct octeontx_pko_vf_ctl_s pko_vf_ctl;
55445371e8SJerin Jacob 
56cad78ca2SJerin Jacob static void *
57cad78ca2SJerin Jacob octeontx_pko_dq_vf_bar0(uint16_t txq)
58cad78ca2SJerin Jacob {
59cad78ca2SJerin Jacob 	int vf_ix;
60cad78ca2SJerin Jacob 
61cad78ca2SJerin Jacob 	vf_ix = txq / PKO_VF_NUM_DQ;
62cad78ca2SJerin Jacob 	return pko_vf_ctl.pko[vf_ix].bar0;
63cad78ca2SJerin Jacob }
64cad78ca2SJerin Jacob 
65cad78ca2SJerin Jacob static int
66cad78ca2SJerin Jacob octeontx_pko_dq_gdq(uint16_t txq)
67cad78ca2SJerin Jacob {
68cad78ca2SJerin Jacob 	return txq % PKO_VF_NUM_DQ;
69cad78ca2SJerin Jacob }
70cad78ca2SJerin Jacob 
71cad78ca2SJerin Jacob /**
72cad78ca2SJerin Jacob  * Open a PKO DQ.
73cad78ca2SJerin Jacob  */
74cad78ca2SJerin Jacob static inline
75cad78ca2SJerin Jacob int octeontx_pko_dq_open(uint16_t txq)
76cad78ca2SJerin Jacob {
77cad78ca2SJerin Jacob 	unsigned int reg_off;
78cad78ca2SJerin Jacob 	uint8_t *vf_bar0;
79cad78ca2SJerin Jacob 	uint64_t rtn;
80cad78ca2SJerin Jacob 	int gdq;
81cad78ca2SJerin Jacob 
82cad78ca2SJerin Jacob 	vf_bar0 = octeontx_pko_dq_vf_bar0(txq);
83cad78ca2SJerin Jacob 	gdq = octeontx_pko_dq_gdq(txq);
84cad78ca2SJerin Jacob 
85cad78ca2SJerin Jacob 	if (unlikely(gdq < 0 || vf_bar0 == NULL))
86cad78ca2SJerin Jacob 		return -EINVAL;
87cad78ca2SJerin Jacob 	*(volatile int64_t*)(pko_vf_ctl.fc_ctl + txq) =
88cad78ca2SJerin Jacob 		PKO_DQ_FC_DEPTH_PAGES - PKO_DQ_FC_SKID;
89cad78ca2SJerin Jacob 
90cad78ca2SJerin Jacob 	rte_wmb();
91cad78ca2SJerin Jacob 
92cad78ca2SJerin Jacob 	octeontx_write64(PKO_DQ_FC_DEPTH_PAGES,
93cad78ca2SJerin Jacob 			 vf_bar0 + PKO_VF_DQ_FC_STATUS(gdq));
94cad78ca2SJerin Jacob 
95cad78ca2SJerin Jacob 	/* Set the register to return descriptor (packet) count as DEPTH */
96cad78ca2SJerin Jacob 	/* KIND=1, NCB_QUERY_RSP=0 */
97cad78ca2SJerin Jacob 	octeontx_write64(1ull << PKO_DQ_KIND_BIT,
98cad78ca2SJerin Jacob 				vf_bar0 + PKO_VF_DQ_WM_CTL(gdq));
99cad78ca2SJerin Jacob 	reg_off = PKO_VF_DQ_OP_OPEN(gdq);
100cad78ca2SJerin Jacob 
101cad78ca2SJerin Jacob 	rtn = octeontx_reg_ldadd_u64(vf_bar0 + reg_off, 0);
102cad78ca2SJerin Jacob 
103cad78ca2SJerin Jacob 	/* PKO_DQOP_E::OPEN */
104cad78ca2SJerin Jacob 	if (((rtn >> PKO_DQ_OP_BIT) & 0x3) != 0x1)
105cad78ca2SJerin Jacob 		return -EIO;
106cad78ca2SJerin Jacob 
107cad78ca2SJerin Jacob 	switch (rtn >> PKO_DQ_STATUS_BIT) {
108cad78ca2SJerin Jacob 	case 0xC:	/* DQALREADYCREATED */
109cad78ca2SJerin Jacob 	case 0x0:	/* PASS */
110cad78ca2SJerin Jacob 		break;
111cad78ca2SJerin Jacob 	default:
112cad78ca2SJerin Jacob 		return -EIO;
113cad78ca2SJerin Jacob 	}
114cad78ca2SJerin Jacob 
115cad78ca2SJerin Jacob 	/* DRAIN=0, DRAIN_NULL_LINK=0, SW_XOFF=0 */
116cad78ca2SJerin Jacob 	octeontx_write64(0, vf_bar0 + PKO_VF_DQ_SW_XOFF(gdq));
117cad78ca2SJerin Jacob 
118cad78ca2SJerin Jacob 	return rtn & ((1ull << PKO_DQ_OP_BIT) - 1);
119cad78ca2SJerin Jacob }
120cad78ca2SJerin Jacob 
121cad78ca2SJerin Jacob /**
122cad78ca2SJerin Jacob  * Close a PKO DQ
123cad78ca2SJerin Jacob  * Flush all packets pending.
124cad78ca2SJerin Jacob  */
125cad78ca2SJerin Jacob static inline
126cad78ca2SJerin Jacob int octeontx_pko_dq_close(uint16_t txq)
127cad78ca2SJerin Jacob {
128cad78ca2SJerin Jacob 	unsigned int reg_off;
129cad78ca2SJerin Jacob 	uint8_t *vf_bar0;
130cad78ca2SJerin Jacob 	uint64_t rtn;
131cad78ca2SJerin Jacob 	int res;
132cad78ca2SJerin Jacob 
133cad78ca2SJerin Jacob 	vf_bar0 = octeontx_pko_dq_vf_bar0(txq);
134cad78ca2SJerin Jacob 	res = octeontx_pko_dq_gdq(txq);
135cad78ca2SJerin Jacob 
136cad78ca2SJerin Jacob 	if (unlikely(res < 0 || vf_bar0 == NULL))
137cad78ca2SJerin Jacob 		return -EINVAL;
138cad78ca2SJerin Jacob 
139cad78ca2SJerin Jacob 	reg_off = PKO_VF_DQ_OP_CLOSE(res);
140cad78ca2SJerin Jacob 
141cad78ca2SJerin Jacob 	rtn = octeontx_reg_ldadd_u64(vf_bar0 + reg_off, 0);
142cad78ca2SJerin Jacob 
143cad78ca2SJerin Jacob 	/* PKO_DQOP_E::CLOSE */
144cad78ca2SJerin Jacob 	if (((rtn >> PKO_DQ_OP_BIT) & 0x3) != 0x2)
145cad78ca2SJerin Jacob 		return -EIO;
146cad78ca2SJerin Jacob 
147cad78ca2SJerin Jacob 	switch (rtn >> PKO_DQ_STATUS_BIT) {
148cad78ca2SJerin Jacob 	case 0xD:	/* DQNOTCREATED */
149cad78ca2SJerin Jacob 	case 0x0:	/* PASS */
150cad78ca2SJerin Jacob 		break;
151cad78ca2SJerin Jacob 	default:
152cad78ca2SJerin Jacob 		return -EIO;
153cad78ca2SJerin Jacob 	}
154cad78ca2SJerin Jacob 
155cad78ca2SJerin Jacob 	res = rtn & ((1ull << PKO_DQ_OP_BIT) - 1); /* DEPTH */
156cad78ca2SJerin Jacob 	return res;
157cad78ca2SJerin Jacob }
158cad78ca2SJerin Jacob 
159cad78ca2SJerin Jacob /* Flush all packets pending on a DQ */
160cad78ca2SJerin Jacob static inline
161cad78ca2SJerin Jacob int octeontx_pko_dq_drain(uint16_t txq)
162cad78ca2SJerin Jacob {
163cad78ca2SJerin Jacob 	unsigned int gdq;
164cad78ca2SJerin Jacob 	uint8_t *vf_bar0;
165cad78ca2SJerin Jacob 	uint64_t reg;
166cad78ca2SJerin Jacob 	int res, timo = PKO_DQ_DRAIN_TO;
167cad78ca2SJerin Jacob 
168cad78ca2SJerin Jacob 	vf_bar0 = octeontx_pko_dq_vf_bar0(txq);
169cad78ca2SJerin Jacob 	res = octeontx_pko_dq_gdq(txq);
170cad78ca2SJerin Jacob 	gdq = res;
171cad78ca2SJerin Jacob 
172cad78ca2SJerin Jacob 	 /* DRAIN=1, DRAIN_NULL_LINK=0, SW_XOFF=1 */
173cad78ca2SJerin Jacob 	 octeontx_write64(0x3, vf_bar0 + PKO_VF_DQ_SW_XOFF(gdq));
174cad78ca2SJerin Jacob 	/* Wait until buffers leave DQs */
175cad78ca2SJerin Jacob 	reg = octeontx_read64(vf_bar0 + PKO_VF_DQ_WM_CNT(gdq));
176cad78ca2SJerin Jacob 	while (reg && timo > 0) {
177cad78ca2SJerin Jacob 		rte_delay_us(100);
178cad78ca2SJerin Jacob 		timo--;
179cad78ca2SJerin Jacob 		reg = octeontx_read64(vf_bar0 + PKO_VF_DQ_WM_CNT(gdq));
180cad78ca2SJerin Jacob 	}
181cad78ca2SJerin Jacob 	/* DRAIN=0, DRAIN_NULL_LINK=0, SW_XOFF=0 */
182cad78ca2SJerin Jacob 	octeontx_write64(0, vf_bar0 + PKO_VF_DQ_SW_XOFF(gdq));
183cad78ca2SJerin Jacob 
184cad78ca2SJerin Jacob 	return reg;
185cad78ca2SJerin Jacob }
186cad78ca2SJerin Jacob 
187cad78ca2SJerin Jacob static inline int
188cad78ca2SJerin Jacob octeontx_pko_dq_range_lookup(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid,
189cad78ca2SJerin Jacob 			     unsigned int dq_num, unsigned int dq_from)
190cad78ca2SJerin Jacob {
191cad78ca2SJerin Jacob 	unsigned int dq, dq_cnt;
192cad78ca2SJerin Jacob 	unsigned int dq_base;
193cad78ca2SJerin Jacob 
194cad78ca2SJerin Jacob 	dq_cnt = 0;
195cad78ca2SJerin Jacob 	dq = dq_from;
196cad78ca2SJerin Jacob 	while (dq < RTE_DIM(ctl->dq_map)) {
197cad78ca2SJerin Jacob 		dq_base = dq;
198cad78ca2SJerin Jacob 		dq_cnt = 0;
199cad78ca2SJerin Jacob 		while (ctl->dq_map[dq].chanid == ~chanid &&
200cad78ca2SJerin Jacob 			dq < RTE_DIM(ctl->dq_map)) {
201cad78ca2SJerin Jacob 			dq_cnt++;
202cad78ca2SJerin Jacob 			if (dq_cnt == dq_num)
203cad78ca2SJerin Jacob 				return dq_base;
204cad78ca2SJerin Jacob 			dq++;
205cad78ca2SJerin Jacob 		}
206cad78ca2SJerin Jacob 		dq++;
207cad78ca2SJerin Jacob 	}
208cad78ca2SJerin Jacob 	return -1;
209cad78ca2SJerin Jacob }
210cad78ca2SJerin Jacob 
211cad78ca2SJerin Jacob static inline void
212cad78ca2SJerin Jacob octeontx_pko_dq_range_assign(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid,
213cad78ca2SJerin Jacob 			     unsigned int dq_base, unsigned int dq_num)
214cad78ca2SJerin Jacob {
215cad78ca2SJerin Jacob 	unsigned int dq, dq_cnt;
216cad78ca2SJerin Jacob 
217cad78ca2SJerin Jacob 	dq_cnt = 0;
218cad78ca2SJerin Jacob 	while (dq_cnt < dq_num) {
219cad78ca2SJerin Jacob 		dq = dq_base + dq_cnt;
220cad78ca2SJerin Jacob 
221cad78ca2SJerin Jacob 		octeontx_log_dbg("DQ# %u assigned to CHAN# %" PRIx64 "", dq,
222cad78ca2SJerin Jacob 			chanid);
223cad78ca2SJerin Jacob 
224cad78ca2SJerin Jacob 		ctl->dq_map[dq].chanid = ~chanid;
225cad78ca2SJerin Jacob 		dq_cnt++;
226cad78ca2SJerin Jacob 	}
227cad78ca2SJerin Jacob }
228cad78ca2SJerin Jacob 
229cad78ca2SJerin Jacob static inline int
230cad78ca2SJerin Jacob octeontx_pko_dq_claim(struct octeontx_pko_vf_ctl_s *ctl, unsigned int dq_base,
231cad78ca2SJerin Jacob 		      unsigned int dq_num, uint64_t chanid)
232cad78ca2SJerin Jacob {
233cad78ca2SJerin Jacob 	const uint64_t null_chanid = ~0ull;
234cad78ca2SJerin Jacob 	int dq;
235cad78ca2SJerin Jacob 
236cad78ca2SJerin Jacob 	rte_spinlock_lock(&ctl->lock);
237cad78ca2SJerin Jacob 
238cad78ca2SJerin Jacob 	dq = octeontx_pko_dq_range_lookup(ctl, null_chanid, dq_num, dq_base);
239cad78ca2SJerin Jacob 	if (dq < 0 || (unsigned int)dq != dq_base) {
240cad78ca2SJerin Jacob 		rte_spinlock_unlock(&ctl->lock);
241cad78ca2SJerin Jacob 		return -1;
242cad78ca2SJerin Jacob 	}
243cad78ca2SJerin Jacob 	octeontx_pko_dq_range_assign(ctl, chanid, dq_base, dq_num);
244cad78ca2SJerin Jacob 
245cad78ca2SJerin Jacob 	rte_spinlock_unlock(&ctl->lock);
246cad78ca2SJerin Jacob 
247cad78ca2SJerin Jacob 	return 0;
248cad78ca2SJerin Jacob }
249cad78ca2SJerin Jacob 
250cad78ca2SJerin Jacob static inline int
251cad78ca2SJerin Jacob octeontx_pko_dq_free(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid)
252cad78ca2SJerin Jacob {
253cad78ca2SJerin Jacob 	const uint64_t null_chanid = ~0ull;
254cad78ca2SJerin Jacob 	unsigned int dq = 0, dq_cnt = 0;
255cad78ca2SJerin Jacob 
256cad78ca2SJerin Jacob 	rte_spinlock_lock(&ctl->lock);
257cad78ca2SJerin Jacob 	while (dq < RTE_DIM(ctl->dq_map)) {
258cad78ca2SJerin Jacob 		if (ctl->dq_map[dq].chanid == ~chanid) {
259cad78ca2SJerin Jacob 			ctl->dq_map[dq].chanid = ~null_chanid;
260cad78ca2SJerin Jacob 			dq_cnt++;
261cad78ca2SJerin Jacob 		}
262cad78ca2SJerin Jacob 		dq++;
263cad78ca2SJerin Jacob 	}
264cad78ca2SJerin Jacob 	rte_spinlock_unlock(&ctl->lock);
265cad78ca2SJerin Jacob 
266cad78ca2SJerin Jacob 	return dq_cnt > 0 ? 0 : -EINVAL;
267cad78ca2SJerin Jacob }
268cad78ca2SJerin Jacob 
269cad78ca2SJerin Jacob int
270cad78ca2SJerin Jacob octeontx_pko_channel_open(int dq_base, int dq_num, int chanid)
271cad78ca2SJerin Jacob {
272cad78ca2SJerin Jacob 	struct octeontx_pko_vf_ctl_s *ctl = &pko_vf_ctl;
273cad78ca2SJerin Jacob 	int res;
274cad78ca2SJerin Jacob 
275cad78ca2SJerin Jacob 	res = octeontx_pko_dq_claim(ctl, dq_base, dq_num, chanid);
276cad78ca2SJerin Jacob 	if (res < 0)
277cad78ca2SJerin Jacob 		return -1;
278cad78ca2SJerin Jacob 
279cad78ca2SJerin Jacob 	return 0;
280cad78ca2SJerin Jacob }
281cad78ca2SJerin Jacob 
282cad78ca2SJerin Jacob int
283cad78ca2SJerin Jacob octeontx_pko_channel_close(int chanid)
284cad78ca2SJerin Jacob {
285cad78ca2SJerin Jacob 	struct octeontx_pko_vf_ctl_s *ctl = &pko_vf_ctl;
286cad78ca2SJerin Jacob 	int res;
287cad78ca2SJerin Jacob 
288cad78ca2SJerin Jacob 	res = octeontx_pko_dq_free(ctl, chanid);
289cad78ca2SJerin Jacob 	if (res < 0)
290cad78ca2SJerin Jacob 		return -1;
291cad78ca2SJerin Jacob 
292cad78ca2SJerin Jacob 	return 0;
293cad78ca2SJerin Jacob }
294cad78ca2SJerin Jacob 
295cad78ca2SJerin Jacob static inline int
296cad78ca2SJerin Jacob octeontx_pko_chan_start(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid)
297cad78ca2SJerin Jacob {
298cad78ca2SJerin Jacob 	unsigned int dq_vf;
299cad78ca2SJerin Jacob 	unsigned int dq, dq_cnt;
300cad78ca2SJerin Jacob 
301cad78ca2SJerin Jacob 	dq_cnt = 0;
302cad78ca2SJerin Jacob 	dq = 0;
303cad78ca2SJerin Jacob 	while (dq < RTE_DIM(ctl->dq_map)) {
304cad78ca2SJerin Jacob 		dq_vf = dq / PKO_VF_NUM_DQ;
305cad78ca2SJerin Jacob 
306cad78ca2SJerin Jacob 		if (!ctl->pko[dq_vf].bar0) {
307cad78ca2SJerin Jacob 			dq += PKO_VF_NUM_DQ;
308cad78ca2SJerin Jacob 			continue;
309cad78ca2SJerin Jacob 		}
310cad78ca2SJerin Jacob 
311cad78ca2SJerin Jacob 		if (ctl->dq_map[dq].chanid != ~chanid) {
312cad78ca2SJerin Jacob 			dq++;
313cad78ca2SJerin Jacob 			continue;
314cad78ca2SJerin Jacob 		}
315cad78ca2SJerin Jacob 
316cad78ca2SJerin Jacob 		if (octeontx_pko_dq_open(dq) < 0)
317cad78ca2SJerin Jacob 			break;
318cad78ca2SJerin Jacob 
319cad78ca2SJerin Jacob 		dq_cnt++;
320cad78ca2SJerin Jacob 		dq++;
321cad78ca2SJerin Jacob 	}
322cad78ca2SJerin Jacob 
323cad78ca2SJerin Jacob 	return dq_cnt;
324cad78ca2SJerin Jacob }
325cad78ca2SJerin Jacob 
326cad78ca2SJerin Jacob int
327cad78ca2SJerin Jacob octeontx_pko_channel_start(int chanid)
328cad78ca2SJerin Jacob {
329cad78ca2SJerin Jacob 	struct octeontx_pko_vf_ctl_s *ctl = &pko_vf_ctl;
330cad78ca2SJerin Jacob 	int dq_cnt;
331cad78ca2SJerin Jacob 
332cad78ca2SJerin Jacob 	dq_cnt = octeontx_pko_chan_start(ctl, chanid);
333cad78ca2SJerin Jacob 	if (dq_cnt < 0)
334cad78ca2SJerin Jacob 		return -1;
335cad78ca2SJerin Jacob 
336cad78ca2SJerin Jacob 	return dq_cnt;
337cad78ca2SJerin Jacob }
338cad78ca2SJerin Jacob 
339cad78ca2SJerin Jacob static inline int
340cad78ca2SJerin Jacob octeontx_pko_chan_stop(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid)
341cad78ca2SJerin Jacob {
342cad78ca2SJerin Jacob 	unsigned int dq, dq_cnt, dq_vf;
343cad78ca2SJerin Jacob 	int res;
344cad78ca2SJerin Jacob 
345cad78ca2SJerin Jacob 	dq_cnt = 0;
346cad78ca2SJerin Jacob 	dq = 0;
347cad78ca2SJerin Jacob 	while (dq < RTE_DIM(ctl->dq_map)) {
348cad78ca2SJerin Jacob 		dq_vf = dq / PKO_VF_NUM_DQ;
349cad78ca2SJerin Jacob 
350cad78ca2SJerin Jacob 		if (!ctl->pko[dq_vf].bar0) {
351cad78ca2SJerin Jacob 			dq += PKO_VF_NUM_DQ;
352cad78ca2SJerin Jacob 			continue;
353cad78ca2SJerin Jacob 		}
354cad78ca2SJerin Jacob 
355cad78ca2SJerin Jacob 		if (ctl->dq_map[dq].chanid != ~chanid) {
356cad78ca2SJerin Jacob 			dq++;
357cad78ca2SJerin Jacob 			continue;
358cad78ca2SJerin Jacob 		}
359cad78ca2SJerin Jacob 
360cad78ca2SJerin Jacob 		res = octeontx_pko_dq_drain(dq);
361cad78ca2SJerin Jacob 		if (res > 0)
362cad78ca2SJerin Jacob 			octeontx_log_err("draining DQ%d, buffers left: %x",
363cad78ca2SJerin Jacob 					 dq, res);
364cad78ca2SJerin Jacob 
365cad78ca2SJerin Jacob 		res = octeontx_pko_dq_close(dq);
366cad78ca2SJerin Jacob 		if (res < 0)
367*f665790aSDavid Marchand 			octeontx_log_err("closing DQ%d failed", dq);
368cad78ca2SJerin Jacob 
369cad78ca2SJerin Jacob 		dq_cnt++;
370cad78ca2SJerin Jacob 		dq++;
371cad78ca2SJerin Jacob 	}
372cad78ca2SJerin Jacob 	return dq_cnt;
373cad78ca2SJerin Jacob }
374cad78ca2SJerin Jacob 
375cad78ca2SJerin Jacob int
376cad78ca2SJerin Jacob octeontx_pko_channel_stop(int chanid)
377cad78ca2SJerin Jacob {
378cad78ca2SJerin Jacob 	struct octeontx_pko_vf_ctl_s *ctl = &pko_vf_ctl;
379cad78ca2SJerin Jacob 
380cad78ca2SJerin Jacob 	octeontx_pko_chan_stop(ctl, chanid);
381cad78ca2SJerin Jacob 	return 0;
382cad78ca2SJerin Jacob }
383cad78ca2SJerin Jacob 
3843813a10aSJerin Jacob static inline int
3853813a10aSJerin Jacob octeontx_pko_channel_query(struct octeontx_pko_vf_ctl_s *ctl, uint64_t chanid,
3863813a10aSJerin Jacob 			   void *out, size_t out_elem_size,
3873813a10aSJerin Jacob 			   size_t dq_num, octeontx_pko_dq_getter_t getter)
3883813a10aSJerin Jacob {
3893813a10aSJerin Jacob 	octeontx_dq_t curr;
3903813a10aSJerin Jacob 	unsigned int dq_vf;
3913813a10aSJerin Jacob 	unsigned int dq;
3923813a10aSJerin Jacob 
3933813a10aSJerin Jacob 	RTE_SET_USED(out_elem_size);
3943813a10aSJerin Jacob 	memset(&curr, 0, sizeof(octeontx_dq_t));
3953813a10aSJerin Jacob 
3963813a10aSJerin Jacob 	dq_vf = dq_num / PKO_VF_NUM_DQ;
3973813a10aSJerin Jacob 	dq = dq_num % PKO_VF_NUM_DQ;
3983813a10aSJerin Jacob 
3993813a10aSJerin Jacob 	if (!ctl->pko[dq_vf].bar0)
4003813a10aSJerin Jacob 		return -EINVAL;
4013813a10aSJerin Jacob 
4023813a10aSJerin Jacob 	if (ctl->dq_map[dq_num].chanid != ~chanid)
4033813a10aSJerin Jacob 		return -EINVAL;
4043813a10aSJerin Jacob 
4053813a10aSJerin Jacob 	uint8_t *iter = (uint8_t *)out;
4063813a10aSJerin Jacob 	curr.lmtline_va = ctl->pko[dq_vf].bar2;
4073813a10aSJerin Jacob 	curr.ioreg_va = (void *)((uintptr_t)ctl->pko[dq_vf].bar0
4083813a10aSJerin Jacob 		+ PKO_VF_DQ_OP_SEND((dq), 0));
409a6d6f0afSPavan Nikhilesh 	curr.fc_status_va = ctl->fc_ctl + dq_num;
4103813a10aSJerin Jacob 
4113813a10aSJerin Jacob 	octeontx_log_dbg("lmtline=%p ioreg_va=%p fc_status_va=%p",
4123813a10aSJerin Jacob 			 curr.lmtline_va, curr.ioreg_va,
4133813a10aSJerin Jacob 			 curr.fc_status_va);
4143813a10aSJerin Jacob 
4153813a10aSJerin Jacob 	getter(&curr, (void *)iter);
4163813a10aSJerin Jacob 	return 0;
4173813a10aSJerin Jacob }
4183813a10aSJerin Jacob 
4193813a10aSJerin Jacob int
4203813a10aSJerin Jacob octeontx_pko_channel_query_dqs(int chanid, void *out, size_t out_elem_size,
4213813a10aSJerin Jacob 				size_t dq_num, octeontx_pko_dq_getter_t getter)
4223813a10aSJerin Jacob {
4233813a10aSJerin Jacob 	struct octeontx_pko_vf_ctl_s *ctl = &pko_vf_ctl;
4243813a10aSJerin Jacob 	int dq_cnt;
4253813a10aSJerin Jacob 
4263813a10aSJerin Jacob 	dq_cnt = octeontx_pko_channel_query(ctl, chanid, out, out_elem_size,
4273813a10aSJerin Jacob 						dq_num, getter);
4283813a10aSJerin Jacob 	if (dq_cnt < 0)
4293813a10aSJerin Jacob 		return -1;
4303813a10aSJerin Jacob 
4313813a10aSJerin Jacob 	return dq_cnt;
4323813a10aSJerin Jacob }
4333813a10aSJerin Jacob 
4343813a10aSJerin Jacob int
4353813a10aSJerin Jacob octeontx_pko_vf_count(void)
4363813a10aSJerin Jacob {
437a6d6f0afSPavan Nikhilesh 	uint16_t global_domain = octeontx_get_global_domain();
4383813a10aSJerin Jacob 	int vf_cnt;
4393813a10aSJerin Jacob 
440a6d6f0afSPavan Nikhilesh 	pko_vf_ctl.global_domain = global_domain;
4413813a10aSJerin Jacob 	vf_cnt = 0;
4423813a10aSJerin Jacob 	while (pko_vf_ctl.pko[vf_cnt].bar0)
4433813a10aSJerin Jacob 		vf_cnt++;
4443813a10aSJerin Jacob 
4453813a10aSJerin Jacob 	return vf_cnt;
4463813a10aSJerin Jacob }
4473813a10aSJerin Jacob 
448a6d6f0afSPavan Nikhilesh size_t
449a6d6f0afSPavan Nikhilesh octeontx_pko_get_vfid(void)
450a6d6f0afSPavan Nikhilesh {
451a6d6f0afSPavan Nikhilesh 	size_t vf_cnt = octeontx_pko_vf_count();
452a6d6f0afSPavan Nikhilesh 	size_t vf_idx;
453a6d6f0afSPavan Nikhilesh 
454a6d6f0afSPavan Nikhilesh 
455a6d6f0afSPavan Nikhilesh 	for (vf_idx = 0; vf_idx < vf_cnt; vf_idx++) {
456a6d6f0afSPavan Nikhilesh 		if (!(pko_vf_ctl.pko[vf_idx].status & PKO_VALID))
457a6d6f0afSPavan Nikhilesh 			continue;
458a6d6f0afSPavan Nikhilesh 		if (pko_vf_ctl.pko[vf_idx].status & PKO_INUSE)
459a6d6f0afSPavan Nikhilesh 			continue;
460a6d6f0afSPavan Nikhilesh 
461a6d6f0afSPavan Nikhilesh 		pko_vf_ctl.pko[vf_idx].status |= PKO_INUSE;
462a6d6f0afSPavan Nikhilesh 		return pko_vf_ctl.pko[vf_idx].vfid;
463a6d6f0afSPavan Nikhilesh 	}
464a6d6f0afSPavan Nikhilesh 
465a6d6f0afSPavan Nikhilesh 	return SIZE_MAX;
466a6d6f0afSPavan Nikhilesh }
467a6d6f0afSPavan Nikhilesh 
4683813a10aSJerin Jacob int
4693151e6a6SHarman Kalra octeontx_pko_send_mtu(int port, int mtu)
4703151e6a6SHarman Kalra {
4713151e6a6SHarman Kalra 	struct octeontx_mbox_hdr hdr;
4723151e6a6SHarman Kalra 	int res;
4733151e6a6SHarman Kalra 	mbox_pko_mtu_cfg_t cfg;
4743151e6a6SHarman Kalra 
4753151e6a6SHarman Kalra 	cfg.mtu = mtu;
4763151e6a6SHarman Kalra 
4773151e6a6SHarman Kalra 	hdr.coproc = OCTEONTX_PKO_COPROC;
4783151e6a6SHarman Kalra 	hdr.msg = MBOX_PKO_MTU_CONFIG;
4793151e6a6SHarman Kalra 	hdr.vfid = port;
4803151e6a6SHarman Kalra 
4813151e6a6SHarman Kalra 	res = octeontx_mbox_send(&hdr, &cfg, sizeof(mbox_pko_mtu_cfg_t),
4823151e6a6SHarman Kalra 				 NULL, 0);
4833151e6a6SHarman Kalra 	if (res < 0)
4843151e6a6SHarman Kalra 		return -EACCES;
4853151e6a6SHarman Kalra 
4863151e6a6SHarman Kalra 	return res;
4873151e6a6SHarman Kalra }
4883151e6a6SHarman Kalra 
4893151e6a6SHarman Kalra int
4903813a10aSJerin Jacob octeontx_pko_init_fc(const size_t pko_vf_count)
4913813a10aSJerin Jacob {
4923813a10aSJerin Jacob 	int dq_ix;
4933813a10aSJerin Jacob 	uint64_t reg;
4943813a10aSJerin Jacob 	uint8_t *vf_bar0;
4953813a10aSJerin Jacob 	size_t vf_idx;
4963813a10aSJerin Jacob 	size_t fc_mem_size;
4973813a10aSJerin Jacob 
4983813a10aSJerin Jacob 	fc_mem_size = sizeof(struct octeontx_pko_fc_ctl_s) *
4993813a10aSJerin Jacob 			pko_vf_count * PKO_VF_NUM_DQ;
5003813a10aSJerin Jacob 
5013813a10aSJerin Jacob 	pko_vf_ctl.fc_iomem.va = rte_malloc(NULL, fc_mem_size, 128);
5023813a10aSJerin Jacob 	if (unlikely(!pko_vf_ctl.fc_iomem.va)) {
5033813a10aSJerin Jacob 		octeontx_log_err("fc_iomem: not enough memory");
5043813a10aSJerin Jacob 		return -ENOMEM;
5053813a10aSJerin Jacob 	}
5063813a10aSJerin Jacob 
50787cf4c6cSThomas Monjalon 	pko_vf_ctl.fc_iomem.iova = rte_malloc_virt2iova((void *)
5083813a10aSJerin Jacob 							pko_vf_ctl.fc_iomem.va);
5093813a10aSJerin Jacob 	pko_vf_ctl.fc_iomem.size = fc_mem_size;
5103813a10aSJerin Jacob 
5113813a10aSJerin Jacob 	pko_vf_ctl.fc_ctl =
5123813a10aSJerin Jacob 		(struct octeontx_pko_fc_ctl_s *)pko_vf_ctl.fc_iomem.va;
5133813a10aSJerin Jacob 
5143813a10aSJerin Jacob 	/* Configure Flow-Control feature for all DQs of open VFs */
5153813a10aSJerin Jacob 	for (vf_idx = 0; vf_idx < pko_vf_count; vf_idx++) {
516a6d6f0afSPavan Nikhilesh 		if (pko_vf_ctl.pko[vf_idx].domain != pko_vf_ctl.global_domain)
517a6d6f0afSPavan Nikhilesh 			continue;
5183813a10aSJerin Jacob 
519a6d6f0afSPavan Nikhilesh 		dq_ix = pko_vf_ctl.pko[vf_idx].vfid * PKO_VF_NUM_DQ;
5203813a10aSJerin Jacob 		vf_bar0 = pko_vf_ctl.pko[vf_idx].bar0;
5213813a10aSJerin Jacob 
5223813a10aSJerin Jacob 		reg = (pko_vf_ctl.fc_iomem.iova +
5233813a10aSJerin Jacob 			(sizeof(struct octeontx_pko_fc_ctl_s) * dq_ix)) & ~0x7F;
5243813a10aSJerin Jacob 		reg |=			/* BASE */
5253813a10aSJerin Jacob 		    (0x2 << 3) |	/* HYST_BITS */
5263813a10aSJerin Jacob 		    (((PKO_DQ_FC_STRIDE == PKO_DQ_FC_STRIDE_16) ? 1 : 0) << 2) |
5273813a10aSJerin Jacob 		    (0x1 << 0);		/* ENABLE */
5283813a10aSJerin Jacob 
5293813a10aSJerin Jacob 		octeontx_write64(reg, vf_bar0 + PKO_VF_DQ_FC_CONFIG);
530a6d6f0afSPavan Nikhilesh 		pko_vf_ctl.pko[vf_idx].status = PKO_VALID;
5313813a10aSJerin Jacob 
5323813a10aSJerin Jacob 		octeontx_log_dbg("PKO: bar0 %p VF_idx %d DQ_FC_CFG=%" PRIx64 "",
5333813a10aSJerin Jacob 				 vf_bar0, (int)vf_idx, reg);
5343813a10aSJerin Jacob 	}
5353813a10aSJerin Jacob 	return 0;
5363813a10aSJerin Jacob }
5373813a10aSJerin Jacob 
5383813a10aSJerin Jacob void
5393813a10aSJerin Jacob octeontx_pko_fc_free(void)
5403813a10aSJerin Jacob {
5413813a10aSJerin Jacob 	rte_free(pko_vf_ctl.fc_iomem.va);
5423813a10aSJerin Jacob }
5433813a10aSJerin Jacob 
544445371e8SJerin Jacob static void
545445371e8SJerin Jacob octeontx_pkovf_setup(void)
546445371e8SJerin Jacob {
547445371e8SJerin Jacob 	static bool init_once;
548445371e8SJerin Jacob 
549445371e8SJerin Jacob 	if (!init_once) {
550445371e8SJerin Jacob 		unsigned int i;
551445371e8SJerin Jacob 
552445371e8SJerin Jacob 		rte_spinlock_init(&pko_vf_ctl.lock);
553445371e8SJerin Jacob 
554445371e8SJerin Jacob 		pko_vf_ctl.fc_iomem = PKO_IOMEM_NULL;
555445371e8SJerin Jacob 		pko_vf_ctl.fc_ctl = NULL;
556445371e8SJerin Jacob 
557445371e8SJerin Jacob 		for (i = 0; i < PKO_VF_MAX; i++) {
558445371e8SJerin Jacob 			pko_vf_ctl.pko[i].bar0 = NULL;
559445371e8SJerin Jacob 			pko_vf_ctl.pko[i].bar2 = NULL;
560445371e8SJerin Jacob 			pko_vf_ctl.pko[i].domain = ~(uint16_t)0;
561445371e8SJerin Jacob 			pko_vf_ctl.pko[i].vfid = ~(uint16_t)0;
562445371e8SJerin Jacob 		}
563445371e8SJerin Jacob 
564445371e8SJerin Jacob 		for (i = 0; i < (PKO_VF_MAX * PKO_VF_NUM_DQ); i++)
565445371e8SJerin Jacob 			pko_vf_ctl.dq_map[i].chanid = 0;
566445371e8SJerin Jacob 
567445371e8SJerin Jacob 		init_once = true;
568445371e8SJerin Jacob 	}
569445371e8SJerin Jacob }
570445371e8SJerin Jacob 
571445371e8SJerin Jacob /* PKOVF pcie device*/
572445371e8SJerin Jacob static int
573445371e8SJerin Jacob pkovf_probe(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev)
574445371e8SJerin Jacob {
575445371e8SJerin Jacob 	uint64_t val;
576445371e8SJerin Jacob 	uint16_t vfid;
577445371e8SJerin Jacob 	uint16_t domain;
578445371e8SJerin Jacob 	uint8_t *bar0;
579445371e8SJerin Jacob 	uint8_t *bar2;
580a6d6f0afSPavan Nikhilesh 	static uint8_t vf_cnt;
581445371e8SJerin Jacob 	struct octeontx_pkovf *res;
582445371e8SJerin Jacob 
583445371e8SJerin Jacob 	RTE_SET_USED(pci_drv);
584445371e8SJerin Jacob 
585445371e8SJerin Jacob 	/* For secondary processes, the primary has done all the work */
586445371e8SJerin Jacob 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
587445371e8SJerin Jacob 		return 0;
588445371e8SJerin Jacob 
589445371e8SJerin Jacob 	if (pci_dev->mem_resource[0].addr == NULL ||
590445371e8SJerin Jacob 	    pci_dev->mem_resource[2].addr == NULL) {
591445371e8SJerin Jacob 		octeontx_log_err("Empty bars %p %p",
592445371e8SJerin Jacob 			pci_dev->mem_resource[0].addr,
593445371e8SJerin Jacob 			pci_dev->mem_resource[2].addr);
594445371e8SJerin Jacob 		return -ENODEV;
595445371e8SJerin Jacob 	}
596445371e8SJerin Jacob 	bar0 = pci_dev->mem_resource[0].addr;
597445371e8SJerin Jacob 	bar2 = pci_dev->mem_resource[2].addr;
598445371e8SJerin Jacob 
599445371e8SJerin Jacob 	octeontx_pkovf_setup();
600445371e8SJerin Jacob 
601445371e8SJerin Jacob 	/* get vfid and domain */
602445371e8SJerin Jacob 	val = octeontx_read64(bar0 + PKO_VF_DQ_FC_CONFIG);
603445371e8SJerin Jacob 	domain = (val >> 7) & 0xffff;
604445371e8SJerin Jacob 	vfid = (val >> 23) & 0xffff;
605445371e8SJerin Jacob 
606445371e8SJerin Jacob 	if (unlikely(vfid >= PKO_VF_MAX)) {
607445371e8SJerin Jacob 		octeontx_log_err("pko: Invalid vfid %d", vfid);
608445371e8SJerin Jacob 		return -EINVAL;
609445371e8SJerin Jacob 	}
610445371e8SJerin Jacob 
611a6d6f0afSPavan Nikhilesh 	res = &pko_vf_ctl.pko[vf_cnt++];
612445371e8SJerin Jacob 	res->vfid = vfid;
613445371e8SJerin Jacob 	res->domain = domain;
614445371e8SJerin Jacob 	res->bar0 = bar0;
615445371e8SJerin Jacob 	res->bar2 = bar2;
616445371e8SJerin Jacob 
617445371e8SJerin Jacob 	octeontx_log_dbg("Domain=%d group=%d", res->domain, res->vfid);
618445371e8SJerin Jacob 	return 0;
619445371e8SJerin Jacob }
620445371e8SJerin Jacob 
621445371e8SJerin Jacob #define PCI_VENDOR_ID_CAVIUM               0x177D
622445371e8SJerin Jacob #define PCI_DEVICE_ID_OCTEONTX_PKO_VF      0xA049
623445371e8SJerin Jacob 
624445371e8SJerin Jacob static const struct rte_pci_id pci_pkovf_map[] = {
625445371e8SJerin Jacob 	{
626445371e8SJerin Jacob 		RTE_PCI_DEVICE(PCI_VENDOR_ID_CAVIUM,
627445371e8SJerin Jacob 				PCI_DEVICE_ID_OCTEONTX_PKO_VF)
628445371e8SJerin Jacob 	},
629445371e8SJerin Jacob 	{
630445371e8SJerin Jacob 		.vendor_id = 0,
631445371e8SJerin Jacob 	},
632445371e8SJerin Jacob };
633445371e8SJerin Jacob 
634445371e8SJerin Jacob static struct rte_pci_driver pci_pkovf = {
635445371e8SJerin Jacob 	.id_table = pci_pkovf_map,
636445371e8SJerin Jacob 	.drv_flags = RTE_PCI_DRV_NEED_MAPPING,
637445371e8SJerin Jacob 	.probe = pkovf_probe,
638445371e8SJerin Jacob };
639445371e8SJerin Jacob 
640445371e8SJerin Jacob RTE_PMD_REGISTER_PCI(octeontx_pkovf, pci_pkovf);
641