1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2018-2022 Advanced Micro Devices, Inc.
3 */
4
5 #include <stdbool.h>
6
7 #include <rte_malloc.h>
8
9 #include "ionic_dev.h"
10 #include "ionic_lif.h"
11 #include "ionic.h"
12
13 /* Devcmd Interface */
14
15 uint8_t
ionic_dev_cmd_status(struct ionic_dev * idev)16 ionic_dev_cmd_status(struct ionic_dev *idev)
17 {
18 return ioread8(&idev->dev_cmd->comp.comp.status);
19 }
20
21 bool
ionic_dev_cmd_done(struct ionic_dev * idev)22 ionic_dev_cmd_done(struct ionic_dev *idev)
23 {
24 return ioread32(&idev->dev_cmd->done) & IONIC_DEV_CMD_DONE;
25 }
26
27 void
ionic_dev_cmd_comp(struct ionic_dev * idev,void * mem)28 ionic_dev_cmd_comp(struct ionic_dev *idev, void *mem)
29 {
30 union ionic_dev_cmd_comp *comp = mem;
31 uint32_t comp_size = RTE_DIM(comp->words);
32 uint32_t i;
33
34 for (i = 0; i < comp_size; i++)
35 comp->words[i] = ioread32(&idev->dev_cmd->comp.words[i]);
36 }
37
38 void
ionic_dev_cmd_go(struct ionic_dev * idev,union ionic_dev_cmd * cmd)39 ionic_dev_cmd_go(struct ionic_dev *idev, union ionic_dev_cmd *cmd)
40 {
41 uint32_t cmd_size = RTE_DIM(cmd->words);
42 uint32_t i;
43
44 IONIC_PRINT(DEBUG, "Sending %s (%d) via dev_cmd",
45 ionic_opcode_to_str(cmd->cmd.opcode), cmd->cmd.opcode);
46
47 for (i = 0; i < cmd_size; i++)
48 iowrite32(cmd->words[i], &idev->dev_cmd->cmd.words[i]);
49
50 iowrite32(0, &idev->dev_cmd->done);
51 iowrite32(1, &idev->dev_cmd->doorbell);
52 }
53
54 /* Device commands */
55
56 void
ionic_dev_cmd_identify(struct ionic_dev * idev,uint8_t ver)57 ionic_dev_cmd_identify(struct ionic_dev *idev, uint8_t ver)
58 {
59 union ionic_dev_cmd cmd = {
60 .identify.opcode = IONIC_CMD_IDENTIFY,
61 .identify.ver = ver,
62 };
63
64 ionic_dev_cmd_go(idev, &cmd);
65 }
66
67 void
ionic_dev_cmd_init(struct ionic_dev * idev)68 ionic_dev_cmd_init(struct ionic_dev *idev)
69 {
70 union ionic_dev_cmd cmd = {
71 .init.opcode = IONIC_CMD_INIT,
72 .init.type = 0,
73 };
74
75 ionic_dev_cmd_go(idev, &cmd);
76 }
77
78 void
ionic_dev_cmd_reset(struct ionic_dev * idev)79 ionic_dev_cmd_reset(struct ionic_dev *idev)
80 {
81 union ionic_dev_cmd cmd = {
82 .reset.opcode = IONIC_CMD_RESET,
83 };
84
85 ionic_dev_cmd_go(idev, &cmd);
86 }
87
88 /* Port commands */
89
90 void
ionic_dev_cmd_port_identify(struct ionic_dev * idev)91 ionic_dev_cmd_port_identify(struct ionic_dev *idev)
92 {
93 union ionic_dev_cmd cmd = {
94 .port_init.opcode = IONIC_CMD_PORT_IDENTIFY,
95 .port_init.index = 0,
96 };
97
98 ionic_dev_cmd_go(idev, &cmd);
99 }
100
101 void
ionic_dev_cmd_port_init(struct ionic_dev * idev)102 ionic_dev_cmd_port_init(struct ionic_dev *idev)
103 {
104 union ionic_dev_cmd cmd = {
105 .port_init.opcode = IONIC_CMD_PORT_INIT,
106 .port_init.index = 0,
107 .port_init.info_pa = rte_cpu_to_le_64(idev->port_info_pa),
108 };
109
110 ionic_dev_cmd_go(idev, &cmd);
111 }
112
113 void
ionic_dev_cmd_port_reset(struct ionic_dev * idev)114 ionic_dev_cmd_port_reset(struct ionic_dev *idev)
115 {
116 union ionic_dev_cmd cmd = {
117 .port_reset.opcode = IONIC_CMD_PORT_RESET,
118 .port_reset.index = 0,
119 };
120
121 ionic_dev_cmd_go(idev, &cmd);
122 }
123
124 void
ionic_dev_cmd_port_state(struct ionic_dev * idev,uint8_t state)125 ionic_dev_cmd_port_state(struct ionic_dev *idev, uint8_t state)
126 {
127 union ionic_dev_cmd cmd = {
128 .port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
129 .port_setattr.index = 0,
130 .port_setattr.attr = IONIC_PORT_ATTR_STATE,
131 .port_setattr.state = state,
132 };
133
134 ionic_dev_cmd_go(idev, &cmd);
135 }
136
137 void
ionic_dev_cmd_port_speed(struct ionic_dev * idev,uint32_t speed)138 ionic_dev_cmd_port_speed(struct ionic_dev *idev, uint32_t speed)
139 {
140 union ionic_dev_cmd cmd = {
141 .port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
142 .port_setattr.index = 0,
143 .port_setattr.attr = IONIC_PORT_ATTR_SPEED,
144 .port_setattr.speed = rte_cpu_to_le_32(speed),
145 };
146
147 ionic_dev_cmd_go(idev, &cmd);
148 }
149
150 void
ionic_dev_cmd_port_mtu(struct ionic_dev * idev,uint32_t mtu)151 ionic_dev_cmd_port_mtu(struct ionic_dev *idev, uint32_t mtu)
152 {
153 union ionic_dev_cmd cmd = {
154 .port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
155 .port_setattr.index = 0,
156 .port_setattr.attr = IONIC_PORT_ATTR_MTU,
157 .port_setattr.mtu = rte_cpu_to_le_32(mtu),
158 };
159
160 ionic_dev_cmd_go(idev, &cmd);
161 }
162
163 void
ionic_dev_cmd_port_autoneg(struct ionic_dev * idev,uint8_t an_enable)164 ionic_dev_cmd_port_autoneg(struct ionic_dev *idev, uint8_t an_enable)
165 {
166 union ionic_dev_cmd cmd = {
167 .port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
168 .port_setattr.index = 0,
169 .port_setattr.attr = IONIC_PORT_ATTR_AUTONEG,
170 .port_setattr.an_enable = an_enable,
171 };
172
173 ionic_dev_cmd_go(idev, &cmd);
174 }
175
176 void
ionic_dev_cmd_port_fec(struct ionic_dev * idev,uint8_t fec_type)177 ionic_dev_cmd_port_fec(struct ionic_dev *idev, uint8_t fec_type)
178 {
179 union ionic_dev_cmd cmd = {
180 .port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
181 .port_setattr.index = 0,
182 .port_setattr.attr = IONIC_PORT_ATTR_FEC,
183 .port_setattr.fec_type = fec_type,
184 };
185
186 ionic_dev_cmd_go(idev, &cmd);
187 }
188
189 void
ionic_dev_cmd_port_pause(struct ionic_dev * idev,uint8_t pause_type)190 ionic_dev_cmd_port_pause(struct ionic_dev *idev, uint8_t pause_type)
191 {
192 union ionic_dev_cmd cmd = {
193 .port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
194 .port_setattr.index = 0,
195 .port_setattr.attr = IONIC_PORT_ATTR_PAUSE,
196 .port_setattr.pause_type = pause_type,
197 };
198
199 ionic_dev_cmd_go(idev, &cmd);
200 }
201
202 void
ionic_dev_cmd_port_loopback(struct ionic_dev * idev,uint8_t loopback_mode)203 ionic_dev_cmd_port_loopback(struct ionic_dev *idev, uint8_t loopback_mode)
204 {
205 union ionic_dev_cmd cmd = {
206 .port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
207 .port_setattr.index = 0,
208 .port_setattr.attr = IONIC_PORT_ATTR_LOOPBACK,
209 .port_setattr.loopback_mode = loopback_mode,
210 };
211
212 ionic_dev_cmd_go(idev, &cmd);
213 }
214
215 /* LIF commands */
216
217 void
ionic_dev_cmd_queue_identify(struct ionic_dev * idev,uint16_t lif_type,uint8_t qtype,uint8_t qver)218 ionic_dev_cmd_queue_identify(struct ionic_dev *idev,
219 uint16_t lif_type, uint8_t qtype, uint8_t qver)
220 {
221 union ionic_dev_cmd cmd = {
222 .q_identify.opcode = IONIC_CMD_Q_IDENTIFY,
223 .q_identify.lif_type = rte_cpu_to_le_16(lif_type),
224 .q_identify.type = qtype,
225 .q_identify.ver = qver,
226 };
227
228 ionic_dev_cmd_go(idev, &cmd);
229 }
230
231 void
ionic_dev_cmd_lif_identify(struct ionic_dev * idev,uint8_t type,uint8_t ver)232 ionic_dev_cmd_lif_identify(struct ionic_dev *idev, uint8_t type, uint8_t ver)
233 {
234 union ionic_dev_cmd cmd = {
235 .lif_identify.opcode = IONIC_CMD_LIF_IDENTIFY,
236 .lif_identify.type = type,
237 .lif_identify.ver = ver,
238 };
239
240 ionic_dev_cmd_go(idev, &cmd);
241 }
242
243 void
ionic_dev_cmd_lif_init(struct ionic_dev * idev,rte_iova_t info_pa)244 ionic_dev_cmd_lif_init(struct ionic_dev *idev, rte_iova_t info_pa)
245 {
246 union ionic_dev_cmd cmd = {
247 .lif_init.opcode = IONIC_CMD_LIF_INIT,
248 .lif_init.info_pa = rte_cpu_to_le_64(info_pa),
249 };
250
251 ionic_dev_cmd_go(idev, &cmd);
252 }
253
254 void
ionic_dev_cmd_lif_reset(struct ionic_dev * idev)255 ionic_dev_cmd_lif_reset(struct ionic_dev *idev)
256 {
257 union ionic_dev_cmd cmd = {
258 .lif_init.opcode = IONIC_CMD_LIF_RESET,
259 };
260
261 ionic_dev_cmd_go(idev, &cmd);
262 }
263
264 struct ionic_doorbell *
ionic_db_map(struct ionic_lif * lif,struct ionic_queue * q)265 ionic_db_map(struct ionic_lif *lif, struct ionic_queue *q)
266 {
267 return lif->kern_dbpage + q->hw_type;
268 }
269
270 void
ionic_intr_init(struct ionic_dev * idev,struct ionic_intr_info * intr,unsigned long index)271 ionic_intr_init(struct ionic_dev *idev, struct ionic_intr_info *intr,
272 unsigned long index)
273 {
274 ionic_intr_clean(idev->intr_ctrl, index);
275 intr->index = index;
276 }
277
278 void
ionic_dev_cmd_adminq_init(struct ionic_dev * idev,struct ionic_qcq * qcq)279 ionic_dev_cmd_adminq_init(struct ionic_dev *idev, struct ionic_qcq *qcq)
280 {
281 struct ionic_queue *q = &qcq->q;
282 struct ionic_cq *cq = &qcq->cq;
283
284 union ionic_dev_cmd cmd = {
285 .q_init.opcode = IONIC_CMD_Q_INIT,
286 .q_init.type = q->type,
287 .q_init.ver = qcq->lif->qtype_info[q->type].version,
288 .q_init.index = rte_cpu_to_le_32(q->index),
289 .q_init.flags = rte_cpu_to_le_16(IONIC_QINIT_F_ENA),
290 .q_init.intr_index = rte_cpu_to_le_16(IONIC_INTR_NONE),
291 .q_init.ring_size = rte_log2_u32(q->num_descs),
292 .q_init.ring_base = rte_cpu_to_le_64(q->base_pa),
293 .q_init.cq_ring_base = rte_cpu_to_le_64(cq->base_pa),
294 };
295
296 IONIC_PRINT(DEBUG, "adminq.q_init.ver %u", cmd.q_init.ver);
297
298 ionic_dev_cmd_go(idev, &cmd);
299 }
300
301 int
ionic_cq_init(struct ionic_cq * cq,uint16_t num_descs)302 ionic_cq_init(struct ionic_cq *cq, uint16_t num_descs)
303 {
304 if (!rte_is_power_of_2(num_descs) ||
305 num_descs < IONIC_MIN_RING_DESC ||
306 num_descs > IONIC_MAX_RING_DESC) {
307 IONIC_PRINT(ERR, "%u descriptors (min: %u max: %u)",
308 num_descs, IONIC_MIN_RING_DESC, IONIC_MAX_RING_DESC);
309 return -EINVAL;
310 }
311
312 cq->num_descs = num_descs;
313 cq->size_mask = num_descs - 1;
314 cq->tail_idx = 0;
315 cq->done_color = 1;
316
317 return 0;
318 }
319
320 void
ionic_cq_reset(struct ionic_cq * cq)321 ionic_cq_reset(struct ionic_cq *cq)
322 {
323 cq->tail_idx = 0;
324 cq->done_color = 1;
325
326 memset(cq->base, 0, sizeof(struct ionic_nop_comp) * cq->num_descs);
327 }
328
329 void
ionic_cq_map(struct ionic_cq * cq,void * base,rte_iova_t base_pa)330 ionic_cq_map(struct ionic_cq *cq, void *base, rte_iova_t base_pa)
331 {
332 cq->base = base;
333 cq->base_pa = base_pa;
334 }
335
336 uint32_t
ionic_cq_service(struct ionic_cq * cq,uint32_t work_to_do,ionic_cq_cb cb,void * cb_arg)337 ionic_cq_service(struct ionic_cq *cq, uint32_t work_to_do,
338 ionic_cq_cb cb, void *cb_arg)
339 {
340 uint32_t work_done = 0;
341
342 if (work_to_do == 0)
343 return 0;
344
345 while (cb(cq, cq->tail_idx, cb_arg)) {
346 cq->tail_idx = Q_NEXT_TO_SRVC(cq, 1);
347 if (cq->tail_idx == 0)
348 cq->done_color = !cq->done_color;
349
350 if (++work_done == work_to_do)
351 break;
352 }
353
354 return work_done;
355 }
356
357 int
ionic_q_init(struct ionic_queue * q,uint32_t index,uint16_t num_descs)358 ionic_q_init(struct ionic_queue *q, uint32_t index, uint16_t num_descs)
359 {
360 uint32_t ring_size;
361
362 if (!rte_is_power_of_2(num_descs))
363 return -EINVAL;
364
365 ring_size = rte_log2_u32(num_descs);
366 if (ring_size < 2 || ring_size > 16)
367 return -EINVAL;
368
369 q->index = index;
370 q->num_descs = num_descs;
371 q->size_mask = num_descs - 1;
372 ionic_q_reset(q);
373
374 return 0;
375 }
376
377 void
ionic_q_map(struct ionic_queue * q,void * base,rte_iova_t base_pa,void * cmb_base,rte_iova_t cmb_base_pa)378 ionic_q_map(struct ionic_queue *q, void *base, rte_iova_t base_pa,
379 void *cmb_base, rte_iova_t cmb_base_pa)
380 {
381 q->base = base;
382 q->base_pa = base_pa;
383 q->cmb_base = cmb_base;
384 q->cmb_base_pa = cmb_base_pa;
385 }
386
387 void
ionic_q_sg_map(struct ionic_queue * q,void * base,rte_iova_t base_pa)388 ionic_q_sg_map(struct ionic_queue *q, void *base, rte_iova_t base_pa)
389 {
390 q->sg_base = base;
391 q->sg_base_pa = base_pa;
392 }
393
394 void
ionic_q_reset(struct ionic_queue * q)395 ionic_q_reset(struct ionic_queue *q)
396 {
397 q->head_idx = 0;
398 q->cmb_head_idx = 0;
399 q->tail_idx = 0;
400 }
401