Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2024 ZTE Corporation
3 : : */
4 : :
5 : : #include <stdint.h>
6 : : #include <unistd.h>
7 : :
8 : : #include <rte_io.h>
9 : : #include <rte_bus.h>
10 : : #include <rte_pci.h>
11 : : #include <rte_common.h>
12 : : #include <rte_cycles.h>
13 : :
14 : : #include "zxdh_ethdev.h"
15 : : #include "zxdh_pci.h"
16 : : #include "zxdh_logs.h"
17 : : #include "zxdh_queue.h"
18 : :
19 : : #define ZXDH_PMD_DEFAULT_GUEST_FEATURES \
20 : : (1ULL << ZXDH_NET_F_MRG_RXBUF | \
21 : : 1ULL << ZXDH_NET_F_STATUS | \
22 : : 1ULL << ZXDH_NET_F_MQ | \
23 : : 1ULL << ZXDH_F_ANY_LAYOUT | \
24 : : 1ULL << ZXDH_F_VERSION_1 | \
25 : : 1ULL << ZXDH_F_RING_PACKED | \
26 : : 1ULL << ZXDH_F_IN_ORDER | \
27 : : 1ULL << ZXDH_F_NOTIFICATION_DATA | \
28 : : 1ULL << ZXDH_NET_F_MAC)
29 : :
30 : : #define ZXDH_PMD_DEFAULT_HOST_FEATURES \
31 : : (1ULL << ZXDH_NET_F_MRG_RXBUF | \
32 : : 1ULL << ZXDH_NET_F_STATUS | \
33 : : 1ULL << ZXDH_NET_F_MQ | \
34 : : 1ULL << ZXDH_F_ANY_LAYOUT | \
35 : : 1ULL << ZXDH_F_VERSION_1 | \
36 : : 1ULL << ZXDH_F_RING_PACKED | \
37 : : 1ULL << ZXDH_F_IN_ORDER | \
38 : : 1ULL << ZXDH_F_NOTIFICATION_DATA |\
39 : : 1ULL << ZXDH_NET_F_MAC | \
40 : : 1ULL << ZXDH_NET_F_CSUM |\
41 : : 1ULL << ZXDH_NET_F_GUEST_CSUM |\
42 : : 1ULL << ZXDH_NET_F_GUEST_TSO4 |\
43 : : 1ULL << ZXDH_NET_F_GUEST_TSO6 |\
44 : : 1ULL << ZXDH_NET_F_HOST_TSO4 |\
45 : : 1ULL << ZXDH_NET_F_HOST_TSO6)
46 : :
47 : : static void
48 : 0 : zxdh_read_dev_config(struct zxdh_hw *hw, size_t offset,
49 : : void *dst, int32_t length)
50 : : {
51 : : int32_t i = 0;
52 : : uint8_t *p = NULL;
53 : : uint8_t old_gen = 0;
54 : : uint8_t new_gen = 0;
55 : :
56 : : do {
57 : 0 : old_gen = rte_read8(&hw->common_cfg->config_generation);
58 : :
59 : : p = dst;
60 [ # # ]: 0 : for (i = 0; i < length; i++)
61 : 0 : *p++ = rte_read8((uint8_t *)hw->dev_cfg + offset + i);
62 : :
63 : 0 : new_gen = rte_read8(&hw->common_cfg->config_generation);
64 [ # # ]: 0 : } while (old_gen != new_gen);
65 : 0 : }
66 : :
67 : : static void
68 : 0 : zxdh_write_dev_config(struct zxdh_hw *hw, size_t offset,
69 : : const void *src, int32_t length)
70 : : {
71 : : int32_t i = 0;
72 : : const uint8_t *p = src;
73 : :
74 [ # # ]: 0 : for (i = 0; i < length; i++)
75 : 0 : rte_write8((*p++), (((uint8_t *)hw->dev_cfg) + offset + i));
76 : 0 : }
77 : :
78 : : static uint8_t
79 : 0 : zxdh_get_status(struct zxdh_hw *hw)
80 : : {
81 : 0 : return rte_read8(&hw->common_cfg->device_status);
82 : : }
83 : :
84 : : static void
85 : 0 : zxdh_set_status(struct zxdh_hw *hw, uint8_t status)
86 : : {
87 : 0 : rte_write8(status, &hw->common_cfg->device_status);
88 : 0 : }
89 : :
90 : : static uint64_t
91 : 0 : zxdh_get_features(struct zxdh_hw *hw)
92 : : {
93 : : uint32_t features_lo = 0;
94 : : uint32_t features_hi = 0;
95 : :
96 : 0 : rte_write32(0, &hw->common_cfg->device_feature_select);
97 : 0 : features_lo = rte_read32(&hw->common_cfg->device_feature);
98 : :
99 : 0 : rte_write32(1, &hw->common_cfg->device_feature_select);
100 : 0 : features_hi = rte_read32(&hw->common_cfg->device_feature);
101 : :
102 : 0 : return ((uint64_t)features_hi << 32) | features_lo;
103 : : }
104 : :
105 : : static void
106 : 0 : zxdh_set_features(struct zxdh_hw *hw, uint64_t features)
107 : : {
108 : 0 : rte_write32(0, &hw->common_cfg->guest_feature_select);
109 : 0 : rte_write32(features & ((1ULL << 32) - 1), &hw->common_cfg->guest_feature);
110 : 0 : rte_write32(1, &hw->common_cfg->guest_feature_select);
111 : 0 : rte_write32(features >> 32, &hw->common_cfg->guest_feature);
112 : 0 : }
113 : :
114 : : static uint16_t
115 : 0 : zxdh_set_config_irq(struct zxdh_hw *hw, uint16_t vec)
116 : : {
117 : 0 : rte_write16(vec, &hw->common_cfg->msix_config);
118 : 0 : return rte_read16(&hw->common_cfg->msix_config);
119 : : }
120 : :
121 : : static uint16_t
122 : 0 : zxdh_set_queue_irq(struct zxdh_hw *hw, struct zxdh_virtqueue *vq, uint16_t vec)
123 : : {
124 : 0 : rte_write16(vq->vq_queue_index, &hw->common_cfg->queue_select);
125 : 0 : rte_write16(vec, &hw->common_cfg->queue_msix_vector);
126 : 0 : return rte_read16(&hw->common_cfg->queue_msix_vector);
127 : : }
128 : :
129 : : static uint8_t
130 : 0 : zxdh_get_isr(struct zxdh_hw *hw)
131 : : {
132 : 0 : return rte_read8(hw->isr);
133 : : }
134 : :
135 : : static uint16_t
136 : 0 : zxdh_get_queue_num(struct zxdh_hw *hw, uint16_t queue_id)
137 : : {
138 : 0 : rte_write16(queue_id, &hw->common_cfg->queue_select);
139 : 0 : return rte_read16(&hw->common_cfg->queue_size);
140 : : }
141 : :
142 : : static void
143 : 0 : zxdh_set_queue_num(struct zxdh_hw *hw, uint16_t queue_id, uint16_t vq_size)
144 : : {
145 : 0 : rte_write16(queue_id, &hw->common_cfg->queue_select);
146 : 0 : rte_write16(vq_size, &hw->common_cfg->queue_size);
147 : 0 : }
148 : :
149 : : static int32_t
150 : 0 : check_vq_phys_addr_ok(struct zxdh_virtqueue *vq)
151 : : {
152 [ # # ]: 0 : if ((vq->vq_ring_mem + vq->vq_ring_size - 1) >> (ZXDH_PCI_QUEUE_ADDR_SHIFT + 32)) {
153 : 0 : PMD_DRV_LOG(ERR, "vring address shouldn't be above 16TB!");
154 : 0 : return 0;
155 : : }
156 : : return 1;
157 : : }
158 : :
159 : : static inline void
160 : : io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi)
161 : : {
162 : 0 : rte_write32(val & ((1ULL << 32) - 1), lo);
163 : 0 : rte_write32(val >> 32, hi);
164 : : }
165 : :
166 : : static int32_t
167 : 0 : zxdh_setup_queue(struct zxdh_hw *hw, struct zxdh_virtqueue *vq)
168 : : {
169 : : uint64_t desc_addr = 0;
170 : : uint64_t avail_addr = 0;
171 : : uint64_t used_addr = 0;
172 : : uint16_t notify_off = 0;
173 : :
174 [ # # ]: 0 : if (!check_vq_phys_addr_ok(vq))
175 : : return -1;
176 : :
177 : 0 : desc_addr = vq->vq_ring_mem;
178 : 0 : avail_addr = desc_addr + vq->vq_nentries * sizeof(struct zxdh_vring_desc);
179 [ # # ]: 0 : if (zxdh_pci_packed_queue(vq->hw)) {
180 : 0 : used_addr = RTE_ALIGN_CEIL((avail_addr +
181 : : sizeof(struct zxdh_vring_packed_desc_event)),
182 : : ZXDH_PCI_VRING_ALIGN);
183 : : } else {
184 : 0 : used_addr = RTE_ALIGN_CEIL(avail_addr + offsetof(struct zxdh_vring_avail,
185 : : ring[vq->vq_nentries]), ZXDH_PCI_VRING_ALIGN);
186 : : }
187 : :
188 : 0 : rte_write16(vq->vq_queue_index, &hw->common_cfg->queue_select);
189 : :
190 : : io_write64_twopart(desc_addr, &hw->common_cfg->queue_desc_lo,
191 : 0 : &hw->common_cfg->queue_desc_hi);
192 : : io_write64_twopart(avail_addr, &hw->common_cfg->queue_avail_lo,
193 : 0 : &hw->common_cfg->queue_avail_hi);
194 : : io_write64_twopart(used_addr, &hw->common_cfg->queue_used_lo,
195 : 0 : &hw->common_cfg->queue_used_hi);
196 : :
197 : 0 : notify_off = rte_read16(&hw->common_cfg->queue_notify_off); /* default 0 */
198 : : notify_off = 0;
199 : 0 : vq->notify_addr = (void *)((uint8_t *)hw->notify_base +
200 : : notify_off * hw->notify_off_multiplier);
201 : :
202 : 0 : rte_write16(1, &hw->common_cfg->queue_enable);
203 : :
204 : 0 : return 0;
205 : : }
206 : :
207 : : static void
208 : 0 : zxdh_del_queue(struct zxdh_hw *hw, struct zxdh_virtqueue *vq)
209 : : {
210 : 0 : rte_write16(vq->vq_queue_index, &hw->common_cfg->queue_select);
211 : :
212 : : io_write64_twopart(0, &hw->common_cfg->queue_desc_lo,
213 : 0 : &hw->common_cfg->queue_desc_hi);
214 : : io_write64_twopart(0, &hw->common_cfg->queue_avail_lo,
215 : 0 : &hw->common_cfg->queue_avail_hi);
216 : : io_write64_twopart(0, &hw->common_cfg->queue_used_lo,
217 : 0 : &hw->common_cfg->queue_used_hi);
218 : :
219 : 0 : rte_write16(0, &hw->common_cfg->queue_enable);
220 : 0 : }
221 : :
222 : : static void
223 [ # # ]: 0 : zxdh_notify_queue(struct zxdh_hw *hw, struct zxdh_virtqueue *vq)
224 : : {
225 : : uint32_t notify_data = 0;
226 : :
227 [ # # ]: 0 : if (!zxdh_pci_with_feature(hw, ZXDH_F_NOTIFICATION_DATA)) {
228 : 0 : rte_write16(vq->vq_queue_index, vq->notify_addr);
229 : 0 : return;
230 : : }
231 : :
232 [ # # ]: 0 : notify_data = ((uint32_t)vq->vq_avail_idx << 16) | vq->vq_queue_index;
233 [ # # ]: 0 : if (zxdh_pci_with_feature(hw, ZXDH_F_RING_PACKED) &&
234 [ # # ]: 0 : (vq->vq_packed.cached_flags & ZXDH_VRING_PACKED_DESC_F_AVAIL))
235 : 0 : notify_data |= RTE_BIT32(31);
236 : :
237 : 0 : PMD_DRV_LOG(DEBUG, "queue:%d notify_data 0x%x notify_addr 0x%p",
238 : : vq->vq_queue_index, notify_data, vq->notify_addr);
239 : 0 : rte_write32(notify_data, vq->notify_addr);
240 : : }
241 : :
242 : : const struct zxdh_pci_ops zxdh_dev_pci_ops = {
243 : : .read_dev_cfg = zxdh_read_dev_config,
244 : : .write_dev_cfg = zxdh_write_dev_config,
245 : : .get_status = zxdh_get_status,
246 : : .set_status = zxdh_set_status,
247 : : .get_features = zxdh_get_features,
248 : : .set_features = zxdh_set_features,
249 : : .set_queue_irq = zxdh_set_queue_irq,
250 : : .set_config_irq = zxdh_set_config_irq,
251 : : .get_isr = zxdh_get_isr,
252 : : .get_queue_num = zxdh_get_queue_num,
253 : : .set_queue_num = zxdh_set_queue_num,
254 : : .setup_queue = zxdh_setup_queue,
255 : : .del_queue = zxdh_del_queue,
256 : : .notify_queue = zxdh_notify_queue,
257 : : };
258 : :
259 : : uint8_t
260 : 0 : zxdh_pci_isr(struct zxdh_hw *hw)
261 : : {
262 : 0 : return ZXDH_VTPCI_OPS(hw)->get_isr(hw);
263 : : }
264 : :
265 : : uint16_t
266 : 0 : zxdh_pci_get_features(struct zxdh_hw *hw)
267 : : {
268 : 0 : return ZXDH_VTPCI_OPS(hw)->get_features(hw);
269 : : }
270 : :
271 : : void
272 : 0 : zxdh_pci_reset(struct zxdh_hw *hw)
273 : : {
274 : 0 : PMD_DRV_LOG(INFO, "port %u device start reset, just wait", hw->port_id);
275 : : uint32_t retry = 0;
276 : :
277 : 0 : ZXDH_VTPCI_OPS(hw)->set_status(hw, ZXDH_CONFIG_STATUS_RESET);
278 : : /* Flush status write and wait device ready max 3 seconds. */
279 [ # # ]: 0 : while (ZXDH_VTPCI_OPS(hw)->get_status(hw) != ZXDH_CONFIG_STATUS_RESET) {
280 : 0 : ++retry;
281 : : rte_delay_ms(1);
282 : : }
283 : 0 : PMD_DRV_LOG(INFO, "port %u device reset %u ms done", hw->port_id, retry);
284 : 0 : }
285 : :
286 : : void
287 : 0 : zxdh_pci_reinit_complete(struct zxdh_hw *hw)
288 : : {
289 : 0 : zxdh_pci_set_status(hw, ZXDH_CONFIG_STATUS_DRIVER_OK);
290 : 0 : }
291 : :
292 : : void
293 : 0 : zxdh_pci_set_status(struct zxdh_hw *hw, uint8_t status)
294 : : {
295 [ # # ]: 0 : if (status != ZXDH_CONFIG_STATUS_RESET)
296 : 0 : status |= ZXDH_VTPCI_OPS(hw)->get_status(hw);
297 : :
298 : 0 : ZXDH_VTPCI_OPS(hw)->set_status(hw, status);
299 : 0 : }
300 : :
301 : : static void
302 : 0 : *get_cfg_addr(struct rte_pci_device *dev, struct zxdh_pci_cap *cap)
303 : : {
304 : 0 : uint8_t bar = cap->bar;
305 : 0 : uint32_t length = cap->length;
306 : 0 : uint32_t offset = cap->offset;
307 : :
308 [ # # ]: 0 : if (bar >= PCI_MAX_RESOURCE) {
309 : 0 : PMD_DRV_LOG(ERR, "invalid bar: %u", bar);
310 : 0 : return NULL;
311 : : }
312 [ # # ]: 0 : if (offset + length < offset) {
313 : 0 : PMD_DRV_LOG(ERR, "offset(%u) + length(%u) overflows", offset, length);
314 : 0 : return NULL;
315 : : }
316 [ # # ]: 0 : if (offset + length > dev->mem_resource[bar].len) {
317 : 0 : PMD_DRV_LOG(ERR, "invalid cap: overflows bar space");
318 : 0 : return NULL;
319 : : }
320 : 0 : uint8_t *base = dev->mem_resource[bar].addr;
321 : :
322 [ # # ]: 0 : if (base == NULL) {
323 : 0 : PMD_DRV_LOG(ERR, "bar %u base addr is NULL", bar);
324 : 0 : return NULL;
325 : : }
326 : 0 : return base + offset;
327 : : }
328 : :
329 : : int32_t
330 : 0 : zxdh_read_pci_caps(struct rte_pci_device *dev, struct zxdh_hw *hw)
331 : : {
332 : : struct zxdh_pci_cap cap;
333 : : uint8_t pos = 0;
334 : : int32_t ret = 0;
335 : :
336 [ # # ]: 0 : if (dev->mem_resource[0].addr == NULL) {
337 : 0 : PMD_DRV_LOG(ERR, "bar0 base addr is NULL");
338 : 0 : return -1;
339 : : }
340 : :
341 : 0 : hw->use_msix = zxdh_pci_msix_detect(dev);
342 : :
343 : 0 : pos = rte_pci_find_capability(dev, RTE_PCI_CAP_ID_VNDR);
344 [ # # ]: 0 : while (pos) {
345 : 0 : ret = rte_pci_read_config(dev, &cap, sizeof(cap), pos);
346 [ # # ]: 0 : if (ret != sizeof(cap)) {
347 : 0 : PMD_DRV_LOG(ERR, "failed to read pci cap at pos: %x ret %d", pos, ret);
348 : 0 : break;
349 : : }
350 [ # # ]: 0 : if (cap.cap_vndr != RTE_PCI_CAP_ID_VNDR) {
351 : 0 : PMD_DRV_LOG(DEBUG, "[%2x] skipping non VNDR cap id: %02x",
352 : : pos, cap.cap_vndr);
353 : 0 : goto next;
354 : : }
355 : 0 : PMD_DRV_LOG(DEBUG, "[%2x] cfg type: %u, bar: %u, offset: %04x, len: %u",
356 : : pos, cap.cfg_type, cap.bar, cap.offset, cap.length);
357 : :
358 [ # # # # : 0 : switch (cap.cfg_type) {
# # ]
359 : 0 : case ZXDH_PCI_CAP_COMMON_CFG:
360 : 0 : hw->common_cfg = get_cfg_addr(dev, &cap);
361 : 0 : break;
362 : 0 : case ZXDH_PCI_CAP_NOTIFY_CFG: {
363 : 0 : ret = rte_pci_read_config(dev, &hw->notify_off_multiplier,
364 : 0 : 4, pos + sizeof(cap));
365 [ # # ]: 0 : if (ret != 4)
366 : 0 : PMD_DRV_LOG(ERR,
367 : : "failed to read notify_off_multiplier, ret %d", ret);
368 : : else
369 : 0 : hw->notify_base = get_cfg_addr(dev, &cap);
370 : : break;
371 : : }
372 : 0 : case ZXDH_PCI_CAP_DEVICE_CFG:
373 : 0 : hw->dev_cfg = get_cfg_addr(dev, &cap);
374 : 0 : break;
375 : 0 : case ZXDH_PCI_CAP_ISR_CFG:
376 : 0 : hw->isr = get_cfg_addr(dev, &cap);
377 : 0 : break;
378 : 0 : case ZXDH_PCI_CAP_PCI_CFG: {
379 : 0 : hw->pcie_id = *(uint16_t *)&cap.padding[1];
380 : 0 : PMD_DRV_LOG(DEBUG, "get pcie id 0x%x", hw->pcie_id);
381 : :
382 [ # # ]: 0 : if ((hw->pcie_id >> 11) & 0x1) /* PF */ {
383 : 0 : PMD_DRV_LOG(DEBUG, "EP %u PF %u",
384 : : hw->pcie_id >> 12, (hw->pcie_id >> 8) & 0x7);
385 : : } else { /* VF */
386 : 0 : PMD_DRV_LOG(DEBUG, "EP %u PF %u VF %u",
387 : : hw->pcie_id >> 12,
388 : : (hw->pcie_id >> 8) & 0x7,
389 : : hw->pcie_id & 0xff);
390 : : }
391 : : break;
392 : : }
393 : : }
394 : 0 : next:
395 : 0 : pos = cap.cap_next;
396 : : }
397 [ # # # # ]: 0 : if (hw->common_cfg == NULL || hw->notify_base == NULL ||
398 [ # # # # ]: 0 : hw->dev_cfg == NULL || hw->isr == NULL) {
399 : 0 : PMD_DRV_LOG(ERR, "no zxdh pci device found");
400 : 0 : return -1;
401 : : }
402 : : return 0;
403 : : }
404 : :
405 : : void
406 : 0 : zxdh_pci_read_dev_config(struct zxdh_hw *hw, size_t offset, void *dst, int32_t length)
407 : : {
408 : 0 : ZXDH_VTPCI_OPS(hw)->read_dev_cfg(hw, offset, dst, length);
409 : 0 : }
410 : :
411 : 0 : void zxdh_pci_write_dev_config(struct zxdh_hw *hw, size_t offset, const void *src, int32_t length)
412 : : {
413 : 0 : ZXDH_VTPCI_OPS(hw)->write_dev_cfg(hw, offset, src, length);
414 : 0 : }
415 : :
416 : : void
417 : 0 : zxdh_get_pci_dev_config(struct zxdh_hw *hw)
418 : : {
419 : : uint64_t guest_features = 0;
420 : : uint64_t nego_features = 0;
421 : :
422 : 0 : hw->host_features = ZXDH_PMD_DEFAULT_HOST_FEATURES;
423 : :
424 : : guest_features = (uint64_t)ZXDH_PMD_DEFAULT_GUEST_FEATURES;
425 : : nego_features = guest_features & hw->host_features;
426 : :
427 : 0 : hw->guest_features = nego_features;
428 : :
429 : : if (hw->guest_features & (1ULL << ZXDH_NET_F_MAC)) {
430 : 0 : zxdh_pci_read_dev_config(hw, offsetof(struct zxdh_net_config, mac),
431 : 0 : &hw->mac_addr, RTE_ETHER_ADDR_LEN);
432 : : } else {
433 : : rte_eth_random_addr(&hw->mac_addr[0]);
434 : : }
435 : 0 : }
436 : :
437 : 0 : enum zxdh_msix_status zxdh_pci_msix_detect(struct rte_pci_device *dev)
438 : : {
439 : 0 : uint16_t flags = 0;
440 : : uint8_t pos = 0;
441 : : int16_t ret = 0;
442 : :
443 : 0 : pos = rte_pci_find_capability(dev, RTE_PCI_CAP_ID_MSIX);
444 : :
445 [ # # ]: 0 : if (pos > 0) {
446 : 0 : ret = rte_pci_read_config(dev, &flags, 2, pos + RTE_PCI_MSIX_FLAGS);
447 [ # # # # ]: 0 : if (ret == 2 && flags & RTE_PCI_MSIX_FLAGS_ENABLE)
448 : : return ZXDH_MSIX_ENABLED;
449 : : else
450 : 0 : return ZXDH_MSIX_DISABLED;
451 : : }
452 : : return ZXDH_MSIX_NONE;
453 : : }
|