remove extra parentheses in return statement
[dpdk.git] / drivers / net / virtio / virtio_pci.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 #include <stdint.h>
34
35 #ifdef RTE_EXEC_ENV_LINUXAPP
36  #include <dirent.h>
37  #include <fcntl.h>
38 #endif
39
40 #include "virtio_pci.h"
41 #include "virtio_logs.h"
42 #include "virtqueue.h"
43
44 /*
45  * Following macros are derived from linux/pci_regs.h, however,
46  * we can't simply include that header here, as there is no such
47  * file for non-Linux platform.
48  */
49 #define PCI_CAPABILITY_LIST     0x34
50 #define PCI_CAP_ID_VNDR         0x09
51
52 #define VIRTIO_PCI_REG_ADDR(hw, reg) \
53         (unsigned short)((hw)->io_base + (reg))
54
55 #define VIRTIO_READ_REG_1(hw, reg) \
56         inb((VIRTIO_PCI_REG_ADDR((hw), (reg))))
57 #define VIRTIO_WRITE_REG_1(hw, reg, value) \
58         outb_p((unsigned char)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg))))
59
60 #define VIRTIO_READ_REG_2(hw, reg) \
61         inw((VIRTIO_PCI_REG_ADDR((hw), (reg))))
62 #define VIRTIO_WRITE_REG_2(hw, reg, value) \
63         outw_p((unsigned short)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg))))
64
65 #define VIRTIO_READ_REG_4(hw, reg) \
66         inl((VIRTIO_PCI_REG_ADDR((hw), (reg))))
67 #define VIRTIO_WRITE_REG_4(hw, reg, value) \
68         outl_p((unsigned int)(value), (VIRTIO_PCI_REG_ADDR((hw), (reg))))
69
70 static void
71 legacy_read_dev_config(struct virtio_hw *hw, size_t offset,
72                        void *dst, int length)
73 {
74         uint64_t off;
75         uint8_t *d;
76         int size;
77
78         off = VIRTIO_PCI_CONFIG(hw) + offset;
79         for (d = dst; length > 0; d += size, off += size, length -= size) {
80                 if (length >= 4) {
81                         size = 4;
82                         *(uint32_t *)d = VIRTIO_READ_REG_4(hw, off);
83                 } else if (length >= 2) {
84                         size = 2;
85                         *(uint16_t *)d = VIRTIO_READ_REG_2(hw, off);
86                 } else {
87                         size = 1;
88                         *d = VIRTIO_READ_REG_1(hw, off);
89                 }
90         }
91 }
92
93 static void
94 legacy_write_dev_config(struct virtio_hw *hw, size_t offset,
95                         const void *src, int length)
96 {
97         uint64_t off;
98         const uint8_t *s;
99         int size;
100
101         off = VIRTIO_PCI_CONFIG(hw) + offset;
102         for (s = src; length > 0; s += size, off += size, length -= size) {
103                 if (length >= 4) {
104                         size = 4;
105                         VIRTIO_WRITE_REG_4(hw, off, *(const uint32_t *)s);
106                 } else if (length >= 2) {
107                         size = 2;
108                         VIRTIO_WRITE_REG_2(hw, off, *(const uint16_t *)s);
109                 } else {
110                         size = 1;
111                         VIRTIO_WRITE_REG_1(hw, off, *s);
112                 }
113         }
114 }
115
116 static uint64_t
117 legacy_get_features(struct virtio_hw *hw)
118 {
119         return VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
120 }
121
122 static void
123 legacy_set_features(struct virtio_hw *hw, uint64_t features)
124 {
125         if ((features >> 32) != 0) {
126                 PMD_DRV_LOG(ERR,
127                         "only 32 bit features are allowed for legacy virtio!");
128                 return;
129         }
130         VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
131 }
132
133 static uint8_t
134 legacy_get_status(struct virtio_hw *hw)
135 {
136         return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_STATUS);
137 }
138
139 static void
140 legacy_set_status(struct virtio_hw *hw, uint8_t status)
141 {
142         VIRTIO_WRITE_REG_1(hw, VIRTIO_PCI_STATUS, status);
143 }
144
145 static void
146 legacy_reset(struct virtio_hw *hw)
147 {
148         legacy_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
149 }
150
151 static uint8_t
152 legacy_get_isr(struct virtio_hw *hw)
153 {
154         return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR);
155 }
156
157 /* Enable one vector (0) for Link State Intrerrupt */
158 static uint16_t
159 legacy_set_config_irq(struct virtio_hw *hw, uint16_t vec)
160 {
161         VIRTIO_WRITE_REG_2(hw, VIRTIO_MSI_CONFIG_VECTOR, vec);
162         return VIRTIO_READ_REG_2(hw, VIRTIO_MSI_CONFIG_VECTOR);
163 }
164
165 static uint16_t
166 legacy_get_queue_num(struct virtio_hw *hw, uint16_t queue_id)
167 {
168         VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, queue_id);
169         return VIRTIO_READ_REG_2(hw, VIRTIO_PCI_QUEUE_NUM);
170 }
171
172 static void
173 legacy_setup_queue(struct virtio_hw *hw, struct virtqueue *vq)
174 {
175         VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vq->vq_queue_index);
176
177         VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN,
178                 vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
179 }
180
181 static void
182 legacy_del_queue(struct virtio_hw *hw, struct virtqueue *vq)
183 {
184         VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vq->vq_queue_index);
185
186         VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN, 0);
187 }
188
189 static void
190 legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq)
191 {
192         VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index);
193 }
194
195 #ifdef RTE_EXEC_ENV_LINUXAPP
196 static int
197 parse_sysfs_value(const char *filename, unsigned long *val)
198 {
199         FILE *f;
200         char buf[BUFSIZ];
201         char *end = NULL;
202
203         f = fopen(filename, "r");
204         if (f == NULL) {
205                 PMD_INIT_LOG(ERR, "%s(): cannot open sysfs value %s",
206                              __func__, filename);
207                 return -1;
208         }
209
210         if (fgets(buf, sizeof(buf), f) == NULL) {
211                 PMD_INIT_LOG(ERR, "%s(): cannot read sysfs value %s",
212                              __func__, filename);
213                 fclose(f);
214                 return -1;
215         }
216         *val = strtoul(buf, &end, 0);
217         if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) {
218                 PMD_INIT_LOG(ERR, "%s(): cannot parse sysfs value %s",
219                              __func__, filename);
220                 fclose(f);
221                 return -1;
222         }
223         fclose(f);
224         return 0;
225 }
226
227 static int
228 get_uio_dev(struct rte_pci_addr *loc, char *buf, unsigned int buflen,
229                         unsigned int *uio_num)
230 {
231         struct dirent *e;
232         DIR *dir;
233         char dirname[PATH_MAX];
234
235         /*
236          * depending on kernel version, uio can be located in uio/uioX
237          * or uio:uioX
238          */
239         snprintf(dirname, sizeof(dirname),
240                      SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/uio",
241                      loc->domain, loc->bus, loc->devid, loc->function);
242         dir = opendir(dirname);
243         if (dir == NULL) {
244                 /* retry with the parent directory */
245                 snprintf(dirname, sizeof(dirname),
246                              SYSFS_PCI_DEVICES "/" PCI_PRI_FMT,
247                              loc->domain, loc->bus, loc->devid, loc->function);
248                 dir = opendir(dirname);
249
250                 if (dir == NULL) {
251                         PMD_INIT_LOG(ERR, "Cannot opendir %s", dirname);
252                         return -1;
253                 }
254         }
255
256         /* take the first file starting with "uio" */
257         while ((e = readdir(dir)) != NULL) {
258                 /* format could be uio%d ...*/
259                 int shortprefix_len = sizeof("uio") - 1;
260                 /* ... or uio:uio%d */
261                 int longprefix_len = sizeof("uio:uio") - 1;
262                 char *endptr;
263
264                 if (strncmp(e->d_name, "uio", 3) != 0)
265                         continue;
266
267                 /* first try uio%d */
268                 errno = 0;
269                 *uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10);
270                 if (errno == 0 && endptr != (e->d_name + shortprefix_len)) {
271                         snprintf(buf, buflen, "%s/uio%u", dirname, *uio_num);
272                         break;
273                 }
274
275                 /* then try uio:uio%d */
276                 errno = 0;
277                 *uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10);
278                 if (errno == 0 && endptr != (e->d_name + longprefix_len)) {
279                         snprintf(buf, buflen, "%s/uio:uio%u", dirname,
280                                      *uio_num);
281                         break;
282                 }
283         }
284         closedir(dir);
285
286         /* No uio resource found */
287         if (e == NULL) {
288                 PMD_INIT_LOG(ERR, "Could not find uio resource");
289                 return -1;
290         }
291
292         return 0;
293 }
294
295 static int
296 legacy_virtio_has_msix(const struct rte_pci_addr *loc)
297 {
298         DIR *d;
299         char dirname[PATH_MAX];
300
301         snprintf(dirname, sizeof(dirname),
302                      SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs",
303                      loc->domain, loc->bus, loc->devid, loc->function);
304
305         d = opendir(dirname);
306         if (d)
307                 closedir(d);
308
309         return d != NULL;
310 }
311
312 /* Extract I/O port numbers from sysfs */
313 static int
314 virtio_resource_init_by_uio(struct rte_pci_device *pci_dev)
315 {
316         char dirname[PATH_MAX];
317         char filename[PATH_MAX];
318         unsigned long start, size;
319         unsigned int uio_num;
320
321         if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname), &uio_num) < 0)
322                 return -1;
323
324         /* get portio size */
325         snprintf(filename, sizeof(filename),
326                      "%s/portio/port0/size", dirname);
327         if (parse_sysfs_value(filename, &size) < 0) {
328                 PMD_INIT_LOG(ERR, "%s(): cannot parse size",
329                              __func__);
330                 return -1;
331         }
332
333         /* get portio start */
334         snprintf(filename, sizeof(filename),
335                  "%s/portio/port0/start", dirname);
336         if (parse_sysfs_value(filename, &start) < 0) {
337                 PMD_INIT_LOG(ERR, "%s(): cannot parse portio start",
338                              __func__);
339                 return -1;
340         }
341         pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start;
342         pci_dev->mem_resource[0].len =  (uint64_t)size;
343         PMD_INIT_LOG(DEBUG,
344                      "PCI Port IO found start=0x%lx with size=0x%lx",
345                      start, size);
346
347         /* save fd */
348         memset(dirname, 0, sizeof(dirname));
349         snprintf(dirname, sizeof(dirname), "/dev/uio%u", uio_num);
350         pci_dev->intr_handle.fd = open(dirname, O_RDWR);
351         if (pci_dev->intr_handle.fd < 0) {
352                 PMD_INIT_LOG(ERR, "Cannot open %s: %s\n",
353                         dirname, strerror(errno));
354                 return -1;
355         }
356
357         pci_dev->intr_handle.type = RTE_INTR_HANDLE_UIO;
358         pci_dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC;
359
360         return 0;
361 }
362
363 /* Extract port I/O numbers from proc/ioports */
364 static int
365 virtio_resource_init_by_ioports(struct rte_pci_device *pci_dev)
366 {
367         uint16_t start, end;
368         int size;
369         FILE *fp;
370         char *line = NULL;
371         char pci_id[16];
372         int found = 0;
373         size_t linesz;
374
375         snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT,
376                  pci_dev->addr.domain,
377                  pci_dev->addr.bus,
378                  pci_dev->addr.devid,
379                  pci_dev->addr.function);
380
381         fp = fopen("/proc/ioports", "r");
382         if (fp == NULL) {
383                 PMD_INIT_LOG(ERR, "%s(): can't open ioports", __func__);
384                 return -1;
385         }
386
387         while (getdelim(&line, &linesz, '\n', fp) > 0) {
388                 char *ptr = line;
389                 char *left;
390                 int n;
391
392                 n = strcspn(ptr, ":");
393                 ptr[n] = 0;
394                 left = &ptr[n + 1];
395
396                 while (*left && isspace(*left))
397                         left++;
398
399                 if (!strncmp(left, pci_id, strlen(pci_id))) {
400                         found = 1;
401
402                         while (*ptr && isspace(*ptr))
403                                 ptr++;
404
405                         sscanf(ptr, "%04hx-%04hx", &start, &end);
406                         size = end - start + 1;
407
408                         break;
409                 }
410         }
411
412         free(line);
413         fclose(fp);
414
415         if (!found)
416                 return -1;
417
418         pci_dev->mem_resource[0].addr = (void *)(uintptr_t)(uint32_t)start;
419         pci_dev->mem_resource[0].len =  (uint64_t)size;
420         PMD_INIT_LOG(DEBUG,
421                 "PCI Port IO found start=0x%x with size=0x%x",
422                 start, size);
423
424         /* can't support lsc interrupt without uio */
425         pci_dev->driver->drv_flags &= ~RTE_PCI_DRV_INTR_LSC;
426
427         return 0;
428 }
429
430 /* Extract I/O port numbers from sysfs */
431 static int
432 legacy_virtio_resource_init(struct rte_pci_device *pci_dev)
433 {
434         if (virtio_resource_init_by_uio(pci_dev) == 0)
435                 return 0;
436         else
437                 return virtio_resource_init_by_ioports(pci_dev);
438 }
439
440 #else
441 static int
442 legayc_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
443 {
444         /* nic_uio does not enable interrupts, return 0 (false). */
445         return 0;
446 }
447
448 static int
449 legacy_virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused)
450 {
451         /* no setup required */
452         return 0;
453 }
454 #endif
455
456 static const struct virtio_pci_ops legacy_ops = {
457         .read_dev_cfg   = legacy_read_dev_config,
458         .write_dev_cfg  = legacy_write_dev_config,
459         .reset          = legacy_reset,
460         .get_status     = legacy_get_status,
461         .set_status     = legacy_set_status,
462         .get_features   = legacy_get_features,
463         .set_features   = legacy_set_features,
464         .get_isr        = legacy_get_isr,
465         .set_config_irq = legacy_set_config_irq,
466         .get_queue_num  = legacy_get_queue_num,
467         .setup_queue    = legacy_setup_queue,
468         .del_queue      = legacy_del_queue,
469         .notify_queue   = legacy_notify_queue,
470 };
471
472
473 static inline uint8_t
474 io_read8(uint8_t *addr)
475 {
476         return *(volatile uint8_t *)addr;
477 }
478
479 static inline void
480 io_write8(uint8_t val, uint8_t *addr)
481 {
482         *(volatile uint8_t *)addr = val;
483 }
484
485 static inline uint16_t
486 io_read16(uint16_t *addr)
487 {
488         return *(volatile uint16_t *)addr;
489 }
490
491 static inline void
492 io_write16(uint16_t val, uint16_t *addr)
493 {
494         *(volatile uint16_t *)addr = val;
495 }
496
497 static inline uint32_t
498 io_read32(uint32_t *addr)
499 {
500         return *(volatile uint32_t *)addr;
501 }
502
503 static inline void
504 io_write32(uint32_t val, uint32_t *addr)
505 {
506         *(volatile uint32_t *)addr = val;
507 }
508
509 static inline void
510 io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi)
511 {
512         io_write32(val & ((1ULL << 32) - 1), lo);
513         io_write32(val >> 32,                hi);
514 }
515
516 static void
517 modern_read_dev_config(struct virtio_hw *hw, size_t offset,
518                        void *dst, int length)
519 {
520         int i;
521         uint8_t *p;
522         uint8_t old_gen, new_gen;
523
524         do {
525                 old_gen = io_read8(&hw->common_cfg->config_generation);
526
527                 p = dst;
528                 for (i = 0;  i < length; i++)
529                         *p++ = io_read8((uint8_t *)hw->dev_cfg + offset + i);
530
531                 new_gen = io_read8(&hw->common_cfg->config_generation);
532         } while (old_gen != new_gen);
533 }
534
535 static void
536 modern_write_dev_config(struct virtio_hw *hw, size_t offset,
537                         const void *src, int length)
538 {
539         int i;
540         const uint8_t *p = src;
541
542         for (i = 0;  i < length; i++)
543                 io_write8(*p++, (uint8_t *)hw->dev_cfg + offset + i);
544 }
545
546 static uint64_t
547 modern_get_features(struct virtio_hw *hw)
548 {
549         uint32_t features_lo, features_hi;
550
551         io_write32(0, &hw->common_cfg->device_feature_select);
552         features_lo = io_read32(&hw->common_cfg->device_feature);
553
554         io_write32(1, &hw->common_cfg->device_feature_select);
555         features_hi = io_read32(&hw->common_cfg->device_feature);
556
557         return ((uint64_t)features_hi << 32) | features_lo;
558 }
559
560 static void
561 modern_set_features(struct virtio_hw *hw, uint64_t features)
562 {
563         io_write32(0, &hw->common_cfg->guest_feature_select);
564         io_write32(features & ((1ULL << 32) - 1),
565                 &hw->common_cfg->guest_feature);
566
567         io_write32(1, &hw->common_cfg->guest_feature_select);
568         io_write32(features >> 32,
569                 &hw->common_cfg->guest_feature);
570 }
571
572 static uint8_t
573 modern_get_status(struct virtio_hw *hw)
574 {
575         return io_read8(&hw->common_cfg->device_status);
576 }
577
578 static void
579 modern_set_status(struct virtio_hw *hw, uint8_t status)
580 {
581         io_write8(status, &hw->common_cfg->device_status);
582 }
583
584 static void
585 modern_reset(struct virtio_hw *hw)
586 {
587         modern_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
588         modern_get_status(hw);
589 }
590
591 static uint8_t
592 modern_get_isr(struct virtio_hw *hw)
593 {
594         return io_read8(hw->isr);
595 }
596
597 static uint16_t
598 modern_set_config_irq(struct virtio_hw *hw, uint16_t vec)
599 {
600         io_write16(vec, &hw->common_cfg->msix_config);
601         return io_read16(&hw->common_cfg->msix_config);
602 }
603
604 static uint16_t
605 modern_get_queue_num(struct virtio_hw *hw, uint16_t queue_id)
606 {
607         io_write16(queue_id, &hw->common_cfg->queue_select);
608         return io_read16(&hw->common_cfg->queue_size);
609 }
610
611 static void
612 modern_setup_queue(struct virtio_hw *hw, struct virtqueue *vq)
613 {
614         uint64_t desc_addr, avail_addr, used_addr;
615         uint16_t notify_off;
616
617         desc_addr = vq->mz->phys_addr;
618         avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc);
619         used_addr = RTE_ALIGN_CEIL(avail_addr + offsetof(struct vring_avail,
620                                                          ring[vq->vq_nentries]),
621                                    VIRTIO_PCI_VRING_ALIGN);
622
623         io_write16(vq->vq_queue_index, &hw->common_cfg->queue_select);
624
625         io_write64_twopart(desc_addr, &hw->common_cfg->queue_desc_lo,
626                                       &hw->common_cfg->queue_desc_hi);
627         io_write64_twopart(avail_addr, &hw->common_cfg->queue_avail_lo,
628                                        &hw->common_cfg->queue_avail_hi);
629         io_write64_twopart(used_addr, &hw->common_cfg->queue_used_lo,
630                                       &hw->common_cfg->queue_used_hi);
631
632         notify_off = io_read16(&hw->common_cfg->queue_notify_off);
633         vq->notify_addr = (void *)((uint8_t *)hw->notify_base +
634                                 notify_off * hw->notify_off_multiplier);
635
636         io_write16(1, &hw->common_cfg->queue_enable);
637
638         PMD_INIT_LOG(DEBUG, "queue %u addresses:", vq->vq_queue_index);
639         PMD_INIT_LOG(DEBUG, "\t desc_addr: %" PRIx64, desc_addr);
640         PMD_INIT_LOG(DEBUG, "\t aval_addr: %" PRIx64, avail_addr);
641         PMD_INIT_LOG(DEBUG, "\t used_addr: %" PRIx64, used_addr);
642         PMD_INIT_LOG(DEBUG, "\t notify addr: %p (notify offset: %u)",
643                 vq->notify_addr, notify_off);
644 }
645
646 static void
647 modern_del_queue(struct virtio_hw *hw, struct virtqueue *vq)
648 {
649         io_write16(vq->vq_queue_index, &hw->common_cfg->queue_select);
650
651         io_write64_twopart(0, &hw->common_cfg->queue_desc_lo,
652                                   &hw->common_cfg->queue_desc_hi);
653         io_write64_twopart(0, &hw->common_cfg->queue_avail_lo,
654                                   &hw->common_cfg->queue_avail_hi);
655         io_write64_twopart(0, &hw->common_cfg->queue_used_lo,
656                                   &hw->common_cfg->queue_used_hi);
657
658         io_write16(0, &hw->common_cfg->queue_enable);
659 }
660
661 static void
662 modern_notify_queue(struct virtio_hw *hw __rte_unused, struct virtqueue *vq)
663 {
664         io_write16(1, vq->notify_addr);
665 }
666
667 static const struct virtio_pci_ops modern_ops = {
668         .read_dev_cfg   = modern_read_dev_config,
669         .write_dev_cfg  = modern_write_dev_config,
670         .reset          = modern_reset,
671         .get_status     = modern_get_status,
672         .set_status     = modern_set_status,
673         .get_features   = modern_get_features,
674         .set_features   = modern_set_features,
675         .get_isr        = modern_get_isr,
676         .set_config_irq = modern_set_config_irq,
677         .get_queue_num  = modern_get_queue_num,
678         .setup_queue    = modern_setup_queue,
679         .del_queue      = modern_del_queue,
680         .notify_queue   = modern_notify_queue,
681 };
682
683
684 void
685 vtpci_read_dev_config(struct virtio_hw *hw, size_t offset,
686                       void *dst, int length)
687 {
688         hw->vtpci_ops->read_dev_cfg(hw, offset, dst, length);
689 }
690
691 void
692 vtpci_write_dev_config(struct virtio_hw *hw, size_t offset,
693                        const void *src, int length)
694 {
695         hw->vtpci_ops->write_dev_cfg(hw, offset, src, length);
696 }
697
698 uint64_t
699 vtpci_negotiate_features(struct virtio_hw *hw, uint64_t host_features)
700 {
701         uint64_t features;
702
703         /*
704          * Limit negotiated features to what the driver, virtqueue, and
705          * host all support.
706          */
707         features = host_features & hw->guest_features;
708         hw->vtpci_ops->set_features(hw, features);
709
710         return features;
711 }
712
713 void
714 vtpci_reset(struct virtio_hw *hw)
715 {
716         hw->vtpci_ops->set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
717         /* flush status write */
718         hw->vtpci_ops->get_status(hw);
719 }
720
721 void
722 vtpci_reinit_complete(struct virtio_hw *hw)
723 {
724         vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER_OK);
725 }
726
727 void
728 vtpci_set_status(struct virtio_hw *hw, uint8_t status)
729 {
730         if (status != VIRTIO_CONFIG_STATUS_RESET)
731                 status |= hw->vtpci_ops->get_status(hw);
732
733         hw->vtpci_ops->set_status(hw, status);
734 }
735
736 uint8_t
737 vtpci_get_status(struct virtio_hw *hw)
738 {
739         return hw->vtpci_ops->get_status(hw);
740 }
741
742 uint8_t
743 vtpci_isr(struct virtio_hw *hw)
744 {
745         return hw->vtpci_ops->get_isr(hw);
746 }
747
748
749 /* Enable one vector (0) for Link State Intrerrupt */
750 uint16_t
751 vtpci_irq_config(struct virtio_hw *hw, uint16_t vec)
752 {
753         return hw->vtpci_ops->set_config_irq(hw, vec);
754 }
755
756 static void *
757 get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap)
758 {
759         uint8_t  bar    = cap->bar;
760         uint32_t length = cap->length;
761         uint32_t offset = cap->offset;
762         uint8_t *base;
763
764         if (bar > 5) {
765                 PMD_INIT_LOG(ERR, "invalid bar: %u", bar);
766                 return NULL;
767         }
768
769         if (offset + length < offset) {
770                 PMD_INIT_LOG(ERR, "offset(%u) + length(%u) overflows",
771                         offset, length);
772                 return NULL;
773         }
774
775         if (offset + length > dev->mem_resource[bar].len) {
776                 PMD_INIT_LOG(ERR,
777                         "invalid cap: overflows bar space: %u > %" PRIu64,
778                         offset + length, dev->mem_resource[bar].len);
779                 return NULL;
780         }
781
782         base = dev->mem_resource[bar].addr;
783         if (base == NULL) {
784                 PMD_INIT_LOG(ERR, "bar %u base addr is NULL", bar);
785                 return NULL;
786         }
787
788         return base + offset;
789 }
790
791 static int
792 virtio_read_caps(struct rte_pci_device *dev, struct virtio_hw *hw)
793 {
794         uint8_t pos;
795         struct virtio_pci_cap cap;
796         int ret;
797
798         if (rte_eal_pci_map_device(dev) < 0) {
799                 PMD_INIT_LOG(DEBUG, "failed to map pci device!");
800                 return -1;
801         }
802
803         ret = rte_eal_pci_read_config(dev, &pos, 1, PCI_CAPABILITY_LIST);
804         if (ret < 0) {
805                 PMD_INIT_LOG(DEBUG, "failed to read pci capability list");
806                 return -1;
807         }
808
809         while (pos) {
810                 ret = rte_eal_pci_read_config(dev, &cap, sizeof(cap), pos);
811                 if (ret < 0) {
812                         PMD_INIT_LOG(ERR,
813                                 "failed to read pci cap at pos: %x", pos);
814                         break;
815                 }
816
817                 if (cap.cap_vndr != PCI_CAP_ID_VNDR) {
818                         PMD_INIT_LOG(DEBUG,
819                                 "[%2x] skipping non VNDR cap id: %02x",
820                                 pos, cap.cap_vndr);
821                         goto next;
822                 }
823
824                 PMD_INIT_LOG(DEBUG,
825                         "[%2x] cfg type: %u, bar: %u, offset: %04x, len: %u",
826                         pos, cap.cfg_type, cap.bar, cap.offset, cap.length);
827
828                 switch (cap.cfg_type) {
829                 case VIRTIO_PCI_CAP_COMMON_CFG:
830                         hw->common_cfg = get_cfg_addr(dev, &cap);
831                         break;
832                 case VIRTIO_PCI_CAP_NOTIFY_CFG:
833                         rte_eal_pci_read_config(dev, &hw->notify_off_multiplier,
834                                                 4, pos + sizeof(cap));
835                         hw->notify_base = get_cfg_addr(dev, &cap);
836                         break;
837                 case VIRTIO_PCI_CAP_DEVICE_CFG:
838                         hw->dev_cfg = get_cfg_addr(dev, &cap);
839                         break;
840                 case VIRTIO_PCI_CAP_ISR_CFG:
841                         hw->isr = get_cfg_addr(dev, &cap);
842                         break;
843                 }
844
845 next:
846                 pos = cap.cap_next;
847         }
848
849         if (hw->common_cfg == NULL || hw->notify_base == NULL ||
850             hw->dev_cfg == NULL    || hw->isr == NULL) {
851                 PMD_INIT_LOG(INFO, "no modern virtio pci device found.");
852                 return -1;
853         }
854
855         PMD_INIT_LOG(INFO, "found modern virtio pci device.");
856
857         PMD_INIT_LOG(DEBUG, "common cfg mapped at: %p", hw->common_cfg);
858         PMD_INIT_LOG(DEBUG, "device cfg mapped at: %p", hw->dev_cfg);
859         PMD_INIT_LOG(DEBUG, "isr cfg mapped at: %p", hw->isr);
860         PMD_INIT_LOG(DEBUG, "notify base: %p, notify off multiplier: %u",
861                 hw->notify_base, hw->notify_off_multiplier);
862
863         return 0;
864 }
865
866 int
867 vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw)
868 {
869         hw->dev = dev;
870
871         /*
872          * Try if we can succeed reading virtio pci caps, which exists
873          * only on modern pci device. If failed, we fallback to legacy
874          * virtio handling.
875          */
876         if (virtio_read_caps(dev, hw) == 0) {
877                 PMD_INIT_LOG(INFO, "modern virtio pci detected.");
878                 hw->vtpci_ops = &modern_ops;
879                 hw->modern    = 1;
880                 dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC;
881                 return 0;
882         }
883
884         PMD_INIT_LOG(INFO, "trying with legacy virtio pci.");
885         if (legacy_virtio_resource_init(dev) < 0)
886                 return -1;
887
888         hw->vtpci_ops = &legacy_ops;
889         hw->use_msix = legacy_virtio_has_msix(&dev->addr);
890         hw->io_base  = (uint32_t)(uintptr_t)dev->mem_resource[0].addr;
891         hw->modern   = 0;
892
893         return 0;
894 }