Drivers: hv: vmbus: Teardown clockevent devices on module unload
Newly introduced clockevent devices made it impossible to unload hv_vmbus module as clockevents_config_and_register() takes additional reverence to the module. To make it possible again we do the following: - avoid setting dev->owner for clockevent devices; - implement hv_synic_clockevents_cleanup() doing clockevents_unbind_device(); - call it from vmbus_exit(). In theory hv_synic_clockevents_cleanup() can be merged with hv_synic_cleanup(), however, we call hv_synic_cleanup() from smp_call_function_single() and this doesn't work for clockevents_unbind_device() as it does such call on its own. I opted for a separate function. Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com> Signed-off-by: K. Y. Srinivasan <kys@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
32a158325a
commit
e086748c65
@ -312,7 +312,11 @@ static void hv_init_clockevent_device(struct clock_event_device *dev, int cpu)
|
||||
dev->features = CLOCK_EVT_FEAT_ONESHOT;
|
||||
dev->cpumask = cpumask_of(cpu);
|
||||
dev->rating = 1000;
|
||||
dev->owner = THIS_MODULE;
|
||||
/*
|
||||
* Avoid settint dev->owner = THIS_MODULE deliberately as doing so will
|
||||
* result in clockevents_config_and_register() taking additional
|
||||
* references to the hv_vmbus module making it impossible to unload.
|
||||
*/
|
||||
|
||||
dev->set_mode = hv_ce_setmode;
|
||||
dev->set_next_event = hv_ce_set_next_event;
|
||||
@ -469,6 +473,20 @@ void hv_synic_init(void *arg)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* hv_synic_clockevents_cleanup - Cleanup clockevent devices
|
||||
*/
|
||||
void hv_synic_clockevents_cleanup(void)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
if (!(ms_hyperv.features & HV_X64_MSR_SYNTIMER_AVAILABLE))
|
||||
return;
|
||||
|
||||
for_each_online_cpu(cpu)
|
||||
clockevents_unbind_device(hv_context.clk_evt[cpu], cpu);
|
||||
}
|
||||
|
||||
/*
|
||||
* hv_synic_cleanup - Cleanup routine for hv_synic_init().
|
||||
*/
|
||||
@ -483,6 +501,11 @@ void hv_synic_cleanup(void *arg)
|
||||
if (!hv_context.synic_initialized)
|
||||
return;
|
||||
|
||||
/* Turn off clockevent device */
|
||||
if (ms_hyperv.features & HV_X64_MSR_SYNTIMER_AVAILABLE)
|
||||
hv_ce_setmode(CLOCK_EVT_MODE_SHUTDOWN,
|
||||
hv_context.clk_evt[cpu]);
|
||||
|
||||
rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
|
||||
|
||||
shared_sint.masked = 1;
|
||||
|
@ -572,6 +572,8 @@ extern void hv_synic_init(void *irqarg);
|
||||
|
||||
extern void hv_synic_cleanup(void *arg);
|
||||
|
||||
extern void hv_synic_clockevents_cleanup(void);
|
||||
|
||||
/*
|
||||
* Host version information.
|
||||
*/
|
||||
|
@ -1032,6 +1032,7 @@ static void __exit vmbus_exit(void)
|
||||
int cpu;
|
||||
|
||||
vmbus_connection.conn_state = DISCONNECTED;
|
||||
hv_synic_clockevents_cleanup();
|
||||
hv_remove_vmbus_irq();
|
||||
vmbus_free_channels();
|
||||
bus_unregister(&hv_bus);
|
||||
|
Loading…
Reference in New Issue
Block a user