diff options
Diffstat (limited to 'arch/powerpc/platforms/powernv/opal.c')
-rw-r--r-- | arch/powerpc/platforms/powernv/opal.c | 69 |
1 files changed, 66 insertions, 3 deletions
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index 49d2f00019e5..360ad80c754c 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c | |||
@@ -242,14 +242,14 @@ void opal_notifier_update_evt(uint64_t evt_mask, | |||
242 | void opal_notifier_enable(void) | 242 | void opal_notifier_enable(void) |
243 | { | 243 | { |
244 | int64_t rc; | 244 | int64_t rc; |
245 | uint64_t evt = 0; | 245 | __be64 evt = 0; |
246 | 246 | ||
247 | atomic_set(&opal_notifier_hold, 0); | 247 | atomic_set(&opal_notifier_hold, 0); |
248 | 248 | ||
249 | /* Process pending events */ | 249 | /* Process pending events */ |
250 | rc = opal_poll_events(&evt); | 250 | rc = opal_poll_events(&evt); |
251 | if (rc == OPAL_SUCCESS && evt) | 251 | if (rc == OPAL_SUCCESS && evt) |
252 | opal_do_notifier(evt); | 252 | opal_do_notifier(be64_to_cpu(evt)); |
253 | } | 253 | } |
254 | 254 | ||
255 | void opal_notifier_disable(void) | 255 | void opal_notifier_disable(void) |
@@ -529,7 +529,7 @@ static irqreturn_t opal_interrupt(int irq, void *data) | |||
529 | 529 | ||
530 | opal_handle_interrupt(virq_to_hw(irq), &events); | 530 | opal_handle_interrupt(virq_to_hw(irq), &events); |
531 | 531 | ||
532 | opal_do_notifier(events); | 532 | opal_do_notifier(be64_to_cpu(events)); |
533 | 533 | ||
534 | return IRQ_HANDLED; | 534 | return IRQ_HANDLED; |
535 | } | 535 | } |
@@ -638,3 +638,66 @@ void opal_shutdown(void) | |||
638 | 638 | ||
639 | /* Export this so that test modules can use it */ | 639 | /* Export this so that test modules can use it */ |
640 | EXPORT_SYMBOL_GPL(opal_invalid_call); | 640 | EXPORT_SYMBOL_GPL(opal_invalid_call); |
641 | |||
642 | /* Convert a region of vmalloc memory to an opal sg list */ | ||
643 | struct opal_sg_list *opal_vmalloc_to_sg_list(void *vmalloc_addr, | ||
644 | unsigned long vmalloc_size) | ||
645 | { | ||
646 | struct opal_sg_list *sg, *first = NULL; | ||
647 | unsigned long i = 0; | ||
648 | |||
649 | sg = kzalloc(PAGE_SIZE, GFP_KERNEL); | ||
650 | if (!sg) | ||
651 | goto nomem; | ||
652 | |||
653 | first = sg; | ||
654 | |||
655 | while (vmalloc_size > 0) { | ||
656 | uint64_t data = vmalloc_to_pfn(vmalloc_addr) << PAGE_SHIFT; | ||
657 | uint64_t length = min(vmalloc_size, PAGE_SIZE); | ||
658 | |||
659 | sg->entry[i].data = cpu_to_be64(data); | ||
660 | sg->entry[i].length = cpu_to_be64(length); | ||
661 | i++; | ||
662 | |||
663 | if (i >= SG_ENTRIES_PER_NODE) { | ||
664 | struct opal_sg_list *next; | ||
665 | |||
666 | next = kzalloc(PAGE_SIZE, GFP_KERNEL); | ||
667 | if (!next) | ||
668 | goto nomem; | ||
669 | |||
670 | sg->length = cpu_to_be64( | ||
671 | i * sizeof(struct opal_sg_entry) + 16); | ||
672 | i = 0; | ||
673 | sg->next = cpu_to_be64(__pa(next)); | ||
674 | sg = next; | ||
675 | } | ||
676 | |||
677 | vmalloc_addr += length; | ||
678 | vmalloc_size -= length; | ||
679 | } | ||
680 | |||
681 | sg->length = cpu_to_be64(i * sizeof(struct opal_sg_entry) + 16); | ||
682 | |||
683 | return first; | ||
684 | |||
685 | nomem: | ||
686 | pr_err("%s : Failed to allocate memory\n", __func__); | ||
687 | opal_free_sg_list(first); | ||
688 | return NULL; | ||
689 | } | ||
690 | |||
691 | void opal_free_sg_list(struct opal_sg_list *sg) | ||
692 | { | ||
693 | while (sg) { | ||
694 | uint64_t next = be64_to_cpu(sg->next); | ||
695 | |||
696 | kfree(sg); | ||
697 | |||
698 | if (next) | ||
699 | sg = __va(next); | ||
700 | else | ||
701 | sg = NULL; | ||
702 | } | ||
703 | } | ||