virtio: switch to 64 bit features
[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 static void
45 legacy_read_dev_config(struct virtio_hw *hw, size_t offset,
46                        void *dst, int length)
47 {
48         uint64_t off;
49         uint8_t *d;
50         int size;
51
52         off = VIRTIO_PCI_CONFIG(hw) + offset;
53         for (d = dst; length > 0; d += size, off += size, length -= size) {
54                 if (length >= 4) {
55                         size = 4;
56                         *(uint32_t *)d = VIRTIO_READ_REG_4(hw, off);
57                 } else if (length >= 2) {
58                         size = 2;
59                         *(uint16_t *)d = VIRTIO_READ_REG_2(hw, off);
60                 } else {
61                         size = 1;
62                         *d = VIRTIO_READ_REG_1(hw, off);
63                 }
64         }
65 }
66
67 static void
68 legacy_write_dev_config(struct virtio_hw *hw, size_t offset,
69                         const void *src, int length)
70 {
71         uint64_t off;
72         const uint8_t *s;
73         int size;
74
75         off = VIRTIO_PCI_CONFIG(hw) + offset;
76         for (s = src; length > 0; s += size, off += size, length -= size) {
77                 if (length >= 4) {
78                         size = 4;
79                         VIRTIO_WRITE_REG_4(hw, off, *(const uint32_t *)s);
80                 } else if (length >= 2) {
81                         size = 2;
82                         VIRTIO_WRITE_REG_2(hw, off, *(const uint16_t *)s);
83                 } else {
84                         size = 1;
85                         VIRTIO_WRITE_REG_1(hw, off, *s);
86                 }
87         }
88 }
89
90 static uint64_t
91 legacy_get_features(struct virtio_hw *hw)
92 {
93         return VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
94 }
95
96 static void
97 legacy_set_features(struct virtio_hw *hw, uint64_t features)
98 {
99         if ((features >> 32) != 0) {
100                 PMD_DRV_LOG(ERR,
101                         "only 32 bit features are allowed for legacy virtio!");
102                 return;
103         }
104         VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
105 }
106
107 static uint8_t
108 legacy_get_status(struct virtio_hw *hw)
109 {
110         return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_STATUS);
111 }
112
113 static void
114 legacy_set_status(struct virtio_hw *hw, uint8_t status)
115 {
116         VIRTIO_WRITE_REG_1(hw, VIRTIO_PCI_STATUS, status);
117 }
118
119 static void
120 legacy_reset(struct virtio_hw *hw)
121 {
122         legacy_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
123 }
124
125 static uint8_t
126 legacy_get_isr(struct virtio_hw *hw)
127 {
128         return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR);
129 }
130
131 /* Enable one vector (0) for Link State Intrerrupt */
132 static uint16_t
133 legacy_set_config_irq(struct virtio_hw *hw, uint16_t vec)
134 {
135         VIRTIO_WRITE_REG_2(hw, VIRTIO_MSI_CONFIG_VECTOR, vec);
136         return VIRTIO_READ_REG_2(hw, VIRTIO_MSI_CONFIG_VECTOR);
137 }
138
139 static uint16_t
140 legacy_get_queue_num(struct virtio_hw *hw, uint16_t queue_id)
141 {
142         VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, queue_id);
143         return VIRTIO_READ_REG_2(hw, VIRTIO_PCI_QUEUE_NUM);
144 }
145
146 static void
147 legacy_setup_queue(struct virtio_hw *hw, struct virtqueue *vq)
148 {
149         VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vq->vq_queue_index);
150
151         VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN,
152                 vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
153 }
154
155 static void
156 legacy_del_queue(struct virtio_hw *hw, struct virtqueue *vq)
157 {
158         VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vq->vq_queue_index);
159
160         VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN, 0);
161 }
162
163 static void
164 legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq)
165 {
166         VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index);
167 }
168
169 #ifdef RTE_EXEC_ENV_LINUXAPP
170 static int
171 parse_sysfs_value(const char *filename, unsigned long *val)
172 {
173         FILE *f;
174         char buf[BUFSIZ];
175         char *end = NULL;
176
177         f = fopen(filename, "r");
178         if (f == NULL) {
179                 PMD_INIT_LOG(ERR, "%s(): cannot open sysfs value %s",
180                              __func__, filename);
181                 return -1;
182         }
183
184         if (fgets(buf, sizeof(buf), f) == NULL) {
185                 PMD_INIT_LOG(ERR, "%s(): cannot read sysfs value %s",
186                              __func__, filename);
187                 fclose(f);
188                 return -1;
189         }
190         *val = strtoul(buf, &end, 0);
191         if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) {
192                 PMD_INIT_LOG(ERR, "%s(): cannot parse sysfs value %s",
193                              __func__, filename);
194                 fclose(f);
195                 return -1;
196         }
197         fclose(f);
198         return 0;
199 }
200
201 static int
202 get_uio_dev(struct rte_pci_addr *loc, char *buf, unsigned int buflen,
203                         unsigned int *uio_num)
204 {
205         struct dirent *e;
206         DIR *dir;
207         char dirname[PATH_MAX];
208
209         /*
210          * depending on kernel version, uio can be located in uio/uioX
211          * or uio:uioX
212          */
213         snprintf(dirname, sizeof(dirname),
214                      SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/uio",
215                      loc->domain, loc->bus, loc->devid, loc->function);
216         dir = opendir(dirname);
217         if (dir == NULL) {
218                 /* retry with the parent directory */
219                 snprintf(dirname, sizeof(dirname),
220                              SYSFS_PCI_DEVICES "/" PCI_PRI_FMT,
221                              loc->domain, loc->bus, loc->devid, loc->function);
222                 dir = opendir(dirname);
223
224                 if (dir == NULL) {
225                         PMD_INIT_LOG(ERR, "Cannot opendir %s", dirname);
226                         return -1;
227                 }
228         }
229
230         /* take the first file starting with "uio" */
231         while ((e = readdir(dir)) != NULL) {
232                 /* format could be uio%d ...*/
233                 int shortprefix_len = sizeof("uio") - 1;
234                 /* ... or uio:uio%d */
235                 int longprefix_len = sizeof("uio:uio") - 1;
236                 char *endptr;
237
238                 if (strncmp(e->d_name, "uio", 3) != 0)
239                         continue;
240
241                 /* first try uio%d */
242                 errno = 0;
243                 *uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10);
244                 if (errno == 0 && endptr != (e->d_name + shortprefix_len)) {
245                         snprintf(buf, buflen, "%s/uio%u", dirname, *uio_num);
246                         break;
247                 }
248
249                 /* then try uio:uio%d */
250                 errno = 0;
251                 *uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10);
252                 if (errno == 0 && endptr != (e->d_name + longprefix_len)) {
253                         snprintf(buf, buflen, "%s/uio:uio%u", dirname,
254                                      *uio_num);
255                         break;
256                 }
257         }
258         closedir(dir);
259
260         /* No uio resource found */
261         if (e == NULL) {
262                 PMD_INIT_LOG(ERR, "Could not find uio resource");
263                 return -1;
264         }
265
266         return 0;
267 }
268
269 static int
270 legacy_virtio_has_msix(const struct rte_pci_addr *loc)
271 {
272         DIR *d;
273         char dirname[PATH_MAX];
274
275         snprintf(dirname, sizeof(dirname),
276                      SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs",
277                      loc->domain, loc->bus, loc->devid, loc->function);
278
279         d = opendir(dirname);
280         if (d)
281                 closedir(d);
282
283         return (d != NULL);
284 }
285
286 /* Extract I/O port numbers from sysfs */
287 static int
288 virtio_resource_init_by_uio(struct rte_pci_device *pci_dev)
289 {
290         char dirname[PATH_MAX];
291         char filename[PATH_MAX];
292         unsigned long start, size;
293         unsigned int uio_num;
294
295         if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname), &uio_num) < 0)
296                 return -1;
297
298         /* get portio size */
299         snprintf(filename, sizeof(filename),
300                      "%s/portio/port0/size", dirname);
301         if (parse_sysfs_value(filename, &size) < 0) {
302                 PMD_INIT_LOG(ERR, "%s(): cannot parse size",
303                              __func__);
304                 return -1;
305         }
306
307         /* get portio start */
308         snprintf(filename, sizeof(filename),
309                  "%s/portio/port0/start", dirname);
310         if (parse_sysfs_value(filename, &start) < 0) {
311                 PMD_INIT_LOG(ERR, "%s(): cannot parse portio start",
312                              __func__);
313                 return -1;
314         }
315         pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start;
316         pci_dev->mem_resource[0].len =  (uint64_t)size;
317         PMD_INIT_LOG(DEBUG,
318                      "PCI Port IO found start=0x%lx with size=0x%lx",
319                      start, size);
320
321         /* save fd */
322         memset(dirname, 0, sizeof(dirname));
323         snprintf(dirname, sizeof(dirname), "/dev/uio%u", uio_num);
324         pci_dev->intr_handle.fd = open(dirname, O_RDWR);
325         if (pci_dev->intr_handle.fd < 0) {
326                 PMD_INIT_LOG(ERR, "Cannot open %s: %s\n",
327                         dirname, strerror(errno));
328                 return -1;
329         }
330
331         pci_dev->intr_handle.type = RTE_INTR_HANDLE_UIO;
332         pci_dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC;
333
334         return 0;
335 }
336
337 /* Extract port I/O numbers from proc/ioports */
338 static int
339 virtio_resource_init_by_ioports(struct rte_pci_device *pci_dev)
340 {
341         uint16_t start, end;
342         int size;
343         FILE *fp;
344         char *line = NULL;
345         char pci_id[16];
346         int found = 0;
347         size_t linesz;
348
349         snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT,
350                  pci_dev->addr.domain,
351                  pci_dev->addr.bus,
352                  pci_dev->addr.devid,
353                  pci_dev->addr.function);
354
355         fp = fopen("/proc/ioports", "r");
356         if (fp == NULL) {
357                 PMD_INIT_LOG(ERR, "%s(): can't open ioports", __func__);
358                 return -1;
359         }
360
361         while (getdelim(&line, &linesz, '\n', fp) > 0) {
362                 char *ptr = line;
363                 char *left;
364                 int n;
365
366                 n = strcspn(ptr, ":");
367                 ptr[n] = 0;
368                 left = &ptr[n + 1];
369
370                 while (*left && isspace(*left))
371                         left++;
372
373                 if (!strncmp(left, pci_id, strlen(pci_id))) {
374                         found = 1;
375
376                         while (*ptr && isspace(*ptr))
377                                 ptr++;
378
379                         sscanf(ptr, "%04hx-%04hx", &start, &end);
380                         size = end - start + 1;
381
382                         break;
383                 }
384         }
385
386         free(line);
387         fclose(fp);
388
389         if (!found)
390                 return -1;
391
392         pci_dev->mem_resource[0].addr = (void *)(uintptr_t)(uint32_t)start;
393         pci_dev->mem_resource[0].len =  (uint64_t)size;
394         PMD_INIT_LOG(DEBUG,
395                 "PCI Port IO found start=0x%x with size=0x%x",
396                 start, size);
397
398         /* can't support lsc interrupt without uio */
399         pci_dev->driver->drv_flags &= ~RTE_PCI_DRV_INTR_LSC;
400
401         return 0;
402 }
403
404 /* Extract I/O port numbers from sysfs */
405 static int
406 legacy_virtio_resource_init(struct rte_pci_device *pci_dev)
407 {
408         if (virtio_resource_init_by_uio(pci_dev) == 0)
409                 return 0;
410         else
411                 return virtio_resource_init_by_ioports(pci_dev);
412 }
413
414 #else
415 static int
416 legayc_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
417 {
418         /* nic_uio does not enable interrupts, return 0 (false). */
419         return 0;
420 }
421
422 static int
423 legacy_virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused)
424 {
425         /* no setup required */
426         return 0;
427 }
428 #endif
429
430 static const struct virtio_pci_ops legacy_ops = {
431         .read_dev_cfg   = legacy_read_dev_config,
432         .write_dev_cfg  = legacy_write_dev_config,
433         .reset          = legacy_reset,
434         .get_status     = legacy_get_status,
435         .set_status     = legacy_set_status,
436         .get_features   = legacy_get_features,
437         .set_features   = legacy_set_features,
438         .get_isr        = legacy_get_isr,
439         .set_config_irq = legacy_set_config_irq,
440         .get_queue_num  = legacy_get_queue_num,
441         .setup_queue    = legacy_setup_queue,
442         .del_queue      = legacy_del_queue,
443         .notify_queue   = legacy_notify_queue,
444 };
445
446
447 void
448 vtpci_read_dev_config(struct virtio_hw *hw, size_t offset,
449                       void *dst, int length)
450 {
451         hw->vtpci_ops->read_dev_cfg(hw, offset, dst, length);
452 }
453
454 void
455 vtpci_write_dev_config(struct virtio_hw *hw, size_t offset,
456                        const void *src, int length)
457 {
458         hw->vtpci_ops->write_dev_cfg(hw, offset, src, length);
459 }
460
461 uint64_t
462 vtpci_negotiate_features(struct virtio_hw *hw, uint64_t host_features)
463 {
464         uint64_t features;
465
466         /*
467          * Limit negotiated features to what the driver, virtqueue, and
468          * host all support.
469          */
470         features = host_features & hw->guest_features;
471         hw->vtpci_ops->set_features(hw, features);
472
473         return features;
474 }
475
476 void
477 vtpci_reset(struct virtio_hw *hw)
478 {
479         hw->vtpci_ops->set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
480         /* flush status write */
481         hw->vtpci_ops->get_status(hw);
482 }
483
484 void
485 vtpci_reinit_complete(struct virtio_hw *hw)
486 {
487         vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER_OK);
488 }
489
490 void
491 vtpci_set_status(struct virtio_hw *hw, uint8_t status)
492 {
493         if (status != VIRTIO_CONFIG_STATUS_RESET)
494                 status |= hw->vtpci_ops->get_status(hw);
495
496         hw->vtpci_ops->set_status(hw, status);
497 }
498
499 uint8_t
500 vtpci_isr(struct virtio_hw *hw)
501 {
502         return hw->vtpci_ops->get_isr(hw);
503 }
504
505
506 /* Enable one vector (0) for Link State Intrerrupt */
507 uint16_t
508 vtpci_irq_config(struct virtio_hw *hw, uint16_t vec)
509 {
510         return hw->vtpci_ops->set_config_irq(hw, vec);
511 }
512
513 int
514 vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw)
515 {
516         hw->vtpci_ops = &legacy_ops;
517
518         if (legacy_virtio_resource_init(dev) < 0)
519                 return -1;
520         hw->use_msix = legacy_virtio_has_msix(&dev->addr);
521         hw->io_base  = (uint32_t)(uintptr_t)dev->mem_resource[0].addr;
522
523         return 0;
524 }