@@ -60,6 +60,13 @@ typedef struct VRingUsed
60
60
VRingUsedElem ring [0 ];
61
61
} VRingUsed ;
62
62
63
+ typedef struct VRingMemoryRegionCaches {
64
+ struct rcu_head rcu ;
65
+ MemoryRegionCache desc ;
66
+ MemoryRegionCache avail ;
67
+ MemoryRegionCache used ;
68
+ } VRingMemoryRegionCaches ;
69
+
63
70
typedef struct VRing
64
71
{
65
72
unsigned int num ;
@@ -68,6 +75,7 @@ typedef struct VRing
68
75
hwaddr desc ;
69
76
hwaddr avail ;
70
77
hwaddr used ;
78
+ VRingMemoryRegionCaches * caches ;
71
79
} VRing ;
72
80
73
81
struct VirtQueue
@@ -104,6 +112,51 @@ struct VirtQueue
104
112
QLIST_ENTRY (VirtQueue ) node ;
105
113
};
106
114
115
+ static void virtio_free_region_cache (VRingMemoryRegionCaches * caches )
116
+ {
117
+ if (!caches ) {
118
+ return ;
119
+ }
120
+
121
+ address_space_cache_destroy (& caches -> desc );
122
+ address_space_cache_destroy (& caches -> avail );
123
+ address_space_cache_destroy (& caches -> used );
124
+ g_free (caches );
125
+ }
126
+
127
+ static void virtio_init_region_cache (VirtIODevice * vdev , int n )
128
+ {
129
+ VirtQueue * vq = & vdev -> vq [n ];
130
+ VRingMemoryRegionCaches * old = vq -> vring .caches ;
131
+ VRingMemoryRegionCaches * new ;
132
+ hwaddr addr , size ;
133
+ int event_size ;
134
+
135
+ event_size = virtio_vdev_has_feature (vq -> vdev , VIRTIO_RING_F_EVENT_IDX ) ? 2 : 0 ;
136
+
137
+ addr = vq -> vring .desc ;
138
+ if (!addr ) {
139
+ return ;
140
+ }
141
+ new = g_new0 (VRingMemoryRegionCaches , 1 );
142
+ size = virtio_queue_get_desc_size (vdev , n );
143
+ address_space_cache_init (& new -> desc , vdev -> dma_as ,
144
+ addr , size , false);
145
+
146
+ size = virtio_queue_get_used_size (vdev , n ) + event_size ;
147
+ address_space_cache_init (& new -> used , vdev -> dma_as ,
148
+ vq -> vring .used , size , true);
149
+
150
+ size = virtio_queue_get_avail_size (vdev , n ) + event_size ;
151
+ address_space_cache_init (& new -> avail , vdev -> dma_as ,
152
+ vq -> vring .avail , size , false);
153
+
154
+ atomic_rcu_set (& vq -> vring .caches , new );
155
+ if (old ) {
156
+ call_rcu (old , virtio_free_region_cache , rcu );
157
+ }
158
+ }
159
+
107
160
/* virt queue functions */
108
161
void virtio_queue_update_rings (VirtIODevice * vdev , int n )
109
162
{
@@ -117,6 +170,7 @@ void virtio_queue_update_rings(VirtIODevice *vdev, int n)
117
170
vring -> used = vring_align (vring -> avail +
118
171
offsetof(VRingAvail , ring [vring -> num ]),
119
172
vring -> align );
173
+ virtio_init_region_cache (vdev , n );
120
174
}
121
175
122
176
static void vring_desc_read (VirtIODevice * vdev , VRingDesc * desc ,
@@ -1264,6 +1318,7 @@ void virtio_queue_set_rings(VirtIODevice *vdev, int n, hwaddr desc,
1264
1318
vdev -> vq [n ].vring .desc = desc ;
1265
1319
vdev -> vq [n ].vring .avail = avail ;
1266
1320
vdev -> vq [n ].vring .used = used ;
1321
+ virtio_init_region_cache (vdev , n );
1267
1322
}
1268
1323
1269
1324
void virtio_queue_set_num (VirtIODevice * vdev , int n , int num )
@@ -1984,9 +2039,6 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
1984
2039
void virtio_cleanup (VirtIODevice * vdev )
1985
2040
{
1986
2041
qemu_del_vm_change_state_handler (vdev -> vmstate );
1987
- g_free (vdev -> config );
1988
- g_free (vdev -> vq );
1989
- g_free (vdev -> vector_queues );
1990
2042
}
1991
2043
1992
2044
static void virtio_vmstate_change (void * opaque , int running , RunState state )
@@ -2248,6 +2300,19 @@ void GCC_FMT_ATTR(2, 3) virtio_error(VirtIODevice *vdev, const char *fmt, ...)
2248
2300
}
2249
2301
}
2250
2302
2303
+ static void virtio_memory_listener_commit (MemoryListener * listener )
2304
+ {
2305
+ VirtIODevice * vdev = container_of (listener , VirtIODevice , listener );
2306
+ int i ;
2307
+
2308
+ for (i = 0 ; i < VIRTIO_QUEUE_MAX ; i ++ ) {
2309
+ if (vdev -> vq [i ].vring .num == 0 ) {
2310
+ break ;
2311
+ }
2312
+ virtio_init_region_cache (vdev , i );
2313
+ }
2314
+ }
2315
+
2251
2316
static void virtio_device_realize (DeviceState * dev , Error * * errp )
2252
2317
{
2253
2318
VirtIODevice * vdev = VIRTIO_DEVICE (dev );
@@ -2270,6 +2335,9 @@ static void virtio_device_realize(DeviceState *dev, Error **errp)
2270
2335
error_propagate (errp , err );
2271
2336
return ;
2272
2337
}
2338
+
2339
+ vdev -> listener .commit = virtio_memory_listener_commit ;
2340
+ memory_listener_register (& vdev -> listener , vdev -> dma_as );
2273
2341
}
2274
2342
2275
2343
static void virtio_device_unrealize (DeviceState * dev , Error * * errp )
@@ -2292,6 +2360,36 @@ static void virtio_device_unrealize(DeviceState *dev, Error **errp)
2292
2360
vdev -> bus_name = NULL ;
2293
2361
}
2294
2362
2363
+ static void virtio_device_free_virtqueues (VirtIODevice * vdev )
2364
+ {
2365
+ int i ;
2366
+ if (!vdev -> vq ) {
2367
+ return ;
2368
+ }
2369
+
2370
+ for (i = 0 ; i < VIRTIO_QUEUE_MAX ; i ++ ) {
2371
+ VRingMemoryRegionCaches * caches ;
2372
+ if (vdev -> vq [i ].vring .num == 0 ) {
2373
+ break ;
2374
+ }
2375
+ caches = atomic_read (& vdev -> vq [i ].vring .caches );
2376
+ atomic_set (& vdev -> vq [i ].vring .caches , NULL );
2377
+ virtio_free_region_cache (caches );
2378
+ }
2379
+ g_free (vdev -> vq );
2380
+ }
2381
+
2382
+ static void virtio_device_instance_finalize (Object * obj )
2383
+ {
2384
+ VirtIODevice * vdev = VIRTIO_DEVICE (obj );
2385
+
2386
+ memory_listener_unregister (& vdev -> listener );
2387
+ virtio_device_free_virtqueues (vdev );
2388
+
2389
+ g_free (vdev -> config );
2390
+ g_free (vdev -> vector_queues );
2391
+ }
2392
+
2295
2393
static Property virtio_properties [] = {
2296
2394
DEFINE_VIRTIO_COMMON_FEATURES (VirtIODevice , host_features ),
2297
2395
DEFINE_PROP_END_OF_LIST (),
@@ -2418,6 +2516,7 @@ static const TypeInfo virtio_device_info = {
2418
2516
.parent = TYPE_DEVICE ,
2419
2517
.instance_size = sizeof (VirtIODevice ),
2420
2518
.class_init = virtio_device_class_init ,
2519
+ .instance_finalize = virtio_device_instance_finalize ,
2421
2520
.abstract = true,
2422
2521
.class_size = sizeof (VirtioDeviceClass ),
2423
2522
};
0 commit comments