~ubuntu-branches/ubuntu/wily/slof/wily

« back to all changes in this revision

Viewing changes to board-qemu/virtio-net/vn-pci.c

  • Committer: Package Import Robot
  • Author(s): Aurelien Jarno
  • Date: 2012-09-16 23:05:23 UTC
  • Revision ID: package-import@ubuntu.com-20120916230523-r2ynulqmp2tyu2e5
Tags: upstream-20120217+dfsg
ImportĀ upstreamĀ versionĀ 20120217+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************************************
 
2
 * Copyright (c) 2011 IBM Corporation
 
3
 * All rights reserved.
 
4
 * This program and the accompanying materials
 
5
 * are made available under the terms of the BSD License
 
6
 * which accompanies this distribution, and is available at
 
7
 * http://www.opensource.org/licenses/bsd-license.php
 
8
 *
 
9
 * Contributors:
 
10
 *     IBM Corporation - initial implementation
 
11
 *****************************************************************************/
 
12
 
 
13
#include <stdarg.h>
 
14
#include <string.h>
 
15
#include <cache.h>
 
16
#include <byteorder.h>
 
17
#include <netdriver_int.h>
 
18
#include <libhvcall.h>
 
19
#include <virtio.h>
 
20
#include "virtio-net.h"
 
21
 
 
22
 
 
23
#define VIRTIOHDR_DEVICE_FEATURES       0
 
24
#define VIRTIOHDR_GUEST_FEATURES        4
 
25
#define VIRTIOHDR_QUEUE_ADDRESS         8
 
26
#define VIRTIOHDR_QUEUE_SIZE            12
 
27
#define VIRTIOHDR_QUEUE_SELECT          14
 
28
#define VIRTIOHDR_QUEUE_NOTIFY          16
 
29
#define VIRTIOHDR_DEVICE_STATUS         18
 
30
#define VIRTIOHDR_ISR_STATUS            19
 
31
#define VIRTIOHDR_MAC_ADDRESS           20
 
32
 
 
33
 
 
34
/**
 
35
 * Module init for virtio via PCI.
 
36
 * Checks whether we're reponsible for the given device and set up
 
37
 * the virtqueue configuration.
 
38
 */
 
39
int
 
40
vn_module_init_pci(snk_kernel_t *snk_kernel_int, pci_config_t *conf)
 
41
{
 
42
        uint64_t bar;
 
43
        int i;
 
44
 
 
45
        dprintk("virtionet: doing virtionet_module_init_pci!\n");
 
46
 
 
47
        virtiodev.type = VIRTIO_TYPE_PCI;
 
48
 
 
49
        /* Check whether the driver can handle this device by verifying vendor,
 
50
         * device id and class code. */
 
51
        if (conf->vendor_id != 0x1af4) {
 
52
                dprintk("virtionet: unsupported vendor id\n");
 
53
                return -1;
 
54
        }
 
55
        if (conf->device_id < 0x1000 || conf->device_id > 0x103f) {
 
56
                dprintk("virtionet: unsupported device id\n");
 
57
                return -1;
 
58
        }
 
59
        if (conf->class_code != 0x20000) {
 
60
                dprintk("virtionet: unsupported class code\n");
 
61
                return -1;
 
62
        }
 
63
 
 
64
        bar = snk_kernel_interface->pci_config_read(conf->puid, 4, conf->bus,
 
65
                                                    conf->devfn, 0x10);
 
66
 
 
67
        if (!(bar & 1)) {
 
68
                printk("First BAR is not an I/O BAR!\n");
 
69
                return -1;
 
70
        }
 
71
        bar &= ~3ULL;
 
72
 
 
73
        dprintk("untranslated bar = %llx\n", bar);
 
74
 
 
75
        snk_kernel_interface->translate_addr((void *)&bar);
 
76
 
 
77
        dprintk("translated bar = %llx\n", bar);
 
78
        virtiodev.base = (void*)bar;
 
79
 
 
80
        /* Reset device */
 
81
        virtio_reset_device(&virtiodev);
 
82
 
 
83
        /* The queue information can be retrieved via the virtio header that
 
84
         * can be found in the I/O BAR. First queue is the receive queue,
 
85
         * second the transmit queue, and the forth is the control queue for
 
86
         * networking options.
 
87
         * We are only interested in the receive and transmit queue here. */
 
88
 
 
89
        for (i=VQ_RX; i<=VQ_TX; i++) {
 
90
                /* Select ring (0=RX, 1=TX): */
 
91
                vq[i].id = i-VQ_RX;
 
92
                ci_write_16(virtiodev.base+VIRTIOHDR_QUEUE_SELECT,
 
93
                            cpu_to_le16(vq[i].id));
 
94
 
 
95
                vq[i].size = le16_to_cpu(ci_read_16(virtiodev.base+VIRTIOHDR_QUEUE_SIZE));
 
96
                vq[i].desc = malloc_aligned(virtio_vring_size(vq[i].size), 4096);
 
97
                if (!vq[i].desc) {
 
98
                        printk("malloc failed!\n");
 
99
                        return -1;
 
100
                }
 
101
                memset(vq[i].desc, 0, virtio_vring_size(vq[i].size));
 
102
                ci_write_32(virtiodev.base+VIRTIOHDR_QUEUE_ADDRESS,
 
103
                            cpu_to_le32((long)vq[i].desc / 4096));
 
104
                vq[i].avail = (void*)vq[i].desc
 
105
                                    + vq[i].size * sizeof(struct vring_desc);
 
106
                vq[i].used = (void*)VQ_ALIGN((long)vq[i].avail
 
107
                                    + vq[i].size * sizeof(struct vring_avail));
 
108
 
 
109
                dprintk("%i: vq.id = %lx\nvq.size =%lx\n vq.avail =%lx\nvq.used=%lx\n",
 
110
                        i, vq[i].id, vq[i].size, vq[i].avail, vq[i].used);
 
111
        }
 
112
 
 
113
        /* Copy MAC address */
 
114
        for (i = 0; i < 6; i++) {
 
115
                virtionet_interface.mac_addr[i]
 
116
                                = ci_read_8(virtiodev.base+VIRTIOHDR_MAC_ADDRESS+i);
 
117
        }
 
118
 
 
119
        /* Acknowledge device. */
 
120
        virtio_set_status(&virtiodev, VIRTIO_STAT_ACKNOWLEDGE);
 
121
 
 
122
        return 0;
 
123
}