|
|
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 <cpu.h>
14: #include <cache.h>
15: #include <byteorder.h>
16: #include "virtio.h"
17:
18: /* PCI virtio header offsets */
19: #define VIRTIOHDR_DEVICE_FEATURES 0
20: #define VIRTIOHDR_GUEST_FEATURES 4
21: #define VIRTIOHDR_QUEUE_ADDRESS 8
22: #define VIRTIOHDR_QUEUE_SIZE 12
23: #define VIRTIOHDR_QUEUE_SELECT 14
24: #define VIRTIOHDR_QUEUE_NOTIFY 16
25: #define VIRTIOHDR_DEVICE_STATUS 18
26: #define VIRTIOHDR_ISR_STATUS 19
27: #define VIRTIOHDR_DEVICE_CONFIG 20
28:
29:
30: /**
31: * Calculate ring size according to queue size number
32: */
33: unsigned long virtio_vring_size(unsigned int qsize)
34: {
35: return VQ_ALIGN(sizeof(struct vring_desc) * qsize + 2 * (2 + qsize))
36: + VQ_ALIGN(sizeof(struct vring_used_elem) * qsize);
37: }
38:
39:
40: /**
41: * Get number of elements in a vring
42: * @param dev pointer to virtio device information
43: * @param queue virtio queue number
44: * @return number of elements
45: */
46: int virtio_get_qsize(struct virtio_device *dev, int queue)
47: {
48: int size = 0;
49:
50: if (dev->type == VIRTIO_TYPE_PCI) {
51: ci_write_16(dev->base+VIRTIOHDR_QUEUE_SELECT,
52: cpu_to_le16(queue));
53: eieio();
54: size = le16_to_cpu(ci_read_16(dev->base+VIRTIOHDR_QUEUE_SIZE));
55: }
56:
57: return size;
58: }
59:
60:
61: /**
62: * Get address of descriptor vring
63: * @param dev pointer to virtio device information
64: * @param queue virtio queue number
65: * @return pointer to the descriptor ring
66: */
67: struct vring_desc *virtio_get_vring_desc(struct virtio_device *dev, int queue)
68: {
69: struct vring_desc *desc = 0;
70:
71: if (dev->type == VIRTIO_TYPE_PCI) {
72: ci_write_16(dev->base+VIRTIOHDR_QUEUE_SELECT,
73: cpu_to_le16(queue));
74: eieio();
75: desc = (void*)(4096L *
76: le32_to_cpu(ci_read_32(dev->base+VIRTIOHDR_QUEUE_ADDRESS)));
77: }
78:
79: return desc;
80: }
81:
82:
83: /**
84: * Get address of "available" vring
85: * @param dev pointer to virtio device information
86: * @param queue virtio queue number
87: * @return pointer to the "available" ring
88: */
89: struct vring_avail *virtio_get_vring_avail(struct virtio_device *dev, int queue)
90: {
91: return (void*)((uint64_t)virtio_get_vring_desc(dev, queue)
92: + virtio_get_qsize(dev, queue) * sizeof(struct vring_desc));
93: }
94:
95:
96: /**
97: * Get address of "used" vring
98: * @param dev pointer to virtio device information
99: * @param queue virtio queue number
100: * @return pointer to the "used" ring
101: */
102: struct vring_used *virtio_get_vring_used(struct virtio_device *dev, int queue)
103: {
104: return (void*)VQ_ALIGN((uint64_t)virtio_get_vring_avail(dev, queue)
105: + virtio_get_qsize(dev, queue)
106: * sizeof(struct vring_avail));
107: }
108:
109:
110: /**
111: * Reset virtio device
112: */
113: void virtio_reset_device(struct virtio_device *dev)
114: {
115: if (dev->type == VIRTIO_TYPE_PCI) {
116: ci_write_8(dev->base+VIRTIOHDR_DEVICE_STATUS, 0);
117: }
118: }
119:
120:
121: /**
122: * Notify hypervisor about queue update
123: */
124: void virtio_queue_notify(struct virtio_device *dev, int queue)
125: {
126: if (dev->type == VIRTIO_TYPE_PCI) {
127: ci_write_16(dev->base+VIRTIOHDR_QUEUE_NOTIFY, cpu_to_le16(queue));
128: }
129: }
130:
131:
132: /**
133: * Set device status bits
134: */
135: void virtio_set_status(struct virtio_device *dev, int status)
136: {
137: if (dev->type == VIRTIO_TYPE_PCI) {
138: ci_write_8(dev->base+VIRTIOHDR_DEVICE_STATUS, status);
139: }
140: }
141:
142:
143: /**
144: * Set guest feature bits
145: */
146: void virtio_set_guest_features(struct virtio_device *dev, int features)
147:
148: {
149: if (dev->type == VIRTIO_TYPE_PCI) {
150: ci_write_32(dev->base+VIRTIOHDR_GUEST_FEATURES, features);
151: }
152: }
153:
154:
155: /**
156: * Get additional config values
157: */
158: uint64_t virtio_get_config(struct virtio_device *dev, int offset, int size)
159: {
160: uint64_t val = ~0ULL;
161: void *confbase;
162:
163: switch (dev->type) {
164: case VIRTIO_TYPE_PCI:
165: confbase = dev->base+VIRTIOHDR_DEVICE_CONFIG;
166: break;
167: default:
168: return ~0ULL;
169: }
170: switch (size) {
171: case 1:
172: val = ci_read_8(confbase+offset);
173: break;
174: case 2:
175: val = ci_read_16(confbase+offset);
176: break;
177: case 4:
178: val = ci_read_32(confbase+offset);
179: break;
180: case 8:
181: /* We don't support 8 bytes PIO accesses
182: * in qemu and this is all PIO
183: */
184: val = ci_read_32(confbase+offset);
185: val <<= 32;
186: val |= ci_read_32(confbase+offset+4);
187: break;
188: }
189:
190: return val;
191: }
192:
193: /**
194: * Get config blob
195: */
196: int __virtio_read_config(struct virtio_device *dev, void *dst,
197: int offset, int len)
198: {
199: void *confbase;
200: unsigned char *buf = dst;
201: int i;
202:
203: switch (dev->type) {
204: case VIRTIO_TYPE_PCI:
205: confbase = dev->base+VIRTIOHDR_DEVICE_CONFIG;
206: break;
207: default:
208: return 0;
209: }
210: for (i = 0; i < len; i++)
211: buf[i] = ci_read_8(confbase + offset + i);
212: return len;
213: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.