diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index fb8cd8469328ee..4b30e2d07f2c93 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -632,8 +632,8 @@ static void vmbus_free_requestor(struct vmbus_requestor *rqstor) } static int __vmbus_open(struct vmbus_channel *newchannel, - void *userdata, u32 userdatalen, - void (*onchannelcallback)(void *context), void *context) + void *userdata, u32 userdatalen, bool channelapiv1, + void *onchannelcallback, void *context) { struct vmbus_channel_open_channel *open_msg; struct vmbus_channel_msginfo *open_info = NULL; @@ -658,7 +658,15 @@ static int __vmbus_open(struct vmbus_channel *newchannel, } newchannel->state = CHANNEL_OPENING_STATE; - newchannel->onchannel_callback = onchannelcallback; + + if (channelapiv1) { + newchannel->onchannel_callback = NULL; + newchannel->onchannel_callback_v1 = onchannelcallback; + } else { + newchannel->onchannel_callback = onchannelcallback; + newchannel->onchannel_callback_v1 = NULL; + } + newchannel->channel_callback_context = context; if (!newchannel->max_pkt_size) @@ -775,10 +783,22 @@ static int __vmbus_open(struct vmbus_channel *newchannel, int vmbus_connect_ring(struct vmbus_channel *newchannel, void (*onchannelcallback)(void *context), void *context) { - return __vmbus_open(newchannel, NULL, 0, onchannelcallback, context); + bool channelapiv1 = true; + return __vmbus_open(newchannel, NULL, 0, channelapiv1, onchannelcallback, context); } EXPORT_SYMBOL_GPL(vmbus_connect_ring); +/* + * vmbus_connect_ring - Open the channel but reuse ring buffer + */ +int vmbus_connect_ring_channel(struct vmbus_channel *newchannel, + onchannel_t *onchannelcallback, void *context) +{ + bool channelapiv1 = false; + return __vmbus_open(newchannel, NULL, 0, channelapiv1, onchannelcallback, context); +} +EXPORT_SYMBOL_GPL(vmbus_connect_ring_channel); + /* * vmbus_open - Open the specified channel. */ @@ -788,6 +808,7 @@ int vmbus_open(struct vmbus_channel *newchannel, void (*onchannelcallback)(void *context), void *context) { int err; + bool channelapiv1 = true; err = vmbus_alloc_ring(newchannel, send_ringbuffer_size, recv_ringbuffer_size); @@ -795,7 +816,7 @@ int vmbus_open(struct vmbus_channel *newchannel, return err; err = __vmbus_open(newchannel, userdata, userdatalen, - onchannelcallback, context); + channelapiv1, onchannelcallback, context); if (err) vmbus_free_ring(newchannel); @@ -803,6 +824,31 @@ int vmbus_open(struct vmbus_channel *newchannel, } EXPORT_SYMBOL_GPL(vmbus_open); +/* + * vmbus_open - Open the specified channel. + */ +int vmbus_open_channel(struct vmbus_channel *newchannel, + u32 send_ringbuffer_size, u32 recv_ringbuffer_size, + void *userdata, u32 userdatalen, + onchannel_t *onchannelcallback, void *context) +{ + int err; + bool channelapiv1 = false; + + err = vmbus_alloc_ring(newchannel, send_ringbuffer_size, + recv_ringbuffer_size); + if (err) + return err; + + err = __vmbus_open(newchannel, userdata, userdatalen, + channelapiv1, onchannelcallback, context); + if (err) + vmbus_free_ring(newchannel); + + return err; +} +EXPORT_SYMBOL_GPL(vmbus_open_channel); + /* * vmbus_teardown_gpadl -Teardown the specified GPADL handle */ @@ -895,6 +941,7 @@ void vmbus_reset_channel_cb(struct vmbus_channel *channel) /* See the inline comments in vmbus_chan_sched(). */ spin_lock_irqsave(&channel->sched_lock, flags); channel->onchannel_callback = NULL; + channel->onchannel_callback_v1 = NULL; spin_unlock_irqrestore(&channel->sched_lock, flags); channel->sc_creation_callback = NULL; diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index f001ae880e1dbe..fd48b74e6a3672 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c @@ -393,7 +393,8 @@ struct vmbus_channel *relid2channel(u32 relid) void vmbus_on_event(unsigned long data) { struct vmbus_channel *channel = (void *) data; - void (*callback_fn)(void *context); + void (*callback_fn_v1)(void *context); + onchannel_t *callback_fn; trace_vmbus_on_event(channel); @@ -403,12 +404,16 @@ void vmbus_on_event(unsigned long data) * there is no driver handling the device. An * unloading driver sets the onchannel_callback to NULL. */ - callback_fn = READ_ONCE(channel->onchannel_callback); - if (unlikely(!callback_fn)) + if (channel->onchannel_callback_v1 != NULL) { + callback_fn_v1 = READ_ONCE(channel->onchannel_callback_v1); + (*callback_fn_v1)(channel->channel_callback_context); + } else if (channel->onchannel_callback != NULL) { + callback_fn = READ_ONCE(channel->onchannel_callback); + (*callback_fn)(channel->channel_callback_context, channel); + } else { return; - - (*callback_fn)(channel->channel_callback_context); - + } + if (channel->callback_mode != HV_CALL_BATCHED) return; diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index e000fa3b9f978c..15025184d66580 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c @@ -1407,7 +1407,7 @@ static void balloon_down(struct hv_dynmem_device *dm, dm->state = DM_INITIALIZED; } -static void balloon_onchannelcallback(void *context); +static void balloon_onchannelcallback(void *context, struct vmbus_channel *chan); static int dm_thread_func(void *dm_dev) { @@ -1511,7 +1511,7 @@ static void cap_resp(struct hv_dynmem_device *dm, complete(&dm->host_event); } -static void balloon_onchannelcallback(void *context) +static void balloon_onchannelcallback(void *context, struct vmbus_channel *chan) { struct hv_device *dev = context; u32 recvlen; @@ -1770,7 +1770,7 @@ static int balloon_connect_vsp(struct hv_device *dev) */ dev->channel->max_pkt_size = HV_HYP_PAGE_SIZE * 2; - ret = vmbus_open(dev->channel, dm_ring_size, dm_ring_size, NULL, 0, + ret = vmbus_open_channel(dev->channel, dm_ring_size, dm_ring_size, NULL, 0, balloon_onchannelcallback, dev); if (ret) return ret; diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c index d35b60c0611486..1ec72b2d5d96c2 100644 --- a/drivers/hv/hv_kvp.c +++ b/drivers/hv/hv_kvp.c @@ -632,7 +632,7 @@ kvp_respond_to_host(struct hv_kvp_msg *msg_to_host, int error) * we stash away the transaction state in a set of global variables. */ -void hv_kvp_onchannelcallback(void *context) +void hv_kvp_onchannelcallback(void *context, struct vmbus_channel *chan) { struct vmbus_channel *channel = context; u32 recvlen; diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c index 0d2184be169125..f62865e52530c3 100644 --- a/drivers/hv/hv_snapshot.c +++ b/drivers/hv/hv_snapshot.c @@ -288,7 +288,7 @@ vss_respond_to_host(int error) * The host ensures that only one VSS transaction can be active at a time. */ -void hv_vss_onchannelcallback(void *context) +void hv_vss_onchannelcallback(void *context, struct vmbus_channel *chan) { struct vmbus_channel *channel = context; u32 recvlen; diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c index c4f525325790fa..bb3707339c1b7f 100644 --- a/drivers/hv/hv_util.c +++ b/drivers/hv/hv_util.c @@ -115,7 +115,8 @@ static int hv_shutdown_init(struct hv_util_service *srv) return 0; } -static void shutdown_onchannelcallback(void *context); +static void shutdown_onchannelcallback(void *context, + struct vmbus_channel *chan); static struct hv_util_service util_shutdown = { .util_cb = shutdown_onchannelcallback, .util_init = hv_shutdown_init, @@ -125,7 +126,8 @@ static int hv_timesync_init(struct hv_util_service *srv); static int hv_timesync_pre_suspend(void); static void hv_timesync_deinit(void); -static void timesync_onchannelcallback(void *context); +static void timesync_onchannelcallback(void *context, + struct vmbus_channel *chan); static struct hv_util_service util_timesynch = { .util_cb = timesync_onchannelcallback, .util_init = hv_timesync_init, @@ -133,7 +135,8 @@ static struct hv_util_service util_timesynch = { .util_deinit = hv_timesync_deinit, }; -static void heartbeat_onchannelcallback(void *context); +static void heartbeat_onchannelcallback(void *context, + struct vmbus_channel *chan); static struct hv_util_service util_heartbeat = { .util_cb = heartbeat_onchannelcallback, }; @@ -174,7 +177,7 @@ static DECLARE_WORK(shutdown_work, perform_shutdown); */ static DECLARE_WORK(restart_work, perform_restart); -static void shutdown_onchannelcallback(void *context) +static void shutdown_onchannelcallback(void *context, struct vmbus_channel *chan) { struct vmbus_channel *channel = context; struct work_struct *work = NULL; @@ -412,7 +415,7 @@ static inline void adj_guesttime(u64 hosttime, u64 reftime, u8 adj_flags) /* * Time Sync Channel message handler. */ -static void timesync_onchannelcallback(void *context) +static void timesync_onchannelcallback(void *context, struct vmbus_channel *chan) { struct vmbus_channel *channel = context; u32 recvlen; @@ -505,7 +508,7 @@ static void timesync_onchannelcallback(void *context) * Every two seconds, Hyper-V send us a heartbeat request message. * we respond to this message, and Hyper-V knows we are alive. */ -static void heartbeat_onchannelcallback(void *context) +static void heartbeat_onchannelcallback(void *context, struct vmbus_channel *chan) { struct vmbus_channel *channel = context; u32 recvlen; @@ -607,7 +610,7 @@ static int util_probe(struct hv_device *dev, hv_set_drvdata(dev, srv); - ret = vmbus_open(dev->channel, HV_UTIL_RING_SEND_SIZE, + ret = vmbus_open_channel(dev->channel, HV_UTIL_RING_SEND_SIZE, HV_UTIL_RING_RECV_SIZE, NULL, 0, srv->util_cb, dev->channel); if (ret) @@ -665,7 +668,7 @@ static int util_resume(struct hv_device *dev) return ret; } - ret = vmbus_open(dev->channel, HV_UTIL_RING_SEND_SIZE, + ret = vmbus_open_channel(dev->channel, HV_UTIL_RING_SEND_SIZE, HV_UTIL_RING_RECV_SIZE, NULL, 0, srv->util_cb, dev->channel); return ret; diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 76ac5185a01a88..0a0711114f75e6 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -373,19 +373,19 @@ int hv_kvp_init(struct hv_util_service *srv); void hv_kvp_deinit(void); int hv_kvp_pre_suspend(void); int hv_kvp_pre_resume(void); -void hv_kvp_onchannelcallback(void *context); +onchannel_t hv_kvp_onchannelcallback; int hv_vss_init(struct hv_util_service *srv); void hv_vss_deinit(void); int hv_vss_pre_suspend(void); int hv_vss_pre_resume(void); -void hv_vss_onchannelcallback(void *context); +onchannel_t hv_vss_onchannelcallback; int hv_fcopy_init(struct hv_util_service *srv); void hv_fcopy_deinit(void); int hv_fcopy_pre_suspend(void); int hv_fcopy_pre_resume(void); -void hv_fcopy_onchannelcallback(void *context); +onchannel_t hv_fcopy_onchannelcallback; void vmbus_initiate_unload(bool crash); static inline void hv_poll_channel(struct vmbus_channel *channel, diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 12a707ab73f85c..9746b7a522eeaa 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -1214,7 +1214,8 @@ static void vmbus_chan_sched(struct hv_per_cpu_context *hv_cpu) return; for_each_set_bit(relid, recv_int_page, maxbits) { - void (*callback_fn)(void *context); + void (*callback_fn_v1)(void *context); + onchannel_t *callback_fn; struct vmbus_channel *channel; if (!sync_test_and_clear_bit(relid, recv_int_page)) @@ -1249,9 +1250,15 @@ static void vmbus_chan_sched(struct hv_per_cpu_context *hv_cpu) */ spin_lock(&channel->sched_lock); - callback_fn = channel->onchannel_callback; - if (unlikely(callback_fn == NULL)) + bool channelapiv1 = false; + if (channel->onchannel_callback_v1 != NULL) { + callback_fn_v1 = channel->onchannel_callback_v1; + } else if (channel->onchannel_callback != NULL) { + callback_fn =channel->onchannel_callback; + channelapiv1 = true; + } else { goto sched_unlock; + } trace_vmbus_chan_sched(channel); @@ -1259,7 +1266,11 @@ static void vmbus_chan_sched(struct hv_per_cpu_context *hv_cpu) switch (channel->callback_mode) { case HV_CALL_ISR: - (*callback_fn)(channel->channel_callback_context); + if (channelapiv1) { + (*callback_fn_v1)(channel->channel_callback_context); + } else { + (*callback_fn)(channel->channel_callback_context, channel); + } break; case HV_CALL_BATCHED: diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 5e39baa7f6cbb6..958db9e8e35828 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -837,6 +837,8 @@ struct vmbus_gpadl { bool decrypted; }; +typedef void onchannel_t(void *context, struct vmbus_channel *chan); + struct vmbus_channel { struct list_head listentry; @@ -886,7 +888,8 @@ struct vmbus_channel { /* Channel callback's invoked in softirq context */ struct tasklet_struct callback_event; - void (*onchannel_callback)(void *context); + void (*onchannel_callback_v1)(void *context); + onchannel_t *onchannel_callback; void *channel_callback_context; void (*change_target_cpu_callback)(struct vmbus_channel *channel, @@ -1200,6 +1203,9 @@ void vmbus_free_ring(struct vmbus_channel *channel); int vmbus_connect_ring(struct vmbus_channel *channel, void (*onchannel_callback)(void *context), void *context); +int vmbus_connect_ring_channel(struct vmbus_channel *channel, + onchannel_t *onchannel_callback, + void *context); int vmbus_disconnect_ring(struct vmbus_channel *channel); extern int vmbus_open(struct vmbus_channel *channel, @@ -1210,6 +1216,14 @@ extern int vmbus_open(struct vmbus_channel *channel, void (*onchannel_callback)(void *context), void *context); +extern int vmbus_open_channel(struct vmbus_channel *channel, + u32 send_ringbuffersize, + u32 recv_ringbuffersize, + void *userdata, + u32 userdatalen, + onchannel_t *onchannelcallback, + void *context); + extern void vmbus_close(struct vmbus_channel *channel); extern int vmbus_sendpacket_getid(struct vmbus_channel *channel, @@ -1561,7 +1575,7 @@ void vmbus_free_mmio(resource_size_t start, resource_size_t size); struct hv_util_service { u8 *recv_buffer; void *channel; - void (*util_cb)(void *); + onchannel_t *util_cb; int (*util_init)(struct hv_util_service *); void (*util_deinit)(void); int (*util_pre_suspend)(void);