"Das U-Boot" Source Tree
at master 469 lines 12 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2018, Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi> 4 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com> 5 * 6 * virtio ring implementation 7 */ 8 9#include <bouncebuf.h> 10#include <dm.h> 11#include <log.h> 12#include <malloc.h> 13#include <virtio_types.h> 14#include <virtio.h> 15#include <virtio_ring.h> 16#include <linux/bug.h> 17#include <linux/compat.h> 18#include <linux/kernel.h> 19 20static void *virtio_alloc_pages(struct udevice *vdev, u32 npages) 21{ 22 return memalign(PAGE_SIZE, npages * PAGE_SIZE); 23} 24 25static void virtio_free_pages(struct udevice *vdev, void *ptr, u32 npages) 26{ 27 free(ptr); 28} 29 30static int __bb_force_page_align(struct bounce_buffer *state) 31{ 32 const ulong align_mask = PAGE_SIZE - 1; 33 34 if ((ulong)state->user_buffer & align_mask) 35 return 0; 36 37 if (state->len != state->len_aligned) 38 return 0; 39 40 return 1; 41} 42 43static unsigned int virtqueue_attach_desc(struct virtqueue *vq, unsigned int i, 44 struct virtio_sg *sg, u16 flags) 45{ 46 struct vring_desc_shadow *desc_shadow = &vq->vring_desc_shadow[i]; 47 struct vring_desc *desc = &vq->vring.desc[i]; 48 void *addr; 49 50 if (IS_ENABLED(CONFIG_BOUNCE_BUFFER) && vq->vring.bouncebufs) { 51 struct bounce_buffer *bb = &vq->vring.bouncebufs[i]; 52 unsigned int bbflags; 53 int ret; 54 55 if (flags & VRING_DESC_F_WRITE) 56 bbflags = GEN_BB_WRITE; 57 else 58 bbflags = GEN_BB_READ; 59 60 ret = bounce_buffer_start_extalign(bb, sg->addr, sg->length, 61 bbflags, PAGE_SIZE, 62 __bb_force_page_align); 63 if (ret) { 64 debug("%s: failed to allocate bounce buffer (length 0x%zx)\n", 65 vq->vdev->name, sg->length); 66 } 67 68 addr = bb->bounce_buffer; 69 } else { 70 addr = sg->addr; 71 } 72 73 /* Update the shadow descriptor. */ 74 desc_shadow->addr = (u64)(uintptr_t)addr; 75 desc_shadow->len = sg->length; 76 desc_shadow->flags = flags; 77 78 /* Update the shared descriptor to match the shadow. */ 79 desc->addr = cpu_to_virtio64(vq->vdev, desc_shadow->addr); 80 desc->len = cpu_to_virtio32(vq->vdev, desc_shadow->len); 81 desc->flags = cpu_to_virtio16(vq->vdev, desc_shadow->flags); 82 desc->next = cpu_to_virtio16(vq->vdev, desc_shadow->next); 83 84 return desc_shadow->next; 85} 86 87static void virtqueue_detach_desc(struct virtqueue *vq, unsigned int idx) 88{ 89 struct vring_desc *desc = &vq->vring.desc[idx]; 90 struct bounce_buffer *bb; 91 92 if (!IS_ENABLED(CONFIG_BOUNCE_BUFFER) || !vq->vring.bouncebufs) 93 return; 94 95 bb = &vq->vring.bouncebufs[idx]; 96 bounce_buffer_stop(bb); 97 desc->addr = cpu_to_virtio64(vq->vdev, (u64)(uintptr_t)bb->user_buffer); 98} 99 100int virtqueue_add(struct virtqueue *vq, struct virtio_sg *sgs[], 101 unsigned int out_sgs, unsigned int in_sgs) 102{ 103 struct vring_desc *desc; 104 unsigned int descs_used = out_sgs + in_sgs; 105 unsigned int i, n, avail, uninitialized_var(prev); 106 int head; 107 108 WARN_ON(descs_used == 0); 109 110 head = vq->free_head; 111 112 desc = vq->vring.desc; 113 i = head; 114 115 if (vq->num_free < descs_used) { 116 debug("Can't add buf len %i - avail = %i\n", 117 descs_used, vq->num_free); 118 /* 119 * FIXME: for historical reasons, we force a notify here if 120 * there are outgoing parts to the buffer. Presumably the 121 * host should service the ring ASAP. 122 */ 123 if (out_sgs) 124 virtio_notify(vq->vdev, vq); 125 return -ENOSPC; 126 } 127 128 for (n = 0; n < descs_used; n++) { 129 u16 flags = VRING_DESC_F_NEXT; 130 131 if (n >= out_sgs) 132 flags |= VRING_DESC_F_WRITE; 133 prev = i; 134 i = virtqueue_attach_desc(vq, i, sgs[n], flags); 135 } 136 /* Last one doesn't continue */ 137 vq->vring_desc_shadow[prev].flags &= ~VRING_DESC_F_NEXT; 138 desc[prev].flags = cpu_to_virtio16(vq->vdev, vq->vring_desc_shadow[prev].flags); 139 140 /* We're using some buffers from the free list. */ 141 vq->num_free -= descs_used; 142 143 /* Update free pointer */ 144 vq->free_head = i; 145 146 /* Mark the descriptor as the head of a chain. */ 147 vq->vring_desc_shadow[head].chain_head = true; 148 149 /* 150 * Put entry in available array (but don't update avail->idx 151 * until they do sync). 152 */ 153 avail = vq->avail_idx_shadow & (vq->vring.num - 1); 154 vq->vring.avail->ring[avail] = cpu_to_virtio16(vq->vdev, head); 155 156 /* 157 * Descriptors and available array need to be set before we expose the 158 * new available array entries. 159 */ 160 virtio_wmb(); 161 vq->avail_idx_shadow++; 162 vq->vring.avail->idx = cpu_to_virtio16(vq->vdev, vq->avail_idx_shadow); 163 vq->num_added++; 164 165 /* 166 * This is very unlikely, but theoretically possible. 167 * Kick just in case. 168 */ 169 if (unlikely(vq->num_added == (1 << 16) - 1)) 170 virtqueue_kick(vq); 171 172 return 0; 173} 174 175static bool virtqueue_kick_prepare(struct virtqueue *vq) 176{ 177 u16 new, old; 178 bool needs_kick; 179 180 /* 181 * We need to expose available array entries before checking 182 * avail event. 183 */ 184 virtio_mb(); 185 186 old = vq->avail_idx_shadow - vq->num_added; 187 new = vq->avail_idx_shadow; 188 vq->num_added = 0; 189 190 if (vq->event) { 191 needs_kick = vring_need_event(virtio16_to_cpu(vq->vdev, 192 vring_avail_event(&vq->vring)), new, old); 193 } else { 194 needs_kick = !(vq->vring.used->flags & cpu_to_virtio16(vq->vdev, 195 VRING_USED_F_NO_NOTIFY)); 196 } 197 198 return needs_kick; 199} 200 201void virtqueue_kick(struct virtqueue *vq) 202{ 203 if (virtqueue_kick_prepare(vq)) 204 virtio_notify(vq->vdev, vq); 205} 206 207static void detach_buf(struct virtqueue *vq, unsigned int head) 208{ 209 unsigned int i; 210 211 /* Unmark the descriptor as the head of a chain. */ 212 vq->vring_desc_shadow[head].chain_head = false; 213 214 /* Put back on free list: unmap first-level descriptors and find end */ 215 i = head; 216 217 while (vq->vring_desc_shadow[i].flags & VRING_DESC_F_NEXT) { 218 virtqueue_detach_desc(vq, i); 219 i = vq->vring_desc_shadow[i].next; 220 vq->num_free++; 221 } 222 223 virtqueue_detach_desc(vq, i); 224 vq->vring_desc_shadow[i].next = vq->free_head; 225 vq->free_head = head; 226 227 /* Plus final descriptor */ 228 vq->num_free++; 229} 230 231static inline bool more_used(const struct virtqueue *vq) 232{ 233 return vq->last_used_idx != virtio16_to_cpu(vq->vdev, 234 vq->vring.used->idx); 235} 236 237void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len) 238{ 239 unsigned int i; 240 u16 last_used; 241 242 if (!more_used(vq)) { 243 debug("(%s.%d): No more buffers in queue\n", 244 vq->vdev->name, vq->index); 245 return NULL; 246 } 247 248 /* Only get used array entries after they have been exposed by host */ 249 virtio_rmb(); 250 251 last_used = (vq->last_used_idx & (vq->vring.num - 1)); 252 i = virtio32_to_cpu(vq->vdev, vq->vring.used->ring[last_used].id); 253 if (len) { 254 *len = virtio32_to_cpu(vq->vdev, 255 vq->vring.used->ring[last_used].len); 256 debug("(%s.%d): last used idx %u with len %u\n", 257 vq->vdev->name, vq->index, i, *len); 258 } 259 260 if (unlikely(i >= vq->vring.num)) { 261 printf("(%s.%d): id %u out of range\n", 262 vq->vdev->name, vq->index, i); 263 return NULL; 264 } 265 266 if (unlikely(!vq->vring_desc_shadow[i].chain_head)) { 267 printf("(%s.%d): id %u is not a head\n", 268 vq->vdev->name, vq->index, i); 269 return NULL; 270 } 271 272 detach_buf(vq, i); 273 vq->last_used_idx++; 274 /* 275 * If we expect an interrupt for the next entry, tell host 276 * by writing event index and flush out the write before 277 * the read in the next get_buf call. 278 */ 279 if (!(vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT)) 280 virtio_store_mb(&vring_used_event(&vq->vring), 281 cpu_to_virtio16(vq->vdev, vq->last_used_idx)); 282 283 return (void *)(uintptr_t)vq->vring_desc_shadow[i].addr; 284} 285 286static struct virtqueue *__vring_new_virtqueue(unsigned int index, 287 struct vring vring, 288 struct udevice *udev) 289{ 290 unsigned int i; 291 struct virtqueue *vq; 292 struct vring_desc_shadow *vring_desc_shadow; 293 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev); 294 struct udevice *vdev = uc_priv->vdev; 295 296 vq = malloc(sizeof(*vq)); 297 if (!vq) 298 return NULL; 299 300 vring_desc_shadow = calloc(vring.num, sizeof(struct vring_desc_shadow)); 301 if (!vring_desc_shadow) { 302 free(vq); 303 return NULL; 304 } 305 306 vq->vdev = vdev; 307 vq->index = index; 308 vq->num_free = vring.num; 309 vq->vring = vring; 310 vq->vring_desc_shadow = vring_desc_shadow; 311 vq->last_used_idx = 0; 312 vq->avail_flags_shadow = 0; 313 vq->avail_idx_shadow = 0; 314 vq->num_added = 0; 315 list_add_tail(&vq->list, &uc_priv->vqs); 316 317 vq->event = virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX); 318 319 /* Tell other side not to bother us */ 320 vq->avail_flags_shadow |= VRING_AVAIL_F_NO_INTERRUPT; 321 if (!vq->event) 322 vq->vring.avail->flags = cpu_to_virtio16(vdev, 323 vq->avail_flags_shadow); 324 325 /* Put everything in free lists */ 326 vq->free_head = 0; 327 for (i = 0; i < vring.num - 1; i++) 328 vq->vring_desc_shadow[i].next = i + 1; 329 330 return vq; 331} 332 333struct virtqueue *vring_create_virtqueue(unsigned int index, unsigned int num, 334 unsigned int vring_align, 335 struct udevice *udev) 336{ 337 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev); 338 struct udevice *vdev = uc_priv->vdev; 339 struct virtqueue *vq; 340 void *queue = NULL; 341 struct bounce_buffer *bbs = NULL; 342 struct vring vring; 343 344 /* We assume num is a power of 2 */ 345 if (num & (num - 1)) { 346 printf("Bad virtqueue length %u\n", num); 347 return NULL; 348 } 349 350 /* TODO: allocate each queue chunk individually */ 351 for (; num && vring_size(num, vring_align) > PAGE_SIZE; num /= 2) { 352 size_t sz = vring_size(num, vring_align); 353 354 queue = virtio_alloc_pages(vdev, DIV_ROUND_UP(sz, PAGE_SIZE)); 355 if (queue) 356 break; 357 } 358 359 if (!num) 360 return NULL; 361 362 if (!queue) { 363 /* Try to get a single page. You are my only hope! */ 364 queue = virtio_alloc_pages(vdev, 1); 365 } 366 if (!queue) 367 return NULL; 368 369 memset(queue, 0, vring_size(num, vring_align)); 370 371 if (virtio_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM)) { 372 bbs = calloc(num, sizeof(*bbs)); 373 if (!bbs) 374 goto err_free_queue; 375 } 376 377 vring_init(&vring, num, queue, vring_align, bbs); 378 379 vq = __vring_new_virtqueue(index, vring, udev); 380 if (!vq) 381 goto err_free_bbs; 382 383 debug("(%s): created vring @ %p for vq @ %p with num %u\n", udev->name, 384 queue, vq, num); 385 386 return vq; 387 388err_free_bbs: 389 free(bbs); 390err_free_queue: 391 virtio_free_pages(vdev, queue, DIV_ROUND_UP(vring.size, PAGE_SIZE)); 392 return NULL; 393} 394 395void vring_del_virtqueue(struct virtqueue *vq) 396{ 397 virtio_free_pages(vq->vdev, vq->vring.desc, 398 DIV_ROUND_UP(vq->vring.size, PAGE_SIZE)); 399 free(vq->vring_desc_shadow); 400 list_del(&vq->list); 401 free(vq->vring.bouncebufs); 402 free(vq); 403} 404 405unsigned int virtqueue_get_vring_size(struct virtqueue *vq) 406{ 407 return vq->vring.num; 408} 409 410ulong virtqueue_get_desc_addr(struct virtqueue *vq) 411{ 412 return (ulong)vq->vring.desc; 413} 414 415ulong virtqueue_get_avail_addr(struct virtqueue *vq) 416{ 417 return (ulong)vq->vring.desc + 418 ((char *)vq->vring.avail - (char *)vq->vring.desc); 419} 420 421ulong virtqueue_get_used_addr(struct virtqueue *vq) 422{ 423 return (ulong)vq->vring.desc + 424 ((char *)vq->vring.used - (char *)vq->vring.desc); 425} 426 427bool virtqueue_poll(struct virtqueue *vq, u16 last_used_idx) 428{ 429 virtio_mb(); 430 431 return last_used_idx != virtio16_to_cpu(vq->vdev, vq->vring.used->idx); 432} 433 434void virtqueue_dump(struct virtqueue *vq) 435{ 436 unsigned int i; 437 438 printf("virtqueue %p for dev %s:\n", vq, vq->vdev->name); 439 printf("\tindex %u, phys addr %p num %u\n", 440 vq->index, vq->vring.desc, vq->vring.num); 441 printf("\tfree_head %u, num_added %u, num_free %u\n", 442 vq->free_head, vq->num_added, vq->num_free); 443 printf("\tlast_used_idx %u, avail_flags_shadow %u, avail_idx_shadow %u\n", 444 vq->last_used_idx, vq->avail_flags_shadow, vq->avail_idx_shadow); 445 446 printf("Shadow descriptor dump:\n"); 447 for (i = 0; i < vq->vring.num; i++) { 448 struct vring_desc_shadow *desc = &vq->vring_desc_shadow[i]; 449 450 printf("\tdesc_shadow[%u] = { 0x%llx, len %u, flags %u, next %u }\n", 451 i, desc->addr, desc->len, desc->flags, desc->next); 452 } 453 454 printf("Avail ring dump:\n"); 455 printf("\tflags %u, idx %u\n", 456 vq->vring.avail->flags, vq->vring.avail->idx); 457 for (i = 0; i < vq->vring.num; i++) { 458 printf("\tavail[%u] = %u\n", 459 i, vq->vring.avail->ring[i]); 460 } 461 462 printf("Used ring dump:\n"); 463 printf("\tflags %u, idx %u\n", 464 vq->vring.used->flags, vq->vring.used->idx); 465 for (i = 0; i < vq->vring.num; i++) { 466 printf("\tused[%u] = { %u, %u }\n", i, 467 vq->vring.used->ring[i].id, vq->vring.used->ring[i].len); 468 } 469}