Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(C) 2024 Marvell.
3 : : */
4 : :
5 : : #include <stdint.h>
6 : :
7 : : #include <bus_pci_driver.h>
8 : :
9 : : #include <rte_io.h>
10 : : #include <rte_malloc.h>
11 : :
12 : : #include "odm.h"
13 : : #include "odm_priv.h"
14 : :
15 : : static void
16 : 0 : odm_vchan_resc_free(struct odm_dev *odm, int qno)
17 : : {
18 : : struct odm_queue *vq = &odm->vq[qno];
19 : :
20 : 0 : rte_memzone_free(vq->iring_mz);
21 : 0 : rte_memzone_free(vq->cring_mz);
22 : 0 : rte_free(vq->extra_ins_sz);
23 : :
24 : 0 : vq->iring_mz = NULL;
25 : 0 : vq->cring_mz = NULL;
26 : 0 : vq->extra_ins_sz = NULL;
27 : 0 : }
28 : :
29 : : static int
30 : 0 : send_mbox_to_pf(struct odm_dev *odm, union odm_mbox_msg *msg, union odm_mbox_msg *rsp)
31 : : {
32 : : int retry_cnt = ODM_MBOX_RETRY_CNT;
33 : : union odm_mbox_msg pf_msg;
34 : :
35 : 0 : msg->d.err = ODM_MBOX_ERR_CODE_MAX;
36 : 0 : odm_write64(msg->u[0], odm->rbase + ODM_MBOX_VF_PF_DATA(0));
37 : 0 : odm_write64(msg->u[1], odm->rbase + ODM_MBOX_VF_PF_DATA(1));
38 : :
39 : : pf_msg.u[0] = 0;
40 : : pf_msg.u[1] = 0;
41 : 0 : pf_msg.u[0] = odm_read64(odm->rbase + ODM_MBOX_VF_PF_DATA(0));
42 : :
43 [ # # # # ]: 0 : while (pf_msg.d.rsp == 0 && retry_cnt > 0) {
44 : 0 : pf_msg.u[0] = odm_read64(odm->rbase + ODM_MBOX_VF_PF_DATA(0));
45 : 0 : --retry_cnt;
46 : : }
47 : :
48 [ # # ]: 0 : if (retry_cnt <= 0)
49 : : return -EBADE;
50 : :
51 : : pf_msg.u[1] = odm_read64(odm->rbase + ODM_MBOX_VF_PF_DATA(1));
52 : :
53 [ # # ]: 0 : if (rsp) {
54 : 0 : rsp->u[0] = pf_msg.u[0];
55 : 0 : rsp->u[1] = pf_msg.u[1];
56 : : }
57 : :
58 [ # # # # ]: 0 : if (pf_msg.d.rsp == msg->d.err && pf_msg.d.err != 0)
59 : 0 : return -EBADE;
60 : :
61 : : return 0;
62 : : }
63 : :
64 : : static int
65 : 0 : odm_queue_ring_config(struct odm_dev *odm, int vchan, int isize, int csize)
66 : : {
67 : 0 : union odm_vdma_ring_cfg_s ring_cfg = {0};
68 : : struct odm_queue *vq = &odm->vq[vchan];
69 : :
70 [ # # # # ]: 0 : if (vq->iring_mz == NULL || vq->cring_mz == NULL)
71 : : return -EINVAL;
72 : :
73 : 0 : ring_cfg.s.isize = (isize / 1024) - 1;
74 : 0 : ring_cfg.s.csize = (csize / 1024) - 1;
75 : :
76 : 0 : odm_write64(ring_cfg.u, odm->rbase + ODM_VDMA_RING_CFG(vchan));
77 : 0 : odm_write64(vq->iring_mz->iova, odm->rbase + ODM_VDMA_IRING_BADDR(vchan));
78 : 0 : odm_write64(vq->cring_mz->iova, odm->rbase + ODM_VDMA_CRING_BADDR(vchan));
79 : :
80 : 0 : return 0;
81 : : }
82 : :
83 : : int
84 : 0 : odm_enable(struct odm_dev *odm)
85 : : {
86 : : struct odm_queue *vq;
87 : : int qno, rc = 0;
88 : :
89 [ # # ]: 0 : for (qno = 0; qno < odm->num_qs; qno++) {
90 : : vq = &odm->vq[qno];
91 : :
92 : 0 : vq->desc_idx = vq->stats.completed_offset;
93 : 0 : vq->pending_submit_len = 0;
94 : 0 : vq->pending_submit_cnt = 0;
95 : 0 : vq->iring_head = 0;
96 : 0 : vq->cring_head = 0;
97 : 0 : vq->ins_ring_head = 0;
98 : 0 : vq->iring_sz_available = vq->iring_max_words;
99 : :
100 : 0 : rc = odm_queue_ring_config(odm, qno, vq->iring_max_words * 8,
101 : 0 : vq->cring_max_entry * 4);
102 [ # # ]: 0 : if (rc < 0)
103 : : break;
104 : :
105 : 0 : odm_write64(0x1, odm->rbase + ODM_VDMA_EN(qno));
106 : : }
107 : :
108 : 0 : return rc;
109 : : }
110 : :
111 : : int
112 : 0 : odm_disable(struct odm_dev *odm)
113 : : {
114 : : int qno, wait_cnt = ODM_IRING_IDLE_WAIT_CNT;
115 : : uint64_t val;
116 : :
117 : : /* Disable the queue and wait for the queue to became idle */
118 [ # # ]: 0 : for (qno = 0; qno < odm->num_qs; qno++) {
119 : 0 : odm_write64(0x0, odm->rbase + ODM_VDMA_EN(qno));
120 : : do {
121 [ # # ]: 0 : val = odm_read64(odm->rbase + ODM_VDMA_IRING_BADDR(qno));
122 [ # # # # ]: 0 : } while ((!(val & 1ULL << 63)) && (--wait_cnt > 0));
123 : : }
124 : :
125 : 0 : return 0;
126 : : }
127 : :
128 : : static int
129 : 0 : odm_get_ext_port_type(const struct rte_dma_vchan_conf *conf, uint8_t *ext_port)
130 : : {
131 : : uint8_t coreid;
132 : :
133 [ # # ]: 0 : if (conf->src_port.port_type == RTE_DMA_PORT_PCIE) {
134 : 0 : coreid = conf->src_port.pcie.coreid;
135 [ # # ]: 0 : } else if (conf->dst_port.port_type == RTE_DMA_PORT_PCIE) {
136 : 0 : coreid = conf->dst_port.pcie.coreid;
137 : : } else {
138 : 0 : *ext_port = ODM_EXT_PORT_NCB;
139 : 0 : return 0;
140 : : }
141 : :
142 [ # # # ]: 0 : switch (coreid) {
143 : 0 : case 0:
144 : 0 : *ext_port = ODM_EXT_PORT_PEM0;
145 : 0 : return 0;
146 : 0 : case 1:
147 : 0 : *ext_port = ODM_EXT_PORT_PEM1;
148 : 0 : return 0;
149 : 0 : default:
150 : 0 : ODM_LOG(ERR, "Unsupported PCIe coreid %u (only 0 and 1 are valid)", coreid);
151 : 0 : return -EINVAL;
152 : : }
153 : : }
154 : :
155 : : int
156 : 0 : odm_vchan_setup(struct odm_dev *odm, int vchan, const struct rte_dma_vchan_conf *conf)
157 : : {
158 : : struct odm_queue *vq = &odm->vq[vchan];
159 : : int isize, csize, max_nb_desc, rc = 0;
160 : : union odm_mbox_msg mbox_msg;
161 : : const struct rte_memzone *mz;
162 : : uint8_t ext_port;
163 : : char name[32];
164 : :
165 [ # # ]: 0 : if (vq->iring_mz != NULL)
166 : 0 : odm_vchan_resc_free(odm, vchan);
167 : :
168 : 0 : mbox_msg.u[0] = 0;
169 : 0 : mbox_msg.u[1] = 0;
170 : :
171 [ # # # # ]: 0 : switch (conf->direction) {
172 : 0 : case RTE_DMA_DIR_DEV_TO_MEM:
173 : 0 : vq->xtype = ODM_XTYPE_INBOUND;
174 : 0 : break;
175 : 0 : case RTE_DMA_DIR_MEM_TO_DEV:
176 : 0 : vq->xtype = ODM_XTYPE_OUTBOUND;
177 : 0 : break;
178 : 0 : case RTE_DMA_DIR_MEM_TO_MEM:
179 : 0 : vq->xtype = ODM_XTYPE_INTERNAL;
180 : 0 : break;
181 : 0 : default:
182 : 0 : ODM_LOG(ERR, "Unsupported DMA direction %d", conf->direction);
183 : 0 : return -EINVAL;
184 : : }
185 : :
186 : : /* ODM PF driver expects vfid starts from index 0 */
187 : 0 : mbox_msg.q.vfid = odm->vfid;
188 : 0 : mbox_msg.q.cmd = ODM_QUEUE_OPEN;
189 : 0 : mbox_msg.q.qidx = vchan;
190 : 0 : rc = odm_get_ext_port_type(conf, &ext_port);
191 [ # # ]: 0 : if (rc < 0)
192 : : return rc;
193 : 0 : mbox_msg.q.ext_port = ext_port;
194 : 0 : rc = send_mbox_to_pf(odm, &mbox_msg, &mbox_msg);
195 [ # # ]: 0 : if (rc < 0)
196 : : return rc;
197 : :
198 : : /* Determine instruction & completion ring sizes. */
199 : :
200 : : /* Create iring that can support nb_desc. Round up to a multiple of 1024. */
201 : 0 : isize = RTE_ALIGN_CEIL(conf->nb_desc * ODM_IRING_ENTRY_SIZE_MAX * 8, 1024);
202 : 0 : isize = RTE_MIN(isize, ODM_IRING_MAX_SIZE);
203 : 0 : snprintf(name, sizeof(name), "vq%d_iring%d", odm->vfid, vchan);
204 : 0 : mz = rte_memzone_reserve_aligned(name, isize, SOCKET_ID_ANY, 0, 1024);
205 [ # # ]: 0 : if (mz == NULL)
206 : : return -ENOMEM;
207 : 0 : vq->iring_mz = mz;
208 : 0 : vq->iring_max_words = isize / 8;
209 : :
210 : : /* Create cring that can support max instructions that can be inflight in hw. */
211 : 0 : max_nb_desc = (isize / (ODM_IRING_ENTRY_SIZE_MIN * 8));
212 : 0 : csize = RTE_ALIGN_CEIL(max_nb_desc * sizeof(union odm_cmpl_ent_s), 1024);
213 : 0 : snprintf(name, sizeof(name), "vq%d_cring%d", odm->vfid, vchan);
214 : 0 : mz = rte_memzone_reserve_aligned(name, csize, SOCKET_ID_ANY, 0, 1024);
215 [ # # ]: 0 : if (mz == NULL) {
216 : : rc = -ENOMEM;
217 : 0 : goto iring_free;
218 : : }
219 : 0 : vq->cring_mz = mz;
220 : 0 : vq->cring_max_entry = csize / 4;
221 : :
222 : : /* Allocate memory to track the size of each instruction. */
223 : 0 : snprintf(name, sizeof(name), "vq%d_extra%d", odm->vfid, vchan);
224 : 0 : vq->extra_ins_sz = rte_zmalloc(name, vq->cring_max_entry, 0);
225 [ # # ]: 0 : if (vq->extra_ins_sz == NULL) {
226 : : rc = -ENOMEM;
227 : 0 : goto cring_free;
228 : : }
229 : :
230 : 0 : vq->stats = (struct vq_stats){0};
231 : 0 : return rc;
232 : :
233 : : cring_free:
234 : 0 : rte_memzone_free(odm->vq[vchan].cring_mz);
235 : 0 : vq->cring_mz = NULL;
236 : 0 : iring_free:
237 : 0 : rte_memzone_free(odm->vq[vchan].iring_mz);
238 : 0 : vq->iring_mz = NULL;
239 : :
240 : 0 : return rc;
241 : : }
242 : :
243 : : int
244 : 0 : odm_dev_init(struct odm_dev *odm)
245 : : {
246 : 0 : struct rte_pci_device *pci_dev = odm->pci_dev;
247 : : union odm_mbox_msg mbox_msg;
248 : : uint16_t vfid;
249 : : int rc;
250 : :
251 : 0 : odm->rbase = pci_dev->mem_resource[0].addr;
252 : 0 : vfid = ((pci_dev->addr.devid & 0x1F) << 3) | (pci_dev->addr.function & 0x7);
253 : 0 : vfid -= 1;
254 : 0 : odm->vfid = vfid;
255 : 0 : odm->num_qs = 0;
256 : :
257 : 0 : mbox_msg.u[0] = 0;
258 : 0 : mbox_msg.u[1] = 0;
259 : 0 : mbox_msg.q.vfid = odm->vfid;
260 : 0 : mbox_msg.q.cmd = ODM_DEV_INIT;
261 : 0 : rc = send_mbox_to_pf(odm, &mbox_msg, &mbox_msg);
262 [ # # ]: 0 : if (!rc)
263 : 0 : odm->max_qs = 1 << (4 - mbox_msg.d.nvfs);
264 : :
265 : 0 : return rc;
266 : : }
267 : :
268 : : int
269 : 0 : odm_dev_fini(struct odm_dev *odm)
270 : : {
271 : : union odm_mbox_msg mbox_msg;
272 : : int qno, rc = 0;
273 : :
274 : 0 : mbox_msg.u[0] = 0;
275 : 0 : mbox_msg.u[1] = 0;
276 : 0 : mbox_msg.q.vfid = odm->vfid;
277 : 0 : mbox_msg.q.cmd = ODM_DEV_CLOSE;
278 : 0 : rc = send_mbox_to_pf(odm, &mbox_msg, &mbox_msg);
279 : :
280 [ # # ]: 0 : for (qno = 0; qno < odm->num_qs; qno++)
281 : 0 : odm_vchan_resc_free(odm, qno);
282 : :
283 : 0 : return rc;
284 : : }
|