diff options
author | Jason Wang <jasowang@redhat.com> | 2013-06-19 11:28:10 +0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-06-24 16:24:17 -0700 |
commit | 2608fb653103419ac163206ff6d51b7b6528e2d9 (patch) | |
tree | 772e6b8d52a07a4cb1fc6f5825689666e501cfe6 /drivers/hv/hv.c | |
parent | e91e84fa4cfeb67a9a096f1adaa1a1a692474724 (diff) |
drivers: hv: allocate synic structures before hv_synic_init()
We currently allocate synic structures in hv_sync_init(), but there's no way for
the driver to know about the allocation failure and it may continue to use the
uninitialized pointers. Solve this by introducing helpers for allocating and
freeing and doing the allocation before the on_each_cpu() call in
vmbus_bus_init().
Cc: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/hv/hv.c')
-rw-r--r-- | drivers/hv/hv.c | 85 |
1 files changed, 53 insertions, 32 deletions
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index ae4923756d98..88f4096fa078 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -265,6 +265,59 @@ u16 hv_signal_event(void *con_id) return status; } + +int hv_synic_alloc(void) +{ + size_t size = sizeof(struct tasklet_struct); + int cpu; + + for_each_online_cpu(cpu) { + hv_context.event_dpc[cpu] = kmalloc(size, GFP_ATOMIC); + if (hv_context.event_dpc[cpu] == NULL) { + pr_err("Unable to allocate event dpc\n"); + goto err; + } + tasklet_init(hv_context.event_dpc[cpu], vmbus_on_event, cpu); + + hv_context.synic_message_page[cpu] = + (void *)get_zeroed_page(GFP_ATOMIC); + + if (hv_context.synic_message_page[cpu] == NULL) { + pr_err("Unable to allocate SYNIC message page\n"); + goto err; + } + + hv_context.synic_event_page[cpu] = + (void *)get_zeroed_page(GFP_ATOMIC); + + if (hv_context.synic_event_page[cpu] == NULL) { + pr_err("Unable to allocate SYNIC event page\n"); + goto err; + } + } + + return 0; +err: + return -ENOMEM; +} + +void hv_synic_free_cpu(int cpu) +{ + kfree(hv_context.event_dpc[cpu]); + if (hv_context.synic_message_page[cpu]) + free_page((unsigned long)hv_context.synic_event_page[cpu]); + if (hv_context.synic_message_page[cpu]) + free_page((unsigned long)hv_context.synic_message_page[cpu]); +} + +void hv_synic_free(void) +{ + int cpu; + + for_each_online_cpu(cpu) + hv_synic_free_cpu(cpu); +} + /* * hv_synic_init - Initialize the Synthethic Interrupt Controller. * @@ -289,30 +342,6 @@ void hv_synic_init(void *arg) /* Check the version */ rdmsrl(HV_X64_MSR_SVERSION, version); - hv_context.event_dpc[cpu] = kmalloc(sizeof(struct tasklet_struct), - GFP_ATOMIC); - if (hv_context.event_dpc[cpu] == NULL) { - pr_err("Unable to allocate event dpc\n"); - goto cleanup; - } - tasklet_init(hv_context.event_dpc[cpu], vmbus_on_event, cpu); - - hv_context.synic_message_page[cpu] = - (void *)get_zeroed_page(GFP_ATOMIC); - - if (hv_context.synic_message_page[cpu] == NULL) { - pr_err("Unable to allocate SYNIC message page\n"); - goto cleanup; - } - - hv_context.synic_event_page[cpu] = - (void *)get_zeroed_page(GFP_ATOMIC); - - if (hv_context.synic_event_page[cpu] == NULL) { - pr_err("Unable to allocate SYNIC event page\n"); - goto cleanup; - } - /* Setup the Synic's message page */ rdmsrl(HV_X64_MSR_SIMP, simp.as_uint64); simp.simp_enabled = 1; @@ -355,14 +384,6 @@ void hv_synic_init(void *arg) rdmsrl(HV_X64_MSR_VP_INDEX, vp_index); hv_context.vp_index[cpu] = (u32)vp_index; return; - -cleanup: - if (hv_context.synic_event_page[cpu]) - free_page((unsigned long)hv_context.synic_event_page[cpu]); - - if (hv_context.synic_message_page[cpu]) - free_page((unsigned long)hv_context.synic_message_page[cpu]); - return; } /* |