|
|
1.1 root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.