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 : : const struct zxdh_pci_ops zxdh_dev_pci_ops = {
223 : : .read_dev_cfg = zxdh_read_dev_config,
224 : : .write_dev_cfg = zxdh_write_dev_config,
225 : : .get_status = zxdh_get_status,
226 : : .set_status = zxdh_set_status,
227 : : .get_features = zxdh_get_features,
228 : : .set_features = zxdh_set_features,
229 : : .set_queue_irq = zxdh_set_queue_irq,
230 : : .set_config_irq = zxdh_set_config_irq,
231 : : .get_isr = zxdh_get_isr,
232 : : .get_queue_num = zxdh_get_queue_num,
233 : : .set_queue_num = zxdh_set_queue_num,
234 : : .setup_queue = zxdh_setup_queue,
235 : : .del_queue = zxdh_del_queue,
236 : : };
237 : :
238 : : uint8_t
239 : 0 : zxdh_pci_isr(struct zxdh_hw *hw)
240 : : {
241 : 0 : return ZXDH_VTPCI_OPS(hw)->get_isr(hw);
242 : : }
243 : :
244 : : uint16_t
245 : 0 : zxdh_pci_get_features(struct zxdh_hw *hw)
246 : : {
247 : 0 : return ZXDH_VTPCI_OPS(hw)->get_features(hw);
248 : : }
249 : :
250 : : void
251 : 0 : zxdh_pci_reset(struct zxdh_hw *hw)
252 : : {
253 : 0 : PMD_DRV_LOG(INFO, "port %u device start reset, just wait", hw->port_id);
254 : : uint32_t retry = 0;
255 : :
256 : 0 : ZXDH_VTPCI_OPS(hw)->set_status(hw, ZXDH_CONFIG_STATUS_RESET);
257 : : /* Flush status write and wait device ready max 3 seconds. */
258 [ # # ]: 0 : while (ZXDH_VTPCI_OPS(hw)->get_status(hw) != ZXDH_CONFIG_STATUS_RESET) {
259 : 0 : ++retry;
260 : : rte_delay_ms(1);
261 : : }
262 : 0 : PMD_DRV_LOG(INFO, "port %u device reset %u ms done", hw->port_id, retry);
263 : 0 : }
264 : :
265 : : void
266 : 0 : zxdh_pci_reinit_complete(struct zxdh_hw *hw)
267 : : {
268 : 0 : zxdh_pci_set_status(hw, ZXDH_CONFIG_STATUS_DRIVER_OK);
269 : 0 : }
270 : :
271 : : void
272 : 0 : zxdh_pci_set_status(struct zxdh_hw *hw, uint8_t status)
273 : : {
274 [ # # ]: 0 : if (status != ZXDH_CONFIG_STATUS_RESET)
275 : 0 : status |= ZXDH_VTPCI_OPS(hw)->get_status(hw);
276 : :
277 : 0 : ZXDH_VTPCI_OPS(hw)->set_status(hw, status);
278 : 0 : }
279 : :
280 : : static void
281 : 0 : *get_cfg_addr(struct rte_pci_device *dev, struct zxdh_pci_cap *cap)
282 : : {
283 : 0 : uint8_t bar = cap->bar;
284 : 0 : uint32_t length = cap->length;
285 : 0 : uint32_t offset = cap->offset;
286 : :
287 [ # # ]: 0 : if (bar >= PCI_MAX_RESOURCE) {
288 : 0 : PMD_DRV_LOG(ERR, "invalid bar: %u", bar);
289 : 0 : return NULL;
290 : : }
291 [ # # ]: 0 : if (offset + length < offset) {
292 : 0 : PMD_DRV_LOG(ERR, "offset(%u) + length(%u) overflows", offset, length);
293 : 0 : return NULL;
294 : : }
295 [ # # ]: 0 : if (offset + length > dev->mem_resource[bar].len) {
296 : 0 : PMD_DRV_LOG(ERR, "invalid cap: overflows bar space");
297 : 0 : return NULL;
298 : : }
299 : 0 : uint8_t *base = dev->mem_resource[bar].addr;
300 : :
301 [ # # ]: 0 : if (base == NULL) {
302 : 0 : PMD_DRV_LOG(ERR, "bar %u base addr is NULL", bar);
303 : 0 : return NULL;
304 : : }
305 : 0 : return base + offset;
306 : : }
307 : :
308 : : int32_t
309 : 0 : zxdh_read_pci_caps(struct rte_pci_device *dev, struct zxdh_hw *hw)
310 : : {
311 : : struct zxdh_pci_cap cap;
312 : : uint8_t pos = 0;
313 : : int32_t ret = 0;
314 : :
315 [ # # ]: 0 : if (dev->mem_resource[0].addr == NULL) {
316 : 0 : PMD_DRV_LOG(ERR, "bar0 base addr is NULL");
317 : 0 : return -1;
318 : : }
319 : :
320 : 0 : hw->use_msix = zxdh_pci_msix_detect(dev);
321 : :
322 : 0 : pos = rte_pci_find_capability(dev, RTE_PCI_CAP_ID_VNDR);
323 [ # # ]: 0 : while (pos) {
324 : 0 : ret = rte_pci_read_config(dev, &cap, sizeof(cap), pos);
325 [ # # ]: 0 : if (ret != sizeof(cap)) {
326 : 0 : PMD_DRV_LOG(ERR, "failed to read pci cap at pos: %x ret %d", pos, ret);
327 : 0 : break;
328 : : }
329 [ # # ]: 0 : if (cap.cap_vndr != RTE_PCI_CAP_ID_VNDR) {
330 : 0 : PMD_DRV_LOG(DEBUG, "[%2x] skipping non VNDR cap id: %02x",
331 : : pos, cap.cap_vndr);
332 : 0 : goto next;
333 : : }
334 : 0 : PMD_DRV_LOG(DEBUG, "[%2x] cfg type: %u, bar: %u, offset: %04x, len: %u",
335 : : pos, cap.cfg_type, cap.bar, cap.offset, cap.length);
336 : :
337 [ # # # # : 0 : switch (cap.cfg_type) {
# # ]
338 : 0 : case ZXDH_PCI_CAP_COMMON_CFG:
339 : 0 : hw->common_cfg = get_cfg_addr(dev, &cap);
340 : 0 : break;
341 : 0 : case ZXDH_PCI_CAP_NOTIFY_CFG: {
342 : 0 : ret = rte_pci_read_config(dev, &hw->notify_off_multiplier,
343 : 0 : 4, pos + sizeof(cap));
344 [ # # ]: 0 : if (ret != 4)
345 : 0 : PMD_DRV_LOG(ERR,
346 : : "failed to read notify_off_multiplier, ret %d", ret);
347 : : else
348 : 0 : hw->notify_base = get_cfg_addr(dev, &cap);
349 : : break;
350 : : }
351 : 0 : case ZXDH_PCI_CAP_DEVICE_CFG:
352 : 0 : hw->dev_cfg = get_cfg_addr(dev, &cap);
353 : 0 : break;
354 : 0 : case ZXDH_PCI_CAP_ISR_CFG:
355 : 0 : hw->isr = get_cfg_addr(dev, &cap);
356 : 0 : break;
357 : 0 : case ZXDH_PCI_CAP_PCI_CFG: {
358 : 0 : hw->pcie_id = *(uint16_t *)&cap.padding[1];
359 : 0 : PMD_DRV_LOG(DEBUG, "get pcie id 0x%x", hw->pcie_id);
360 : :
361 [ # # ]: 0 : if ((hw->pcie_id >> 11) & 0x1) /* PF */ {
362 : 0 : PMD_DRV_LOG(DEBUG, "EP %u PF %u",
363 : : hw->pcie_id >> 12, (hw->pcie_id >> 8) & 0x7);
364 : : } else { /* VF */
365 : 0 : PMD_DRV_LOG(DEBUG, "EP %u PF %u VF %u",
366 : : hw->pcie_id >> 12,
367 : : (hw->pcie_id >> 8) & 0x7,
368 : : hw->pcie_id & 0xff);
369 : : }
370 : : break;
371 : : }
372 : : }
373 : 0 : next:
374 : 0 : pos = cap.cap_next;
375 : : }
376 [ # # # # ]: 0 : if (hw->common_cfg == NULL || hw->notify_base == NULL ||
377 [ # # # # ]: 0 : hw->dev_cfg == NULL || hw->isr == NULL) {
378 : 0 : PMD_DRV_LOG(ERR, "no zxdh pci device found");
379 : 0 : return -1;
380 : : }
381 : : return 0;
382 : : }
383 : :
384 : : void
385 : 0 : zxdh_pci_read_dev_config(struct zxdh_hw *hw, size_t offset, void *dst, int32_t length)
386 : : {
387 : 0 : ZXDH_VTPCI_OPS(hw)->read_dev_cfg(hw, offset, dst, length);
388 : 0 : }
389 : :
390 : 0 : void zxdh_pci_write_dev_config(struct zxdh_hw *hw, size_t offset, const void *src, int32_t length)
391 : : {
392 : 0 : ZXDH_VTPCI_OPS(hw)->write_dev_cfg(hw, offset, src, length);
393 : 0 : }
394 : :
395 : : void
396 : 0 : zxdh_get_pci_dev_config(struct zxdh_hw *hw)
397 : : {
398 : : uint64_t guest_features = 0;
399 : : uint64_t nego_features = 0;
400 : :
401 : 0 : hw->host_features = ZXDH_PMD_DEFAULT_HOST_FEATURES;
402 [ # # ]: 0 : if (hw->switchoffload)
403 : 0 : hw->host_features = zxdh_pci_get_features(hw);
404 : :
405 : : guest_features = (uint64_t)ZXDH_PMD_DEFAULT_GUEST_FEATURES;
406 : 0 : nego_features = guest_features & hw->host_features;
407 : :
408 : 0 : hw->guest_features = nego_features;
409 : :
410 [ # # ]: 0 : if (hw->guest_features & (1ULL << ZXDH_NET_F_MAC)) {
411 : 0 : zxdh_pci_read_dev_config(hw, offsetof(struct zxdh_net_config, mac),
412 : 0 : &hw->mac_addr, RTE_ETHER_ADDR_LEN);
413 : : } else {
414 : 0 : rte_eth_random_addr(&hw->mac_addr[0]);
415 : : }
416 : 0 : }
417 : :
418 : 0 : enum zxdh_msix_status zxdh_pci_msix_detect(struct rte_pci_device *dev)
419 : : {
420 : 0 : uint16_t flags = 0;
421 : : uint8_t pos = 0;
422 : : int16_t ret = 0;
423 : :
424 : 0 : pos = rte_pci_find_capability(dev, RTE_PCI_CAP_ID_MSIX);
425 : :
426 [ # # ]: 0 : if (pos > 0) {
427 : 0 : ret = rte_pci_read_config(dev, &flags, 2, pos + RTE_PCI_MSIX_FLAGS);
428 [ # # # # ]: 0 : if (ret == 2 && flags & RTE_PCI_MSIX_FLAGS_ENABLE)
429 : : return ZXDH_MSIX_ENABLED;
430 : : else
431 : 0 : return ZXDH_MSIX_DISABLED;
432 : : }
433 : : return ZXDH_MSIX_NONE;
434 : : }
|