diff options
author | Hannes Hering <hannes.hering@linux.vnet.ibm.com> | 2008-10-16 05:36:42 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2008-10-22 06:22:17 -0400 |
commit | d4f12daf7ba4efc506c377a9591ecdb692641fe5 (patch) | |
tree | c2a94e5f6a012adfc94b52a30daed50229320edb /drivers/net/ehea/ehea_qmr.c | |
parent | 93fbaae188fba7c2a6e458f62e1f61439caebfc8 (diff) |
ehea: Fix memory hotplug support
This patch implements the memory notifier to update the busmap
instantly instead of rebuilding the whole map. This is necessary
because walk_memory_resource provides different information than
required during memory hotplug.
Signed-off-by: Hannes Hering <hering2@de.ibm.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/net/ehea/ehea_qmr.c')
-rw-r--r-- | drivers/net/ehea/ehea_qmr.c | 131 |
1 files changed, 101 insertions, 30 deletions
diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c index db8a9257e680..9b61dc9865d1 100644 --- a/drivers/net/ehea/ehea_qmr.c +++ b/drivers/net/ehea/ehea_qmr.c | |||
@@ -567,7 +567,7 @@ static inline int ehea_calc_index(unsigned long i, unsigned long s) | |||
567 | static inline int ehea_init_top_bmap(struct ehea_top_bmap *ehea_top_bmap, | 567 | static inline int ehea_init_top_bmap(struct ehea_top_bmap *ehea_top_bmap, |
568 | int dir) | 568 | int dir) |
569 | { | 569 | { |
570 | if(!ehea_top_bmap->dir[dir]) { | 570 | if (!ehea_top_bmap->dir[dir]) { |
571 | ehea_top_bmap->dir[dir] = | 571 | ehea_top_bmap->dir[dir] = |
572 | kzalloc(sizeof(struct ehea_dir_bmap), GFP_KERNEL); | 572 | kzalloc(sizeof(struct ehea_dir_bmap), GFP_KERNEL); |
573 | if (!ehea_top_bmap->dir[dir]) | 573 | if (!ehea_top_bmap->dir[dir]) |
@@ -578,7 +578,7 @@ static inline int ehea_init_top_bmap(struct ehea_top_bmap *ehea_top_bmap, | |||
578 | 578 | ||
579 | static inline int ehea_init_bmap(struct ehea_bmap *ehea_bmap, int top, int dir) | 579 | static inline int ehea_init_bmap(struct ehea_bmap *ehea_bmap, int top, int dir) |
580 | { | 580 | { |
581 | if(!ehea_bmap->top[top]) { | 581 | if (!ehea_bmap->top[top]) { |
582 | ehea_bmap->top[top] = | 582 | ehea_bmap->top[top] = |
583 | kzalloc(sizeof(struct ehea_top_bmap), GFP_KERNEL); | 583 | kzalloc(sizeof(struct ehea_top_bmap), GFP_KERNEL); |
584 | if (!ehea_bmap->top[top]) | 584 | if (!ehea_bmap->top[top]) |
@@ -587,53 +587,124 @@ static inline int ehea_init_bmap(struct ehea_bmap *ehea_bmap, int top, int dir) | |||
587 | return ehea_init_top_bmap(ehea_bmap->top[top], dir); | 587 | return ehea_init_top_bmap(ehea_bmap->top[top], dir); |
588 | } | 588 | } |
589 | 589 | ||
590 | static int ehea_create_busmap_callback(unsigned long pfn, | 590 | static DEFINE_MUTEX(ehea_busmap_mutex); |
591 | unsigned long nr_pages, void *arg) | 591 | static unsigned long ehea_mr_len; |
592 | { | ||
593 | unsigned long i, mr_len, start_section, end_section; | ||
594 | start_section = (pfn * PAGE_SIZE) / EHEA_SECTSIZE; | ||
595 | end_section = start_section + ((nr_pages * PAGE_SIZE) / EHEA_SECTSIZE); | ||
596 | mr_len = *(unsigned long *)arg; | ||
597 | 592 | ||
598 | if (!ehea_bmap) | 593 | #define EHEA_BUSMAP_ADD_SECT 1 |
599 | ehea_bmap = kzalloc(sizeof(struct ehea_bmap), GFP_KERNEL); | 594 | #define EHEA_BUSMAP_REM_SECT 0 |
600 | if (!ehea_bmap) | ||
601 | return -ENOMEM; | ||
602 | 595 | ||
603 | for (i = start_section; i < end_section; i++) { | 596 | static void ehea_rebuild_busmap(void) |
604 | int ret; | 597 | { |
605 | int top, dir, idx; | 598 | u64 vaddr = EHEA_BUSMAP_START; |
606 | u64 vaddr; | 599 | int top, dir, idx; |
600 | |||
601 | for (top = 0; top < EHEA_MAP_ENTRIES; top++) { | ||
602 | struct ehea_top_bmap *ehea_top; | ||
603 | int valid_dir_entries = 0; | ||
607 | 604 | ||
608 | top = ehea_calc_index(i, EHEA_TOP_INDEX_SHIFT); | 605 | if (!ehea_bmap->top[top]) |
609 | dir = ehea_calc_index(i, EHEA_DIR_INDEX_SHIFT); | 606 | continue; |
607 | ehea_top = ehea_bmap->top[top]; | ||
608 | for (dir = 0; dir < EHEA_MAP_ENTRIES; dir++) { | ||
609 | struct ehea_dir_bmap *ehea_dir; | ||
610 | int valid_entries = 0; | ||
610 | 611 | ||
611 | ret = ehea_init_bmap(ehea_bmap, top, dir); | 612 | if (!ehea_top->dir[dir]) |
612 | if(ret) | 613 | continue; |
613 | return ret; | 614 | valid_dir_entries++; |
615 | ehea_dir = ehea_top->dir[dir]; | ||
616 | for (idx = 0; idx < EHEA_MAP_ENTRIES; idx++) { | ||
617 | if (!ehea_dir->ent[idx]) | ||
618 | continue; | ||
619 | valid_entries++; | ||
620 | ehea_dir->ent[idx] = vaddr; | ||
621 | vaddr += EHEA_SECTSIZE; | ||
622 | } | ||
623 | if (!valid_entries) { | ||
624 | ehea_top->dir[dir] = NULL; | ||
625 | kfree(ehea_dir); | ||
626 | } | ||
627 | } | ||
628 | if (!valid_dir_entries) { | ||
629 | ehea_bmap->top[top] = NULL; | ||
630 | kfree(ehea_top); | ||
631 | } | ||
632 | } | ||
633 | } | ||
614 | 634 | ||
615 | idx = i & EHEA_INDEX_MASK; | 635 | static int ehea_update_busmap(unsigned long pfn, unsigned long pgnum, int add) |
616 | vaddr = EHEA_BUSMAP_START + mr_len + i * EHEA_SECTSIZE; | 636 | { |
637 | unsigned long i, start_section, end_section; | ||
617 | 638 | ||
618 | ehea_bmap->top[top]->dir[dir]->ent[idx] = vaddr; | 639 | if (!ehea_bmap) { |
640 | ehea_bmap = kzalloc(sizeof(struct ehea_bmap), GFP_KERNEL); | ||
641 | if (!ehea_bmap) | ||
642 | return -ENOMEM; | ||
619 | } | 643 | } |
620 | 644 | ||
621 | mr_len += nr_pages * PAGE_SIZE; | 645 | start_section = (pfn * PAGE_SIZE) / EHEA_SECTSIZE; |
622 | *(unsigned long *)arg = mr_len; | 646 | end_section = start_section + ((pgnum * PAGE_SIZE) / EHEA_SECTSIZE); |
647 | /* Mark entries as valid or invalid only; address is assigned later */ | ||
648 | for (i = start_section; i < end_section; i++) { | ||
649 | u64 flag; | ||
650 | int top = ehea_calc_index(i, EHEA_TOP_INDEX_SHIFT); | ||
651 | int dir = ehea_calc_index(i, EHEA_DIR_INDEX_SHIFT); | ||
652 | int idx = i & EHEA_INDEX_MASK; | ||
653 | |||
654 | if (add) { | ||
655 | int ret = ehea_init_bmap(ehea_bmap, top, dir); | ||
656 | if (ret) | ||
657 | return ret; | ||
658 | flag = 1; /* valid */ | ||
659 | ehea_mr_len += EHEA_SECTSIZE; | ||
660 | } else { | ||
661 | if (!ehea_bmap->top[top]) | ||
662 | continue; | ||
663 | if (!ehea_bmap->top[top]->dir[dir]) | ||
664 | continue; | ||
665 | flag = 0; /* invalid */ | ||
666 | ehea_mr_len -= EHEA_SECTSIZE; | ||
667 | } | ||
623 | 668 | ||
669 | ehea_bmap->top[top]->dir[dir]->ent[idx] = flag; | ||
670 | } | ||
671 | ehea_rebuild_busmap(); /* Assign contiguous addresses for mr */ | ||
624 | return 0; | 672 | return 0; |
625 | } | 673 | } |
626 | 674 | ||
627 | static unsigned long ehea_mr_len; | 675 | int ehea_add_sect_bmap(unsigned long pfn, unsigned long nr_pages) |
676 | { | ||
677 | int ret; | ||
628 | 678 | ||
629 | static DEFINE_MUTEX(ehea_busmap_mutex); | 679 | mutex_lock(&ehea_busmap_mutex); |
680 | ret = ehea_update_busmap(pfn, nr_pages, EHEA_BUSMAP_ADD_SECT); | ||
681 | mutex_unlock(&ehea_busmap_mutex); | ||
682 | return ret; | ||
683 | } | ||
684 | |||
685 | int ehea_rem_sect_bmap(unsigned long pfn, unsigned long nr_pages) | ||
686 | { | ||
687 | int ret; | ||
688 | |||
689 | mutex_lock(&ehea_busmap_mutex); | ||
690 | ret = ehea_update_busmap(pfn, nr_pages, EHEA_BUSMAP_REM_SECT); | ||
691 | mutex_unlock(&ehea_busmap_mutex); | ||
692 | return ret; | ||
693 | } | ||
694 | |||
695 | static int ehea_create_busmap_callback(unsigned long pfn, | ||
696 | unsigned long nr_pages, void *arg) | ||
697 | { | ||
698 | return ehea_update_busmap(pfn, nr_pages, EHEA_BUSMAP_ADD_SECT); | ||
699 | } | ||
630 | 700 | ||
631 | int ehea_create_busmap(void) | 701 | int ehea_create_busmap(void) |
632 | { | 702 | { |
633 | int ret; | 703 | int ret; |
704 | |||
634 | mutex_lock(&ehea_busmap_mutex); | 705 | mutex_lock(&ehea_busmap_mutex); |
635 | ehea_mr_len = 0; | 706 | ehea_mr_len = 0; |
636 | ret = walk_memory_resource(0, 1ULL << MAX_PHYSMEM_BITS, &ehea_mr_len, | 707 | ret = walk_memory_resource(0, 1ULL << MAX_PHYSMEM_BITS, NULL, |
637 | ehea_create_busmap_callback); | 708 | ehea_create_busmap_callback); |
638 | mutex_unlock(&ehea_busmap_mutex); | 709 | mutex_unlock(&ehea_busmap_mutex); |
639 | return ret; | 710 | return ret; |