7e0c1a52d5b9ce696e4dddb3b68c8f42d7b95a9f
[seabios.git] / src / virtio-pci.c
1 /* virtio-pci.c - pci interface for virtio interface
2  *
3  * (c) Copyright 2008 Bull S.A.S.
4  *
5  *  Author: Laurent Vivier <Laurent.Vivier@bull.net>
6  *
7  * some parts from Linux Virtio PCI driver
8  *
9  *  Copyright IBM Corp. 2007
10  *  Authors: Anthony Liguori  <aliguori@us.ibm.com>
11  *
12  *  Adopted for Seabios: Gleb Natapov <gleb@redhat.com>
13  *
14  * This work is licensed under the terms of the GNU LGPLv3
15  * See the COPYING file in the top-level directory.
16  */
17
18 #include "virtio-ring.h"
19 #include "virtio-pci.h"
20 #include "config.h" // CONFIG_DEBUG_LEVEL
21 #include "util.h" // dprintf
22
23 int vp_find_vq(unsigned int ioaddr, int queue_index,
24                struct vring_virtqueue **p_vq)
25 {
26    u16 num;
27
28    ASSERT32FLAT();
29    struct vring_virtqueue *vq = *p_vq = memalign_low(PAGE_SIZE, sizeof(*vq));
30    if (!vq) {
31        warn_noalloc();
32        goto fail;
33    }
34    memset(vq, 0, sizeof(*vq));
35
36    /* select the queue */
37
38    outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL);
39
40    /* check if the queue is available */
41
42    num = inw(ioaddr + VIRTIO_PCI_QUEUE_NUM);
43    if (!num) {
44        dprintf(1, "ERROR: queue size is 0\n");
45        goto fail;
46    }
47
48    if (num > MAX_QUEUE_NUM) {
49        dprintf(1, "ERROR: queue size %d > %d\n", num, MAX_QUEUE_NUM);
50        goto fail;
51    }
52
53    /* check if the queue is already active */
54
55    if (inl(ioaddr + VIRTIO_PCI_QUEUE_PFN)) {
56        dprintf(1, "ERROR: queue already active\n");
57        goto fail;
58    }
59
60    vq->queue_index = queue_index;
61
62    /* initialize the queue */
63
64    struct vring * vr = &vq->vring;
65    vring_init(vr, num, (unsigned char*)&vq->queue);
66
67    /* activate the queue
68     *
69     * NOTE: vr->desc is initialized by vring_init()
70     */
71
72    outl((unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT,
73         ioaddr + VIRTIO_PCI_QUEUE_PFN);
74
75    return num;
76
77 fail:
78    free(vq);
79    *p_vq = NULL;
80    return -1;
81 }
82
83 u16 vp_init_simple(u16 bdf)
84 {
85     u16 ioaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0) &
86         PCI_BASE_ADDRESS_IO_MASK;
87
88     vp_reset(ioaddr);
89     vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE |
90                   VIRTIO_CONFIG_S_DRIVER );
91     return ioaddr;
92 }