1
/******************************************************************************
2
* Copyright (c) 2011 IBM Corporation
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
10
* IBM Corporation - initial implementation
11
*****************************************************************************/
16
#include <byteorder.h>
17
#include <netdriver_int.h>
18
#include <libhvcall.h>
20
#include "virtio-net.h"
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
35
* Module init for virtio via PCI.
36
* Checks whether we're reponsible for the given device and set up
37
* the virtqueue configuration.
40
vn_module_init_pci(snk_kernel_t *snk_kernel_int, pci_config_t *conf)
45
dprintk("virtionet: doing virtionet_module_init_pci!\n");
47
virtiodev.type = VIRTIO_TYPE_PCI;
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");
55
if (conf->device_id < 0x1000 || conf->device_id > 0x103f) {
56
dprintk("virtionet: unsupported device id\n");
59
if (conf->class_code != 0x20000) {
60
dprintk("virtionet: unsupported class code\n");
64
bar = snk_kernel_interface->pci_config_read(conf->puid, 4, conf->bus,
68
printk("First BAR is not an I/O BAR!\n");
73
dprintk("untranslated bar = %llx\n", bar);
75
snk_kernel_interface->translate_addr((void *)&bar);
77
dprintk("translated bar = %llx\n", bar);
78
virtiodev.base = (void*)bar;
81
virtio_reset_device(&virtiodev);
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
87
* We are only interested in the receive and transmit queue here. */
89
for (i=VQ_RX; i<=VQ_TX; i++) {
90
/* Select ring (0=RX, 1=TX): */
92
ci_write_16(virtiodev.base+VIRTIOHDR_QUEUE_SELECT,
93
cpu_to_le16(vq[i].id));
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);
98
printk("malloc failed!\n");
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));
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);
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);
119
/* Acknowledge device. */
120
virtio_set_status(&virtiodev, VIRTIO_STAT_ACKNOWLEDGE);