aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHannes Hering <hannes.hering@linux.vnet.ibm.com>2008-05-07 08:43:36 -0400
committerJeff Garzik <jgarzik@redhat.com>2008-05-13 01:31:39 -0400
commit48cfb14f8b89d4d5b3df6c16f08b258686fb12ad (patch)
treeaa517fe0c85010784e24b7f3d9b568f7197aa9fa
parentfb7b6ca2b6b7c23b52be143bdd5f55a23b9780c8 (diff)
ehea: Add DLPAR memory remove support
The eHEA driver uses the recently modified walk_memory_resource for powerpc functionality to detect the memory layout. It further uses the memory hotplug notifiers to catch memory hotplug events. Signed-off-by: Hannes Hering <hering2@de.ibm.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
-rw-r--r--drivers/net/ehea/ehea.h27
-rw-r--r--drivers/net/ehea/ehea_main.c25
-rw-r--r--drivers/net/ehea/ehea_qmr.c286
3 files changed, 254 insertions, 84 deletions
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index f5dacceab95b..fe872fbd671e 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_0090" 43#define DRV_VERSION "EHEA_0091"
44 44
45/* eHEA capability flags */ 45/* eHEA capability flags */
46#define DLPAR_PORT_ADD_REM 1 46#define DLPAR_PORT_ADD_REM 1
@@ -118,6 +118,13 @@
118#define EHEA_MR_ACC_CTRL 0x00800000 118#define EHEA_MR_ACC_CTRL 0x00800000
119 119
120#define EHEA_BUSMAP_START 0x8000000000000000ULL 120#define EHEA_BUSMAP_START 0x8000000000000000ULL
121#define EHEA_INVAL_ADDR 0xFFFFFFFFFFFFFFFFULL
122#define EHEA_DIR_INDEX_SHIFT 13 /* 8k Entries in 64k block */
123#define EHEA_TOP_INDEX_SHIFT (EHEA_DIR_INDEX_SHIFT * 2)
124#define EHEA_MAP_ENTRIES (1 << EHEA_DIR_INDEX_SHIFT)
125#define EHEA_MAP_SIZE (0x10000) /* currently fixed map size */
126#define EHEA_INDEX_MASK (EHEA_MAP_ENTRIES - 1)
127
121 128
122#define EHEA_WATCH_DOG_TIMEOUT 10*HZ 129#define EHEA_WATCH_DOG_TIMEOUT 10*HZ
123 130
@@ -192,10 +199,20 @@ struct h_epas {
192 set to 0 if unused */ 199 set to 0 if unused */
193}; 200};
194 201
195struct ehea_busmap { 202/*
196 unsigned int entries; /* total number of entries */ 203 * Memory map data structures
197 unsigned int valid_sections; /* number of valid sections */ 204 */
198 u64 *vaddr; 205struct ehea_dir_bmap
206{
207 u64 ent[EHEA_MAP_ENTRIES];
208};
209struct ehea_top_bmap
210{
211 struct ehea_dir_bmap *dir[EHEA_MAP_ENTRIES];
212};
213struct ehea_bmap
214{
215 struct ehea_top_bmap *top[EHEA_MAP_ENTRIES];
199}; 216};
200 217
201struct ehea_qp; 218struct ehea_qp;
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index f9bc21c74b59..d1b6d4e7495d 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -35,6 +35,7 @@
35#include <linux/if_ether.h> 35#include <linux/if_ether.h>
36#include <linux/notifier.h> 36#include <linux/notifier.h>
37#include <linux/reboot.h> 37#include <linux/reboot.h>
38#include <linux/memory.h>
38#include <asm/kexec.h> 39#include <asm/kexec.h>
39#include <linux/mutex.h> 40#include <linux/mutex.h>
40 41
@@ -3503,6 +3504,24 @@ void ehea_crash_handler(void)
3503 0, H_DEREG_BCMC); 3504 0, H_DEREG_BCMC);
3504} 3505}
3505 3506
3507static int ehea_mem_notifier(struct notifier_block *nb,
3508 unsigned long action, void *data)
3509{
3510 switch (action) {
3511 case MEM_OFFLINE:
3512 ehea_info("memory has been removed");
3513 ehea_rereg_mrs(NULL);
3514 break;
3515 default:
3516 break;
3517 }
3518 return NOTIFY_OK;
3519}
3520
3521static struct notifier_block ehea_mem_nb = {
3522 .notifier_call = ehea_mem_notifier,
3523};
3524
3506static int ehea_reboot_notifier(struct notifier_block *nb, 3525static int ehea_reboot_notifier(struct notifier_block *nb,
3507 unsigned long action, void *unused) 3526 unsigned long action, void *unused)
3508{ 3527{
@@ -3581,6 +3600,10 @@ int __init ehea_module_init(void)
3581 if (ret) 3600 if (ret)
3582 ehea_info("failed registering reboot notifier"); 3601 ehea_info("failed registering reboot notifier");
3583 3602
3603 ret = register_memory_notifier(&ehea_mem_nb);
3604 if (ret)
3605 ehea_info("failed registering memory remove notifier");
3606
3584 ret = crash_shutdown_register(&ehea_crash_handler); 3607 ret = crash_shutdown_register(&ehea_crash_handler);
3585 if (ret) 3608 if (ret)
3586 ehea_info("failed registering crash handler"); 3609 ehea_info("failed registering crash handler");
@@ -3604,6 +3627,7 @@ int __init ehea_module_init(void)
3604out3: 3627out3:
3605 ibmebus_unregister_driver(&ehea_driver); 3628 ibmebus_unregister_driver(&ehea_driver);
3606out2: 3629out2:
3630 unregister_memory_notifier(&ehea_mem_nb);
3607 unregister_reboot_notifier(&ehea_reboot_nb); 3631 unregister_reboot_notifier(&ehea_reboot_nb);
3608 crash_shutdown_unregister(&ehea_crash_handler); 3632 crash_shutdown_unregister(&ehea_crash_handler);
3609out: 3633out:
@@ -3621,6 +3645,7 @@ static void __exit ehea_module_exit(void)
3621 ret = crash_shutdown_unregister(&ehea_crash_handler); 3645 ret = crash_shutdown_unregister(&ehea_crash_handler);
3622 if (ret) 3646 if (ret)
3623 ehea_info("failed unregistering crash handler"); 3647 ehea_info("failed unregistering crash handler");
3648 unregister_memory_notifier(&ehea_mem_nb);
3624 kfree(ehea_fw_handles.arr); 3649 kfree(ehea_fw_handles.arr);
3625 kfree(ehea_bcmc_regs.arr); 3650 kfree(ehea_bcmc_regs.arr);
3626 ehea_destroy_busmap(); 3651 ehea_destroy_busmap();
diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c
index d522e905f460..140f05baafd8 100644
--- a/drivers/net/ehea/ehea_qmr.c
+++ b/drivers/net/ehea/ehea_qmr.c
@@ -31,8 +31,8 @@
31#include "ehea_phyp.h" 31#include "ehea_phyp.h"
32#include "ehea_qmr.h" 32#include "ehea_qmr.h"
33 33
34struct ehea_bmap *ehea_bmap = NULL;
34 35
35struct ehea_busmap ehea_bmap = { 0, 0, NULL };
36 36
37 37
38static void *hw_qpageit_get_inc(struct hw_queue *queue) 38static void *hw_qpageit_get_inc(struct hw_queue *queue)
@@ -559,125 +559,253 @@ int ehea_destroy_qp(struct ehea_qp *qp)
559 return 0; 559 return 0;
560} 560}
561 561
562int ehea_create_busmap(void) 562static inline int ehea_calc_index(unsigned long i, unsigned long s)
563{ 563{
564 u64 vaddr = EHEA_BUSMAP_START; 564 return (i >> s) & EHEA_INDEX_MASK;
565 unsigned long high_section_index = 0; 565}
566 int i;
567 566
568 /* 567static inline int ehea_init_top_bmap(struct ehea_top_bmap *ehea_top_bmap,
569 * Sections are not in ascending order -> Loop over all sections and 568 int dir)
570 * find the highest PFN to compute the required map size. 569{
571 */ 570 if(!ehea_top_bmap->dir[dir]) {
572 ehea_bmap.valid_sections = 0; 571 ehea_top_bmap->dir[dir] =
572 kzalloc(sizeof(struct ehea_dir_bmap), GFP_KERNEL);
573 if (!ehea_top_bmap->dir[dir])
574 return -ENOMEM;
575 }
576 return 0;
577}
573 578
574 for (i = 0; i < NR_MEM_SECTIONS; i++) 579static inline int ehea_init_bmap(struct ehea_bmap *ehea_bmap, int top, int dir)
575 if (valid_section_nr(i)) 580{
576 high_section_index = i; 581 if(!ehea_bmap->top[top]) {
582 ehea_bmap->top[top] =
583 kzalloc(sizeof(struct ehea_top_bmap), GFP_KERNEL);
584 if (!ehea_bmap->top[top])
585 return -ENOMEM;
586 }
587 return ehea_init_top_bmap(ehea_bmap->top[top], dir);
588}
577 589
578 ehea_bmap.entries = high_section_index + 1; 590static int ehea_create_busmap_callback(unsigned long pfn,
579 ehea_bmap.vaddr = vmalloc(ehea_bmap.entries * sizeof(*ehea_bmap.vaddr)); 591 unsigned long nr_pages, void *arg)
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;
580 597
581 if (!ehea_bmap.vaddr) 598 ehea_bmap = kzalloc(sizeof(struct ehea_bmap), GFP_KERNEL);
599 if (!ehea_bmap)
582 return -ENOMEM; 600 return -ENOMEM;
583 601
584 for (i = 0 ; i < ehea_bmap.entries; i++) { 602 for (i = start_section; i < end_section; i++) {
585 unsigned long pfn = section_nr_to_pfn(i); 603 int ret;
604 int top, dir, idx;
605 u64 vaddr;
606
607 top = ehea_calc_index(i, EHEA_TOP_INDEX_SHIFT);
608 dir = ehea_calc_index(i, EHEA_DIR_INDEX_SHIFT);
609
610 ret = ehea_init_bmap(ehea_bmap, top, dir);
611 if(ret)
612 return ret;
586 613
587 if (pfn_valid(pfn)) { 614 idx = i & EHEA_INDEX_MASK;
588 ehea_bmap.vaddr[i] = vaddr; 615 vaddr = EHEA_BUSMAP_START + mr_len + i * EHEA_SECTSIZE;
589 vaddr += EHEA_SECTSIZE; 616
590 ehea_bmap.valid_sections++; 617 ehea_bmap->top[top]->dir[dir]->ent[idx] = vaddr;
591 } else
592 ehea_bmap.vaddr[i] = 0;
593 } 618 }
594 619
620 mr_len += nr_pages * PAGE_SIZE;
621 *(unsigned long *)arg = mr_len;
622
595 return 0; 623 return 0;
596} 624}
597 625
626static unsigned long ehea_mr_len;
627
628static DEFINE_MUTEX(ehea_busmap_mutex);
629
630int ehea_create_busmap(void)
631{
632 int ret;
633 mutex_lock(&ehea_busmap_mutex);
634 ehea_mr_len = 0;
635 ret = walk_memory_resource(0, 1ULL << MAX_PHYSMEM_BITS, &ehea_mr_len,
636 ehea_create_busmap_callback);
637 mutex_unlock(&ehea_busmap_mutex);
638 return ret;
639}
640
598void ehea_destroy_busmap(void) 641void ehea_destroy_busmap(void)
599{ 642{
600 vfree(ehea_bmap.vaddr); 643 int top, dir;
644 mutex_lock(&ehea_busmap_mutex);
645 if (!ehea_bmap)
646 goto out_destroy;
647
648 for (top = 0; top < EHEA_MAP_ENTRIES; top++) {
649 if (!ehea_bmap->top[top])
650 continue;
651
652 for (dir = 0; dir < EHEA_MAP_ENTRIES; dir++) {
653 if (!ehea_bmap->top[top]->dir[dir])
654 continue;
655
656 kfree(ehea_bmap->top[top]->dir[dir]);
657 }
658
659 kfree(ehea_bmap->top[top]);
660 }
661
662 kfree(ehea_bmap);
663 ehea_bmap = NULL;
664out_destroy:
665 mutex_unlock(&ehea_busmap_mutex);
601} 666}
602 667
603u64 ehea_map_vaddr(void *caddr) 668u64 ehea_map_vaddr(void *caddr)
604{ 669{
605 u64 mapped_addr; 670 int top, dir, idx;
606 unsigned long index = __pa(caddr) >> SECTION_SIZE_BITS; 671 unsigned long index, offset;
607 672
608 if (likely(index < ehea_bmap.entries)) { 673 if (!ehea_bmap)
609 mapped_addr = ehea_bmap.vaddr[index]; 674 return EHEA_INVAL_ADDR;
610 if (likely(mapped_addr)) 675
611 mapped_addr |= (((unsigned long)caddr) 676 index = virt_to_abs(caddr) >> SECTION_SIZE_BITS;
612 & (EHEA_SECTSIZE - 1)); 677 top = (index >> EHEA_TOP_INDEX_SHIFT) & EHEA_INDEX_MASK;
613 else 678 if (!ehea_bmap->top[top])
614 mapped_addr = -1; 679 return EHEA_INVAL_ADDR;
615 } else 680
616 mapped_addr = -1; 681 dir = (index >> EHEA_DIR_INDEX_SHIFT) & EHEA_INDEX_MASK;
617 682 if (!ehea_bmap->top[top]->dir[dir])
618 if (unlikely(mapped_addr == -1)) 683 return EHEA_INVAL_ADDR;
619 if (!test_and_set_bit(__EHEA_STOP_XFER, &ehea_driver_flags)) 684
620 schedule_work(&ehea_rereg_mr_task); 685 idx = index & EHEA_INDEX_MASK;
621 686 if (!ehea_bmap->top[top]->dir[dir]->ent[idx])
622 return mapped_addr; 687 return EHEA_INVAL_ADDR;
688
689 offset = (unsigned long)caddr & (EHEA_SECTSIZE - 1);
690 return ehea_bmap->top[top]->dir[dir]->ent[idx] | offset;
691}
692
693static inline void *ehea_calc_sectbase(int top, int dir, int idx)
694{
695 unsigned long ret = idx;
696 ret |= dir << EHEA_DIR_INDEX_SHIFT;
697 ret |= top << EHEA_TOP_INDEX_SHIFT;
698 return abs_to_virt(ret << SECTION_SIZE_BITS);
699}
700
701static u64 ehea_reg_mr_section(int top, int dir, int idx, u64 *pt,
702 struct ehea_adapter *adapter,
703 struct ehea_mr *mr)
704{
705 void *pg;
706 u64 j, m, hret;
707 unsigned long k = 0;
708 u64 pt_abs = virt_to_abs(pt);
709
710 void *sectbase = ehea_calc_sectbase(top, dir, idx);
711
712 for (j = 0; j < (EHEA_PAGES_PER_SECTION / EHEA_MAX_RPAGE); j++) {
713
714 for (m = 0; m < EHEA_MAX_RPAGE; m++) {
715 pg = sectbase + ((k++) * EHEA_PAGESIZE);
716 pt[m] = virt_to_abs(pg);
717 }
718 hret = ehea_h_register_rpage_mr(adapter->handle, mr->handle, 0,
719 0, pt_abs, EHEA_MAX_RPAGE);
720
721 if ((hret != H_SUCCESS)
722 && (hret != H_PAGE_REGISTERED)) {
723 ehea_h_free_resource(adapter->handle, mr->handle,
724 FORCE_FREE);
725 ehea_error("register_rpage_mr failed");
726 return hret;
727 }
728 }
729 return hret;
730}
731
732static u64 ehea_reg_mr_sections(int top, int dir, u64 *pt,
733 struct ehea_adapter *adapter,
734 struct ehea_mr *mr)
735{
736 u64 hret = H_SUCCESS;
737 int idx;
738
739 for (idx = 0; idx < EHEA_MAP_ENTRIES; idx++) {
740 if (!ehea_bmap->top[top]->dir[dir]->ent[idx])
741 continue;
742
743 hret = ehea_reg_mr_section(top, dir, idx, pt, adapter, mr);
744 if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED))
745 return hret;
746 }
747 return hret;
748}
749
750static u64 ehea_reg_mr_dir_sections(int top, u64 *pt,
751 struct ehea_adapter *adapter,
752 struct ehea_mr *mr)
753{
754 u64 hret = H_SUCCESS;
755 int dir;
756
757 for (dir = 0; dir < EHEA_MAP_ENTRIES; dir++) {
758 if (!ehea_bmap->top[top]->dir[dir])
759 continue;
760
761 hret = ehea_reg_mr_sections(top, dir, pt, adapter, mr);
762 if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED))
763 return hret;
764 }
765 return hret;
623} 766}
624 767
625int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr) 768int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr)
626{ 769{
627 int ret; 770 int ret;
628 u64 *pt; 771 u64 *pt;
629 void *pg; 772 u64 hret;
630 u64 hret, pt_abs, i, j, m, mr_len;
631 u32 acc_ctrl = EHEA_MR_ACC_CTRL; 773 u32 acc_ctrl = EHEA_MR_ACC_CTRL;
632 774
633 mr_len = ehea_bmap.valid_sections * EHEA_SECTSIZE; 775 unsigned long top;
634 776
635 pt = kzalloc(PAGE_SIZE, GFP_KERNEL); 777 pt = kzalloc(PAGE_SIZE, GFP_KERNEL);
636 if (!pt) { 778 if (!pt) {
637 ehea_error("no mem"); 779 ehea_error("no mem");
638 ret = -ENOMEM; 780 ret = -ENOMEM;
639 goto out; 781 goto out;
640 } 782 }
641 pt_abs = virt_to_abs(pt);
642 783
643 hret = ehea_h_alloc_resource_mr(adapter->handle, 784 hret = ehea_h_alloc_resource_mr(adapter->handle, EHEA_BUSMAP_START,
644 EHEA_BUSMAP_START, mr_len, 785 ehea_mr_len, acc_ctrl, adapter->pd,
645 acc_ctrl, adapter->pd,
646 &mr->handle, &mr->lkey); 786 &mr->handle, &mr->lkey);
787
647 if (hret != H_SUCCESS) { 788 if (hret != H_SUCCESS) {
648 ehea_error("alloc_resource_mr failed"); 789 ehea_error("alloc_resource_mr failed");
649 ret = -EIO; 790 ret = -EIO;
650 goto out; 791 goto out;
651 } 792 }
652 793
653 for (i = 0 ; i < ehea_bmap.entries; i++) 794 if (!ehea_bmap) {
654 if (ehea_bmap.vaddr[i]) { 795 ehea_h_free_resource(adapter->handle, mr->handle, FORCE_FREE);
655 void *sectbase = __va(i << SECTION_SIZE_BITS); 796 ehea_error("no busmap available");
656 unsigned long k = 0; 797 ret = -EIO;
657 798 goto out;
658 for (j = 0; j < (EHEA_PAGES_PER_SECTION / 799 }
659 EHEA_MAX_RPAGE); j++) { 800
660 801 for (top = 0; top < EHEA_MAP_ENTRIES; top++) {
661 for (m = 0; m < EHEA_MAX_RPAGE; m++) { 802 if (!ehea_bmap->top[top])
662 pg = sectbase + ((k++) * EHEA_PAGESIZE); 803 continue;
663 pt[m] = virt_to_abs(pg); 804
664 } 805 hret = ehea_reg_mr_dir_sections(top, pt, adapter, mr);
665 806 if((hret != H_PAGE_REGISTERED) && (hret != H_SUCCESS))
666 hret = ehea_h_register_rpage_mr(adapter->handle, 807 break;
667 mr->handle, 808 }
668 0, 0, pt_abs,
669 EHEA_MAX_RPAGE);
670 if ((hret != H_SUCCESS)
671 && (hret != H_PAGE_REGISTERED)) {
672 ehea_h_free_resource(adapter->handle,
673 mr->handle,
674 FORCE_FREE);
675 ehea_error("register_rpage_mr failed");
676 ret = -EIO;
677 goto out;
678 }
679 }
680 }
681 809
682 if (hret != H_SUCCESS) { 810 if (hret != H_SUCCESS) {
683 ehea_h_free_resource(adapter->handle, mr->handle, FORCE_FREE); 811 ehea_h_free_resource(adapter->handle, mr->handle, FORCE_FREE);