Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ehea: Detect 16GB hugepages for firmware restriction

All kernel memory which is used for kernel/hardware data transfer must
be registered with firmware using "memory regions". 16GB hugepages
may not be part of a memory region due to firmware restrictions.
This patch modifies the walk_memory_resource callback fn to filter
hugepages and add only standard memory to the busmap which is later
on used for MR registration.

Signed-off-by: Thomas Klein <tklein@de.ibm.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>

authored by

Thomas Klein and committed by
Jeff Garzik
3fd09c45 74d5e8ac

+56 -6
+1 -1
drivers/net/ehea/ehea.h
··· 40 40 #include <asm/io.h> 41 41 42 42 #define DRV_NAME "ehea" 43 - #define DRV_VERSION "EHEA_0094" 43 + #define DRV_VERSION "EHEA_0095" 44 44 45 45 /* eHEA capability flags */ 46 46 #define DLPAR_PORT_ADD_REM 1
+52 -5
drivers/net/ehea/ehea_qmr.c
··· 632 632 } 633 633 } 634 634 635 - static int ehea_update_busmap(unsigned long pfn, unsigned long pgnum, int add) 635 + static int ehea_update_busmap(unsigned long pfn, unsigned long nr_pages, int add) 636 636 { 637 637 unsigned long i, start_section, end_section; 638 + 639 + if (!nr_pages) 640 + return 0; 638 641 639 642 if (!ehea_bmap) { 640 643 ehea_bmap = kzalloc(sizeof(struct ehea_bmap), GFP_KERNEL); ··· 646 643 } 647 644 648 645 start_section = (pfn * PAGE_SIZE) / EHEA_SECTSIZE; 649 - end_section = start_section + ((pgnum * PAGE_SIZE) / EHEA_SECTSIZE); 646 + end_section = start_section + ((nr_pages * PAGE_SIZE) / EHEA_SECTSIZE); 650 647 /* Mark entries as valid or invalid only; address is assigned later */ 651 648 for (i = start_section; i < end_section; i++) { 652 649 u64 flag; ··· 695 692 return ret; 696 693 } 697 694 698 - static int ehea_create_busmap_callback(unsigned long pfn, 699 - unsigned long nr_pages, void *arg) 695 + static int ehea_is_hugepage(unsigned long pfn) 700 696 { 701 - return ehea_update_busmap(pfn, nr_pages, EHEA_BUSMAP_ADD_SECT); 697 + int page_order; 698 + 699 + if (pfn & EHEA_HUGEPAGE_PFN_MASK) 700 + return 0; 701 + 702 + page_order = compound_order(pfn_to_page(pfn)); 703 + if (page_order + PAGE_SHIFT != EHEA_HUGEPAGESHIFT) 704 + return 0; 705 + 706 + return 1; 707 + } 708 + 709 + static int ehea_create_busmap_callback(unsigned long initial_pfn, 710 + unsigned long total_nr_pages, void *arg) 711 + { 712 + int ret; 713 + unsigned long pfn, start_pfn, end_pfn, nr_pages; 714 + 715 + if ((total_nr_pages * PAGE_SIZE) < EHEA_HUGEPAGE_SIZE) 716 + return ehea_update_busmap(initial_pfn, total_nr_pages, 717 + EHEA_BUSMAP_ADD_SECT); 718 + 719 + /* Given chunk is >= 16GB -> check for hugepages */ 720 + start_pfn = initial_pfn; 721 + end_pfn = initial_pfn + total_nr_pages; 722 + pfn = start_pfn; 723 + 724 + while (pfn < end_pfn) { 725 + if (ehea_is_hugepage(pfn)) { 726 + /* Add mem found in front of the hugepage */ 727 + nr_pages = pfn - start_pfn; 728 + ret = ehea_update_busmap(start_pfn, nr_pages, 729 + EHEA_BUSMAP_ADD_SECT); 730 + if (ret) 731 + return ret; 732 + 733 + /* Skip the hugepage */ 734 + pfn += (EHEA_HUGEPAGE_SIZE / PAGE_SIZE); 735 + start_pfn = pfn; 736 + } else 737 + pfn += (EHEA_SECTSIZE / PAGE_SIZE); 738 + } 739 + 740 + /* Add mem found behind the hugepage(s) */ 741 + nr_pages = pfn - start_pfn; 742 + return ehea_update_busmap(start_pfn, nr_pages, EHEA_BUSMAP_ADD_SECT); 702 743 } 703 744 704 745 int ehea_create_busmap(void)
+3
drivers/net/ehea/ehea_qmr.h
··· 40 40 #define EHEA_PAGESIZE (1UL << EHEA_PAGESHIFT) 41 41 #define EHEA_SECTSIZE (1UL << 24) 42 42 #define EHEA_PAGES_PER_SECTION (EHEA_SECTSIZE >> EHEA_PAGESHIFT) 43 + #define EHEA_HUGEPAGESHIFT 34 44 + #define EHEA_HUGEPAGE_SIZE (1UL << EHEA_HUGEPAGESHIFT) 45 + #define EHEA_HUGEPAGE_PFN_MASK ((EHEA_HUGEPAGE_SIZE - 1) >> PAGE_SHIFT) 43 46 44 47 #if ((1UL << SECTION_SIZE_BITS) < EHEA_SECTSIZE) 45 48 #error eHEA module cannot work if kernel sectionsize < ehea sectionsize