aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Wang <jasowang@redhat.com>2013-06-18 23:28:10 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-06-24 19:24:17 -0400
commit2608fb653103419ac163206ff6d51b7b6528e2d9 (patch)
tree772e6b8d52a07a4cb1fc6f5825689666e501cfe6
parente91e84fa4cfeb67a9a096f1adaa1a1a692474724 (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>
-rw-r--r--drivers/hv/hv.c85
-rw-r--r--drivers/hv/hyperv_vmbus.h4
-rw-r--r--drivers/hv/vmbus_drv.c8
3 files changed, 63 insertions, 34 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)
265 return status; 265 return status;
266} 266}
267 267
268
269int hv_synic_alloc(void)
270{
271 size_t size = sizeof(struct tasklet_struct);
272 int cpu;
273
274 for_each_online_cpu(cpu) {
275 hv_context.event_dpc[cpu] = kmalloc(size, GFP_ATOMIC);
276 if (hv_context.event_dpc[cpu] == NULL) {
277 pr_err("Unable to allocate event dpc\n");
278 goto err;
279 }
280 tasklet_init(hv_context.event_dpc[cpu], vmbus_on_event, cpu);
281
282 hv_context.synic_message_page[cpu] =
283 (void *)get_zeroed_page(GFP_ATOMIC);
284
285 if (hv_context.synic_message_page[cpu] == NULL) {
286 pr_err("Unable to allocate SYNIC message page\n");
287 goto err;
288 }
289
290 hv_context.synic_event_page[cpu] =
291 (void *)get_zeroed_page(GFP_ATOMIC);
292
293 if (hv_context.synic_event_page[cpu] == NULL) {
294 pr_err("Unable to allocate SYNIC event page\n");
295 goto err;
296 }
297 }
298
299 return 0;
300err:
301 return -ENOMEM;
302}
303
304void hv_synic_free_cpu(int cpu)
305{
306 kfree(hv_context.event_dpc[cpu]);
307 if (hv_context.synic_message_page[cpu])
308 free_page((unsigned long)hv_context.synic_event_page[cpu]);
309 if (hv_context.synic_message_page[cpu])
310 free_page((unsigned long)hv_context.synic_message_page[cpu]);
311}
312
313void hv_synic_free(void)
314{
315 int cpu;
316
317 for_each_online_cpu(cpu)
318 hv_synic_free_cpu(cpu);
319}
320
268/* 321/*
269 * hv_synic_init - Initialize the Synthethic Interrupt Controller. 322 * hv_synic_init - Initialize the Synthethic Interrupt Controller.
270 * 323 *
@@ -289,30 +342,6 @@ void hv_synic_init(void *arg)
289 /* Check the version */ 342 /* Check the version */
290 rdmsrl(HV_X64_MSR_SVERSION, version); 343 rdmsrl(HV_X64_MSR_SVERSION, version);
291 344
292 hv_context.event_dpc[cpu] = kmalloc(sizeof(struct tasklet_struct),
293 GFP_ATOMIC);
294 if (hv_context.event_dpc[cpu] == NULL) {
295 pr_err("Unable to allocate event dpc\n");
296 goto cleanup;
297 }
298 tasklet_init(hv_context.event_dpc[cpu], vmbus_on_event, cpu);
299
300 hv_context.synic_message_page[cpu] =
301 (void *)get_zeroed_page(GFP_ATOMIC);
302
303 if (hv_context.synic_message_page[cpu] == NULL) {
304 pr_err("Unable to allocate SYNIC message page\n");
305 goto cleanup;
306 }
307
308 hv_context.synic_event_page[cpu] =
309 (void *)get_zeroed_page(GFP_ATOMIC);
310
311 if (hv_context.synic_event_page[cpu] == NULL) {
312 pr_err("Unable to allocate SYNIC event page\n");
313 goto cleanup;
314 }
315
316 /* Setup the Synic's message page */ 345 /* Setup the Synic's message page */
317 rdmsrl(HV_X64_MSR_SIMP, simp.as_uint64); 346 rdmsrl(HV_X64_MSR_SIMP, simp.as_uint64);
318 simp.simp_enabled = 1; 347 simp.simp_enabled = 1;
@@ -355,14 +384,6 @@ void hv_synic_init(void *arg)
355 rdmsrl(HV_X64_MSR_VP_INDEX, vp_index); 384 rdmsrl(HV_X64_MSR_VP_INDEX, vp_index);
356 hv_context.vp_index[cpu] = (u32)vp_index; 385 hv_context.vp_index[cpu] = (u32)vp_index;
357 return; 386 return;
358
359cleanup:
360 if (hv_context.synic_event_page[cpu])
361 free_page((unsigned long)hv_context.synic_event_page[cpu]);
362
363 if (hv_context.synic_message_page[cpu])
364 free_page((unsigned long)hv_context.synic_message_page[cpu]);
365 return;
366} 387}
367 388
368/* 389/*
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 12f2f9e989f7..d84918fe19ab 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -527,6 +527,10 @@ extern int hv_post_message(union hv_connection_id connection_id,
527 527
528extern u16 hv_signal_event(void *con_id); 528extern u16 hv_signal_event(void *con_id);
529 529
530extern int hv_synic_alloc(void);
531
532extern void hv_synic_free(void);
533
530extern void hv_synic_init(void *irqarg); 534extern void hv_synic_init(void *irqarg);
531 535
532extern void hv_synic_cleanup(void *arg); 536extern void hv_synic_cleanup(void *arg);
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 4004e54ef05d..a2464bf07c49 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -563,6 +563,9 @@ static int vmbus_bus_init(int irq)
563 */ 563 */
564 hv_register_vmbus_handler(irq, vmbus_isr); 564 hv_register_vmbus_handler(irq, vmbus_isr);
565 565
566 ret = hv_synic_alloc();
567 if (ret)
568 goto err_alloc;
566 /* 569 /*
567 * Initialize the per-cpu interrupt state and 570 * Initialize the per-cpu interrupt state and
568 * connect to the host. 571 * connect to the host.
@@ -570,13 +573,14 @@ static int vmbus_bus_init(int irq)
570 on_each_cpu(hv_synic_init, NULL, 1); 573 on_each_cpu(hv_synic_init, NULL, 1);
571 ret = vmbus_connect(); 574 ret = vmbus_connect();
572 if (ret) 575 if (ret)
573 goto err_irq; 576 goto err_alloc;
574 577
575 vmbus_request_offers(); 578 vmbus_request_offers();
576 579
577 return 0; 580 return 0;
578 581
579err_irq: 582err_alloc:
583 hv_synic_free();
580 free_irq(irq, hv_acpi_dev); 584 free_irq(irq, hv_acpi_dev);
581 585
582err_unregister: 586err_unregister: