1 /* 2 * Copyright 2013, Jérôme Duval, korli@users.berlios.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "VirtioPrivate.h" 8 9 10 const char * 11 virtio_get_feature_name(uint32 feature) 12 { 13 switch (feature) { 14 case VIRTIO_FEATURE_NOTIFY_ON_EMPTY: 15 return "notify on empty"; 16 case VIRTIO_FEATURE_RING_INDIRECT_DESC: 17 return "ring indirect"; 18 case VIRTIO_FEATURE_RING_EVENT_IDX: 19 return "ring event index"; 20 case VIRTIO_FEATURE_BAD_FEATURE: 21 return "bad feature"; 22 } 23 return NULL; 24 } 25 26 27 const char * 28 virtio_get_device_type_name(uint16 type) 29 { 30 switch (type) { 31 case VIRTIO_DEVICE_ID_NETWORK: 32 return "network"; 33 case VIRTIO_DEVICE_ID_BLOCK: 34 return "block"; 35 case VIRTIO_DEVICE_ID_CONSOLE: 36 return "console"; 37 case VIRTIO_DEVICE_ID_ENTROPY: 38 return "entropy"; 39 case VIRTIO_DEVICE_ID_BALLOON: 40 return "balloon"; 41 case VIRTIO_DEVICE_ID_IOMEMORY: 42 return "io_memory"; 43 case VIRTIO_DEVICE_ID_SCSI: 44 return "scsi"; 45 case VIRTIO_DEVICE_ID_9P: 46 return "9p transport"; 47 default: 48 return "unknown"; 49 } 50 } 51 52 53 VirtioDevice::VirtioDevice(device_node *node) 54 : 55 fNode(node), 56 fID(0), 57 fController(NULL), 58 fCookie(NULL), 59 fStatus(B_NO_INIT), 60 fQueues(NULL), 61 fFeatures(0), 62 fAlignment(0), 63 fConfigHandler(NULL), 64 fDriverCookie(NULL) 65 { 66 device_node *parent = gDeviceManager->get_parent_node(node); 67 fStatus = gDeviceManager->get_driver(parent, 68 (driver_module_info **)&fController, &fCookie); 69 gDeviceManager->put_node(parent); 70 71 if (fStatus != B_OK) 72 return; 73 74 fStatus = gDeviceManager->get_attr_uint16(fNode, 75 VIRTIO_VRING_ALIGNMENT_ITEM, &fAlignment, true); 76 if (fStatus != B_OK) { 77 ERROR("alignment missing\n"); 78 return; 79 } 80 81 fController->set_sim(fCookie, this); 82 83 fController->set_status(fCookie, VIRTIO_CONFIG_STATUS_DRIVER); 84 } 85 86 87 VirtioDevice::~VirtioDevice() 88 { 89 for (size_t index = 0; index < fQueueCount; index++) { 90 delete fQueues[index]; 91 } 92 delete fQueues; 93 } 94 95 96 status_t 97 VirtioDevice::InitCheck() 98 { 99 return fStatus; 100 } 101 102 103 status_t 104 VirtioDevice::NegociateFeatures(uint32 supported, uint32* negociated, 105 const char* (*get_feature_name)(uint32)) 106 { 107 fFeatures = 0; 108 status_t status = fController->read_host_features(fCookie, &fFeatures); 109 if (status != B_OK) 110 return status; 111 112 DumpFeatures("read features", fFeatures, get_feature_name); 113 114 fFeatures &= supported; 115 116 // filter our own features 117 fFeatures &= (VIRTIO_FEATURE_TRANSPORT_MASK 118 | VIRTIO_FEATURE_RING_INDIRECT_DESC | VIRTIO_FEATURE_RING_EVENT_IDX); 119 120 *negociated = fFeatures; 121 122 DumpFeatures("negociated features", fFeatures, get_feature_name); 123 124 return fController->write_guest_features(fCookie, fFeatures); 125 } 126 127 128 status_t 129 VirtioDevice::ReadDeviceConfig(uint8 offset, void* buffer, size_t bufferSize) 130 { 131 return fController->read_device_config(fCookie, offset, buffer, 132 bufferSize); 133 } 134 135 136 status_t 137 VirtioDevice::WriteDeviceConfig(uint8 offset, const void* buffer, 138 size_t bufferSize) 139 { 140 return fController->write_device_config(fCookie, offset, buffer, 141 bufferSize); 142 } 143 144 145 status_t 146 VirtioDevice::AllocateQueues(size_t count, virtio_queue *queues) 147 { 148 if (count > VIRTIO_VIRTQUEUES_MAX_COUNT || queues == NULL) 149 return B_BAD_VALUE; 150 151 status_t status = B_OK; 152 fQueues = new(std::nothrow) VirtioQueue*[count]; 153 if (fQueues == NULL) { 154 status = B_NO_MEMORY; 155 goto err; 156 } 157 158 fQueueCount = count; 159 for (size_t index = 0; index < count; index++) { 160 uint16 size = fController->get_queue_ring_size(fCookie, index); 161 fQueues[index] = new(std::nothrow) VirtioQueue(this, index, size); 162 queues[index] = fQueues[index]; 163 status = B_NO_MEMORY; 164 if (fQueues[index] != NULL) 165 status = fQueues[index]->InitCheck(); 166 if (status != B_OK) 167 goto err; 168 } 169 170 return B_OK; 171 172 err: 173 return status; 174 } 175 176 177 status_t 178 VirtioDevice::SetupInterrupt(virtio_intr_func configHandler, void *driverCookie) 179 { 180 fConfigHandler = configHandler; 181 fDriverCookie = driverCookie; 182 status_t status = fController->setup_interrupt(fCookie, fQueueCount); 183 if (status != B_OK) 184 return status; 185 186 // ready to go 187 fController->set_status(fCookie, VIRTIO_CONFIG_STATUS_DRIVER_OK); 188 189 for (size_t index = 0; index < fQueueCount; index++) 190 fQueues[index]->EnableInterrupt(); 191 return B_OK; 192 } 193 194 195 status_t 196 VirtioDevice::SetupQueue(uint16 queueNumber, phys_addr_t physAddr) 197 { 198 return fController->setup_queue(fCookie, queueNumber, physAddr); 199 } 200 201 202 void 203 VirtioDevice::NotifyQueue(uint16 queueNumber) 204 { 205 fController->notify_queue(fCookie, queueNumber); 206 } 207 208 209 status_t 210 VirtioDevice::QueueInterrupt(uint16 queueNumber) 211 { 212 if (queueNumber != INT16_MAX) { 213 if (queueNumber >= fQueueCount) 214 return B_BAD_VALUE; 215 return fQueues[queueNumber]->Interrupt(); 216 } 217 218 status_t status = B_OK; 219 for (uint16 i = 0; i < fQueueCount; i++) { 220 status = fQueues[i]->Interrupt(); 221 if (status != B_OK) 222 break; 223 } 224 225 return status; 226 } 227 228 229 status_t 230 VirtioDevice::ConfigInterrupt() 231 { 232 if (fConfigHandler != NULL) 233 fConfigHandler(fDriverCookie); 234 return B_OK; 235 } 236 237 238 void 239 VirtioDevice::DumpFeatures(const char* title, uint32 features, 240 const char* (*get_feature_name)(uint32)) 241 { 242 char features_string[512] = ""; 243 for (uint32 i = 0; i < 32; i++) { 244 uint32 feature = features & (1 << i); 245 if (feature == 0) 246 continue; 247 const char* name = virtio_get_feature_name(feature); 248 if (name == NULL) 249 name = get_feature_name(feature); 250 if (name != NULL) { 251 snprintf(features_string, sizeof(features_string), "%s[%s] ", 252 features_string, name); 253 } 254 } 255 TRACE("%s: %s\n", title, features_string); 256 } 257