|
|
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.