15566a3e3SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
25566a3e3SBruce Richardson * Copyright(c) 2010-2014 Intel Corporation
36c3169a3SBruce Richardson */
46c3169a3SBruce Richardson #include <stdint.h>
56c3169a3SBruce Richardson
6742bde12SBruce Richardson #ifdef RTE_EXEC_ENV_LINUX
7c52afa68SYuanhan Liu #include <dirent.h>
8c52afa68SYuanhan Liu #include <fcntl.h>
9c52afa68SYuanhan Liu #endif
10c52afa68SYuanhan Liu
11631d4ee4SSantosh Shukla #include <rte_io.h>
12a04322f6SDavid Marchand #include <bus_driver.h>
13631d4ee4SSantosh Shukla
146c3169a3SBruce Richardson #include "virtio_pci.h"
156c3169a3SBruce Richardson #include "virtio_logs.h"
16d5bbeefcSYuanhan Liu #include "virtqueue.h"
176c3169a3SBruce Richardson
186ba1f63bSYuanhan Liu /*
19b8f04520SDavid Marchand * The remaining space is defined by each driver as the per-driver
20b8f04520SDavid Marchand * configuration space.
21b8f04520SDavid Marchand */
226a504290SMaxime Coquelin #define VIRTIO_PCI_CONFIG(dev) \
236a504290SMaxime Coquelin (((dev)->msix_status == VIRTIO_MSIX_ENABLED) ? 24 : 20)
24b86af7b1SYuanhan Liu
25c8d4b02fSMaxime Coquelin struct virtio_pci_internal virtio_pci_internal[RTE_MAX_ETHPORTS];
26c8d4b02fSMaxime Coquelin
277793d293SMaxime Coquelin static enum virtio_msix_status
vtpci_msix_detect(struct rte_pci_device * dev)287793d293SMaxime Coquelin vtpci_msix_detect(struct rte_pci_device *dev)
297793d293SMaxime Coquelin {
307793d293SMaxime Coquelin uint16_t flags;
31a10b6e53SDavid Marchand off_t pos;
327793d293SMaxime Coquelin
33baa9c550SDavid Marchand pos = rte_pci_find_capability(dev, RTE_PCI_CAP_ID_MSIX);
34a10b6e53SDavid Marchand if (pos > 0 && rte_pci_read_config(dev, &flags, sizeof(flags),
35*7bb1168dSDavid Marchand pos + RTE_PCI_MSIX_FLAGS) == sizeof(flags)) {
36*7bb1168dSDavid Marchand if (flags & RTE_PCI_MSIX_FLAGS_ENABLE)
377793d293SMaxime Coquelin return VIRTIO_MSIX_ENABLED;
387793d293SMaxime Coquelin else
397793d293SMaxime Coquelin return VIRTIO_MSIX_DISABLED;
407793d293SMaxime Coquelin }
417793d293SMaxime Coquelin
427793d293SMaxime Coquelin return VIRTIO_MSIX_NONE;
437793d293SMaxime Coquelin }
447793d293SMaxime Coquelin
45281ccccbSDavid Marchand /*
46281ccccbSDavid Marchand * Since we are in legacy mode:
47281ccccbSDavid Marchand * http://ozlabs.org/~rusty/virtio-spec/virtio-0.9.5.pdf
48281ccccbSDavid Marchand *
49281ccccbSDavid Marchand * "Note that this is possible because while the virtio header is PCI (i.e.
50281ccccbSDavid Marchand * little) endian, the device-specific region is encoded in the native endian of
51281ccccbSDavid Marchand * the guest (where such distinction is applicable)."
52281ccccbSDavid Marchand *
53281ccccbSDavid Marchand * For powerpc which supports both, qemu supposes that cpu is big endian and
54281ccccbSDavid Marchand * enforces this for the virtio-net stuff.
55281ccccbSDavid Marchand */
56d5bbeefcSYuanhan Liu static void
legacy_read_dev_config(struct virtio_hw * hw,size_t offset,void * dst,int length)57d5bbeefcSYuanhan Liu legacy_read_dev_config(struct virtio_hw *hw, size_t offset,
586c3169a3SBruce Richardson void *dst, int length)
596c3169a3SBruce Richardson {
606a504290SMaxime Coquelin struct virtio_pci_dev *dev = virtio_pci_get_dev(hw);
61281ccccbSDavid Marchand #ifdef RTE_ARCH_PPC_64
62281ccccbSDavid Marchand int size;
63281ccccbSDavid Marchand
64281ccccbSDavid Marchand while (length > 0) {
65281ccccbSDavid Marchand if (length >= 4) {
66281ccccbSDavid Marchand size = 4;
673dcfe039SThomas Monjalon rte_pci_ioport_read(VTPCI_IO(hw), dst, size,
686a504290SMaxime Coquelin VIRTIO_PCI_CONFIG(dev) + offset);
69281ccccbSDavid Marchand *(uint32_t *)dst = rte_be_to_cpu_32(*(uint32_t *)dst);
70281ccccbSDavid Marchand } else if (length >= 2) {
71281ccccbSDavid Marchand size = 2;
723dcfe039SThomas Monjalon rte_pci_ioport_read(VTPCI_IO(hw), dst, size,
736a504290SMaxime Coquelin VIRTIO_PCI_CONFIG(dev) + offset);
74281ccccbSDavid Marchand *(uint16_t *)dst = rte_be_to_cpu_16(*(uint16_t *)dst);
75281ccccbSDavid Marchand } else {
76281ccccbSDavid Marchand size = 1;
773dcfe039SThomas Monjalon rte_pci_ioport_read(VTPCI_IO(hw), dst, size,
786a504290SMaxime Coquelin VIRTIO_PCI_CONFIG(dev) + offset);
79281ccccbSDavid Marchand }
80281ccccbSDavid Marchand
81281ccccbSDavid Marchand dst = (char *)dst + size;
82281ccccbSDavid Marchand offset += size;
83281ccccbSDavid Marchand length -= size;
84281ccccbSDavid Marchand }
85281ccccbSDavid Marchand #else
863dcfe039SThomas Monjalon rte_pci_ioport_read(VTPCI_IO(hw), dst, length,
876a504290SMaxime Coquelin VIRTIO_PCI_CONFIG(dev) + offset);
88281ccccbSDavid Marchand #endif
896c3169a3SBruce Richardson }
906c3169a3SBruce Richardson
91d5bbeefcSYuanhan Liu static void
legacy_write_dev_config(struct virtio_hw * hw,size_t offset,const void * src,int length)92d5bbeefcSYuanhan Liu legacy_write_dev_config(struct virtio_hw *hw, size_t offset,
93d5bbeefcSYuanhan Liu const void *src, int length)
946c3169a3SBruce Richardson {
956a504290SMaxime Coquelin struct virtio_pci_dev *dev = virtio_pci_get_dev(hw);
96281ccccbSDavid Marchand #ifdef RTE_ARCH_PPC_64
97281ccccbSDavid Marchand union {
98281ccccbSDavid Marchand uint32_t u32;
99281ccccbSDavid Marchand uint16_t u16;
100281ccccbSDavid Marchand } tmp;
101281ccccbSDavid Marchand int size;
102281ccccbSDavid Marchand
103281ccccbSDavid Marchand while (length > 0) {
104281ccccbSDavid Marchand if (length >= 4) {
105281ccccbSDavid Marchand size = 4;
106281ccccbSDavid Marchand tmp.u32 = rte_cpu_to_be_32(*(const uint32_t *)src);
1073dcfe039SThomas Monjalon rte_pci_ioport_write(VTPCI_IO(hw), &tmp.u32, size,
1086a504290SMaxime Coquelin VIRTIO_PCI_CONFIG(dev) + offset);
109281ccccbSDavid Marchand } else if (length >= 2) {
110281ccccbSDavid Marchand size = 2;
111281ccccbSDavid Marchand tmp.u16 = rte_cpu_to_be_16(*(const uint16_t *)src);
1123dcfe039SThomas Monjalon rte_pci_ioport_write(VTPCI_IO(hw), &tmp.u16, size,
1136a504290SMaxime Coquelin VIRTIO_PCI_CONFIG(dev) + offset);
114281ccccbSDavid Marchand } else {
115281ccccbSDavid Marchand size = 1;
1163dcfe039SThomas Monjalon rte_pci_ioport_write(VTPCI_IO(hw), src, size,
1176a504290SMaxime Coquelin VIRTIO_PCI_CONFIG(dev) + offset);
118281ccccbSDavid Marchand }
119281ccccbSDavid Marchand
120281ccccbSDavid Marchand src = (const char *)src + size;
121281ccccbSDavid Marchand offset += size;
122281ccccbSDavid Marchand length -= size;
123281ccccbSDavid Marchand }
124281ccccbSDavid Marchand #else
1253dcfe039SThomas Monjalon rte_pci_ioport_write(VTPCI_IO(hw), src, length,
1266a504290SMaxime Coquelin VIRTIO_PCI_CONFIG(dev) + offset);
127281ccccbSDavid Marchand #endif
1286c3169a3SBruce Richardson }
1296c3169a3SBruce Richardson
1303891f233SYuanhan Liu static uint64_t
legacy_get_features(struct virtio_hw * hw)131d5bbeefcSYuanhan Liu legacy_get_features(struct virtio_hw *hw)
132d5bbeefcSYuanhan Liu {
13336ea36efSYuanhan Liu uint32_t dst;
134b8f04520SDavid Marchand
1353dcfe039SThomas Monjalon rte_pci_ioport_read(VTPCI_IO(hw), &dst, 4, VIRTIO_PCI_HOST_FEATURES);
136b8f04520SDavid Marchand return dst;
137d5bbeefcSYuanhan Liu }
138d5bbeefcSYuanhan Liu
139d5bbeefcSYuanhan Liu static void
legacy_set_features(struct virtio_hw * hw,uint64_t features)1403891f233SYuanhan Liu legacy_set_features(struct virtio_hw *hw, uint64_t features)
141d5bbeefcSYuanhan Liu {
1423891f233SYuanhan Liu if ((features >> 32) != 0) {
1433891f233SYuanhan Liu PMD_DRV_LOG(ERR,
1443891f233SYuanhan Liu "only 32 bit features are allowed for legacy virtio!");
1453891f233SYuanhan Liu return;
1463891f233SYuanhan Liu }
1473dcfe039SThomas Monjalon rte_pci_ioport_write(VTPCI_IO(hw), &features, 4,
148b8f04520SDavid Marchand VIRTIO_PCI_GUEST_FEATURES);
149d5bbeefcSYuanhan Liu }
150d5bbeefcSYuanhan Liu
151cbb135b3SMaxime Coquelin static int
legacy_features_ok(struct virtio_hw * hw __rte_unused)152cbb135b3SMaxime Coquelin legacy_features_ok(struct virtio_hw *hw __rte_unused)
153cbb135b3SMaxime Coquelin {
154cbb135b3SMaxime Coquelin return 0;
155cbb135b3SMaxime Coquelin }
156cbb135b3SMaxime Coquelin
157d5bbeefcSYuanhan Liu static uint8_t
legacy_get_status(struct virtio_hw * hw)158d5bbeefcSYuanhan Liu legacy_get_status(struct virtio_hw *hw)
159d5bbeefcSYuanhan Liu {
160b8f04520SDavid Marchand uint8_t dst;
161b8f04520SDavid Marchand
1623dcfe039SThomas Monjalon rte_pci_ioport_read(VTPCI_IO(hw), &dst, 1, VIRTIO_PCI_STATUS);
163b8f04520SDavid Marchand return dst;
164d5bbeefcSYuanhan Liu }
165d5bbeefcSYuanhan Liu
166d5bbeefcSYuanhan Liu static void
legacy_set_status(struct virtio_hw * hw,uint8_t status)167d5bbeefcSYuanhan Liu legacy_set_status(struct virtio_hw *hw, uint8_t status)
168d5bbeefcSYuanhan Liu {
1693dcfe039SThomas Monjalon rte_pci_ioport_write(VTPCI_IO(hw), &status, 1, VIRTIO_PCI_STATUS);
170d5bbeefcSYuanhan Liu }
171d5bbeefcSYuanhan Liu
172d5bbeefcSYuanhan Liu static uint8_t
legacy_get_isr(struct virtio_hw * hw)173d5bbeefcSYuanhan Liu legacy_get_isr(struct virtio_hw *hw)
174d5bbeefcSYuanhan Liu {
175b8f04520SDavid Marchand uint8_t dst;
176b8f04520SDavid Marchand
1773dcfe039SThomas Monjalon rte_pci_ioport_read(VTPCI_IO(hw), &dst, 1, VIRTIO_PCI_ISR);
178b8f04520SDavid Marchand return dst;
179d5bbeefcSYuanhan Liu }
180d5bbeefcSYuanhan Liu
1817be78d02SJosh Soref /* Enable one vector (0) for Link State Interrupt */
182d5bbeefcSYuanhan Liu static uint16_t
legacy_set_config_irq(struct virtio_hw * hw,uint16_t vec)183d5bbeefcSYuanhan Liu legacy_set_config_irq(struct virtio_hw *hw, uint16_t vec)
184d5bbeefcSYuanhan Liu {
185b8f04520SDavid Marchand uint16_t dst;
186b8f04520SDavid Marchand
1873dcfe039SThomas Monjalon rte_pci_ioport_write(VTPCI_IO(hw), &vec, 2, VIRTIO_MSI_CONFIG_VECTOR);
1883dcfe039SThomas Monjalon rte_pci_ioport_read(VTPCI_IO(hw), &dst, 2, VIRTIO_MSI_CONFIG_VECTOR);
189b8f04520SDavid Marchand return dst;
190d5bbeefcSYuanhan Liu }
191d5bbeefcSYuanhan Liu
192d5bbeefcSYuanhan Liu static uint16_t
legacy_set_queue_irq(struct virtio_hw * hw,struct virtqueue * vq,uint16_t vec)193c49526acSJianfeng Tan legacy_set_queue_irq(struct virtio_hw *hw, struct virtqueue *vq, uint16_t vec)
194c49526acSJianfeng Tan {
195c49526acSJianfeng Tan uint16_t dst;
196c49526acSJianfeng Tan
1973dcfe039SThomas Monjalon rte_pci_ioport_write(VTPCI_IO(hw), &vq->vq_queue_index, 2,
198c49526acSJianfeng Tan VIRTIO_PCI_QUEUE_SEL);
1993dcfe039SThomas Monjalon rte_pci_ioport_write(VTPCI_IO(hw), &vec, 2, VIRTIO_MSI_QUEUE_VECTOR);
2003dcfe039SThomas Monjalon rte_pci_ioport_read(VTPCI_IO(hw), &dst, 2, VIRTIO_MSI_QUEUE_VECTOR);
201c49526acSJianfeng Tan return dst;
202c49526acSJianfeng Tan }
203c49526acSJianfeng Tan
204c49526acSJianfeng Tan static uint16_t
legacy_get_queue_num(struct virtio_hw * hw,uint16_t queue_id)205d5bbeefcSYuanhan Liu legacy_get_queue_num(struct virtio_hw *hw, uint16_t queue_id)
206d5bbeefcSYuanhan Liu {
207b8f04520SDavid Marchand uint16_t dst;
208b8f04520SDavid Marchand
2093dcfe039SThomas Monjalon rte_pci_ioport_write(VTPCI_IO(hw), &queue_id, 2, VIRTIO_PCI_QUEUE_SEL);
2103dcfe039SThomas Monjalon rte_pci_ioport_read(VTPCI_IO(hw), &dst, 2, VIRTIO_PCI_QUEUE_NUM);
211b8f04520SDavid Marchand return dst;
212d5bbeefcSYuanhan Liu }
213d5bbeefcSYuanhan Liu
214595454c5SJianfeng Tan static int
legacy_setup_queue(struct virtio_hw * hw,struct virtqueue * vq)215d5bbeefcSYuanhan Liu legacy_setup_queue(struct virtio_hw *hw, struct virtqueue *vq)
216d5bbeefcSYuanhan Liu {
217b8f04520SDavid Marchand uint32_t src;
218d5bbeefcSYuanhan Liu
2198b76b3a0SDavid Marchand /* Virtio PCI device VIRTIO_PCI_QUEUE_PFN register is 32bit,
2208b76b3a0SDavid Marchand * and only accepts 32 bit page frame number.
2218b76b3a0SDavid Marchand * Check if the allocated physical memory exceeds 16TB.
2228b76b3a0SDavid Marchand */
2238b76b3a0SDavid Marchand if ((vq->vq_ring_mem + vq->vq_ring_size - 1) >>
2248b76b3a0SDavid Marchand (VIRTIO_PCI_QUEUE_ADDR_SHIFT + 32)) {
2258b76b3a0SDavid Marchand PMD_INIT_LOG(ERR, "vring address shouldn't be above 16TB!");
226595454c5SJianfeng Tan return -1;
2278b76b3a0SDavid Marchand }
228595454c5SJianfeng Tan
2293dcfe039SThomas Monjalon rte_pci_ioport_write(VTPCI_IO(hw), &vq->vq_queue_index, 2,
230b8f04520SDavid Marchand VIRTIO_PCI_QUEUE_SEL);
23101ad44fdSHuawei Xie src = vq->vq_ring_mem >> VIRTIO_PCI_QUEUE_ADDR_SHIFT;
2323dcfe039SThomas Monjalon rte_pci_ioport_write(VTPCI_IO(hw), &src, 4, VIRTIO_PCI_QUEUE_PFN);
233595454c5SJianfeng Tan
234595454c5SJianfeng Tan return 0;
235d5bbeefcSYuanhan Liu }
236d5bbeefcSYuanhan Liu
237d5bbeefcSYuanhan Liu static void
legacy_del_queue(struct virtio_hw * hw,struct virtqueue * vq)238d5bbeefcSYuanhan Liu legacy_del_queue(struct virtio_hw *hw, struct virtqueue *vq)
239d5bbeefcSYuanhan Liu {
240b8f04520SDavid Marchand uint32_t src = 0;
241d5bbeefcSYuanhan Liu
2423dcfe039SThomas Monjalon rte_pci_ioport_write(VTPCI_IO(hw), &vq->vq_queue_index, 2,
243b8f04520SDavid Marchand VIRTIO_PCI_QUEUE_SEL);
2443dcfe039SThomas Monjalon rte_pci_ioport_write(VTPCI_IO(hw), &src, 4, VIRTIO_PCI_QUEUE_PFN);
245d5bbeefcSYuanhan Liu }
246d5bbeefcSYuanhan Liu
247d5bbeefcSYuanhan Liu static void
legacy_notify_queue(struct virtio_hw * hw,struct virtqueue * vq)248d5bbeefcSYuanhan Liu legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq)
249d5bbeefcSYuanhan Liu {
2503dcfe039SThomas Monjalon rte_pci_ioport_write(VTPCI_IO(hw), &vq->vq_queue_index, 2,
251b8f04520SDavid Marchand VIRTIO_PCI_QUEUE_NOTIFY);
252d5bbeefcSYuanhan Liu }
253d5bbeefcSYuanhan Liu
2547793d293SMaxime Coquelin static void
legacy_intr_detect(struct virtio_hw * hw)2557793d293SMaxime Coquelin legacy_intr_detect(struct virtio_hw *hw)
2567793d293SMaxime Coquelin {
257c8d4b02fSMaxime Coquelin struct virtio_pci_dev *dev = virtio_pci_get_dev(hw);
258c8d4b02fSMaxime Coquelin
259aa0d4b8aSMaxime Coquelin dev->msix_status = vtpci_msix_detect(VTPCI_DEV(hw));
2606a504290SMaxime Coquelin hw->intr_lsc = !!dev->msix_status;
2617793d293SMaxime Coquelin }
2627793d293SMaxime Coquelin
263f12908c8SMaxime Coquelin static int
legacy_dev_close(struct virtio_hw * hw)264f12908c8SMaxime Coquelin legacy_dev_close(struct virtio_hw *hw)
265f12908c8SMaxime Coquelin {
266aa0d4b8aSMaxime Coquelin rte_pci_unmap_device(VTPCI_DEV(hw));
267f12908c8SMaxime Coquelin rte_pci_ioport_unmap(VTPCI_IO(hw));
268f12908c8SMaxime Coquelin
269f12908c8SMaxime Coquelin return 0;
270f12908c8SMaxime Coquelin }
271f12908c8SMaxime Coquelin
272f8b60756SMaxime Coquelin const struct virtio_ops legacy_ops = {
273d5bbeefcSYuanhan Liu .read_dev_cfg = legacy_read_dev_config,
274d5bbeefcSYuanhan Liu .write_dev_cfg = legacy_write_dev_config,
275d5bbeefcSYuanhan Liu .get_status = legacy_get_status,
276d5bbeefcSYuanhan Liu .set_status = legacy_set_status,
277d5bbeefcSYuanhan Liu .get_features = legacy_get_features,
278d5bbeefcSYuanhan Liu .set_features = legacy_set_features,
279cbb135b3SMaxime Coquelin .features_ok = legacy_features_ok,
280d5bbeefcSYuanhan Liu .get_isr = legacy_get_isr,
281d5bbeefcSYuanhan Liu .set_config_irq = legacy_set_config_irq,
282c49526acSJianfeng Tan .set_queue_irq = legacy_set_queue_irq,
283d5bbeefcSYuanhan Liu .get_queue_num = legacy_get_queue_num,
284d5bbeefcSYuanhan Liu .setup_queue = legacy_setup_queue,
285d5bbeefcSYuanhan Liu .del_queue = legacy_del_queue,
286d5bbeefcSYuanhan Liu .notify_queue = legacy_notify_queue,
2877793d293SMaxime Coquelin .intr_detect = legacy_intr_detect,
288f12908c8SMaxime Coquelin .dev_close = legacy_dev_close,
289d5bbeefcSYuanhan Liu };
290d5bbeefcSYuanhan Liu
2916ba1f63bSYuanhan Liu static inline void
io_write64_twopart(uint64_t val,uint32_t * lo,uint32_t * hi)2926ba1f63bSYuanhan Liu io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi)
2936ba1f63bSYuanhan Liu {
294631d4ee4SSantosh Shukla rte_write32(val & ((1ULL << 32) - 1), lo);
295631d4ee4SSantosh Shukla rte_write32(val >> 32, hi);
2966ba1f63bSYuanhan Liu }
2976ba1f63bSYuanhan Liu
2986ba1f63bSYuanhan Liu static void
modern_read_dev_config(struct virtio_hw * hw,size_t offset,void * dst,int length)2996ba1f63bSYuanhan Liu modern_read_dev_config(struct virtio_hw *hw, size_t offset,
3006ba1f63bSYuanhan Liu void *dst, int length)
3016ba1f63bSYuanhan Liu {
302266ece29SMaxime Coquelin struct virtio_pci_dev *dev = virtio_pci_get_dev(hw);
3036ba1f63bSYuanhan Liu int i;
3046ba1f63bSYuanhan Liu uint8_t *p;
3056ba1f63bSYuanhan Liu uint8_t old_gen, new_gen;
3066ba1f63bSYuanhan Liu
3076ba1f63bSYuanhan Liu do {
308266ece29SMaxime Coquelin old_gen = rte_read8(&dev->common_cfg->config_generation);
3096ba1f63bSYuanhan Liu
3106ba1f63bSYuanhan Liu p = dst;
3116ba1f63bSYuanhan Liu for (i = 0; i < length; i++)
312266ece29SMaxime Coquelin *p++ = rte_read8((uint8_t *)dev->dev_cfg + offset + i);
3136ba1f63bSYuanhan Liu
314266ece29SMaxime Coquelin new_gen = rte_read8(&dev->common_cfg->config_generation);
3156ba1f63bSYuanhan Liu } while (old_gen != new_gen);
3166ba1f63bSYuanhan Liu }
3176ba1f63bSYuanhan Liu
3186ba1f63bSYuanhan Liu static void
modern_write_dev_config(struct virtio_hw * hw,size_t offset,const void * src,int length)3196ba1f63bSYuanhan Liu modern_write_dev_config(struct virtio_hw *hw, size_t offset,
3206ba1f63bSYuanhan Liu const void *src, int length)
3216ba1f63bSYuanhan Liu {
322266ece29SMaxime Coquelin struct virtio_pci_dev *dev = virtio_pci_get_dev(hw);
3236ba1f63bSYuanhan Liu int i;
3246ba1f63bSYuanhan Liu const uint8_t *p = src;
3256ba1f63bSYuanhan Liu
3266ba1f63bSYuanhan Liu for (i = 0; i < length; i++)
327266ece29SMaxime Coquelin rte_write8((*p++), (((uint8_t *)dev->dev_cfg) + offset + i));
3286ba1f63bSYuanhan Liu }
3296ba1f63bSYuanhan Liu
3306ba1f63bSYuanhan Liu static uint64_t
modern_get_features(struct virtio_hw * hw)3316ba1f63bSYuanhan Liu modern_get_features(struct virtio_hw *hw)
3326ba1f63bSYuanhan Liu {
333266ece29SMaxime Coquelin struct virtio_pci_dev *dev = virtio_pci_get_dev(hw);
3346ba1f63bSYuanhan Liu uint32_t features_lo, features_hi;
3356ba1f63bSYuanhan Liu
336266ece29SMaxime Coquelin rte_write32(0, &dev->common_cfg->device_feature_select);
337266ece29SMaxime Coquelin features_lo = rte_read32(&dev->common_cfg->device_feature);
3386ba1f63bSYuanhan Liu
339266ece29SMaxime Coquelin rte_write32(1, &dev->common_cfg->device_feature_select);
340266ece29SMaxime Coquelin features_hi = rte_read32(&dev->common_cfg->device_feature);
3416ba1f63bSYuanhan Liu
3426ba1f63bSYuanhan Liu return ((uint64_t)features_hi << 32) | features_lo;
3436ba1f63bSYuanhan Liu }
3446ba1f63bSYuanhan Liu
3456ba1f63bSYuanhan Liu static void
modern_set_features(struct virtio_hw * hw,uint64_t features)3466ba1f63bSYuanhan Liu modern_set_features(struct virtio_hw *hw, uint64_t features)
3476ba1f63bSYuanhan Liu {
348266ece29SMaxime Coquelin struct virtio_pci_dev *dev = virtio_pci_get_dev(hw);
3496ba1f63bSYuanhan Liu
350266ece29SMaxime Coquelin rte_write32(0, &dev->common_cfg->guest_feature_select);
351266ece29SMaxime Coquelin rte_write32(features & ((1ULL << 32) - 1),
352266ece29SMaxime Coquelin &dev->common_cfg->guest_feature);
353266ece29SMaxime Coquelin
354266ece29SMaxime Coquelin rte_write32(1, &dev->common_cfg->guest_feature_select);
355631d4ee4SSantosh Shukla rte_write32(features >> 32,
356266ece29SMaxime Coquelin &dev->common_cfg->guest_feature);
3576ba1f63bSYuanhan Liu }
3586ba1f63bSYuanhan Liu
359cbb135b3SMaxime Coquelin static int
modern_features_ok(struct virtio_hw * hw)360cbb135b3SMaxime Coquelin modern_features_ok(struct virtio_hw *hw)
361cbb135b3SMaxime Coquelin {
362b4f9a45aSMaxime Coquelin if (!virtio_with_feature(hw, VIRTIO_F_VERSION_1)) {
363f3854ebaSThomas Monjalon PMD_INIT_LOG(ERR, "Version 1+ required with modern devices");
364cbb135b3SMaxime Coquelin return -1;
365cbb135b3SMaxime Coquelin }
366cbb135b3SMaxime Coquelin
367cbb135b3SMaxime Coquelin return 0;
368cbb135b3SMaxime Coquelin }
369cbb135b3SMaxime Coquelin
3706ba1f63bSYuanhan Liu static uint8_t
modern_get_status(struct virtio_hw * hw)3716ba1f63bSYuanhan Liu modern_get_status(struct virtio_hw *hw)
3726ba1f63bSYuanhan Liu {
373266ece29SMaxime Coquelin struct virtio_pci_dev *dev = virtio_pci_get_dev(hw);
374266ece29SMaxime Coquelin
375266ece29SMaxime Coquelin return rte_read8(&dev->common_cfg->device_status);
3766ba1f63bSYuanhan Liu }
3776ba1f63bSYuanhan Liu
3786ba1f63bSYuanhan Liu static void
modern_set_status(struct virtio_hw * hw,uint8_t status)3796ba1f63bSYuanhan Liu modern_set_status(struct virtio_hw *hw, uint8_t status)
3806ba1f63bSYuanhan Liu {
381266ece29SMaxime Coquelin struct virtio_pci_dev *dev = virtio_pci_get_dev(hw);
382266ece29SMaxime Coquelin
383266ece29SMaxime Coquelin rte_write8(status, &dev->common_cfg->device_status);
3846ba1f63bSYuanhan Liu }
3856ba1f63bSYuanhan Liu
3866ba1f63bSYuanhan Liu static uint8_t
modern_get_isr(struct virtio_hw * hw)3876ba1f63bSYuanhan Liu modern_get_isr(struct virtio_hw *hw)
3886ba1f63bSYuanhan Liu {
389266ece29SMaxime Coquelin struct virtio_pci_dev *dev = virtio_pci_get_dev(hw);
390266ece29SMaxime Coquelin
391266ece29SMaxime Coquelin return rte_read8(dev->isr);
3926ba1f63bSYuanhan Liu }
3936ba1f63bSYuanhan Liu
3946ba1f63bSYuanhan Liu static uint16_t
modern_set_config_irq(struct virtio_hw * hw,uint16_t vec)3956ba1f63bSYuanhan Liu modern_set_config_irq(struct virtio_hw *hw, uint16_t vec)
3966ba1f63bSYuanhan Liu {
397266ece29SMaxime Coquelin struct virtio_pci_dev *dev = virtio_pci_get_dev(hw);
398266ece29SMaxime Coquelin
399266ece29SMaxime Coquelin rte_write16(vec, &dev->common_cfg->msix_config);
400266ece29SMaxime Coquelin return rte_read16(&dev->common_cfg->msix_config);
4016ba1f63bSYuanhan Liu }
4026ba1f63bSYuanhan Liu
4036ba1f63bSYuanhan Liu static uint16_t
modern_set_queue_irq(struct virtio_hw * hw,struct virtqueue * vq,uint16_t vec)404c49526acSJianfeng Tan modern_set_queue_irq(struct virtio_hw *hw, struct virtqueue *vq, uint16_t vec)
405c49526acSJianfeng Tan {
406266ece29SMaxime Coquelin struct virtio_pci_dev *dev = virtio_pci_get_dev(hw);
407266ece29SMaxime Coquelin
408266ece29SMaxime Coquelin rte_write16(vq->vq_queue_index, &dev->common_cfg->queue_select);
409266ece29SMaxime Coquelin rte_write16(vec, &dev->common_cfg->queue_msix_vector);
410266ece29SMaxime Coquelin return rte_read16(&dev->common_cfg->queue_msix_vector);
411c49526acSJianfeng Tan }
412c49526acSJianfeng Tan
413c49526acSJianfeng Tan static uint16_t
modern_get_queue_num(struct virtio_hw * hw,uint16_t queue_id)4146ba1f63bSYuanhan Liu modern_get_queue_num(struct virtio_hw *hw, uint16_t queue_id)
4156ba1f63bSYuanhan Liu {
416266ece29SMaxime Coquelin struct virtio_pci_dev *dev = virtio_pci_get_dev(hw);
417266ece29SMaxime Coquelin
418266ece29SMaxime Coquelin rte_write16(queue_id, &dev->common_cfg->queue_select);
419266ece29SMaxime Coquelin return rte_read16(&dev->common_cfg->queue_size);
4206ba1f63bSYuanhan Liu }
4216ba1f63bSYuanhan Liu
422595454c5SJianfeng Tan static int
modern_setup_queue(struct virtio_hw * hw,struct virtqueue * vq)4236ba1f63bSYuanhan Liu modern_setup_queue(struct virtio_hw *hw, struct virtqueue *vq)
4246ba1f63bSYuanhan Liu {
425266ece29SMaxime Coquelin struct virtio_pci_dev *dev = virtio_pci_get_dev(hw);
4266ba1f63bSYuanhan Liu uint64_t desc_addr, avail_addr, used_addr;
4276ba1f63bSYuanhan Liu uint16_t notify_off;
4286ba1f63bSYuanhan Liu
42901ad44fdSHuawei Xie desc_addr = vq->vq_ring_mem;
4306ba1f63bSYuanhan Liu avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc);
4316ba1f63bSYuanhan Liu used_addr = RTE_ALIGN_CEIL(avail_addr + offsetof(struct vring_avail,
4326ba1f63bSYuanhan Liu ring[vq->vq_nentries]),
433df968842SMaxime Coquelin VIRTIO_VRING_ALIGN);
4346ba1f63bSYuanhan Liu
435266ece29SMaxime Coquelin rte_write16(vq->vq_queue_index, &dev->common_cfg->queue_select);
4366ba1f63bSYuanhan Liu
437266ece29SMaxime Coquelin io_write64_twopart(desc_addr, &dev->common_cfg->queue_desc_lo,
438266ece29SMaxime Coquelin &dev->common_cfg->queue_desc_hi);
439266ece29SMaxime Coquelin io_write64_twopart(avail_addr, &dev->common_cfg->queue_avail_lo,
440266ece29SMaxime Coquelin &dev->common_cfg->queue_avail_hi);
441266ece29SMaxime Coquelin io_write64_twopart(used_addr, &dev->common_cfg->queue_used_lo,
442266ece29SMaxime Coquelin &dev->common_cfg->queue_used_hi);
4436ba1f63bSYuanhan Liu
444266ece29SMaxime Coquelin notify_off = rte_read16(&dev->common_cfg->queue_notify_off);
445266ece29SMaxime Coquelin vq->notify_addr = (void *)((uint8_t *)dev->notify_base +
446266ece29SMaxime Coquelin notify_off * dev->notify_off_multiplier);
4476ba1f63bSYuanhan Liu
448266ece29SMaxime Coquelin rte_write16(1, &dev->common_cfg->queue_enable);
4496ba1f63bSYuanhan Liu
4506ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "queue %u addresses:", vq->vq_queue_index);
4516ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "\t desc_addr: %" PRIx64, desc_addr);
4526ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "\t aval_addr: %" PRIx64, avail_addr);
4536ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "\t used_addr: %" PRIx64, used_addr);
4546ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "\t notify addr: %p (notify offset: %u)",
4556ba1f63bSYuanhan Liu vq->notify_addr, notify_off);
456595454c5SJianfeng Tan
457595454c5SJianfeng Tan return 0;
4586ba1f63bSYuanhan Liu }
4596ba1f63bSYuanhan Liu
4606ba1f63bSYuanhan Liu static void
modern_del_queue(struct virtio_hw * hw,struct virtqueue * vq)4616ba1f63bSYuanhan Liu modern_del_queue(struct virtio_hw *hw, struct virtqueue *vq)
4626ba1f63bSYuanhan Liu {
463266ece29SMaxime Coquelin struct virtio_pci_dev *dev = virtio_pci_get_dev(hw);
4646ba1f63bSYuanhan Liu
465266ece29SMaxime Coquelin rte_write16(vq->vq_queue_index, &dev->common_cfg->queue_select);
4666ba1f63bSYuanhan Liu
467266ece29SMaxime Coquelin io_write64_twopart(0, &dev->common_cfg->queue_desc_lo,
468266ece29SMaxime Coquelin &dev->common_cfg->queue_desc_hi);
469266ece29SMaxime Coquelin io_write64_twopart(0, &dev->common_cfg->queue_avail_lo,
470266ece29SMaxime Coquelin &dev->common_cfg->queue_avail_hi);
471266ece29SMaxime Coquelin io_write64_twopart(0, &dev->common_cfg->queue_used_lo,
472266ece29SMaxime Coquelin &dev->common_cfg->queue_used_hi);
473266ece29SMaxime Coquelin
474266ece29SMaxime Coquelin rte_write16(0, &dev->common_cfg->queue_enable);
4756ba1f63bSYuanhan Liu }
4766ba1f63bSYuanhan Liu
4776ba1f63bSYuanhan Liu static void
modern_notify_queue(struct virtio_hw * hw,struct virtqueue * vq)4787e72f3ecSCheng Jiang modern_notify_queue(struct virtio_hw *hw, struct virtqueue *vq)
4796ba1f63bSYuanhan Liu {
4807e72f3ecSCheng Jiang uint32_t notify_data;
4817e72f3ecSCheng Jiang
482b4f9a45aSMaxime Coquelin if (!virtio_with_feature(hw, VIRTIO_F_NOTIFICATION_DATA)) {
483518208f3SXiao Wang rte_write16(vq->vq_queue_index, vq->notify_addr);
4847e72f3ecSCheng Jiang return;
4857e72f3ecSCheng Jiang }
4867e72f3ecSCheng Jiang
487b4f9a45aSMaxime Coquelin if (virtio_with_packed_queue(hw)) {
4887e72f3ecSCheng Jiang /*
4897e72f3ecSCheng Jiang * Bit[0:15]: vq queue index
4907e72f3ecSCheng Jiang * Bit[16:30]: avail index
4917e72f3ecSCheng Jiang * Bit[31]: avail wrap counter
4927e72f3ecSCheng Jiang */
4937e72f3ecSCheng Jiang notify_data = ((uint32_t)(!!(vq->vq_packed.cached_flags &
4947e72f3ecSCheng Jiang VRING_PACKED_DESC_F_AVAIL)) << 31) |
4957e72f3ecSCheng Jiang ((uint32_t)vq->vq_avail_idx << 16) |
4967e72f3ecSCheng Jiang vq->vq_queue_index;
4977e72f3ecSCheng Jiang } else {
4987e72f3ecSCheng Jiang /*
4997e72f3ecSCheng Jiang * Bit[0:15]: vq queue index
5007e72f3ecSCheng Jiang * Bit[16:31]: avail index
5017e72f3ecSCheng Jiang */
5027e72f3ecSCheng Jiang notify_data = ((uint32_t)vq->vq_avail_idx << 16) |
5037e72f3ecSCheng Jiang vq->vq_queue_index;
5047e72f3ecSCheng Jiang }
5057e72f3ecSCheng Jiang rte_write32(notify_data, vq->notify_addr);
5066ba1f63bSYuanhan Liu }
5076ba1f63bSYuanhan Liu
5087793d293SMaxime Coquelin
5097793d293SMaxime Coquelin
5107793d293SMaxime Coquelin static void
modern_intr_detect(struct virtio_hw * hw)5117793d293SMaxime Coquelin modern_intr_detect(struct virtio_hw *hw)
5127793d293SMaxime Coquelin {
513c8d4b02fSMaxime Coquelin struct virtio_pci_dev *dev = virtio_pci_get_dev(hw);
514c8d4b02fSMaxime Coquelin
515aa0d4b8aSMaxime Coquelin dev->msix_status = vtpci_msix_detect(VTPCI_DEV(hw));
5166a504290SMaxime Coquelin hw->intr_lsc = !!dev->msix_status;
5177793d293SMaxime Coquelin }
5187793d293SMaxime Coquelin
519f12908c8SMaxime Coquelin static int
modern_dev_close(struct virtio_hw * hw)520f12908c8SMaxime Coquelin modern_dev_close(struct virtio_hw *hw)
521f12908c8SMaxime Coquelin {
522aa0d4b8aSMaxime Coquelin rte_pci_unmap_device(VTPCI_DEV(hw));
523f12908c8SMaxime Coquelin
524f12908c8SMaxime Coquelin return 0;
525f12908c8SMaxime Coquelin }
526f12908c8SMaxime Coquelin
527f8b60756SMaxime Coquelin const struct virtio_ops modern_ops = {
5286ba1f63bSYuanhan Liu .read_dev_cfg = modern_read_dev_config,
5296ba1f63bSYuanhan Liu .write_dev_cfg = modern_write_dev_config,
5306ba1f63bSYuanhan Liu .get_status = modern_get_status,
5316ba1f63bSYuanhan Liu .set_status = modern_set_status,
5326ba1f63bSYuanhan Liu .get_features = modern_get_features,
5336ba1f63bSYuanhan Liu .set_features = modern_set_features,
534cbb135b3SMaxime Coquelin .features_ok = modern_features_ok,
5356ba1f63bSYuanhan Liu .get_isr = modern_get_isr,
5366ba1f63bSYuanhan Liu .set_config_irq = modern_set_config_irq,
537c49526acSJianfeng Tan .set_queue_irq = modern_set_queue_irq,
5386ba1f63bSYuanhan Liu .get_queue_num = modern_get_queue_num,
5396ba1f63bSYuanhan Liu .setup_queue = modern_setup_queue,
5406ba1f63bSYuanhan Liu .del_queue = modern_del_queue,
5416ba1f63bSYuanhan Liu .notify_queue = modern_notify_queue,
5427793d293SMaxime Coquelin .intr_detect = modern_intr_detect,
543f12908c8SMaxime Coquelin .dev_close = modern_dev_close,
5446ba1f63bSYuanhan Liu };
5456ba1f63bSYuanhan Liu
5466ba1f63bSYuanhan Liu static void *
get_cfg_addr(struct rte_pci_device * dev,struct virtio_pci_cap * cap)5476ba1f63bSYuanhan Liu get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap)
5486ba1f63bSYuanhan Liu {
5496ba1f63bSYuanhan Liu uint8_t bar = cap->bar;
5506ba1f63bSYuanhan Liu uint32_t length = cap->length;
5516ba1f63bSYuanhan Liu uint32_t offset = cap->offset;
5526ba1f63bSYuanhan Liu uint8_t *base;
5536ba1f63bSYuanhan Liu
5540373ab9bSZhiyong Yang if (bar >= PCI_MAX_RESOURCE) {
5556ba1f63bSYuanhan Liu PMD_INIT_LOG(ERR, "invalid bar: %u", bar);
5566ba1f63bSYuanhan Liu return NULL;
5576ba1f63bSYuanhan Liu }
5586ba1f63bSYuanhan Liu
5596ba1f63bSYuanhan Liu if (offset + length < offset) {
5606ba1f63bSYuanhan Liu PMD_INIT_LOG(ERR, "offset(%u) + length(%u) overflows",
5616ba1f63bSYuanhan Liu offset, length);
5626ba1f63bSYuanhan Liu return NULL;
5636ba1f63bSYuanhan Liu }
5646ba1f63bSYuanhan Liu
5656ba1f63bSYuanhan Liu if (offset + length > dev->mem_resource[bar].len) {
5666ba1f63bSYuanhan Liu PMD_INIT_LOG(ERR,
5676ba1f63bSYuanhan Liu "invalid cap: overflows bar space: %u > %" PRIu64,
5686ba1f63bSYuanhan Liu offset + length, dev->mem_resource[bar].len);
5696ba1f63bSYuanhan Liu return NULL;
5706ba1f63bSYuanhan Liu }
5716ba1f63bSYuanhan Liu
5726ba1f63bSYuanhan Liu base = dev->mem_resource[bar].addr;
5736ba1f63bSYuanhan Liu if (base == NULL) {
5746ba1f63bSYuanhan Liu PMD_INIT_LOG(ERR, "bar %u base addr is NULL", bar);
5756ba1f63bSYuanhan Liu return NULL;
5766ba1f63bSYuanhan Liu }
5776ba1f63bSYuanhan Liu
5786ba1f63bSYuanhan Liu return base + offset;
5796ba1f63bSYuanhan Liu }
5806ba1f63bSYuanhan Liu
5816ba1f63bSYuanhan Liu static int
virtio_read_caps(struct rte_pci_device * pci_dev,struct virtio_hw * hw)582266ece29SMaxime Coquelin virtio_read_caps(struct rte_pci_device *pci_dev, struct virtio_hw *hw)
5836ba1f63bSYuanhan Liu {
584266ece29SMaxime Coquelin struct virtio_pci_dev *dev = virtio_pci_get_dev(hw);
5856ba1f63bSYuanhan Liu struct virtio_pci_cap cap;
586a10b6e53SDavid Marchand off_t pos;
5876ba1f63bSYuanhan Liu int ret;
5886ba1f63bSYuanhan Liu
589266ece29SMaxime Coquelin if (rte_pci_map_device(pci_dev)) {
5906ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "failed to map pci device!");
5916ba1f63bSYuanhan Liu return -1;
5926ba1f63bSYuanhan Liu }
5936ba1f63bSYuanhan Liu
594a10b6e53SDavid Marchand /*
595a10b6e53SDavid Marchand * Transitional devices would also have this capability,
596cb482cb3SJianfeng Tan * that's why we also check if msix is enabled.
597cb482cb3SJianfeng Tan */
598a10b6e53SDavid Marchand dev->msix_status = vtpci_msix_detect(pci_dev);
59949bb1f7aSBrian Russell
600baa9c550SDavid Marchand pos = rte_pci_find_capability(pci_dev, RTE_PCI_CAP_ID_VNDR);
601a10b6e53SDavid Marchand while (pos > 0) {
602a10b6e53SDavid Marchand if (rte_pci_read_config(pci_dev, &cap, sizeof(cap), pos) != sizeof(cap))
60349bb1f7aSBrian Russell break;
6046ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG,
6056ba1f63bSYuanhan Liu "[%2x] cfg type: %u, bar: %u, offset: %04x, len: %u",
606a10b6e53SDavid Marchand (unsigned int)pos, cap.cfg_type, cap.bar, cap.offset, cap.length);
6076ba1f63bSYuanhan Liu
6086ba1f63bSYuanhan Liu switch (cap.cfg_type) {
6096ba1f63bSYuanhan Liu case VIRTIO_PCI_CAP_COMMON_CFG:
610266ece29SMaxime Coquelin dev->common_cfg = get_cfg_addr(pci_dev, &cap);
6116ba1f63bSYuanhan Liu break;
6126ba1f63bSYuanhan Liu case VIRTIO_PCI_CAP_NOTIFY_CFG:
613a10b6e53SDavid Marchand ret = rte_pci_read_config(pci_dev, &dev->notify_off_multiplier,
6146ba1f63bSYuanhan Liu 4, pos + sizeof(cap));
615ecfae151STiwei Bie if (ret != 4)
616ecfae151STiwei Bie PMD_INIT_LOG(DEBUG,
617ecfae151STiwei Bie "failed to read notify_off_multiplier, ret %d",
618ecfae151STiwei Bie ret);
619ecfae151STiwei Bie else
620266ece29SMaxime Coquelin dev->notify_base = get_cfg_addr(pci_dev, &cap);
6216ba1f63bSYuanhan Liu break;
6226ba1f63bSYuanhan Liu case VIRTIO_PCI_CAP_DEVICE_CFG:
623266ece29SMaxime Coquelin dev->dev_cfg = get_cfg_addr(pci_dev, &cap);
6246ba1f63bSYuanhan Liu break;
6256ba1f63bSYuanhan Liu case VIRTIO_PCI_CAP_ISR_CFG:
626266ece29SMaxime Coquelin dev->isr = get_cfg_addr(pci_dev, &cap);
6276ba1f63bSYuanhan Liu break;
6286ba1f63bSYuanhan Liu }
6296ba1f63bSYuanhan Liu
630baa9c550SDavid Marchand pos = rte_pci_find_next_capability(pci_dev, RTE_PCI_CAP_ID_VNDR, pos);
6316ba1f63bSYuanhan Liu }
6326ba1f63bSYuanhan Liu
633266ece29SMaxime Coquelin if (dev->common_cfg == NULL || dev->notify_base == NULL ||
634266ece29SMaxime Coquelin dev->dev_cfg == NULL || dev->isr == NULL) {
6356ba1f63bSYuanhan Liu PMD_INIT_LOG(INFO, "no modern virtio pci device found.");
6366ba1f63bSYuanhan Liu return -1;
6376ba1f63bSYuanhan Liu }
6386ba1f63bSYuanhan Liu
6396ba1f63bSYuanhan Liu PMD_INIT_LOG(INFO, "found modern virtio pci device.");
6406ba1f63bSYuanhan Liu
641266ece29SMaxime Coquelin PMD_INIT_LOG(DEBUG, "common cfg mapped at: %p", dev->common_cfg);
642266ece29SMaxime Coquelin PMD_INIT_LOG(DEBUG, "device cfg mapped at: %p", dev->dev_cfg);
643266ece29SMaxime Coquelin PMD_INIT_LOG(DEBUG, "isr cfg mapped at: %p", dev->isr);
6446ba1f63bSYuanhan Liu PMD_INIT_LOG(DEBUG, "notify base: %p, notify off multiplier: %u",
645266ece29SMaxime Coquelin dev->notify_base, dev->notify_off_multiplier);
6466ba1f63bSYuanhan Liu
6476ba1f63bSYuanhan Liu return 0;
6486ba1f63bSYuanhan Liu }
6496ba1f63bSYuanhan Liu
650ac5e1d83SHuawei Xie /*
651ac5e1d83SHuawei Xie * Return -1:
652ac5e1d83SHuawei Xie * if there is error mapping with VFIO/UIO.
653ac5e1d83SHuawei Xie * if port map error when driver type is KDRV_NONE.
654a65a34a8SStephen Hemminger * if marked as allowed but driver type is KDRV_UNKNOWN.
655ac5e1d83SHuawei Xie * Return 1 if kernel driver is managing the device.
656ac5e1d83SHuawei Xie * Return 0 on success.
657ac5e1d83SHuawei Xie */
658d5bbeefcSYuanhan Liu int
vtpci_init(struct rte_pci_device * pci_dev,struct virtio_pci_dev * dev)6591ac79346SMaxime Coquelin vtpci_init(struct rte_pci_device *pci_dev, struct virtio_pci_dev *dev)
660d5bbeefcSYuanhan Liu {
6611ac79346SMaxime Coquelin struct virtio_hw *hw = &dev->hw;
6621ac79346SMaxime Coquelin
663f305ecbbSMaxime Coquelin RTE_BUILD_BUG_ON(offsetof(struct virtio_pci_dev, hw) != 0);
664f305ecbbSMaxime Coquelin
6656ba1f63bSYuanhan Liu /*
6666ba1f63bSYuanhan Liu * Try if we can succeed reading virtio pci caps, which exists
6676ba1f63bSYuanhan Liu * only on modern pci device. If failed, we fallback to legacy
6686ba1f63bSYuanhan Liu * virtio handling.
6696ba1f63bSYuanhan Liu */
6701ac79346SMaxime Coquelin if (virtio_read_caps(pci_dev, hw) == 0) {
6716ba1f63bSYuanhan Liu PMD_INIT_LOG(INFO, "modern virtio pci detected.");
672f8b60756SMaxime Coquelin VIRTIO_OPS(hw) = &modern_ops;
6731ac79346SMaxime Coquelin dev->modern = true;
6747793d293SMaxime Coquelin goto msix_detect;
6756ba1f63bSYuanhan Liu }
6766ba1f63bSYuanhan Liu
6776ba1f63bSYuanhan Liu PMD_INIT_LOG(INFO, "trying with legacy virtio pci.");
6781ac79346SMaxime Coquelin if (rte_pci_ioport_map(pci_dev, 0, VTPCI_IO(hw)) < 0) {
6791ac79346SMaxime Coquelin rte_pci_unmap_device(pci_dev);
6801ac79346SMaxime Coquelin if (pci_dev->kdrv == RTE_PCI_KDRV_UNKNOWN &&
6811ac79346SMaxime Coquelin (!pci_dev->device.devargs ||
6821ac79346SMaxime Coquelin pci_dev->device.devargs->bus !=
6832b0e39c1SGaetan Rivet rte_bus_find_by_name("pci"))) {
684ac5e1d83SHuawei Xie PMD_INIT_LOG(INFO,
685ac5e1d83SHuawei Xie "skip kernel managed virtio device.");
686ac5e1d83SHuawei Xie return 1;
687ac5e1d83SHuawei Xie }
688c52afa68SYuanhan Liu return -1;
689ac5e1d83SHuawei Xie }
6906ba1f63bSYuanhan Liu
691f8b60756SMaxime Coquelin VIRTIO_OPS(hw) = &legacy_ops;
6921ac79346SMaxime Coquelin dev->modern = false;
693c52afa68SYuanhan Liu
6947793d293SMaxime Coquelin msix_detect:
695f8b60756SMaxime Coquelin VIRTIO_OPS(hw)->intr_detect(hw);
6967793d293SMaxime Coquelin
697d5bbeefcSYuanhan Liu return 0;
6986c3169a3SBruce Richardson }
699fe19d49cSZhiyong Yang
vtpci_legacy_ioport_unmap(struct virtio_hw * hw)700c8d4b02fSMaxime Coquelin void vtpci_legacy_ioport_unmap(struct virtio_hw *hw)
701c8d4b02fSMaxime Coquelin {
702c8d4b02fSMaxime Coquelin rte_pci_ioport_unmap(VTPCI_IO(hw));
703c8d4b02fSMaxime Coquelin }
704c8d4b02fSMaxime Coquelin
vtpci_legacy_ioport_map(struct virtio_hw * hw)705c8d4b02fSMaxime Coquelin int vtpci_legacy_ioport_map(struct virtio_hw *hw)
706c8d4b02fSMaxime Coquelin {
707aa0d4b8aSMaxime Coquelin return rte_pci_ioport_map(VTPCI_DEV(hw), 0, VTPCI_IO(hw));
708c8d4b02fSMaxime Coquelin }
709