vmbus_drv.c (ecb41832bd2a7a3f8ac93527cec5e51e3827daed) vmbus_drv.c (eec4844fae7c033a0c1fc1eb3b8517aeb8b6cc49)
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (c) 2009, Microsoft Corporation.
4 *
5 * Authors:
6 * Haiyang Zhang <haiyangz@microsoft.com>
7 * Hank Janssen <hjanssen@microsoft.com>
8 * K. Y. Srinivasan <kys@microsoft.com>

--- 16 unchanged lines hidden (view full) ---

25
26#include <asm/mshyperv.h>
27#include <linux/notifier.h>
28#include <linux/ptrace.h>
29#include <linux/screen_info.h>
30#include <linux/kdebug.h>
31#include <linux/efi.h>
32#include <linux/random.h>
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (c) 2009, Microsoft Corporation.
4 *
5 * Authors:
6 * Haiyang Zhang <haiyangz@microsoft.com>
7 * Hank Janssen <hjanssen@microsoft.com>
8 * K. Y. Srinivasan <kys@microsoft.com>

--- 16 unchanged lines hidden (view full) ---

25
26#include <asm/mshyperv.h>
27#include <linux/notifier.h>
28#include <linux/ptrace.h>
29#include <linux/screen_info.h>
30#include <linux/kdebug.h>
31#include <linux/efi.h>
32#include <linux/random.h>
33#include <clocksource/hyperv_timer.h>
33#include "hyperv_vmbus.h"
34
35struct vmbus_dynid {
36 struct list_head node;
37 struct hv_vmbus_device_id id;
38};
39
40static struct acpi_device *hv_acpi_dev;

--- 909 unchanged lines hidden (view full) ---

950 return;
951
952 ctx = container_of(work, struct onmessage_work_context,
953 work);
954 vmbus_onmessage(&ctx->msg);
955 kfree(ctx);
956}
957
34#include "hyperv_vmbus.h"
35
36struct vmbus_dynid {
37 struct list_head node;
38 struct hv_vmbus_device_id id;
39};
40
41static struct acpi_device *hv_acpi_dev;

--- 909 unchanged lines hidden (view full) ---

