diff options
| -rw-r--r-- | drivers/net/ehea/ehea.h | 2 | ||||
| -rw-r--r-- | drivers/net/ehea/ehea_main.c | 25 | ||||
| -rw-r--r-- | drivers/net/ehea/ehea_qmr.c | 131 | ||||
| -rw-r--r-- | drivers/net/ehea/ehea_qmr.h | 2 |
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) | |||
| 3519 | static int ehea_mem_notifier(struct notifier_block *nb, | 3512 | static 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) | |||
| 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; |
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 | ||
| 379 | void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle); | 379 | void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle); |
| 380 | 380 | ||
| 381 | int ehea_add_sect_bmap(unsigned long pfn, unsigned long nr_pages); | ||
| 382 | int ehea_rem_sect_bmap(unsigned long pfn, unsigned long nr_pages); | ||
| 381 | int ehea_create_busmap(void); | 383 | int ehea_create_busmap(void); |
| 382 | void ehea_destroy_busmap(void); | 384 | void ehea_destroy_busmap(void); |
| 383 | u64 ehea_map_vaddr(void *caddr); | 385 | u64 ehea_map_vaddr(void *caddr); |
