1481eaec3SMichael S. Tsirkin /* 2481eaec3SMichael S. Tsirkin * Copyright (C) 2016 Red Hat, Inc. 3481eaec3SMichael S. Tsirkin * Author: Michael S. Tsirkin <mst@redhat.com> 4481eaec3SMichael S. Tsirkin * This work is licensed under the terms of the GNU GPL, version 2. 5481eaec3SMichael S. Tsirkin * 6481eaec3SMichael S. Tsirkin * Partial implementation of virtio 0.9. event index is used for signalling, 7481eaec3SMichael S. Tsirkin * unconditionally. Design roughly follows linux kernel implementation in order 8481eaec3SMichael S. Tsirkin * to be able to judge its performance. 9481eaec3SMichael S. Tsirkin */ 10481eaec3SMichael S. Tsirkin #define _GNU_SOURCE 11481eaec3SMichael S. Tsirkin #include "main.h" 12481eaec3SMichael S. Tsirkin #include <stdlib.h> 13481eaec3SMichael S. Tsirkin #include <stdio.h> 14481eaec3SMichael S. Tsirkin #include <assert.h> 15481eaec3SMichael S. Tsirkin #include <string.h> 16481eaec3SMichael S. Tsirkin #include <linux/virtio_ring.h> 17481eaec3SMichael S. Tsirkin 18481eaec3SMichael S. Tsirkin struct data { 19481eaec3SMichael S. Tsirkin void *data; 20481eaec3SMichael S. Tsirkin } *data; 21481eaec3SMichael S. Tsirkin 22481eaec3SMichael S. Tsirkin struct vring ring; 23481eaec3SMichael S. Tsirkin 24481eaec3SMichael S. Tsirkin /* enabling the below activates experimental ring polling code 25481eaec3SMichael S. Tsirkin * (which skips index reads on consumer in favor of looking at 26481eaec3SMichael S. Tsirkin * high bits of ring id ^ 0x8000). 27481eaec3SMichael S. Tsirkin */ 28481eaec3SMichael S. Tsirkin /* #ifdef RING_POLL */ 29*ce10c1b9SMichael S. Tsirkin /* enabling the below activates experimental in-order code 30*ce10c1b9SMichael S. Tsirkin * (which skips ring updates and reads and writes len in descriptor). 31*ce10c1b9SMichael S. Tsirkin */ 32*ce10c1b9SMichael S. Tsirkin /* #ifdef INORDER */ 33*ce10c1b9SMichael S. Tsirkin 34*ce10c1b9SMichael S. Tsirkin #if defined(RING_POLL) && defined(INORDER) 35*ce10c1b9SMichael S. Tsirkin #error "RING_POLL and INORDER are mutually exclusive" 36*ce10c1b9SMichael S. Tsirkin #endif 37481eaec3SMichael S. Tsirkin 38481eaec3SMichael S. Tsirkin /* how much padding is needed to avoid false cache sharing */ 39481eaec3SMichael S. Tsirkin #define HOST_GUEST_PADDING 0x80 40481eaec3SMichael S. Tsirkin 41481eaec3SMichael S. Tsirkin struct guest { 42481eaec3SMichael S. Tsirkin unsigned short avail_idx; 43481eaec3SMichael S. Tsirkin unsigned short last_used_idx; 44481eaec3SMichael S. Tsirkin unsigned short num_free; 45481eaec3SMichael S. Tsirkin unsigned short kicked_avail_idx; 46*ce10c1b9SMichael S. Tsirkin #ifndef INORDER 47481eaec3SMichael S. Tsirkin unsigned short free_head; 48*ce10c1b9SMichael S. Tsirkin #else 49*ce10c1b9SMichael S. Tsirkin unsigned short reserved_free_head; 50*ce10c1b9SMichael S. Tsirkin #endif 51481eaec3SMichael S. Tsirkin unsigned char reserved[HOST_GUEST_PADDING - 10]; 52481eaec3SMichael S. Tsirkin } guest; 53481eaec3SMichael S. Tsirkin 54481eaec3SMichael S. Tsirkin struct host { 55481eaec3SMichael S. Tsirkin /* we do not need to track last avail index 56481eaec3SMichael S. Tsirkin * unless we have more than one in flight. 57481eaec3SMichael S. Tsirkin */ 58481eaec3SMichael S. Tsirkin unsigned short used_idx; 59481eaec3SMichael S. Tsirkin unsigned short called_used_idx; 60481eaec3SMichael S. Tsirkin unsigned char reserved[HOST_GUEST_PADDING - 4]; 61481eaec3SMichael S. Tsirkin } host; 62481eaec3SMichael S. Tsirkin 63481eaec3SMichael S. Tsirkin /* implemented by ring */ 64481eaec3SMichael S. Tsirkin void alloc_ring(void) 65481eaec3SMichael S. Tsirkin { 66481eaec3SMichael S. Tsirkin int ret; 67481eaec3SMichael S. Tsirkin int i; 68481eaec3SMichael S. Tsirkin void *p; 69481eaec3SMichael S. Tsirkin 70481eaec3SMichael S. Tsirkin ret = posix_memalign(&p, 0x1000, vring_size(ring_size, 0x1000)); 71481eaec3SMichael S. Tsirkin if (ret) { 72481eaec3SMichael S. Tsirkin perror("Unable to allocate ring buffer.\n"); 73481eaec3SMichael S. Tsirkin exit(3); 74481eaec3SMichael S. Tsirkin } 75481eaec3SMichael S. Tsirkin memset(p, 0, vring_size(ring_size, 0x1000)); 76481eaec3SMichael S. Tsirkin vring_init(&ring, ring_size, p, 0x1000); 77481eaec3SMichael S. Tsirkin 78481eaec3SMichael S. Tsirkin guest.avail_idx = 0; 79481eaec3SMichael S. Tsirkin guest.kicked_avail_idx = -1; 80481eaec3SMichael S. Tsirkin guest.last_used_idx = 0; 81*ce10c1b9SMichael S. Tsirkin #ifndef INORDER 82481eaec3SMichael S. Tsirkin /* Put everything in free lists. */ 83481eaec3SMichael S. Tsirkin guest.free_head = 0; 84*ce10c1b9SMichael S. Tsirkin #endif 85481eaec3SMichael S. Tsirkin for (i = 0; i < ring_size - 1; i++) 86481eaec3SMichael S. Tsirkin ring.desc[i].next = i + 1; 87481eaec3SMichael S. Tsirkin host.used_idx = 0; 88481eaec3SMichael S. Tsirkin host.called_used_idx = -1; 89481eaec3SMichael S. Tsirkin guest.num_free = ring_size; 90481eaec3SMichael S. Tsirkin data = malloc(ring_size * sizeof *data); 91481eaec3SMichael S. Tsirkin if (!data) { 92481eaec3SMichael S. Tsirkin perror("Unable to allocate data buffer.\n"); 93481eaec3SMichael S. Tsirkin exit(3); 94481eaec3SMichael S. Tsirkin } 95481eaec3SMichael S. Tsirkin memset(data, 0, ring_size * sizeof *data); 96481eaec3SMichael S. Tsirkin } 97481eaec3SMichael S. Tsirkin 98481eaec3SMichael S. Tsirkin /* guest side */ 99481eaec3SMichael S. Tsirkin int add_inbuf(unsigned len, void *buf, void *datap) 100481eaec3SMichael S. Tsirkin { 101*ce10c1b9SMichael S. Tsirkin unsigned head; 102*ce10c1b9SMichael S. Tsirkin #ifndef INORDER 103*ce10c1b9SMichael S. Tsirkin unsigned avail; 104*ce10c1b9SMichael S. Tsirkin #endif 105481eaec3SMichael S. Tsirkin struct vring_desc *desc; 106481eaec3SMichael S. Tsirkin 107481eaec3SMichael S. Tsirkin if (!guest.num_free) 108481eaec3SMichael S. Tsirkin return -1; 109481eaec3SMichael S. Tsirkin 110*ce10c1b9SMichael S. Tsirkin #ifdef INORDER 111*ce10c1b9SMichael S. Tsirkin head = (ring_size - 1) & (guest.avail_idx++); 112*ce10c1b9SMichael S. Tsirkin #else 113481eaec3SMichael S. Tsirkin head = guest.free_head; 114*ce10c1b9SMichael S. Tsirkin #endif 115481eaec3SMichael S. Tsirkin guest.num_free--; 116481eaec3SMichael S. Tsirkin 117481eaec3SMichael S. Tsirkin desc = ring.desc; 118481eaec3SMichael S. Tsirkin desc[head].flags = VRING_DESC_F_NEXT; 119481eaec3SMichael S. Tsirkin desc[head].addr = (unsigned long)(void *)buf; 120481eaec3SMichael S. Tsirkin desc[head].len = len; 121481eaec3SMichael S. Tsirkin /* We do it like this to simulate the way 122481eaec3SMichael S. Tsirkin * we'd have to flip it if we had multiple 123481eaec3SMichael S. Tsirkin * descriptors. 124481eaec3SMichael S. Tsirkin */ 125481eaec3SMichael S. Tsirkin desc[head].flags &= ~VRING_DESC_F_NEXT; 126*ce10c1b9SMichael S. Tsirkin #ifndef INORDER 127481eaec3SMichael S. Tsirkin guest.free_head = desc[head].next; 128*ce10c1b9SMichael S. Tsirkin #endif 129481eaec3SMichael S. Tsirkin 130481eaec3SMichael S. Tsirkin data[head].data = datap; 131481eaec3SMichael S. Tsirkin 132481eaec3SMichael S. Tsirkin #ifdef RING_POLL 133481eaec3SMichael S. Tsirkin /* Barrier A (for pairing) */ 134481eaec3SMichael S. Tsirkin smp_release(); 135481eaec3SMichael S. Tsirkin avail = guest.avail_idx++; 136481eaec3SMichael S. Tsirkin ring.avail->ring[avail & (ring_size - 1)] = 137481eaec3SMichael S. Tsirkin (head | (avail & ~(ring_size - 1))) ^ 0x8000; 138481eaec3SMichael S. Tsirkin #else 139*ce10c1b9SMichael S. Tsirkin #ifndef INORDER 140*ce10c1b9SMichael S. Tsirkin /* Barrier A (for pairing) */ 141*ce10c1b9SMichael S. Tsirkin smp_release(); 142481eaec3SMichael S. Tsirkin avail = (ring_size - 1) & (guest.avail_idx++); 143481eaec3SMichael S. Tsirkin ring.avail->ring[avail] = head; 144*ce10c1b9SMichael S. Tsirkin #endif 145481eaec3SMichael S. Tsirkin /* Barrier A (for pairing) */ 146481eaec3SMichael S. Tsirkin smp_release(); 147481eaec3SMichael S. Tsirkin #endif 148481eaec3SMichael S. Tsirkin ring.avail->idx = guest.avail_idx; 149481eaec3SMichael S. Tsirkin return 0; 150481eaec3SMichael S. Tsirkin } 151481eaec3SMichael S. Tsirkin 152481eaec3SMichael S. Tsirkin void *get_buf(unsigned *lenp, void **bufp) 153481eaec3SMichael S. Tsirkin { 154481eaec3SMichael S. Tsirkin unsigned head; 155481eaec3SMichael S. Tsirkin unsigned index; 156481eaec3SMichael S. Tsirkin void *datap; 157481eaec3SMichael S. Tsirkin 158481eaec3SMichael S. Tsirkin #ifdef RING_POLL 159481eaec3SMichael S. Tsirkin head = (ring_size - 1) & guest.last_used_idx; 160481eaec3SMichael S. Tsirkin index = ring.used->ring[head].id; 161481eaec3SMichael S. Tsirkin if ((index ^ guest.last_used_idx ^ 0x8000) & ~(ring_size - 1)) 162481eaec3SMichael S. Tsirkin return NULL; 163481eaec3SMichael S. Tsirkin /* Barrier B (for pairing) */ 164481eaec3SMichael S. Tsirkin smp_acquire(); 165481eaec3SMichael S. Tsirkin index &= ring_size - 1; 166481eaec3SMichael S. Tsirkin #else 167481eaec3SMichael S. Tsirkin if (ring.used->idx == guest.last_used_idx) 168481eaec3SMichael S. Tsirkin return NULL; 169481eaec3SMichael S. Tsirkin /* Barrier B (for pairing) */ 170481eaec3SMichael S. Tsirkin smp_acquire(); 171*ce10c1b9SMichael S. Tsirkin #ifdef INORDER 172*ce10c1b9SMichael S. Tsirkin head = (ring_size - 1) & guest.last_used_idx; 173*ce10c1b9SMichael S. Tsirkin index = head; 174*ce10c1b9SMichael S. Tsirkin #else 175481eaec3SMichael S. Tsirkin head = (ring_size - 1) & guest.last_used_idx; 176481eaec3SMichael S. Tsirkin index = ring.used->ring[head].id; 177481eaec3SMichael S. Tsirkin #endif 178*ce10c1b9SMichael S. Tsirkin 179*ce10c1b9SMichael S. Tsirkin #endif 180*ce10c1b9SMichael S. Tsirkin #ifdef INORDER 181*ce10c1b9SMichael S. Tsirkin *lenp = ring.desc[index].len; 182*ce10c1b9SMichael S. Tsirkin #else 183481eaec3SMichael S. Tsirkin *lenp = ring.used->ring[head].len; 184*ce10c1b9SMichael S. Tsirkin #endif 185481eaec3SMichael S. Tsirkin datap = data[index].data; 186481eaec3SMichael S. Tsirkin *bufp = (void*)(unsigned long)ring.desc[index].addr; 187481eaec3SMichael S. Tsirkin data[index].data = NULL; 188*ce10c1b9SMichael S. Tsirkin #ifndef INORDER 189481eaec3SMichael S. Tsirkin ring.desc[index].next = guest.free_head; 190481eaec3SMichael S. Tsirkin guest.free_head = index; 191*ce10c1b9SMichael S. Tsirkin #endif 192481eaec3SMichael S. Tsirkin guest.num_free++; 193481eaec3SMichael S. Tsirkin guest.last_used_idx++; 194481eaec3SMichael S. Tsirkin return datap; 195481eaec3SMichael S. Tsirkin } 196481eaec3SMichael S. Tsirkin 197481eaec3SMichael S. Tsirkin void poll_used(void) 198481eaec3SMichael S. Tsirkin { 199481eaec3SMichael S. Tsirkin #ifdef RING_POLL 200481eaec3SMichael S. Tsirkin unsigned head = (ring_size - 1) & guest.last_used_idx; 201481eaec3SMichael S. Tsirkin 202481eaec3SMichael S. Tsirkin for (;;) { 203481eaec3SMichael S. Tsirkin unsigned index = ring.used->ring[head].id; 204481eaec3SMichael S. Tsirkin 205481eaec3SMichael S. Tsirkin if ((index ^ guest.last_used_idx ^ 0x8000) & ~(ring_size - 1)) 206481eaec3SMichael S. Tsirkin busy_wait(); 207481eaec3SMichael S. Tsirkin else 208481eaec3SMichael S. Tsirkin break; 209481eaec3SMichael S. Tsirkin } 210481eaec3SMichael S. Tsirkin #else 211481eaec3SMichael S. Tsirkin unsigned head = guest.last_used_idx; 212481eaec3SMichael S. Tsirkin 213481eaec3SMichael S. Tsirkin while (ring.used->idx == head) 214481eaec3SMichael S. Tsirkin busy_wait(); 215481eaec3SMichael S. Tsirkin #endif 216481eaec3SMichael S. Tsirkin } 217481eaec3SMichael S. Tsirkin 218481eaec3SMichael S. Tsirkin void disable_call() 219481eaec3SMichael S. Tsirkin { 220481eaec3SMichael S. Tsirkin /* Doing nothing to disable calls might cause 221481eaec3SMichael S. Tsirkin * extra interrupts, but reduces the number of cache misses. 222481eaec3SMichael S. Tsirkin */ 223481eaec3SMichael S. Tsirkin } 224481eaec3SMichael S. Tsirkin 225481eaec3SMichael S. Tsirkin bool enable_call() 226481eaec3SMichael S. Tsirkin { 227481eaec3SMichael S. Tsirkin unsigned short last_used_idx; 228481eaec3SMichael S. Tsirkin 229481eaec3SMichael S. Tsirkin vring_used_event(&ring) = (last_used_idx = guest.last_used_idx); 230481eaec3SMichael S. Tsirkin /* Flush call index write */ 231481eaec3SMichael S. Tsirkin /* Barrier D (for pairing) */ 232481eaec3SMichael S. Tsirkin smp_mb(); 233481eaec3SMichael S. Tsirkin #ifdef RING_POLL 234481eaec3SMichael S. Tsirkin { 235481eaec3SMichael S. Tsirkin unsigned short head = last_used_idx & (ring_size - 1); 236481eaec3SMichael S. Tsirkin unsigned index = ring.used->ring[head].id; 237481eaec3SMichael S. Tsirkin 238481eaec3SMichael S. Tsirkin return (index ^ last_used_idx ^ 0x8000) & ~(ring_size - 1); 239481eaec3SMichael S. Tsirkin } 240481eaec3SMichael S. Tsirkin #else 241481eaec3SMichael S. Tsirkin return ring.used->idx == last_used_idx; 242481eaec3SMichael S. Tsirkin #endif 243481eaec3SMichael S. Tsirkin } 244481eaec3SMichael S. Tsirkin 245481eaec3SMichael S. Tsirkin void kick_available(void) 246481eaec3SMichael S. Tsirkin { 247481eaec3SMichael S. Tsirkin /* Flush in previous flags write */ 248481eaec3SMichael S. Tsirkin /* Barrier C (for pairing) */ 249481eaec3SMichael S. Tsirkin smp_mb(); 250481eaec3SMichael S. Tsirkin if (!vring_need_event(vring_avail_event(&ring), 251481eaec3SMichael S. Tsirkin guest.avail_idx, 252481eaec3SMichael S. Tsirkin guest.kicked_avail_idx)) 253481eaec3SMichael S. Tsirkin return; 254481eaec3SMichael S. Tsirkin 255481eaec3SMichael S. Tsirkin guest.kicked_avail_idx = guest.avail_idx; 256481eaec3SMichael S. Tsirkin kick(); 257481eaec3SMichael S. Tsirkin } 258481eaec3SMichael S. Tsirkin 259481eaec3SMichael S. Tsirkin /* host side */ 260481eaec3SMichael S. Tsirkin void disable_kick() 261481eaec3SMichael S. Tsirkin { 262481eaec3SMichael S. Tsirkin /* Doing nothing to disable kicks might cause 263481eaec3SMichael S. Tsirkin * extra interrupts, but reduces the number of cache misses. 264481eaec3SMichael S. Tsirkin */ 265481eaec3SMichael S. Tsirkin } 266481eaec3SMichael S. Tsirkin 267481eaec3SMichael S. Tsirkin bool enable_kick() 268481eaec3SMichael S. Tsirkin { 269481eaec3SMichael S. Tsirkin unsigned head = host.used_idx; 270481eaec3SMichael S. Tsirkin 271481eaec3SMichael S. Tsirkin vring_avail_event(&ring) = head; 272481eaec3SMichael S. Tsirkin /* Barrier C (for pairing) */ 273481eaec3SMichael S. Tsirkin smp_mb(); 274481eaec3SMichael S. Tsirkin #ifdef RING_POLL 275481eaec3SMichael S. Tsirkin { 276481eaec3SMichael S. Tsirkin unsigned index = ring.avail->ring[head & (ring_size - 1)]; 277481eaec3SMichael S. Tsirkin 278481eaec3SMichael S. Tsirkin return (index ^ head ^ 0x8000) & ~(ring_size - 1); 279481eaec3SMichael S. Tsirkin } 280481eaec3SMichael S. Tsirkin #else 281481eaec3SMichael S. Tsirkin return head == ring.avail->idx; 282481eaec3SMichael S. Tsirkin #endif 283481eaec3SMichael S. Tsirkin } 284481eaec3SMichael S. Tsirkin 285481eaec3SMichael S. Tsirkin void poll_avail(void) 286481eaec3SMichael S. Tsirkin { 287481eaec3SMichael S. Tsirkin unsigned head = host.used_idx; 288481eaec3SMichael S. Tsirkin #ifdef RING_POLL 289481eaec3SMichael S. Tsirkin for (;;) { 290481eaec3SMichael S. Tsirkin unsigned index = ring.avail->ring[head & (ring_size - 1)]; 291481eaec3SMichael S. Tsirkin if ((index ^ head ^ 0x8000) & ~(ring_size - 1)) 292481eaec3SMichael S. Tsirkin busy_wait(); 293481eaec3SMichael S. Tsirkin else 294481eaec3SMichael S. Tsirkin break; 295481eaec3SMichael S. Tsirkin } 296481eaec3SMichael S. Tsirkin #else 297481eaec3SMichael S. Tsirkin while (ring.avail->idx == head) 298481eaec3SMichael S. Tsirkin busy_wait(); 299481eaec3SMichael S. Tsirkin #endif 300481eaec3SMichael S. Tsirkin } 301481eaec3SMichael S. Tsirkin 302481eaec3SMichael S. Tsirkin bool use_buf(unsigned *lenp, void **bufp) 303481eaec3SMichael S. Tsirkin { 304481eaec3SMichael S. Tsirkin unsigned used_idx = host.used_idx; 305481eaec3SMichael S. Tsirkin struct vring_desc *desc; 306481eaec3SMichael S. Tsirkin unsigned head; 307481eaec3SMichael S. Tsirkin 308481eaec3SMichael S. Tsirkin #ifdef RING_POLL 309481eaec3SMichael S. Tsirkin head = ring.avail->ring[used_idx & (ring_size - 1)]; 310481eaec3SMichael S. Tsirkin if ((used_idx ^ head ^ 0x8000) & ~(ring_size - 1)) 311481eaec3SMichael S. Tsirkin return false; 312481eaec3SMichael S. Tsirkin /* Barrier A (for pairing) */ 313481eaec3SMichael S. Tsirkin smp_acquire(); 314481eaec3SMichael S. Tsirkin 315481eaec3SMichael S. Tsirkin used_idx &= ring_size - 1; 316481eaec3SMichael S. Tsirkin desc = &ring.desc[head & (ring_size - 1)]; 317481eaec3SMichael S. Tsirkin #else 318481eaec3SMichael S. Tsirkin if (used_idx == ring.avail->idx) 319481eaec3SMichael S. Tsirkin return false; 320481eaec3SMichael S. Tsirkin 321481eaec3SMichael S. Tsirkin /* Barrier A (for pairing) */ 322481eaec3SMichael S. Tsirkin smp_acquire(); 323481eaec3SMichael S. Tsirkin 324481eaec3SMichael S. Tsirkin used_idx &= ring_size - 1; 325*ce10c1b9SMichael S. Tsirkin #ifdef INORDER 326*ce10c1b9SMichael S. Tsirkin head = used_idx; 327*ce10c1b9SMichael S. Tsirkin #else 328481eaec3SMichael S. Tsirkin head = ring.avail->ring[used_idx]; 329*ce10c1b9SMichael S. Tsirkin #endif 330481eaec3SMichael S. Tsirkin desc = &ring.desc[head]; 331481eaec3SMichael S. Tsirkin #endif 332481eaec3SMichael S. Tsirkin 333481eaec3SMichael S. Tsirkin *lenp = desc->len; 334481eaec3SMichael S. Tsirkin *bufp = (void *)(unsigned long)desc->addr; 335481eaec3SMichael S. Tsirkin 336*ce10c1b9SMichael S. Tsirkin #ifdef INORDER 337*ce10c1b9SMichael S. Tsirkin desc->len = desc->len - 1; 338*ce10c1b9SMichael S. Tsirkin #else 339481eaec3SMichael S. Tsirkin /* now update used ring */ 340481eaec3SMichael S. Tsirkin ring.used->ring[used_idx].id = head; 341481eaec3SMichael S. Tsirkin ring.used->ring[used_idx].len = desc->len - 1; 342*ce10c1b9SMichael S. Tsirkin #endif 343481eaec3SMichael S. Tsirkin /* Barrier B (for pairing) */ 344481eaec3SMichael S. Tsirkin smp_release(); 345481eaec3SMichael S. Tsirkin host.used_idx++; 346481eaec3SMichael S. Tsirkin ring.used->idx = host.used_idx; 347481eaec3SMichael S. Tsirkin 348481eaec3SMichael S. Tsirkin return true; 349481eaec3SMichael S. Tsirkin } 350481eaec3SMichael S. Tsirkin 351481eaec3SMichael S. Tsirkin void call_used(void) 352481eaec3SMichael S. Tsirkin { 353481eaec3SMichael S. Tsirkin /* Flush in previous flags write */ 354481eaec3SMichael S. Tsirkin /* Barrier D (for pairing) */ 355481eaec3SMichael S. Tsirkin smp_mb(); 356481eaec3SMichael S. Tsirkin if (!vring_need_event(vring_used_event(&ring), 357481eaec3SMichael S. Tsirkin host.used_idx, 358481eaec3SMichael S. Tsirkin host.called_used_idx)) 359481eaec3SMichael S. Tsirkin return; 360481eaec3SMichael S. Tsirkin 361481eaec3SMichael S. Tsirkin host.called_used_idx = host.used_idx; 362481eaec3SMichael S. Tsirkin call(); 363481eaec3SMichael S. Tsirkin } 364