951 return;
952
953 ctx = container_of(work, struct onmessage_work_context,
954 work);
955 vmbus_onmessage(&ctx->msg);
956 kfree(ctx);
957}
958
958static void hv_process_timer_expiration(struct hv_message *msg,
959 struct hv_per_cpu_context *hv_cpu)
960{
961 struct clock_event_device *dev = hv_cpu->clk_evt;
962
963 if (dev->event_handler)
964 dev->event_handler(dev);
965
966 vmbus_signal_eom(msg, HVMSG_TIMER_EXPIRED);
967}
968
969void vmbus_on_msg_dpc(unsigned long data)
970{
971 struct hv_per_cpu_context *hv_cpu = (void *)data;
972 void *page_addr = hv_cpu->synic_message_page;
973 struct hv_message *msg = (struct hv_message *)page_addr +
974 VMBUS_MESSAGE_SINT;
975 struct vmbus_channel_message_header *hdr;
976 const struct vmbus_channel_message_table_entry *entry;

--- 177 unchanged lines hidden (view full) ---

1154 if (handled)
1155 vmbus_chan_sched(hv_cpu);
1156
1157 page_addr = hv_cpu->synic_message_page;
1158 msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
1159
1160 /* Check if there are actual msgs to be processed */
1161 if (msg->header.message_type != HVMSG_NONE) {
959void vmbus_on_msg_dpc(unsigned long data)
960{
961 struct hv_per_cpu_context *hv_cpu = (void *)data;
962 void *page_addr = hv_cpu->synic_message_page;
963 struct hv_message *msg = (struct hv_message *)page_addr +
964 VMBUS_MESSAGE_SINT;
965 struct vmbus_channel_message_header *hdr;
966 const struct vmbus_channel_message_table_entry *entry;

--- 177 unchanged lines hidden (view full) ---

1144 if (handled)
1145 vmbus_chan_sched(hv_cpu);
1146
1147 page_addr = hv_cpu->synic_message_page;
1148 msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
1149
1150 /* Check if there are actual msgs to be processed */
1151 if (msg->header.message_type != HVMSG_NONE) {
1162 if (msg->header.message_type == HVMSG_TIMER_EXPIRED)
1163 hv_process_timer_expiration(msg, hv_cpu);
1164 else
1152 if (msg->header.message_type == HVMSG_TIMER_EXPIRED) {
1153 hv_stimer0_isr();
1154 vmbus_signal_eom(msg, HVMSG_TIMER_EXPIRED);
1155 } else
1165 tasklet_schedule(&hv_cpu->msg_dpc);
1166 }
1167
1168 add_interrupt_randomness(HYPERVISOR_CALLBACK_VECTOR, 0);
1169}
1170
1171/*
1172 * Boolean to control whether to report panic messages over Hyper-V.

--- 28 unchanged lines hidden (view full) ---

1201 hyperv_report_panic_msg(panic_pa, bytes_written);
1202}
1203
1204static struct kmsg_dumper hv_kmsg_dumper = {
1205 .dump = hv_kmsg_dump,
1206};
1207
1208static struct ctl_table_header *hv_ctl_table_hdr;
1156 tasklet_schedule(&hv_cpu->msg_dpc);
1157 }
1158
1159 add_interrupt_randomness(HYPERVISOR_CALLBACK_VECTOR, 0);
1160}
1161
1162/*
1163 * Boolean to control whether to report panic messages over Hyper-V.

--- 28 unchanged lines hidden (view full) ---

1192 hyperv_report_panic_msg(panic_pa, bytes_written);
1193}
1194
1195static struct kmsg_dumper hv_kmsg_dumper = {
1196 .dump = hv_kmsg_dump,
1197};
1198
1199static struct ctl_table_header *hv_ctl_table_hdr;
1209static int zero;
1210static int one = 1;
1211
1212/*
1213 * sysctl option to allow the user to control whether kmsg data should be
1214 * reported to Hyper-V on panic.
1215 */
1216static struct ctl_table hv_ctl_table[] = {
1217 {
1218 .procname = "hyperv_record_panic_msg",
1219 .data = &sysctl_record_panic_msg,
1220 .maxlen = sizeof(int),
1221 .mode = 0644,
1222 .proc_handler = proc_dointvec_minmax,
1200
1201/*
1202 * sysctl option to allow the user to control whether kmsg data should be
1203 * reported to Hyper-V on panic.
1204 */
1205static struct ctl_table hv_ctl_table[] = {
1206 {
1207 .procname = "hyperv_record_panic_msg",
1208 .data = &sysctl_record_panic_msg,
1209 .maxlen = sizeof(int),
1210 .mode = 0644,
1211 .proc_handler = proc_dointvec_minmax,
1223 .extra1 = &zero,
1224 .extra2 = &one
1212 .extra1 = SYSCTL_ZERO,
1213 .extra2 = SYSCTL_ONE
1225 },
1226 {}
1227};
1228
1229static struct ctl_table hv_root_table[] = {
1230 {
1231 .procname = "kernel",
1232 .mode = 0555,

--- 25 unchanged lines hidden (view full) ---

1258 if (ret)
1259 return ret;
1260
1261 hv_setup_vmbus_irq(vmbus_isr);
1262
1263 ret = hv_synic_alloc();
1264 if (ret)
1265 goto err_alloc;
1214 },
1215 {}
1216};
1217
1218static struct ctl_table hv_root_table[] = {
1219 {
1220 .procname = "kernel",
1221 .mode = 0555,

--- 25 unchanged lines hidden (view full) ---

1247 if (ret)
1248 return ret;
1249
1250 hv_setup_vmbus_irq(vmbus_isr);
1251
1252 ret = hv_synic_alloc();
1253 if (ret)
1254 goto err_alloc;
1255
1256 ret = hv_stimer_alloc(VMBUS_MESSAGE_SINT);
1257 if (ret < 0)
1258 goto err_alloc;
1259
1266 /*
1260 /*
1267 * Initialize the per-cpu interrupt state and
1268 * connect to the host.
1261 * Initialize the per-cpu interrupt state and stimer state.
1262 * Then connect to the host.
1269 */
1270 ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hyperv/vmbus:online",
1271 hv_synic_init, hv_synic_cleanup);
1272 if (ret < 0)
1263 */
1264 ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hyperv/vmbus:online",
1265 hv_synic_init, hv_synic_cleanup);
1266 if (ret < 0)
1273 goto err_alloc;
1267 goto err_cpuhp;
1274 hyperv_cpuhp_online = ret;
1275
1276 ret = vmbus_connect();
1277 if (ret)
1278 goto err_connect;
1279
1280 /*
1281 * Only register if the crash MSRs are available

--- 31 unchanged lines hidden (view full) ---

1313 }
1314
1315 vmbus_request_offers();
1316
1317 return 0;
1318
1319err_connect:
1320 cpuhp_remove_state(hyperv_cpuhp_online);
1268 hyperv_cpuhp_online = ret;
1269
1270 ret = vmbus_connect();
1271 if (ret)
1272 goto err_connect;
1273
1274 /*
1275 * Only register if the crash MSRs are available

--- 31 unchanged lines hidden (view full) ---

1307 }
1308
1309 vmbus_request_offers();
1310
1311 return 0;
1312
1313err_connect:
1314 cpuhp_remove_state(hyperv_cpuhp_online);
1315err_cpuhp:
1316 hv_stimer_free();
1321err_alloc:
1322 hv_synic_free();
1323 hv_remove_vmbus_irq();
1324
1325 bus_unregister(&hv_bus);
1326 free_page((unsigned long)hv_panic_page);
1327 unregister_sysctl_table(hv_ctl_table_hdr);
1328 hv_ctl_table_hdr = NULL;

--- 730 unchanged lines hidden (view full) ---

2059 .ops = {
2060 .add = vmbus_acpi_add,
2061 .remove = vmbus_acpi_remove,
2062 },
2063};
2064
2065static void hv_kexec_handler(void)
2066{
1317err_alloc:
1318 hv_synic_free();
1319 hv_remove_vmbus_irq();
1320
1321 bus_unregister(&hv_bus);
1322 free_page((unsigned long)hv_panic_page);
1323 unregister_sysctl_table(hv_ctl_table_hdr);
1324 hv_ctl_table_hdr = NULL;

--- 730 unchanged lines hidden (view full) ---

2055 .ops = {
2056 .add = vmbus_acpi_add,
2057 .remove = vmbus_acpi_remove,
2058 },
2059};
2060
2061static void hv_kexec_handler(void)
2062{
2067 hv_synic_clockevents_cleanup();
2063 hv_stimer_global_cleanup();
2068 vmbus_initiate_unload(false);
2069 vmbus_connection.conn_state = DISCONNECTED;
2070 /* Make sure conn_state is set as hv_synic_cleanup checks for it */
2071 mb();
2072 cpuhp_remove_state(hyperv_cpuhp_online);
2073 hyperv_cleanup();
2074};
2075
2076static void hv_crash_handler(struct pt_regs *regs)
2077{
2064 vmbus_initiate_unload(false);
2065 vmbus_connection.conn_state = DISCONNECTED;
2066 /* Make sure conn_state is set as hv_synic_cleanup checks for it */
2067 mb();
2068 cpuhp_remove_state(hyperv_cpuhp_online);
2069 hyperv_cleanup();
2070};
2071
2072static void hv_crash_handler(struct pt_regs *regs)
2073{
2074 int cpu;
2075
2078 vmbus_initiate_unload(true);
2079 /*
2080 * In crash handler we can't schedule synic cleanup for all CPUs,
2081 * doing the cleanup for current CPU only. This should be sufficient
2082 * for kdump.
2083 */
2084 vmbus_connection.conn_state = DISCONNECTED;
2076 vmbus_initiate_unload(true);
2077 /*
2078 * In crash handler we can't schedule synic cleanup for all CPUs,
2079 * doing the cleanup for current CPU only. This should be sufficient
2080 * for kdump.
2081 */
2082 vmbus_connection.conn_state = DISCONNECTED;
2085 hv_synic_cleanup(smp_processor_id());
2083 cpu = smp_processor_id();
2084 hv_stimer_cleanup(cpu);
2085 hv_synic_cleanup(cpu);
2086 hyperv_cleanup();
2087};
2088
2089static int __init hv_acpi_init(void)
2090{
2091 int ret, t;
2092
2093 if (!hv_is_hyperv_initialized())

--- 32 unchanged lines hidden (view full) ---

2126
2127static void __exit vmbus_exit(void)
2128{
2129 int cpu;
2130
2131 hv_remove_kexec_handler();
2132 hv_remove_crash_handler();
2133 vmbus_connection.conn_state = DISCONNECTED;
2086 hyperv_cleanup();
2087};
2088
2089static int __init hv_acpi_init(void)
2090{
2091 int ret, t;
2092
2093 if (!hv_is_hyperv_initialized())

--- 32 unchanged lines hidden (view full) ---

2126
2127static void __exit vmbus_exit(void)
2128{
2129 int cpu;
2130
2131 hv_remove_kexec_handler();
2132 hv_remove_crash_handler();
2133 vmbus_connection.conn_state = DISCONNECTED;
2134 hv_synic_clockevents_cleanup();
2134 hv_stimer_global_cleanup();
2135 vmbus_disconnect();
2136 hv_remove_vmbus_irq();
2137 for_each_online_cpu(cpu) {
2138 struct hv_per_cpu_context *hv_cpu
2139 = per_cpu_ptr(hv_context.cpu_context, cpu);
2140
2141 tasklet_kill(&hv_cpu->msg_dpc);
2142 }

--- 13 unchanged lines hidden (view full) ---

2156
2157 cpuhp_remove_state(hyperv_cpuhp_online);
2158 hv_synic_free();
2159 acpi_bus_unregister_driver(&vmbus_acpi_driver);
2160}
2161
2162
2163MODULE_LICENSE("GPL");
2135 vmbus_disconnect();
2136 hv_remove_vmbus_irq();
2137 for_each_online_cpu(cpu) {
2138 struct hv_per_cpu_context *hv_cpu
2139 = per_cpu_ptr(hv_context.cpu_context, cpu);
2140
2141 tasklet_kill(&hv_cpu->msg_dpc);
2142 }

--- 13 unchanged lines hidden (view full) ---

2156
2157 cpuhp_remove_state(hyperv_cpuhp_online);
2158 hv_synic_free();
2159 acpi_bus_unregister_driver(&vmbus_acpi_driver);
2160}
2161
2162
2163MODULE_LICENSE("GPL");
2164MODULE_DESCRIPTION("Microsoft Hyper-V VMBus Driver");
2164
2165subsys_initcall(hv_acpi_init);
2166module_exit(vmbus_exit);
2165
2166subsys_initcall(hv_acpi_init);
2167module_exit(vmbus_exit);