aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorHannes Hering <hannes.hering@linux.vnet.ibm.com>2008-10-16 05:36:42 -0400
committerJeff Garzik <jgarzik@redhat.com>2008-10-22 06:22:17 -0400
commitd4f12daf7ba4efc506c377a9591ecdb692641fe5 (patch)
treec2a94e5f6a012adfc94b52a30daed50229320edb /drivers
parent93fbaae188fba7c2a6e458f62e1f61439caebfc8 (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')
-rw-r--r--drivers/net/ehea/ehea.h2
-rw-r--r--drivers/net/ehea/ehea_main.c25
-rw-r--r--drivers/net/ehea/ehea_qmr.c131
-rw-r--r--drivers/net/ehea/ehea_qmr.h2
4 files changed, 119 insertions, 41 deletions
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index 5524271eedca..82dd1a891ce7 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -40,7 +40,7 @@
40#include <asm/io.h> 40#include <asm/io.h>
41 41
42#define DRV_NAME "ehea" 42#define DRV_NAME "ehea"
43#define DRV_VERSION "EHEA_0093" 43#define DRV_VERSION "EHEA_0094"
44 44
45/* eHEA capability flags */ 45/* eHEA capability flags */
46#define DLPAR_PORT_ADD_REM 1 46#define DLPAR_PORT_ADD_REM 1
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index b70c5314f537..422fcb93e2c3 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -2863,7 +2863,7 @@ static void ehea_rereg_mrs(struct work_struct *work)
2863 struct ehea_adapter *adapter; 2863 struct ehea_adapter *adapter;
2864 2864
2865 mutex_lock(&dlpar_mem_lock); 2865 mutex_lock(&dlpar_mem_lock);
2866 ehea_info("LPAR memory enlarged - re-initializing driver"); 2866 ehea_info("LPAR memory changed - re-initializing driver");
2867 2867
2868 list_for_each_entry(adapter, &adapter_list, list) 2868 list_for_each_entry(adapter, &adapter_list, list)
2869 if (adapter->active_ports) { 2869 if (adapter->active_ports) {
@@ -2900,13 +2900,6 @@ static void ehea_rereg_mrs(struct work_struct *work)
2900 } 2900 }
2901 } 2901 }
2902 2902
2903 ehea_destroy_busmap();
2904 ret = ehea_create_busmap();
2905 if (ret) {
2906 ehea_error("creating ehea busmap failed");
2907 goto out;
2908 }
2909
2910 clear_bit(__EHEA_STOP_XFER, &ehea_driver_flags); 2903 clear_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
2911 2904
2912 list_for_each_entry(adapter, &adapter_list, list) 2905 list_for_each_entry(adapter, &adapter_list, list)
@@ -3519,9 +3512,21 @@ void ehea_crash_handler(void)
3519static int ehea_mem_notifier(struct notifier_block *nb, 3512static int ehea_mem_notifier(struct notifier_block *nb,
3520 unsigned long action, void *data) 3513 unsigned long action, void *data)
3521{ 3514{
3515 struct memory_notify *arg = data;
3522 switch (action) { 3516 switch (action) {
3523 case MEM_OFFLINE: 3517 case MEM_CANCEL_OFFLINE:
3524 ehea_info("memory has been removed"); 3518 ehea_info("memory offlining canceled");
3519 /* Readd canceled memory block */
3520 case MEM_ONLINE:
3521 ehea_info("memory is going online");
3522 if (ehea_add_sect_bmap(arg->start_pfn, arg->nr_pages))
3523 return NOTIFY_BAD;
3524 ehea_rereg_mrs(NULL);
3525 break;
3526 case MEM_GOING_OFFLINE:
3527 ehea_info("memory is going offline");
3528 if (ehea_rem_sect_bmap(arg->start_pfn, arg->nr_pages))
3529 return NOTIFY_BAD;
3525 ehea_rereg_mrs(NULL); 3530 ehea_rereg_mrs(NULL);
3526 break; 3531 break;
3527 default: 3532 default:
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)
567static inline int ehea_init_top_bmap(struct ehea_top_bmap *ehea_top_bmap, 567static 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
579static inline int ehea_init_bmap(struct ehea_bmap *ehea_bmap, int top, int dir) 579static 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
590static int ehea_create_busmap_callback(unsigned long pfn, 590static DEFINE_MUTEX(ehea_busmap_mutex);
591 unsigned long nr_pages, void *arg) 591static 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++) { 596static 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; 635static 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
627static unsigned long ehea_mr_len; 675int ehea_add_sect_bmap(unsigned long pfn, unsigned long nr_pages)
676{
677 int ret;
628 678
629static 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
685int 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
695static 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
631int ehea_create_busmap(void) 701int 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;
diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h
index 0bb6f92fa2f8..1e58dc06b7d2 100644
--- a/drivers/net/ehea/ehea_qmr.h
+++ b/drivers/net/ehea/ehea_qmr.h
@@ -378,6 +378,8 @@ int ehea_rem_mr(struct ehea_mr *mr);
378 378
379void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle); 379void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle);
380 380
381int ehea_add_sect_bmap(unsigned long pfn, unsigned long nr_pages);
382int ehea_rem_sect_bmap(unsigned long pfn, unsigned long nr_pages);
381int ehea_create_busmap(void); 383int ehea_create_busmap(void);
382void ehea_destroy_busmap(void); 384void ehea_destroy_busmap(void);
383u64 ehea_map_vaddr(void *caddr); 385u64 ehea_map_vaddr(void *caddr);