|
@@ -286,6 +286,7 @@ void memory_device_plug(MemoryDeviceState *md, MachineState *ms)
|
|
|
g_assert(ms->device_memory);
|
|
|
|
|
|
ms->device_memory->used_region_size += memory_region_size(mr);
|
|
|
+ ms->device_memory->required_memslots += memory_device_get_memslots(md);
|
|
|
memory_region_add_subregion(&ms->device_memory->mr,
|
|
|
addr - ms->device_memory->base, mr);
|
|
|
trace_memory_device_plug(DEVICE(md)->id ? DEVICE(md)->id : "", addr);
|
|
@@ -305,6 +306,7 @@ void memory_device_unplug(MemoryDeviceState *md, MachineState *ms)
|
|
|
|
|
|
memory_region_del_subregion(&ms->device_memory->mr, mr);
|
|
|
ms->device_memory->used_region_size -= memory_region_size(mr);
|
|
|
+ ms->device_memory->required_memslots -= memory_device_get_memslots(md);
|
|
|
trace_memory_device_unplug(DEVICE(md)->id ? DEVICE(md)->id : "",
|
|
|
mdc->get_addr(md));
|
|
|
}
|
|
@@ -324,6 +326,50 @@ uint64_t memory_device_get_region_size(const MemoryDeviceState *md,
|
|
|
return memory_region_size(mr);
|
|
|
}
|
|
|
|
|
|
+static void memory_devices_region_mod(MemoryListener *listener,
|
|
|
+ MemoryRegionSection *mrs, bool add)
|
|
|
+{
|
|
|
+ DeviceMemoryState *dms = container_of(listener, DeviceMemoryState,
|
|
|
+ listener);
|
|
|
+
|
|
|
+ if (!memory_region_is_ram(mrs->mr)) {
|
|
|
+ warn_report("Unexpected memory region mapped into device memory region.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * The expectation is that each distinct RAM memory region section in
|
|
|
+ * our region for memory devices consumes exactly one memslot in KVM
|
|
|
+ * and in vhost. For vhost, this is true, except:
|
|
|
+ * * ROM memory regions don't consume a memslot. These get used very
|
|
|
+ * rarely for memory devices (R/O NVDIMMs).
|
|
|
+ * * Memslots without a fd (memory-backend-ram) don't necessarily
|
|
|
+ * consume a memslot. Such setups are quite rare and possibly bogus:
|
|
|
+ * the memory would be inaccessible by such vhost devices.
|
|
|
+ *
|
|
|
+ * So for vhost, in corner cases we might over-estimate the number of
|
|
|
+ * memslots that are currently used or that might still be reserved
|
|
|
+ * (required - used).
|
|
|
+ */
|
|
|
+ dms->used_memslots += add ? 1 : -1;
|
|
|
+
|
|
|
+ if (dms->used_memslots > dms->required_memslots) {
|
|
|
+ warn_report("Memory devices use more memory slots than indicated as required.");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void memory_devices_region_add(MemoryListener *listener,
|
|
|
+ MemoryRegionSection *mrs)
|
|
|
+{
|
|
|
+ return memory_devices_region_mod(listener, mrs, true);
|
|
|
+}
|
|
|
+
|
|
|
+static void memory_devices_region_del(MemoryListener *listener,
|
|
|
+ MemoryRegionSection *mrs)
|
|
|
+{
|
|
|
+ return memory_devices_region_mod(listener, mrs, false);
|
|
|
+}
|
|
|
+
|
|
|
void machine_memory_devices_init(MachineState *ms, hwaddr base, uint64_t size)
|
|
|
{
|
|
|
g_assert(size);
|
|
@@ -333,8 +379,16 @@ void machine_memory_devices_init(MachineState *ms, hwaddr base, uint64_t size)
|
|
|
|
|
|
memory_region_init(&ms->device_memory->mr, OBJECT(ms), "device-memory",
|
|
|
size);
|
|
|
+ address_space_init(&ms->device_memory->as, &ms->device_memory->mr,
|
|
|
+ "device-memory");
|
|
|
memory_region_add_subregion(get_system_memory(), ms->device_memory->base,
|
|
|
&ms->device_memory->mr);
|
|
|
+
|
|
|
+ /* Track the number of memslots used by memory devices. */
|
|
|
+ ms->device_memory->listener.region_add = memory_devices_region_add;
|
|
|
+ ms->device_memory->listener.region_del = memory_devices_region_del;
|
|
|
+ memory_listener_register(&ms->device_memory->listener,
|
|
|
+ &ms->device_memory->as);
|
|
|
}
|
|
|
|
|
|
static const TypeInfo memory_device_info = {
|