Skip to content

Commit

Permalink
hyperv: support for unused page reporting
Browse files Browse the repository at this point in the history
This patch provides integration of the cold memory discard with Hyper-V.

TAG_MSFT: wsl

Signed-off-by: Sunil Muthuswamy <sunilmut@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
sunilmut authored and Sasha Levin committed Sep 27, 2019
1 parent 1dd1f4c commit a98b8fc
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 1 deletion.
41 changes: 41 additions & 0 deletions arch/arm64/include/asm/hyperv-tlfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@
#define HVCALL_RETARGET_INTERRUPT 0x007e
#define HVCALL_START_VIRTUAL_PROCESSOR 0x0099
#define HVCALL_GET_VP_INDEX_FROM_APICID 0x009a
#define HVCALL_QUERY_CAPABILITIES 0x8001
#define HVCALL_MEMORY_HEAT_HINT 0x8003

/* Declare standard hypercall field values. */
#define HV_PARTITION_ID_SELF ((u64)-1)
Expand Down Expand Up @@ -340,4 +342,43 @@ struct hv_timer_message_payload {
#define HV_STIMER_AUTOENABLE (1ULL << 3)
#define HV_STIMER_SINT(config) (__u8)(((config) >> 16) & 0x0F)

/*
* HV_MAX_FLUSH_PAGES = "additional_pages" + 1. It's limited
* by the bitwidth of "additional_pages" in union hv_gpa_page_range.
*/
#define HV_MAX_FLUSH_PAGES (2048)

/* HvFlushGuestPhysicalAddressList hypercall */
union hv_gpa_page_range {
u64 address_space;
struct {
u64 additional_pages:11;
u64 largepage:1;
u64 basepfn:52;
} page;
struct {
u64:12;
u64 page_size:1;
u64 reserved:8;
u64 base_large_pfn:43;
};
};

#ifdef CONFIG_PAGE_REPORTING
#define HV_CAPABILITY_MEMORY_COLD_DISCARD_HINT BIT(8)

// The whole argument should fit in a page to be able to pass to the hypervisor
// in one hypercall.
#define HV_MAX_GPA_PAGE_RANGES ((PAGE_SIZE - 8)/sizeof(union hv_gpa_page_range))

/* HvExtMemoryHeatHint hypercall */
#define HV_MEMORY_HINT_TYPE_COLD_DISCARD BIT(1)
struct hv_memory_hint {
u64 type:2;
u64 reserved:62;
union hv_gpa_page_range ranges[1];
};

#endif // CONFIG_PAGE_REPORTING

#endif
40 changes: 40 additions & 0 deletions arch/x86/include/asm/hyperv-tlfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,8 @@ struct hv_tsc_emulation_status {
#define HVCALL_POST_MESSAGE 0x005c
#define HVCALL_SIGNAL_EVENT 0x005d
#define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_SPACE 0x00af
#define HVCALL_QUERY_CAPABILITIES 0x8001
#define HVCALL_MEMORY_HEAT_HINT 0x8003

#define HV_X64_MSR_VP_ASSIST_PAGE_ENABLE 0x00000001
#define HV_X64_MSR_VP_ASSIST_PAGE_ADDRESS_SHIFT 12
Expand Down Expand Up @@ -746,6 +748,28 @@ struct hv_send_ipi_ex {
struct hv_vpset vp_set;
};

/*
* HV_MAX_FLUSH_PAGES = "additional_pages" + 1. It's limited
* by the bitwidth of "additional_pages" in union hv_gpa_page_range.
*/
#define HV_MAX_FLUSH_PAGES (2048)

/* HvFlushGuestPhysicalAddressList hypercall */
union hv_gpa_page_range {
u64 address_space;
struct {
u64 additional_pages:11;
u64 largepage:1;
u64 basepfn:52;
} page;
struct {
u64:12;
u64 page_size:1;
u64 reserved:8;
u64 base_large_pfn:43;
};
};

/* HvFlushGuestPhysicalAddressSpace hypercalls */
struct hv_guest_mapping_flush {
u64 address_space;
Expand All @@ -768,4 +792,20 @@ struct hv_tlb_flush_ex {
u64 gva_list[];
};

#ifdef CONFIG_PAGE_REPORTING
#define HV_CAPABILITY_MEMORY_COLD_DISCARD_HINT BIT(8)

// The whole argument should fit in a page to be able to pass to the hypervisor
// in one hypercall.
#define HV_MAX_GPA_PAGE_RANGES ((PAGE_SIZE - 8)/sizeof(union hv_gpa_page_range))

/* HvExtMemoryHeatHint hypercall */
#define HV_MEMORY_HINT_TYPE_COLD_DISCARD BIT(1)
struct hv_memory_hint {
u64 type:2;
u64 reserved:62;
union hv_gpa_page_range ranges[1];
};

#endif //CONFIG_PAGE_REPORTING
#endif
1 change: 1 addition & 0 deletions drivers/hv/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ config HYPERV_UTILS
config HYPERV_BALLOON
tristate "Microsoft Hyper-V Balloon driver"
depends on HYPERV
select PAGE_REPORTING
help
Select this option to enable Hyper-V Balloon driver.

Expand Down
104 changes: 103 additions & 1 deletion drivers/hv/hv_balloon.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@
#include <linux/memory.h>
#include <linux/notifier.h>
#include <linux/percpu_counter.h>

#include <linux/page_reporting.h>
#include <linux/hyperv.h>

#include <asm/mshyperv.h>

#define CREATE_TRACE_POINTS
#include "hv_trace_balloon.h"

Expand Down Expand Up @@ -572,6 +574,10 @@ struct hv_dynmem_device {
* The negotiated version agreed by host.
*/
__u32 version;

#ifdef CONFIG_PAGE_REPORTING
struct page_reporting_dev_info ph_dev_info;
#endif
};

static struct hv_dynmem_device dm_device;
Expand Down Expand Up @@ -1562,6 +1568,93 @@ static void balloon_onchannelcallback(void *context)

}

#ifdef CONFIG_PAGE_REPORTING
static u64 hyperv_query_ext_cap(void)
{
u64 *cap;
unsigned long flags;
u64 ret = 0;

local_irq_save(flags);
cap = *(u64 **)this_cpu_ptr(hyperv_pcpu_input_arg);
if (hv_do_hypercall(HVCALL_QUERY_CAPABILITIES, NULL, cap) ==
HV_STATUS_SUCCESS)
ret = *cap;

local_irq_restore(flags);
return ret;
}

static void hyperv_discard_pages(struct scatterlist **sgs, int nents)
{
unsigned long flags;
struct hv_memory_hint *hint;
int i;
struct scatterlist *sg;
u64 status;

WARN_ON(nents > HV_MAX_GPA_PAGE_RANGES);
local_irq_save(flags);
hint = *(struct hv_memory_hint **)this_cpu_ptr(hyperv_pcpu_input_arg);
if (!hint) {
local_irq_restore(flags);
return;
}

hint->type = HV_MEMORY_HINT_TYPE_COLD_DISCARD;
hint->reserved = 0;
for (i = 0, sg = sgs[0]; sg; sg = sg_next(sg), i++) {
int order;
union hv_gpa_page_range *range;

order = get_order(sg->length);
range = &hint->ranges[i];
range->address_space = 0;
range->page.largepage = 1;
range->page.additional_pages = (1ull << (order - 9)) - 1;
range->base_large_pfn = page_to_pfn(sg_page(sg)) >> 9;
}

WARN_ON(i != nents);

status = hv_do_rep_hypercall(HVCALL_MEMORY_HEAT_HINT, nents, 0,
hint, NULL);
local_irq_restore(flags);
status &= HV_HYPERCALL_RESULT_MASK;
WARN_ON(status != HV_STATUS_SUCCESS);
}

static void hv_page_hinting(struct page_reporting_dev_info *ph_dev_info,
unsigned int nents)
{
hyperv_discard_pages(&ph_dev_info->sg, nents);
}

static int enable_hinting(void)
{
int ret;

if (!(hyperv_query_ext_cap() &
HV_CAPABILITY_MEMORY_COLD_DISCARD_HINT)) {
pr_info("cold discard hint not supported\n");
return 0;
}

dm_device.ph_dev_info.report = hv_page_hinting;
dm_device.ph_dev_info.capacity = HV_MAX_GPA_PAGE_RANGES;
ret = page_reporting_register(&dm_device.ph_dev_info);
if (ret == 0)
pr_info("cold memory discard enabled\n");
return ret;
}

static void disable_hinting(void)
{
if (dm_device.ph_dev_info.report)
page_reporting_unregister(&dm_device.ph_dev_info);
}
#endif //CONFIG_PAGE_REPORTING

static int balloon_probe(struct hv_device *dev,
const struct hv_vmbus_device_id *dev_id)
{
Expand Down Expand Up @@ -1704,6 +1797,11 @@ static int balloon_probe(struct hv_device *dev,
dm_device.state = DM_INITIALIZED;
last_post_time = jiffies;

#ifdef CONFIG_PAGE_REPORTING
if (enable_hinting() < 0)
goto probe_error2;
#endif

return 0;

probe_error2:
Expand Down Expand Up @@ -1732,6 +1830,10 @@ static int balloon_remove(struct hv_device *dev)
cancel_work_sync(&dm->balloon_wrk.wrk);
cancel_work_sync(&dm->ha_wrk.wrk);

#ifdef CONFIG_PAGE_REPORTING
disable_hinting();
#endif

vmbus_close(dev->channel);
kthread_stop(dm->thread);
kfree(send_buffer);
Expand Down

0 comments on commit a98b8fc

Please sign in to comment.