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