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