aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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: