4 * Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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.
35 #ifdef RTE_EXEC_ENV_LINUXAPP
40 #include "virtio_pci.h"
41 #include "virtio_logs.h"
42 #include "virtqueue.h"
45 legacy_read_dev_config(struct virtio_hw *hw, size_t offset,
46 void *dst, int length)
52 off = VIRTIO_PCI_CONFIG(hw) + offset;
53 for (d = dst; length > 0; d += size, off += size, length -= size) {
56 *(uint32_t *)d = VIRTIO_READ_REG_4(hw, off);
57 } else if (length >= 2) {
59 *(uint16_t *)d = VIRTIO_READ_REG_2(hw, off);
62 *d = VIRTIO_READ_REG_1(hw, off);
68 legacy_write_dev_config(struct virtio_hw *hw, size_t offset,
69 const void *src, int length)
75 off = VIRTIO_PCI_CONFIG(hw) + offset;
76 for (s = src; length > 0; s += size, off += size, length -= size) {
79 VIRTIO_WRITE_REG_4(hw, off, *(const uint32_t *)s);
80 } else if (length >= 2) {
82 VIRTIO_WRITE_REG_2(hw, off, *(const uint16_t *)s);
85 VIRTIO_WRITE_REG_1(hw, off, *s);
91 legacy_get_features(struct virtio_hw *hw)
93 return VIRTIO_READ_REG_4(hw, VIRTIO_PCI_HOST_FEATURES);
97 legacy_set_features(struct virtio_hw *hw, uint32_t features)
99 VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_GUEST_FEATURES, features);
103 legacy_get_status(struct virtio_hw *hw)
105 return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_STATUS);
109 legacy_set_status(struct virtio_hw *hw, uint8_t status)
111 VIRTIO_WRITE_REG_1(hw, VIRTIO_PCI_STATUS, status);
115 legacy_reset(struct virtio_hw *hw)
117 legacy_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
121 legacy_get_isr(struct virtio_hw *hw)
123 return VIRTIO_READ_REG_1(hw, VIRTIO_PCI_ISR);
126 /* Enable one vector (0) for Link State Intrerrupt */
128 legacy_set_config_irq(struct virtio_hw *hw, uint16_t vec)
130 VIRTIO_WRITE_REG_2(hw, VIRTIO_MSI_CONFIG_VECTOR, vec);
131 return VIRTIO_READ_REG_2(hw, VIRTIO_MSI_CONFIG_VECTOR);
135 legacy_get_queue_num(struct virtio_hw *hw, uint16_t queue_id)
137 VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, queue_id);
138 return VIRTIO_READ_REG_2(hw, VIRTIO_PCI_QUEUE_NUM);
142 legacy_setup_queue(struct virtio_hw *hw, struct virtqueue *vq)
144 VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vq->vq_queue_index);
146 VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN,
147 vq->mz->phys_addr >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
151 legacy_del_queue(struct virtio_hw *hw, struct virtqueue *vq)
153 VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_SEL, vq->vq_queue_index);
155 VIRTIO_WRITE_REG_4(hw, VIRTIO_PCI_QUEUE_PFN, 0);
159 legacy_notify_queue(struct virtio_hw *hw, struct virtqueue *vq)
161 VIRTIO_WRITE_REG_2(hw, VIRTIO_PCI_QUEUE_NOTIFY, vq->vq_queue_index);
164 #ifdef RTE_EXEC_ENV_LINUXAPP
166 parse_sysfs_value(const char *filename, unsigned long *val)
172 f = fopen(filename, "r");
174 PMD_INIT_LOG(ERR, "%s(): cannot open sysfs value %s",
179 if (fgets(buf, sizeof(buf), f) == NULL) {
180 PMD_INIT_LOG(ERR, "%s(): cannot read sysfs value %s",
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",
197 get_uio_dev(struct rte_pci_addr *loc, char *buf, unsigned int buflen,
198 unsigned int *uio_num)
202 char dirname[PATH_MAX];
205 * depending on kernel version, uio can be located in uio/uioX
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);
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);
220 PMD_INIT_LOG(ERR, "Cannot opendir %s", dirname);
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;
233 if (strncmp(e->d_name, "uio", 3) != 0)
236 /* first try uio%d */
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);
244 /* then try uio:uio%d */
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,
255 /* No uio resource found */
257 PMD_INIT_LOG(ERR, "Could not find uio resource");
265 legacy_virtio_has_msix(const struct rte_pci_addr *loc)
268 char dirname[PATH_MAX];
270 snprintf(dirname, sizeof(dirname),
271 SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/msi_irqs",
272 loc->domain, loc->bus, loc->devid, loc->function);
274 d = opendir(dirname);
281 /* Extract I/O port numbers from sysfs */
283 virtio_resource_init_by_uio(struct rte_pci_device *pci_dev)
285 char dirname[PATH_MAX];
286 char filename[PATH_MAX];
287 unsigned long start, size;
288 unsigned int uio_num;
290 if (get_uio_dev(&pci_dev->addr, dirname, sizeof(dirname), &uio_num) < 0)
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",
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",
310 pci_dev->mem_resource[0].addr = (void *)(uintptr_t)start;
311 pci_dev->mem_resource[0].len = (uint64_t)size;
313 "PCI Port IO found start=0x%lx with size=0x%lx",
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));
326 pci_dev->intr_handle.type = RTE_INTR_HANDLE_UIO;
327 pci_dev->driver->drv_flags |= RTE_PCI_DRV_INTR_LSC;
332 /* Extract port I/O numbers from proc/ioports */
334 virtio_resource_init_by_ioports(struct rte_pci_device *pci_dev)
344 snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT,
345 pci_dev->addr.domain,
348 pci_dev->addr.function);
350 fp = fopen("/proc/ioports", "r");
352 PMD_INIT_LOG(ERR, "%s(): can't open ioports", __func__);
356 while (getdelim(&line, &linesz, '\n', fp) > 0) {
361 n = strcspn(ptr, ":");
365 while (*left && isspace(*left))
368 if (!strncmp(left, pci_id, strlen(pci_id))) {
371 while (*ptr && isspace(*ptr))
374 sscanf(ptr, "%04hx-%04hx", &start, &end);
375 size = end - start + 1;
387 pci_dev->mem_resource[0].addr = (void *)(uintptr_t)(uint32_t)start;
388 pci_dev->mem_resource[0].len = (uint64_t)size;
390 "PCI Port IO found start=0x%x with size=0x%x",
393 /* can't support lsc interrupt without uio */
394 pci_dev->driver->drv_flags &= ~RTE_PCI_DRV_INTR_LSC;
399 /* Extract I/O port numbers from sysfs */
401 legacy_virtio_resource_init(struct rte_pci_device *pci_dev)
403 if (virtio_resource_init_by_uio(pci_dev) == 0)
406 return virtio_resource_init_by_ioports(pci_dev);
411 legayc_virtio_has_msix(const struct rte_pci_addr *loc __rte_unused)
413 /* nic_uio does not enable interrupts, return 0 (false). */
418 legacy_virtio_resource_init(struct rte_pci_device *pci_dev __rte_unused)
420 /* no setup required */
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,
443 vtpci_read_dev_config(struct virtio_hw *hw, size_t offset,
444 void *dst, int length)
446 hw->vtpci_ops->read_dev_cfg(hw, offset, dst, length);
450 vtpci_write_dev_config(struct virtio_hw *hw, size_t offset,
451 const void *src, int length)
453 hw->vtpci_ops->write_dev_cfg(hw, offset, src, length);
457 vtpci_negotiate_features(struct virtio_hw *hw, uint32_t host_features)
462 * Limit negotiated features to what the driver, virtqueue, and
465 features = host_features & hw->guest_features;
466 hw->vtpci_ops->set_features(hw, features);
472 vtpci_reset(struct virtio_hw *hw)
474 hw->vtpci_ops->set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
475 /* flush status write */
476 hw->vtpci_ops->get_status(hw);
480 vtpci_reinit_complete(struct virtio_hw *hw)
482 vtpci_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER_OK);
486 vtpci_set_status(struct virtio_hw *hw, uint8_t status)
488 if (status != VIRTIO_CONFIG_STATUS_RESET)
489 status |= hw->vtpci_ops->get_status(hw);
491 hw->vtpci_ops->set_status(hw, status);
495 vtpci_isr(struct virtio_hw *hw)
497 return hw->vtpci_ops->get_isr(hw);
501 /* Enable one vector (0) for Link State Intrerrupt */
503 vtpci_irq_config(struct virtio_hw *hw, uint16_t vec)
505 return hw->vtpci_ops->set_config_irq(hw, vec);
509 vtpci_init(struct rte_pci_device *dev, struct virtio_hw *hw)
511 hw->vtpci_ops = &legacy_ops;
513 if (legacy_virtio_resource_init(dev) < 0)
515 hw->use_msix = legacy_virtio_has_msix(&dev->addr);
516 hw->io_base = (uint32_t)(uintptr_t)dev->mem_resource[0].addr;