diff options
Diffstat (limited to 'memory.c')
-rw-r--r-- | memory.c | 99 |
1 files changed, 52 insertions, 47 deletions
@@ -217,7 +217,6 @@ struct FlatRange { bool romd_mode; bool readonly; bool nonvolatile; - int has_coalesced_range; }; #define FOR_EACH_FLAT_RANGE(var, view) \ @@ -654,7 +653,6 @@ static void render_memory_region(FlatView *view, fr.romd_mode = mr->romd_mode; fr.readonly = readonly; fr.nonvolatile = nonvolatile; - fr.has_coalesced_range = 0; /* Render the region itself into any gaps left by the current view. */ for (i = 0; i < view->nr && int128_nz(remain); ++i) { @@ -855,46 +853,55 @@ static void address_space_update_ioeventfds(AddressSpace *as) flatview_unref(view); } -static void flat_range_coalesced_io_del(FlatRange *fr, AddressSpace *as) +/* + * Notify the memory listeners about the coalesced IO change events of + * range `cmr'. Only the part that has intersection of the specified + * FlatRange will be sent. + */ +static void flat_range_coalesced_io_notify(FlatRange *fr, AddressSpace *as, + CoalescedMemoryRange *cmr, bool add) { - if (!fr->has_coalesced_range) { + AddrRange tmp; + + tmp = addrrange_shift(cmr->addr, + int128_sub(fr->addr.start, + int128_make64(fr->offset_in_region))); + if (!addrrange_intersects(tmp, fr->addr)) { return; } + tmp = addrrange_intersection(tmp, fr->addr); - if (--fr->has_coalesced_range > 0) { - return; + if (add) { + MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, coalesced_io_add, + int128_get64(tmp.start), + int128_get64(tmp.size)); + } else { + MEMORY_LISTENER_UPDATE_REGION(fr, as, Reverse, coalesced_io_del, + int128_get64(tmp.start), + int128_get64(tmp.size)); } +} - MEMORY_LISTENER_UPDATE_REGION(fr, as, Reverse, coalesced_io_del, - int128_get64(fr->addr.start), - int128_get64(fr->addr.size)); +static void flat_range_coalesced_io_del(FlatRange *fr, AddressSpace *as) +{ + CoalescedMemoryRange *cmr; + + QTAILQ_FOREACH(cmr, &fr->mr->coalesced, link) { + flat_range_coalesced_io_notify(fr, as, cmr, false); + } } static void flat_range_coalesced_io_add(FlatRange *fr, AddressSpace *as) { MemoryRegion *mr = fr->mr; CoalescedMemoryRange *cmr; - AddrRange tmp; if (QTAILQ_EMPTY(&mr->coalesced)) { return; } - if (fr->has_coalesced_range++) { - return; - } - QTAILQ_FOREACH(cmr, &mr->coalesced, link) { - tmp = addrrange_shift(cmr->addr, - int128_sub(fr->addr.start, - int128_make64(fr->offset_in_region))); - if (!addrrange_intersects(tmp, fr->addr)) { - continue; - } - tmp = addrrange_intersection(tmp, fr->addr); - MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, coalesced_io_add, - int128_get64(tmp.start), - int128_get64(tmp.size)); + flat_range_coalesced_io_notify(fr, as, cmr, true); } } @@ -2236,27 +2243,26 @@ void memory_region_ram_resize(MemoryRegion *mr, ram_addr_t newsize, Error **errp qemu_ram_resize(mr->ram_block, newsize, errp); } -static void memory_region_update_coalesced_range_as(MemoryRegion *mr, AddressSpace *as) +/* + * Call proper memory listeners about the change on the newly + * added/removed CoalescedMemoryRange. + */ +static void memory_region_update_coalesced_range(MemoryRegion *mr, + CoalescedMemoryRange *cmr, + bool add) { + AddressSpace *as; FlatView *view; FlatRange *fr; - view = address_space_get_flatview(as); - FOR_EACH_FLAT_RANGE(fr, view) { - if (fr->mr == mr) { - flat_range_coalesced_io_del(fr, as); - flat_range_coalesced_io_add(fr, as); - } - } - flatview_unref(view); -} - -static void memory_region_update_coalesced_range(MemoryRegion *mr) -{ - AddressSpace *as; - QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { - memory_region_update_coalesced_range_as(mr, as); + view = address_space_get_flatview(as); + FOR_EACH_FLAT_RANGE(fr, view) { + if (fr->mr == mr) { + flat_range_coalesced_io_notify(fr, as, cmr, add); + } + } + flatview_unref(view); } } @@ -2274,14 +2280,17 @@ void memory_region_add_coalescing(MemoryRegion *mr, cmr->addr = addrrange_make(int128_make64(offset), int128_make64(size)); QTAILQ_INSERT_TAIL(&mr->coalesced, cmr, link); - memory_region_update_coalesced_range(mr); + memory_region_update_coalesced_range(mr, cmr, true); memory_region_set_flush_coalesced(mr); } void memory_region_clear_coalescing(MemoryRegion *mr) { CoalescedMemoryRange *cmr; - bool updated = false; + + if (QTAILQ_EMPTY(&mr->coalesced)) { + return; + } qemu_flush_coalesced_mmio_buffer(); mr->flush_coalesced_mmio = false; @@ -2289,12 +2298,8 @@ void memory_region_clear_coalescing(MemoryRegion *mr) while (!QTAILQ_EMPTY(&mr->coalesced)) { cmr = QTAILQ_FIRST(&mr->coalesced); QTAILQ_REMOVE(&mr->coalesced, cmr, link); + memory_region_update_coalesced_range(mr, cmr, false); g_free(cmr); - updated = true; - } - - if (updated) { - memory_region_update_coalesced_range(mr); } } |