grml...
[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 #include "pci.h" // pci_config_readl
23 #include "pci_regs.h" // PCI_BASE_ADDRESS_0
24
25 int vp_find_vq(unsigned int ioaddr, int queue_index,
26                struct vring_virtqueue **p_vq)
27 {
28    u16 num;
29
30    ASSERT32FLAT();
31    struct vring_virtqueue *vq = *p_vq = memalign_low(PAGE_SIZE, sizeof(*vq));
32    if (!vq) {
33        warn_noalloc();
34        goto fail;
35    }
36    memset(vq, 0, sizeof(*vq));
37
38    /* select the queue */
39
40    outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL);
41
42    /* check if the queue is available */
43
44    num = inw(ioaddr + VIRTIO_PCI_QUEUE_NUM);
45    if (!num) {
46        dprintf(1, "ERROR: queue size is 0\n");
47        goto fail;
48    }
49
50    if (num > MAX_QUEUE_NUM) {
51        dprintf(1, "ERROR: queue size %d > %d\n", num, MAX_QUEUE_NUM);
52        goto fail;
53    }
54
55    /* check if the queue is already active */
56
57    if (inl(ioaddr + VIRTIO_PCI_QUEUE_PFN)) {
58        dprintf(1, "ERROR: queue already active\n");
59        goto fail;
60    }
61
62    vq->queue_index = queue_index;
63
64    /* initialize the queue */
65
66    struct vring * vr = &vq->vring;
67    vring_init(vr, num, (unsigned char*)&vq->queue);
68
69    /* activate the queue
70     *
71     * NOTE: vr->desc is initialized by vring_init()
72     */
73
74    outl((unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT,
75         ioaddr + VIRTIO_PCI_QUEUE_PFN);
76
77    return num;
78
79 fail:
80    free(vq);
81    *p_vq = NULL;
82    return -1;
83 }
84
85 u16 vp_init_simple(u16 bdf)
86 {
87     u16 ioaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0) &
88         PCI_BASE_ADDRESS_IO_MASK;
89
90     vp_reset(ioaddr);
91     vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE |
92                   VIRTIO_CONFIG_S_DRIVER );
93     return ioaddr;
94 }