blob: 4b9ad0acb8324eed31e2e52edee036de257a4f21 [file] [log] [blame]
Gleb Natapov89acfa32010-05-10 11:36:37 +03001/* 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"
Kevin O'Connor7d09d0e2010-05-10 21:51:38 -040020#include "config.h" // CONFIG_DEBUG_LEVEL
21#include "util.h" // dprintf
Sebastian Herbszt70451b62011-11-21 12:23:20 +010022#include "pci.h" // pci_config_readl
23#include "pci_regs.h" // PCI_BASE_ADDRESS_0
Gleb Natapov89acfa32010-05-10 11:36:37 +030024
25int vp_find_vq(unsigned int ioaddr, int queue_index,
Paolo Bonzinie1a17bb2011-11-16 13:02:57 +010026 struct vring_virtqueue **p_vq)
Gleb Natapov89acfa32010-05-10 11:36:37 +030027{
Gleb Natapov89acfa32010-05-10 11:36:37 +030028 u16 num;
29
30 ASSERT32FLAT();
Paolo Bonzinie1a17bb2011-11-16 13:02:57 +010031 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
Gleb Natapov89acfa32010-05-10 11:36:37 +030038 /* 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");
Paolo Bonzinie1a17bb2011-11-16 13:02:57 +010047 goto fail;
Gleb Natapov89acfa32010-05-10 11:36:37 +030048 }
49
50 if (num > MAX_QUEUE_NUM) {
51 dprintf(1, "ERROR: queue size %d > %d\n", num, MAX_QUEUE_NUM);
Paolo Bonzinie1a17bb2011-11-16 13:02:57 +010052 goto fail;
Gleb Natapov89acfa32010-05-10 11:36:37 +030053 }
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");
Paolo Bonzinie1a17bb2011-11-16 13:02:57 +010059 goto fail;
Gleb Natapov89acfa32010-05-10 11:36:37 +030060 }
61
62 vq->queue_index = queue_index;
63
64 /* initialize the queue */
65
Paolo Bonzinie1a17bb2011-11-16 13:02:57 +010066 struct vring * vr = &vq->vring;
Gleb Natapov89acfa32010-05-10 11:36:37 +030067 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;
Paolo Bonzinie1a17bb2011-11-16 13:02:57 +010078
79fail:
80 free(vq);
81 *p_vq = NULL;
82 return -1;
Gleb Natapov89acfa32010-05-10 11:36:37 +030083}
Paolo Bonzini4e343322011-11-16 13:02:56 +010084
85u16 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}