tree: git://git.cmpxchg.org/linux-mmotm.git master head: 8276ddb3c638602509386f1a05f75326dbf5ce09 commit: 025037cced8bcc78327e8920df22c815e6d4d626 [122/211] mm/hmm/devmem: device memory hotplug using ZONE_DEVICE config: ia64-allmodconfig (attached as .config) compiler: ia64-linux-gcc (GCC) 6.2.0 reproduce: wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross git checkout 025037cced8bcc78327e8920df22c815e6d4d626 # save the attached .config to linux build tree make.cross ARCH=ia64 All error/warnings (new ones prefixed by >>): mm/hmm.c: In function 'hmm_vma_walk': mm/hmm.c:440:24: error: implicit declaration of function 'pmd_pfn' [-Werror=implicit-function-declaration] unsigned long pfn = pmd_pfn(pmd) + pte_index(addr); ^~~~~~~ mm/hmm.c: In function 'hmm_devmem_radix_release': >> mm/hmm.c:809:30: error: 'PA_SECTION_SHIFT' undeclared (first use in this function) #define SECTION_SIZE (1UL << PA_SECTION_SHIFT) ^ >> mm/hmm.c:815:36: note: in expansion of macro 'SECTION_SIZE' align_start = resource->start & ~(SECTION_SIZE - 1); ^~~~~~~~~~~~ mm/hmm.c:809:30: note: each undeclared identifier is reported only once for each function it appears in #define SECTION_SIZE (1UL << PA_SECTION_SHIFT) ^ >> mm/hmm.c:815:36: note: in expansion of macro 'SECTION_SIZE' align_start = resource->start & ~(SECTION_SIZE - 1); ^~~~~~~~~~~~ mm/hmm.c: In function 'hmm_devmem_release': >> mm/hmm.c:809:30: error: 'PA_SECTION_SHIFT' undeclared (first use in this function) #define SECTION_SIZE (1UL << PA_SECTION_SHIFT) ^ mm/hmm.c:837:36: note: in expansion of macro 'SECTION_SIZE' align_start = resource->start & ~(SECTION_SIZE - 1); ^~~~~~~~~~~~ >> mm/hmm.c:839:2: error: implicit declaration of function 'arch_remove_memory' [-Werror=implicit-function-declaration] arch_remove_memory(align_start, align_size, devmem->pagemap.flags); ^~~~~~~~~~~~~~~~~~ mm/hmm.c: In function 'hmm_devmem_find': mm/hmm.c:848:54: error: 'PA_SECTION_SHIFT' undeclared (first use in this function) return radix_tree_lookup(&hmm_devmem_radix, phys >> PA_SECTION_SHIFT); ^~~~~~~~~~~~~~~~ mm/hmm.c: In function 'hmm_devmem_pages_create': >> mm/hmm.c:809:30: error: 'PA_SECTION_SHIFT' undeclared (first use in this function) #define SECTION_SIZE (1UL << PA_SECTION_SHIFT) ^ mm/hmm.c:859:44: note: in expansion of macro 'SECTION_SIZE' align_start = devmem->resource->start & ~(SECTION_SIZE - 1); ^~~~~~~~~~~~ In file included from include/linux/cache.h:4:0, from include/linux/printk.h:8, from include/linux/kernel.h:13, from include/asm-generic/bug.h:13, from arch/ia64/include/asm/bug.h:12, from include/linux/bug.h:4, from include/linux/mmdebug.h:4, from include/linux/mm.h:8, from mm/hmm.c:20: mm/hmm.c: In function 'hmm_devmem_add': >> mm/hmm.c:809:30: error: 'PA_SECTION_SHIFT' undeclared (first use in this function) #define SECTION_SIZE (1UL << PA_SECTION_SHIFT) ^ include/uapi/linux/kernel.h:10:47: note: in definition of macro '__ALIGN_KERNEL_MASK' #define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask)) ^~~~ >> include/linux/kernel.h:49:22: note: in expansion of macro '__ALIGN_KERNEL' #define ALIGN(x, a) __ALIGN_KERNEL((x), (a)) ^~~~~~~~~~~~~~ >> mm/hmm.c:1002:9: note: in expansion of macro 'ALIGN' size = ALIGN(size, SECTION_SIZE); ^~~~~ mm/hmm.c:1002:21: note: in expansion of macro 'SECTION_SIZE' size = ALIGN(size, SECTION_SIZE); ^~~~~~~~~~~~ mm/hmm.c: In function 'hmm_devmem_find': >> mm/hmm.c:849:1: warning: control reaches end of non-void function [-Wreturn-type] } ^ cc1: some warnings being treated as errors vim +/PA_SECTION_SHIFT +809 mm/hmm.c 803 804 devmem->ops->free(devmem, page); 805 } 806 807 static DEFINE_MUTEX(hmm_devmem_lock); 808 static RADIX_TREE(hmm_devmem_radix, GFP_KERNEL); > 809 #define SECTION_SIZE (1UL << PA_SECTION_SHIFT) 810 811 static void hmm_devmem_radix_release(struct resource *resource) 812 { 813 resource_size_t key, align_start, align_size, align_end; 814 > 815 align_start = resource->start & ~(SECTION_SIZE - 1); 816 align_size = ALIGN(resource_size(resource), SECTION_SIZE); 817 align_end = align_start + align_size - 1; 818 819 mutex_lock(&hmm_devmem_lock); 820 for (key = resource->start; key <= resource->end; key += SECTION_SIZE) 821 radix_tree_delete(&hmm_devmem_radix, key >> PA_SECTION_SHIFT); 822 mutex_unlock(&hmm_devmem_lock); 823 } 824 825 static void hmm_devmem_release(struct device *dev, void *data) 826 { 827 struct hmm_devmem *devmem = data; 828 resource_size_t align_start, align_size; 829 struct resource *resource = devmem->resource; 830 831 if (percpu_ref_tryget_live(&devmem->ref)) { 832 dev_WARN(dev, "%s: page mapping is still live!\n", __func__); 833 percpu_ref_put(&devmem->ref); 834 } 835 836 /* pages are dead and unused, undo the arch mapping */ 837 align_start = resource->start & ~(SECTION_SIZE - 1); 838 align_size = ALIGN(resource_size(resource), SECTION_SIZE); > 839 arch_remove_memory(align_start, align_size, devmem->pagemap.flags); 840 untrack_pfn(NULL, PHYS_PFN(align_start), align_size); 841 hmm_devmem_radix_release(resource); 842 } 843 844 static struct hmm_devmem *hmm_devmem_find(resource_size_t phys) 845 { 846 WARN_ON_ONCE(!rcu_read_lock_held()); 847 848 return radix_tree_lookup(&hmm_devmem_radix, phys >> PA_SECTION_SHIFT); > 849 } 850 851 static int hmm_devmem_pages_create(struct hmm_devmem *devmem) 852 { 853 resource_size_t key, align_start, align_size, align_end; 854 struct device *device = devmem->device; 855 pgprot_t pgprot = PAGE_KERNEL; 856 int ret, nid, is_ram; 857 unsigned long pfn; 858 859 align_start = devmem->resource->start & ~(SECTION_SIZE - 1); 860 align_size = ALIGN(devmem->resource->start + 861 resource_size(devmem->resource), 862 SECTION_SIZE) - align_start; 863 864 is_ram = region_intersects(align_start, align_size, 865 IORESOURCE_SYSTEM_RAM, 866 IORES_DESC_NONE); 867 if (is_ram == REGION_MIXED) { 868 WARN_ONCE(1, "%s attempted on mixed region %pr\n", 869 __func__, devmem->resource); 870 return -ENXIO; 871 } 872 if (is_ram == REGION_INTERSECTS) 873 return -ENXIO; 874 875 devmem->pagemap.flags = MEMORY_DEVICE | 876 MEMORY_DEVICE_ALLOW_MIGRATE | 877 MEMORY_DEVICE_UNADDRESSABLE; 878 devmem->pagemap.res = devmem->resource; 879 devmem->pagemap.page_fault = hmm_devmem_fault; 880 devmem->pagemap.page_free = hmm_devmem_free; 881 devmem->pagemap.dev = devmem->device; 882 devmem->pagemap.ref = &devmem->ref; 883 devmem->pagemap.data = devmem; 884 885 mutex_lock(&hmm_devmem_lock); 886 align_end = align_start + align_size - 1; 887 for (key = align_start; key <= align_end; key += SECTION_SIZE) { 888 struct hmm_devmem *dup; 889 890 rcu_read_lock(); 891 dup = hmm_devmem_find(key); 892 rcu_read_unlock(); 893 if (dup) { 894 dev_err(device, "%s: collides with mapping for %s\n", 895 __func__, dev_name(dup->device)); 896 mutex_unlock(&hmm_devmem_lock); 897 ret = -EBUSY; 898 goto error; 899 } 900 ret = radix_tree_insert(&hmm_devmem_radix, 901 key >> PA_SECTION_SHIFT, 902 devmem); 903 if (ret) { 904 dev_err(device, "%s: failed: %d\n", __func__, ret); 905 mutex_unlock(&hmm_devmem_lock); 906 goto error_radix; 907 } 908 } 909 mutex_unlock(&hmm_devmem_lock); 910 911 nid = dev_to_node(device); 912 if (nid < 0) 913 nid = numa_mem_id(); 914 915 ret = track_pfn_remap(NULL, &pgprot, PHYS_PFN(align_start), 916 0, align_size); 917 if (ret) 918 goto error_radix; 919 920 ret = arch_add_memory(nid, align_start, align_size, 921 devmem->pagemap.flags); 922 if (ret) 923 goto error_add_memory; 924 925 for (pfn = devmem->pfn_first; pfn < devmem->pfn_last; pfn++) { 926 struct page *page = pfn_to_page(pfn); 927 928 /* 929 * ZONE_DEVICE pages union ->lru with a ->pgmap back 930 * pointer. It is a bug if a ZONE_DEVICE page is ever 931 * freed or placed on a driver-private list. Seed the 932 * storage with LIST_POISON* values. 933 */ 934 list_del(&page->lru); 935 page->pgmap = &devmem->pagemap; 936 } 937 return 0; 938 939 error_add_memory: 940 untrack_pfn(NULL, PHYS_PFN(align_start), align_size); 941 error_radix: 942 hmm_devmem_radix_release(devmem->resource); 943 error: 944 return ret; 945 } 946 947 static int hmm_devmem_match(struct device *dev, void *data, void *match_data) 948 { 949 struct hmm_devmem *devmem = data; 950 951 return devmem->resource == match_data; 952 } 953 954 static void hmm_devmem_pages_remove(struct hmm_devmem *devmem) 955 { 956 devres_release(devmem->device, &hmm_devmem_release, 957 &hmm_devmem_match, devmem->resource); 958 } 959 960 /* 961 * hmm_devmem_add() - hotplug fake ZONE_DEVICE memory for device memory 962 * 963 * @ops: memory event device driver callback (see struct hmm_devmem_ops) 964 * @device: device struct to bind the resource too 965 * @size: size in bytes of the device memory to add 966 * Returns: pointer to new hmm_devmem struct ERR_PTR otherwise 967 * 968 * This first find an empty range of physical address big enough to for the new 969 * resource and then hotplug it as ZONE_DEVICE memory allocating struct page. 970 * It does not do anything beside that, all events affecting the memory will go 971 * through the various callback provided by hmm_devmem_ops struct. 972 */ 973 struct hmm_devmem *hmm_devmem_add(const struct hmm_devmem_ops *ops, 974 struct device *device, 975 unsigned long size) 976 { 977 struct hmm_devmem *devmem; 978 resource_size_t addr; 979 int ret; 980 981 devmem = devres_alloc_node(&hmm_devmem_release, sizeof(*devmem), 982 GFP_KERNEL, dev_to_node(device)); 983 if (!devmem) 984 return ERR_PTR(-ENOMEM); 985 986 init_completion(&devmem->completion); 987 devmem->pfn_first = -1UL; 988 devmem->pfn_last = -1UL; 989 devmem->resource = NULL; 990 devmem->device = device; 991 devmem->ops = ops; 992 993 ret = percpu_ref_init(&devmem->ref, &hmm_devmem_ref_release, 994 0, GFP_KERNEL); 995 if (ret) 996 goto error_percpu_ref; 997 998 ret = devm_add_action(device, hmm_devmem_ref_exit, &devmem->ref); 999 if (ret) 1000 goto error_devm_add_action; 1001 > 1002 size = ALIGN(size, SECTION_SIZE); 1003 addr = (iomem_resource.end + 1ULL) - size; 1004 1005 /* --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation
Attachment:
.config.gz
Description: application/gzip