aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJake Oshins <jakeo@microsoft.com>2015-08-05 03:52:36 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-08-05 14:41:30 -0400
commit7f163a6fd957a85f7f66a129db1ad243a44399ee (patch)
tree5c72e580e6ff9d18a39005a09e906121783d4317
parentf368ed6088ae9c1fbe1c897bb5f215ce5e63fa1e (diff)
drivers:hv: Modify hv_vmbus to search for all MMIO ranges available.
This patch changes the logic in hv_vmbus to record all of the ranges in the VM's firmware (BIOS or UEFI) that offer regions of memory-mapped I/O space for use by paravirtual front-end drivers. The old logic just found one range above 4GB and called it good. This logic will find any ranges above 1MB. It would have been possible with this patch to just use existing resource allocation functions, rather than keep track of the entire set of Hyper-V related MMIO regions in VMBus. This strategy, however, is not sufficient when the resource allocator needs to be aware of the constraints of a Hyper-V virtual machine, which is what happens in the next patch in the series. So this first patch exists to show the first steps in reworking the MMIO allocation paths for Hyper-V front-end drivers. Signed-off-by: Jake Oshins <jakeo@microsoft.com> Signed-off-by: K. Y. Srinivasan <kys@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/hv/vmbus_drv.c116
-rw-r--r--drivers/video/fbdev/hyperv_fb.c2
-rw-r--r--include/linux/hyperv.h2
3 files changed, 92 insertions, 28 deletions
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index e7b0bcd453e7..ee59e06c2194 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -102,10 +102,7 @@ static struct notifier_block hyperv_panic_block = {
102 .notifier_call = hyperv_panic_event, 102 .notifier_call = hyperv_panic_event,
103}; 103};
104 104
105struct resource hyperv_mmio = { 105struct resource *hyperv_mmio;
106 .name = "hyperv mmio",
107 .flags = IORESOURCE_MEM,
108};
109EXPORT_SYMBOL_GPL(hyperv_mmio); 106EXPORT_SYMBOL_GPL(hyperv_mmio);
110 107
111static int vmbus_exists(void) 108static int vmbus_exists(void)
@@ -1013,30 +1010,105 @@ void vmbus_device_unregister(struct hv_device *device_obj)
1013 1010
1014 1011
1015/* 1012/*
1016 * VMBUS is an acpi enumerated device. Get the the information we 1013 * VMBUS is an acpi enumerated device. Get the information we
1017 * need from DSDT. 1014 * need from DSDT.
1018 */ 1015 */
1019 1016#define VTPM_BASE_ADDRESS 0xfed40000
1020static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx) 1017static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx)
1021{ 1018{
1019 resource_size_t start = 0;
1020 resource_size_t end = 0;
1021 struct resource *new_res;
1022 struct resource **old_res = &hyperv_mmio;
1023 struct resource **prev_res = NULL;
1024
1022 switch (res->type) { 1025 switch (res->type) {
1023 case ACPI_RESOURCE_TYPE_IRQ: 1026 case ACPI_RESOURCE_TYPE_IRQ:
1024 irq = res->data.irq.interrupts[0]; 1027 irq = res->data.irq.interrupts[0];
1028 return AE_OK;
1029
1030 /*
1031 * "Address" descriptors are for bus windows. Ignore
1032 * "memory" descriptors, which are for registers on
1033 * devices.
1034 */
1035 case ACPI_RESOURCE_TYPE_ADDRESS32:
1036 start = res->data.address32.address.minimum;
1037 end = res->data.address32.address.maximum;
1025 break; 1038 break;
1026 1039
1027 case ACPI_RESOURCE_TYPE_ADDRESS64: 1040 case ACPI_RESOURCE_TYPE_ADDRESS64:
1028 hyperv_mmio.start = res->data.address64.address.minimum; 1041 start = res->data.address64.address.minimum;
1029 hyperv_mmio.end = res->data.address64.address.maximum; 1042 end = res->data.address64.address.maximum;
1030 break; 1043 break;
1044
1045 default:
1046 /* Unused resource type */
1047 return AE_OK;
1048
1031 } 1049 }
1050 /*
1051 * Ignore ranges that are below 1MB, as they're not
1052 * necessary or useful here.
1053 */
1054 if (end < 0x100000)
1055 return AE_OK;
1056
1057 new_res = kzalloc(sizeof(*new_res), GFP_ATOMIC);
1058 if (!new_res)
1059 return AE_NO_MEMORY;
1060
1061 /* If this range overlaps the virtual TPM, truncate it. */
1062 if (end > VTPM_BASE_ADDRESS && start < VTPM_BASE_ADDRESS)
1063 end = VTPM_BASE_ADDRESS;
1064
1065 new_res->name = "hyperv mmio";
1066 new_res->flags = IORESOURCE_MEM;
1067 new_res->start = start;
1068 new_res->end = end;
1069
1070 do {
1071 if (!*old_res) {
1072 *old_res = new_res;
1073 break;
1074 }
1075
1076 if ((*old_res)->end < new_res->start) {
1077 new_res->sibling = *old_res;
1078 if (prev_res)
1079 (*prev_res)->sibling = new_res;
1080 *old_res = new_res;
1081 break;
1082 }
1083
1084 prev_res = old_res;
1085 old_res = &(*old_res)->sibling;
1086
1087 } while (1);
1032 1088
1033 return AE_OK; 1089 return AE_OK;
1034} 1090}
1035 1091
1092static int vmbus_acpi_remove(struct acpi_device *device)
1093{
1094 struct resource *cur_res;
1095 struct resource *next_res;
1096
1097 if (hyperv_mmio) {
1098 for (cur_res = hyperv_mmio; cur_res; cur_res = next_res) {
1099 next_res = cur_res->sibling;
1100 kfree(cur_res);
1101 }
1102 }
1103
1104 return 0;
1105}
1106
1036static int vmbus_acpi_add(struct acpi_device *device) 1107static int vmbus_acpi_add(struct acpi_device *device)
1037{ 1108{
1038 acpi_status result; 1109 acpi_status result;
1039 int ret_val = -ENODEV; 1110 int ret_val = -ENODEV;
1111 struct acpi_device *ancestor;
1040 1112
1041 hv_acpi_dev = device; 1113 hv_acpi_dev = device;
1042 1114
@@ -1046,35 +1118,27 @@ static int vmbus_acpi_add(struct acpi_device *device)
1046 if (ACPI_FAILURE(result)) 1118 if (ACPI_FAILURE(result))
1047 goto acpi_walk_err; 1119 goto acpi_walk_err;
1048 /* 1120 /*
1049 * The parent of the vmbus acpi device (Gen2 firmware) is the VMOD that 1121 * Some ancestor of the vmbus acpi device (Gen1 or Gen2
1050 * has the mmio ranges. Get that. 1122 * firmware) is the VMOD that has the mmio ranges. Get that.
1051 */ 1123 */
1052 if (device->parent) { 1124 for (ancestor = device->parent; ancestor; ancestor = ancestor->parent) {
1053 result = acpi_walk_resources(device->parent->handle, 1125 result = acpi_walk_resources(ancestor->handle, METHOD_NAME__CRS,
1054 METHOD_NAME__CRS, 1126 vmbus_walk_resources, NULL);
1055 vmbus_walk_resources, NULL);
1056 1127
1057 if (ACPI_FAILURE(result)) 1128 if (ACPI_FAILURE(result))
1058 goto acpi_walk_err; 1129 continue;
1059 if (hyperv_mmio.start && hyperv_mmio.end) 1130 if (hyperv_mmio)
1060 request_resource(&iomem_resource, &hyperv_mmio); 1131 break;
1061 } 1132 }
1062 ret_val = 0; 1133 ret_val = 0;
1063 1134
1064acpi_walk_err: 1135acpi_walk_err:
1065 complete(&probe_event); 1136 complete(&probe_event);
1137 if (ret_val)
1138 vmbus_acpi_remove(device);
1066 return ret_val; 1139 return ret_val;
1067} 1140}
1068 1141
1069static int vmbus_acpi_remove(struct acpi_device *device)
1070{
1071 int ret = 0;
1072
1073 if (hyperv_mmio.start && hyperv_mmio.end)
1074 ret = release_resource(&hyperv_mmio);
1075 return ret;
1076}
1077
1078static const struct acpi_device_id vmbus_acpi_device_ids[] = { 1142static const struct acpi_device_id vmbus_acpi_device_ids[] = {
1079 {"VMBUS", 0}, 1143 {"VMBUS", 0},
1080 {"VMBus", 0}, 1144 {"VMBus", 0},
diff --git a/drivers/video/fbdev/hyperv_fb.c b/drivers/video/fbdev/hyperv_fb.c
index 807ee22ef229..b54ee1c05a5f 100644
--- a/drivers/video/fbdev/hyperv_fb.c
+++ b/drivers/video/fbdev/hyperv_fb.c
@@ -688,7 +688,7 @@ static int hvfb_getmem(struct fb_info *info)
688 par->mem.name = KBUILD_MODNAME; 688 par->mem.name = KBUILD_MODNAME;
689 par->mem.flags = IORESOURCE_MEM | IORESOURCE_BUSY; 689 par->mem.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
690 if (gen2vm) { 690 if (gen2vm) {
691 ret = allocate_resource(&hyperv_mmio, &par->mem, 691 ret = allocate_resource(hyperv_mmio, &par->mem,
692 screen_fb_size, 692 screen_fb_size,
693 0, -1, 693 0, -1,
694 screen_fb_size, 694 screen_fb_size,
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 30d3a1f79450..217e14be77b9 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -1233,7 +1233,7 @@ extern bool vmbus_prep_negotiate_resp(struct icmsg_hdr *,
1233 1233
1234void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid); 1234void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid);
1235 1235
1236extern struct resource hyperv_mmio; 1236extern struct resource *hyperv_mmio;
1237 1237
1238/* 1238/*
1239 * Negotiated version with the Host. 1239 * Negotiated version with the Host.