xref: /openbmc/linux/drivers/base/node.c (revision dee5d0d5)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * drivers/base/node.c - basic Node class support
31da177e4SLinus Torvalds  */
41da177e4SLinus Torvalds 
51da177e4SLinus Torvalds #include <linux/sysdev.h>
61da177e4SLinus Torvalds #include <linux/module.h>
71da177e4SLinus Torvalds #include <linux/init.h>
81da177e4SLinus Torvalds #include <linux/mm.h>
9c04fc586SGary Hade #include <linux/memory.h>
101da177e4SLinus Torvalds #include <linux/node.h>
111da177e4SLinus Torvalds #include <linux/hugetlb.h>
121da177e4SLinus Torvalds #include <linux/cpumask.h>
131da177e4SLinus Torvalds #include <linux/topology.h>
141da177e4SLinus Torvalds #include <linux/nodemask.h>
1576b67ed9SKAMEZAWA Hiroyuki #include <linux/cpu.h>
16bde631a5SLee Schermerhorn #include <linux/device.h>
17af936a16SLee Schermerhorn #include <linux/swap.h>
181da177e4SLinus Torvalds 
191da177e4SLinus Torvalds static struct sysdev_class node_class = {
20af5ca3f4SKay Sievers 	.name = "node",
211da177e4SLinus Torvalds };
221da177e4SLinus Torvalds 
231da177e4SLinus Torvalds 
2439106dcfSMike Travis static ssize_t node_read_cpumap(struct sys_device *dev, int type, char *buf)
251da177e4SLinus Torvalds {
261da177e4SLinus Torvalds 	struct node *node_dev = to_node(dev);
27a70f7302SRusty Russell 	const struct cpumask *mask = cpumask_of_node(node_dev->sysdev.id);
281da177e4SLinus Torvalds 	int len;
291da177e4SLinus Torvalds 
3039106dcfSMike Travis 	/* 2008/04/07: buf currently PAGE_SIZE, need 9 chars per 32 bits. */
3139106dcfSMike Travis 	BUILD_BUG_ON((NR_CPUS/32 * 9) > (PAGE_SIZE-1));
321da177e4SLinus Torvalds 
3339106dcfSMike Travis 	len = type?
3429c0177eSRusty Russell 		cpulist_scnprintf(buf, PAGE_SIZE-2, mask) :
3529c0177eSRusty Russell 		cpumask_scnprintf(buf, PAGE_SIZE-2, mask);
36c5f59f08SMike Travis  	buf[len++] = '\n';
37c5f59f08SMike Travis  	buf[len] = '\0';
381da177e4SLinus Torvalds 	return len;
391da177e4SLinus Torvalds }
401da177e4SLinus Torvalds 
414a0b2b4dSAndi Kleen static inline ssize_t node_read_cpumask(struct sys_device *dev,
424a0b2b4dSAndi Kleen 				struct sysdev_attribute *attr, char *buf)
4339106dcfSMike Travis {
4439106dcfSMike Travis 	return node_read_cpumap(dev, 0, buf);
4539106dcfSMike Travis }
464a0b2b4dSAndi Kleen static inline ssize_t node_read_cpulist(struct sys_device *dev,
474a0b2b4dSAndi Kleen 				struct sysdev_attribute *attr, char *buf)
4839106dcfSMike Travis {
4939106dcfSMike Travis 	return node_read_cpumap(dev, 1, buf);
5039106dcfSMike Travis }
5139106dcfSMike Travis 
5239106dcfSMike Travis static SYSDEV_ATTR(cpumap,  S_IRUGO, node_read_cpumask, NULL);
5339106dcfSMike Travis static SYSDEV_ATTR(cpulist, S_IRUGO, node_read_cpulist, NULL);
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds #define K(x) ((x) << (PAGE_SHIFT - 10))
564a0b2b4dSAndi Kleen static ssize_t node_read_meminfo(struct sys_device * dev,
574a0b2b4dSAndi Kleen 			struct sysdev_attribute *attr, char * buf)
581da177e4SLinus Torvalds {
591da177e4SLinus Torvalds 	int n;
601da177e4SLinus Torvalds 	int nid = dev->id;
611da177e4SLinus Torvalds 	struct sysinfo i;
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds 	si_meminfo_node(&i, nid);
64c07e02dbSMartin Hicks 
651da177e4SLinus Torvalds 	n = sprintf(buf, "\n"
661da177e4SLinus Torvalds 		       "Node %d MemTotal:       %8lu kB\n"
671da177e4SLinus Torvalds 		       "Node %d MemFree:        %8lu kB\n"
681da177e4SLinus Torvalds 		       "Node %d MemUsed:        %8lu kB\n"
691da177e4SLinus Torvalds 		       "Node %d Active:         %8lu kB\n"
701da177e4SLinus Torvalds 		       "Node %d Inactive:       %8lu kB\n"
714f98a2feSRik van Riel 		       "Node %d Active(anon):   %8lu kB\n"
724f98a2feSRik van Riel 		       "Node %d Inactive(anon): %8lu kB\n"
734f98a2feSRik van Riel 		       "Node %d Active(file):   %8lu kB\n"
744f98a2feSRik van Riel 		       "Node %d Inactive(file): %8lu kB\n"
755344b7e6SNick Piggin 		       "Node %d Unevictable:    %8lu kB\n"
765344b7e6SNick Piggin 		       "Node %d Mlocked:        %8lu kB\n"
77182e8e23SChristoph Lameter #ifdef CONFIG_HIGHMEM
781da177e4SLinus Torvalds 		       "Node %d HighTotal:      %8lu kB\n"
791da177e4SLinus Torvalds 		       "Node %d HighFree:       %8lu kB\n"
801da177e4SLinus Torvalds 		       "Node %d LowTotal:       %8lu kB\n"
81c07e02dbSMartin Hicks 		       "Node %d LowFree:        %8lu kB\n"
82182e8e23SChristoph Lameter #endif
83c07e02dbSMartin Hicks 		       "Node %d Dirty:          %8lu kB\n"
84c07e02dbSMartin Hicks 		       "Node %d Writeback:      %8lu kB\n"
85347ce434SChristoph Lameter 		       "Node %d FilePages:      %8lu kB\n"
86c07e02dbSMartin Hicks 		       "Node %d Mapped:         %8lu kB\n"
87f3dbd344SChristoph Lameter 		       "Node %d AnonPages:      %8lu kB\n"
884b02108aSKOSAKI Motohiro 		       "Node %d Shmem:          %8lu kB\n"
89c6a7f572SKOSAKI Motohiro 		       "Node %d KernelStack:    %8lu kB\n"
90df849a15SChristoph Lameter 		       "Node %d PageTables:     %8lu kB\n"
91f5ef68daSAndrew Morton 		       "Node %d NFS_Unstable:   %8lu kB\n"
92d2c5e30cSChristoph Lameter 		       "Node %d Bounce:         %8lu kB\n"
93fc3ba692SMiklos Szeredi 		       "Node %d WritebackTmp:   %8lu kB\n"
94972d1a7bSChristoph Lameter 		       "Node %d Slab:           %8lu kB\n"
95972d1a7bSChristoph Lameter 		       "Node %d SReclaimable:   %8lu kB\n"
96972d1a7bSChristoph Lameter 		       "Node %d SUnreclaim:     %8lu kB\n",
971da177e4SLinus Torvalds 		       nid, K(i.totalram),
981da177e4SLinus Torvalds 		       nid, K(i.freeram),
991da177e4SLinus Torvalds 		       nid, K(i.totalram - i.freeram),
1004f98a2feSRik van Riel 		       nid, K(node_page_state(nid, NR_ACTIVE_ANON) +
1014f98a2feSRik van Riel 				node_page_state(nid, NR_ACTIVE_FILE)),
1024f98a2feSRik van Riel 		       nid, K(node_page_state(nid, NR_INACTIVE_ANON) +
1034f98a2feSRik van Riel 				node_page_state(nid, NR_INACTIVE_FILE)),
1044f98a2feSRik van Riel 		       nid, K(node_page_state(nid, NR_ACTIVE_ANON)),
1054f98a2feSRik van Riel 		       nid, K(node_page_state(nid, NR_INACTIVE_ANON)),
1064f98a2feSRik van Riel 		       nid, K(node_page_state(nid, NR_ACTIVE_FILE)),
1074f98a2feSRik van Riel 		       nid, K(node_page_state(nid, NR_INACTIVE_FILE)),
1087b854121SLee Schermerhorn 		       nid, K(node_page_state(nid, NR_UNEVICTABLE)),
1095344b7e6SNick Piggin 		       nid, K(node_page_state(nid, NR_MLOCK)),
110182e8e23SChristoph Lameter #ifdef CONFIG_HIGHMEM
1111da177e4SLinus Torvalds 		       nid, K(i.totalhigh),
1121da177e4SLinus Torvalds 		       nid, K(i.freehigh),
1131da177e4SLinus Torvalds 		       nid, K(i.totalram - i.totalhigh),
114c07e02dbSMartin Hicks 		       nid, K(i.freeram - i.freehigh),
115182e8e23SChristoph Lameter #endif
116b1e7a8fdSChristoph Lameter 		       nid, K(node_page_state(nid, NR_FILE_DIRTY)),
117ce866b34SChristoph Lameter 		       nid, K(node_page_state(nid, NR_WRITEBACK)),
118347ce434SChristoph Lameter 		       nid, K(node_page_state(nid, NR_FILE_PAGES)),
11965ba55f5SChristoph Lameter 		       nid, K(node_page_state(nid, NR_FILE_MAPPED)),
120f3dbd344SChristoph Lameter 		       nid, K(node_page_state(nid, NR_ANON_PAGES)),
1214b02108aSKOSAKI Motohiro 		       nid, K(node_page_state(nid, NR_SHMEM)),
122c6a7f572SKOSAKI Motohiro 		       nid, node_page_state(nid, NR_KERNEL_STACK) *
123c6a7f572SKOSAKI Motohiro 				THREAD_SIZE / 1024,
124df849a15SChristoph Lameter 		       nid, K(node_page_state(nid, NR_PAGETABLE)),
125fd39fc85SChristoph Lameter 		       nid, K(node_page_state(nid, NR_UNSTABLE_NFS)),
126d2c5e30cSChristoph Lameter 		       nid, K(node_page_state(nid, NR_BOUNCE)),
127fc3ba692SMiklos Szeredi 		       nid, K(node_page_state(nid, NR_WRITEBACK_TEMP)),
128972d1a7bSChristoph Lameter 		       nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE) +
129972d1a7bSChristoph Lameter 				node_page_state(nid, NR_SLAB_UNRECLAIMABLE)),
130972d1a7bSChristoph Lameter 		       nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE)),
131972d1a7bSChristoph Lameter 		       nid, K(node_page_state(nid, NR_SLAB_UNRECLAIMABLE)));
1321da177e4SLinus Torvalds 	n += hugetlb_report_node_meminfo(nid, buf + n);
1331da177e4SLinus Torvalds 	return n;
1341da177e4SLinus Torvalds }
1351da177e4SLinus Torvalds 
1361da177e4SLinus Torvalds #undef K
1371da177e4SLinus Torvalds static SYSDEV_ATTR(meminfo, S_IRUGO, node_read_meminfo, NULL);
1381da177e4SLinus Torvalds 
1394a0b2b4dSAndi Kleen static ssize_t node_read_numastat(struct sys_device * dev,
1404a0b2b4dSAndi Kleen 				struct sysdev_attribute *attr, char * buf)
1411da177e4SLinus Torvalds {
1421da177e4SLinus Torvalds 	return sprintf(buf,
1431da177e4SLinus Torvalds 		       "numa_hit %lu\n"
1441da177e4SLinus Torvalds 		       "numa_miss %lu\n"
1451da177e4SLinus Torvalds 		       "numa_foreign %lu\n"
1461da177e4SLinus Torvalds 		       "interleave_hit %lu\n"
1471da177e4SLinus Torvalds 		       "local_node %lu\n"
1481da177e4SLinus Torvalds 		       "other_node %lu\n",
149ca889e6cSChristoph Lameter 		       node_page_state(dev->id, NUMA_HIT),
150ca889e6cSChristoph Lameter 		       node_page_state(dev->id, NUMA_MISS),
151ca889e6cSChristoph Lameter 		       node_page_state(dev->id, NUMA_FOREIGN),
152ca889e6cSChristoph Lameter 		       node_page_state(dev->id, NUMA_INTERLEAVE_HIT),
153ca889e6cSChristoph Lameter 		       node_page_state(dev->id, NUMA_LOCAL),
154ca889e6cSChristoph Lameter 		       node_page_state(dev->id, NUMA_OTHER));
1551da177e4SLinus Torvalds }
1561da177e4SLinus Torvalds static SYSDEV_ATTR(numastat, S_IRUGO, node_read_numastat, NULL);
1571da177e4SLinus Torvalds 
1584a0b2b4dSAndi Kleen static ssize_t node_read_distance(struct sys_device * dev,
1594a0b2b4dSAndi Kleen 			struct sysdev_attribute *attr, char * buf)
1601da177e4SLinus Torvalds {
1611da177e4SLinus Torvalds 	int nid = dev->id;
1621da177e4SLinus Torvalds 	int len = 0;
1631da177e4SLinus Torvalds 	int i;
1641da177e4SLinus Torvalds 
1651da177e4SLinus Torvalds 	/* buf currently PAGE_SIZE, need ~4 chars per node */
1661da177e4SLinus Torvalds 	BUILD_BUG_ON(MAX_NUMNODES*4 > PAGE_SIZE/2);
1671da177e4SLinus Torvalds 
1681da177e4SLinus Torvalds 	for_each_online_node(i)
1691da177e4SLinus Torvalds 		len += sprintf(buf + len, "%s%d", i ? " " : "", node_distance(nid, i));
1701da177e4SLinus Torvalds 
1711da177e4SLinus Torvalds 	len += sprintf(buf + len, "\n");
1721da177e4SLinus Torvalds 	return len;
1731da177e4SLinus Torvalds }
1741da177e4SLinus Torvalds static SYSDEV_ATTR(distance, S_IRUGO, node_read_distance, NULL);
1751da177e4SLinus Torvalds 
1769a305230SLee Schermerhorn #ifdef CONFIG_HUGETLBFS
1779a305230SLee Schermerhorn /*
1789a305230SLee Schermerhorn  * hugetlbfs per node attributes registration interface:
1799a305230SLee Schermerhorn  * When/if hugetlb[fs] subsystem initializes [sometime after this module],
1804faf8d95SLee Schermerhorn  * it will register its per node attributes for all online nodes with
1814faf8d95SLee Schermerhorn  * memory.  It will also call register_hugetlbfs_with_node(), below, to
1829a305230SLee Schermerhorn  * register its attribute registration functions with this node driver.
1839a305230SLee Schermerhorn  * Once these hooks have been initialized, the node driver will call into
1849a305230SLee Schermerhorn  * the hugetlb module to [un]register attributes for hot-plugged nodes.
1859a305230SLee Schermerhorn  */
1869a305230SLee Schermerhorn static node_registration_func_t __hugetlb_register_node;
1879a305230SLee Schermerhorn static node_registration_func_t __hugetlb_unregister_node;
1889a305230SLee Schermerhorn 
18939da08cbSLee Schermerhorn static inline bool hugetlb_register_node(struct node *node)
1909a305230SLee Schermerhorn {
1914faf8d95SLee Schermerhorn 	if (__hugetlb_register_node &&
19239da08cbSLee Schermerhorn 			node_state(node->sysdev.id, N_HIGH_MEMORY)) {
1939a305230SLee Schermerhorn 		__hugetlb_register_node(node);
19439da08cbSLee Schermerhorn 		return true;
19539da08cbSLee Schermerhorn 	}
19639da08cbSLee Schermerhorn 	return false;
1979a305230SLee Schermerhorn }
1989a305230SLee Schermerhorn 
1999a305230SLee Schermerhorn static inline void hugetlb_unregister_node(struct node *node)
2009a305230SLee Schermerhorn {
2019a305230SLee Schermerhorn 	if (__hugetlb_unregister_node)
2029a305230SLee Schermerhorn 		__hugetlb_unregister_node(node);
2039a305230SLee Schermerhorn }
2049a305230SLee Schermerhorn 
2059a305230SLee Schermerhorn void register_hugetlbfs_with_node(node_registration_func_t doregister,
2069a305230SLee Schermerhorn 				  node_registration_func_t unregister)
2079a305230SLee Schermerhorn {
2089a305230SLee Schermerhorn 	__hugetlb_register_node   = doregister;
2099a305230SLee Schermerhorn 	__hugetlb_unregister_node = unregister;
2109a305230SLee Schermerhorn }
2119a305230SLee Schermerhorn #else
2129a305230SLee Schermerhorn static inline void hugetlb_register_node(struct node *node) {}
2139a305230SLee Schermerhorn 
2149a305230SLee Schermerhorn static inline void hugetlb_unregister_node(struct node *node) {}
2159a305230SLee Schermerhorn #endif
2169a305230SLee Schermerhorn 
2171da177e4SLinus Torvalds 
2181da177e4SLinus Torvalds /*
219405ae7d3SRobert P. J. Day  * register_node - Setup a sysfs device for a node.
2201da177e4SLinus Torvalds  * @num - Node number to use when creating the device.
2211da177e4SLinus Torvalds  *
2221da177e4SLinus Torvalds  * Initialize and register the node device.
2231da177e4SLinus Torvalds  */
2244b45099bSKeiichiro Tokunaga int register_node(struct node *node, int num, struct node *parent)
2251da177e4SLinus Torvalds {
2261da177e4SLinus Torvalds 	int error;
2271da177e4SLinus Torvalds 
2281da177e4SLinus Torvalds 	node->sysdev.id = num;
2291da177e4SLinus Torvalds 	node->sysdev.cls = &node_class;
2301da177e4SLinus Torvalds 	error = sysdev_register(&node->sysdev);
2311da177e4SLinus Torvalds 
2321da177e4SLinus Torvalds 	if (!error){
2331da177e4SLinus Torvalds 		sysdev_create_file(&node->sysdev, &attr_cpumap);
23439106dcfSMike Travis 		sysdev_create_file(&node->sysdev, &attr_cpulist);
2351da177e4SLinus Torvalds 		sysdev_create_file(&node->sysdev, &attr_meminfo);
2361da177e4SLinus Torvalds 		sysdev_create_file(&node->sysdev, &attr_numastat);
2371da177e4SLinus Torvalds 		sysdev_create_file(&node->sysdev, &attr_distance);
238af936a16SLee Schermerhorn 
239af936a16SLee Schermerhorn 		scan_unevictable_register_node(node);
2404faf8d95SLee Schermerhorn 
2419a305230SLee Schermerhorn 		hugetlb_register_node(node);
2421da177e4SLinus Torvalds 	}
2431da177e4SLinus Torvalds 	return error;
2441da177e4SLinus Torvalds }
2451da177e4SLinus Torvalds 
2464b45099bSKeiichiro Tokunaga /**
2474b45099bSKeiichiro Tokunaga  * unregister_node - unregister a node device
2484b45099bSKeiichiro Tokunaga  * @node: node going away
2494b45099bSKeiichiro Tokunaga  *
2504b45099bSKeiichiro Tokunaga  * Unregisters a node device @node.  All the devices on the node must be
2514b45099bSKeiichiro Tokunaga  * unregistered before calling this function.
2524b45099bSKeiichiro Tokunaga  */
2534b45099bSKeiichiro Tokunaga void unregister_node(struct node *node)
2544b45099bSKeiichiro Tokunaga {
2554b45099bSKeiichiro Tokunaga 	sysdev_remove_file(&node->sysdev, &attr_cpumap);
25639106dcfSMike Travis 	sysdev_remove_file(&node->sysdev, &attr_cpulist);
2574b45099bSKeiichiro Tokunaga 	sysdev_remove_file(&node->sysdev, &attr_meminfo);
2584b45099bSKeiichiro Tokunaga 	sysdev_remove_file(&node->sysdev, &attr_numastat);
2594b45099bSKeiichiro Tokunaga 	sysdev_remove_file(&node->sysdev, &attr_distance);
2601da177e4SLinus Torvalds 
261af936a16SLee Schermerhorn 	scan_unevictable_unregister_node(node);
2624faf8d95SLee Schermerhorn 	hugetlb_unregister_node(node);		/* no-op, if memoryless node */
263af936a16SLee Schermerhorn 
2644b45099bSKeiichiro Tokunaga 	sysdev_unregister(&node->sysdev);
2654b45099bSKeiichiro Tokunaga }
2664b45099bSKeiichiro Tokunaga 
2670fc44159SYasunori Goto struct node node_devices[MAX_NUMNODES];
2680fc44159SYasunori Goto 
26976b67ed9SKAMEZAWA Hiroyuki /*
27076b67ed9SKAMEZAWA Hiroyuki  * register cpu under node
27176b67ed9SKAMEZAWA Hiroyuki  */
27276b67ed9SKAMEZAWA Hiroyuki int register_cpu_under_node(unsigned int cpu, unsigned int nid)
27376b67ed9SKAMEZAWA Hiroyuki {
27476b67ed9SKAMEZAWA Hiroyuki 	if (node_online(nid)) {
27576b67ed9SKAMEZAWA Hiroyuki 		struct sys_device *obj = get_cpu_sysdev(cpu);
27676b67ed9SKAMEZAWA Hiroyuki 		if (!obj)
27776b67ed9SKAMEZAWA Hiroyuki 			return 0;
27876b67ed9SKAMEZAWA Hiroyuki 		return sysfs_create_link(&node_devices[nid].sysdev.kobj,
27976b67ed9SKAMEZAWA Hiroyuki 					 &obj->kobj,
28076b67ed9SKAMEZAWA Hiroyuki 					 kobject_name(&obj->kobj));
28176b67ed9SKAMEZAWA Hiroyuki 	 }
28276b67ed9SKAMEZAWA Hiroyuki 
28376b67ed9SKAMEZAWA Hiroyuki 	return 0;
28476b67ed9SKAMEZAWA Hiroyuki }
28576b67ed9SKAMEZAWA Hiroyuki 
28676b67ed9SKAMEZAWA Hiroyuki int unregister_cpu_under_node(unsigned int cpu, unsigned int nid)
28776b67ed9SKAMEZAWA Hiroyuki {
28876b67ed9SKAMEZAWA Hiroyuki 	if (node_online(nid)) {
28976b67ed9SKAMEZAWA Hiroyuki 		struct sys_device *obj = get_cpu_sysdev(cpu);
29076b67ed9SKAMEZAWA Hiroyuki 		if (obj)
29176b67ed9SKAMEZAWA Hiroyuki 			sysfs_remove_link(&node_devices[nid].sysdev.kobj,
29276b67ed9SKAMEZAWA Hiroyuki 					 kobject_name(&obj->kobj));
29376b67ed9SKAMEZAWA Hiroyuki 	}
29476b67ed9SKAMEZAWA Hiroyuki 	return 0;
29576b67ed9SKAMEZAWA Hiroyuki }
29676b67ed9SKAMEZAWA Hiroyuki 
297c04fc586SGary Hade #ifdef CONFIG_MEMORY_HOTPLUG_SPARSE
298c04fc586SGary Hade #define page_initialized(page)  (page->lru.next)
299c04fc586SGary Hade 
300c04fc586SGary Hade static int get_nid_for_pfn(unsigned long pfn)
301c04fc586SGary Hade {
302c04fc586SGary Hade 	struct page *page;
303c04fc586SGary Hade 
304c04fc586SGary Hade 	if (!pfn_valid_within(pfn))
305c04fc586SGary Hade 		return -1;
306c04fc586SGary Hade 	page = pfn_to_page(pfn);
307c04fc586SGary Hade 	if (!page_initialized(page))
308c04fc586SGary Hade 		return -1;
309c04fc586SGary Hade 	return pfn_to_nid(pfn);
310c04fc586SGary Hade }
311c04fc586SGary Hade 
312c04fc586SGary Hade /* register memory section under specified node if it spans that node */
313c04fc586SGary Hade int register_mem_sect_under_node(struct memory_block *mem_blk, int nid)
314c04fc586SGary Hade {
315dee5d0d5SAlex Chiang 	int ret;
316c04fc586SGary Hade 	unsigned long pfn, sect_start_pfn, sect_end_pfn;
317c04fc586SGary Hade 
318c04fc586SGary Hade 	if (!mem_blk)
319c04fc586SGary Hade 		return -EFAULT;
320c04fc586SGary Hade 	if (!node_online(nid))
321c04fc586SGary Hade 		return 0;
322c04fc586SGary Hade 	sect_start_pfn = section_nr_to_pfn(mem_blk->phys_index);
323c04fc586SGary Hade 	sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1;
324c04fc586SGary Hade 	for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) {
325c04fc586SGary Hade 		int page_nid;
326c04fc586SGary Hade 
327c04fc586SGary Hade 		page_nid = get_nid_for_pfn(pfn);
328c04fc586SGary Hade 		if (page_nid < 0)
329c04fc586SGary Hade 			continue;
330c04fc586SGary Hade 		if (page_nid != nid)
331c04fc586SGary Hade 			continue;
332dee5d0d5SAlex Chiang 		ret = sysfs_create_link_nowarn(&node_devices[nid].sysdev.kobj,
333c04fc586SGary Hade 					&mem_blk->sysdev.kobj,
334c04fc586SGary Hade 					kobject_name(&mem_blk->sysdev.kobj));
335dee5d0d5SAlex Chiang 		if (ret)
336dee5d0d5SAlex Chiang 			return ret;
337dee5d0d5SAlex Chiang 
338dee5d0d5SAlex Chiang 		return sysfs_create_link_nowarn(&mem_blk->sysdev.kobj,
339dee5d0d5SAlex Chiang 				&node_devices[nid].sysdev.kobj,
340dee5d0d5SAlex Chiang 				kobject_name(&node_devices[nid].sysdev.kobj));
341c04fc586SGary Hade 	}
342c04fc586SGary Hade 	/* mem section does not span the specified node */
343c04fc586SGary Hade 	return 0;
344c04fc586SGary Hade }
345c04fc586SGary Hade 
346c04fc586SGary Hade /* unregister memory section under all nodes that it spans */
347c04fc586SGary Hade int unregister_mem_sect_under_nodes(struct memory_block *mem_blk)
348c04fc586SGary Hade {
349c04fc586SGary Hade 	nodemask_t unlinked_nodes;
350c04fc586SGary Hade 	unsigned long pfn, sect_start_pfn, sect_end_pfn;
351c04fc586SGary Hade 
352c04fc586SGary Hade 	if (!mem_blk)
353c04fc586SGary Hade 		return -EFAULT;
354c04fc586SGary Hade 	nodes_clear(unlinked_nodes);
355c04fc586SGary Hade 	sect_start_pfn = section_nr_to_pfn(mem_blk->phys_index);
356c04fc586SGary Hade 	sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1;
357c04fc586SGary Hade 	for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) {
35847504980SRoel Kluin 		int nid;
359c04fc586SGary Hade 
360c04fc586SGary Hade 		nid = get_nid_for_pfn(pfn);
361c04fc586SGary Hade 		if (nid < 0)
362c04fc586SGary Hade 			continue;
363c04fc586SGary Hade 		if (!node_online(nid))
364c04fc586SGary Hade 			continue;
365c04fc586SGary Hade 		if (node_test_and_set(nid, unlinked_nodes))
366c04fc586SGary Hade 			continue;
367c04fc586SGary Hade 		sysfs_remove_link(&node_devices[nid].sysdev.kobj,
368c04fc586SGary Hade 			 kobject_name(&mem_blk->sysdev.kobj));
369dee5d0d5SAlex Chiang 		sysfs_remove_link(&mem_blk->sysdev.kobj,
370dee5d0d5SAlex Chiang 			 kobject_name(&node_devices[nid].sysdev.kobj));
371c04fc586SGary Hade 	}
372c04fc586SGary Hade 	return 0;
373c04fc586SGary Hade }
374c04fc586SGary Hade 
375c04fc586SGary Hade static int link_mem_sections(int nid)
376c04fc586SGary Hade {
377c04fc586SGary Hade 	unsigned long start_pfn = NODE_DATA(nid)->node_start_pfn;
378c04fc586SGary Hade 	unsigned long end_pfn = start_pfn + NODE_DATA(nid)->node_spanned_pages;
379c04fc586SGary Hade 	unsigned long pfn;
380c04fc586SGary Hade 	int err = 0;
381c04fc586SGary Hade 
382c04fc586SGary Hade 	for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
383c04fc586SGary Hade 		unsigned long section_nr = pfn_to_section_nr(pfn);
384c04fc586SGary Hade 		struct mem_section *mem_sect;
385c04fc586SGary Hade 		struct memory_block *mem_blk;
386c04fc586SGary Hade 		int ret;
387c04fc586SGary Hade 
388c04fc586SGary Hade 		if (!present_section_nr(section_nr))
389c04fc586SGary Hade 			continue;
390c04fc586SGary Hade 		mem_sect = __nr_to_section(section_nr);
391c04fc586SGary Hade 		mem_blk = find_memory_block(mem_sect);
392c04fc586SGary Hade 		ret = register_mem_sect_under_node(mem_blk, nid);
393c04fc586SGary Hade 		if (!err)
394c04fc586SGary Hade 			err = ret;
395c04fc586SGary Hade 
396c04fc586SGary Hade 		/* discard ref obtained in find_memory_block() */
397c04fc586SGary Hade 		kobject_put(&mem_blk->sysdev.kobj);
398c04fc586SGary Hade 	}
399c04fc586SGary Hade 	return err;
400c04fc586SGary Hade }
4014faf8d95SLee Schermerhorn 
40239da08cbSLee Schermerhorn #ifdef CONFIG_HUGETLBFS
4034faf8d95SLee Schermerhorn /*
4044faf8d95SLee Schermerhorn  * Handle per node hstate attribute [un]registration on transistions
4054faf8d95SLee Schermerhorn  * to/from memoryless state.
4064faf8d95SLee Schermerhorn  */
40739da08cbSLee Schermerhorn static void node_hugetlb_work(struct work_struct *work)
40839da08cbSLee Schermerhorn {
40939da08cbSLee Schermerhorn 	struct node *node = container_of(work, struct node, node_work);
41039da08cbSLee Schermerhorn 
41139da08cbSLee Schermerhorn 	/*
41239da08cbSLee Schermerhorn 	 * We only get here when a node transitions to/from memoryless state.
41339da08cbSLee Schermerhorn 	 * We can detect which transition occurred by examining whether the
41439da08cbSLee Schermerhorn 	 * node has memory now.  hugetlb_register_node() already check this
41539da08cbSLee Schermerhorn 	 * so we try to register the attributes.  If that fails, then the
41639da08cbSLee Schermerhorn 	 * node has transitioned to memoryless, try to unregister the
41739da08cbSLee Schermerhorn 	 * attributes.
41839da08cbSLee Schermerhorn 	 */
41939da08cbSLee Schermerhorn 	if (!hugetlb_register_node(node))
42039da08cbSLee Schermerhorn 		hugetlb_unregister_node(node);
42139da08cbSLee Schermerhorn }
42239da08cbSLee Schermerhorn 
42339da08cbSLee Schermerhorn static void init_node_hugetlb_work(int nid)
42439da08cbSLee Schermerhorn {
42539da08cbSLee Schermerhorn 	INIT_WORK(&node_devices[nid].node_work, node_hugetlb_work);
42639da08cbSLee Schermerhorn }
4274faf8d95SLee Schermerhorn 
4284faf8d95SLee Schermerhorn static int node_memory_callback(struct notifier_block *self,
4294faf8d95SLee Schermerhorn 				unsigned long action, void *arg)
4304faf8d95SLee Schermerhorn {
4314faf8d95SLee Schermerhorn 	struct memory_notify *mnb = arg;
4324faf8d95SLee Schermerhorn 	int nid = mnb->status_change_nid;
4334faf8d95SLee Schermerhorn 
4344faf8d95SLee Schermerhorn 	switch (action) {
43539da08cbSLee Schermerhorn 	case MEM_ONLINE:
43639da08cbSLee Schermerhorn 	case MEM_OFFLINE:
43739da08cbSLee Schermerhorn 		/*
43839da08cbSLee Schermerhorn 		 * offload per node hstate [un]registration to a work thread
43939da08cbSLee Schermerhorn 		 * when transitioning to/from memoryless state.
44039da08cbSLee Schermerhorn 		 */
4414faf8d95SLee Schermerhorn 		if (nid != NUMA_NO_NODE)
44239da08cbSLee Schermerhorn 			schedule_work(&node_devices[nid].node_work);
4434faf8d95SLee Schermerhorn 		break;
44439da08cbSLee Schermerhorn 
4454faf8d95SLee Schermerhorn 	case MEM_GOING_ONLINE:
4464faf8d95SLee Schermerhorn 	case MEM_GOING_OFFLINE:
4474faf8d95SLee Schermerhorn 	case MEM_CANCEL_ONLINE:
4484faf8d95SLee Schermerhorn 	case MEM_CANCEL_OFFLINE:
4494faf8d95SLee Schermerhorn 	default:
4504faf8d95SLee Schermerhorn 		break;
4514faf8d95SLee Schermerhorn 	}
4524faf8d95SLee Schermerhorn 
4534faf8d95SLee Schermerhorn 	return NOTIFY_OK;
4544faf8d95SLee Schermerhorn }
45539da08cbSLee Schermerhorn #endif	/* CONFIG_HUGETLBFS */
45639da08cbSLee Schermerhorn #else	/* !CONFIG_MEMORY_HOTPLUG_SPARSE */
4574faf8d95SLee Schermerhorn 
45839da08cbSLee Schermerhorn static int link_mem_sections(int nid) { return 0; }
45939da08cbSLee Schermerhorn #endif	/* CONFIG_MEMORY_HOTPLUG_SPARSE */
46039da08cbSLee Schermerhorn 
46139da08cbSLee Schermerhorn #if !defined(CONFIG_MEMORY_HOTPLUG_SPARSE) || \
46239da08cbSLee Schermerhorn     !defined(CONFIG_HUGETLBFS)
4634faf8d95SLee Schermerhorn static inline int node_memory_callback(struct notifier_block *self,
4644faf8d95SLee Schermerhorn 				unsigned long action, void *arg)
4654faf8d95SLee Schermerhorn {
4664faf8d95SLee Schermerhorn 	return NOTIFY_OK;
4674faf8d95SLee Schermerhorn }
46839da08cbSLee Schermerhorn 
46939da08cbSLee Schermerhorn static void init_node_hugetlb_work(int nid) { }
47039da08cbSLee Schermerhorn 
47139da08cbSLee Schermerhorn #endif
472c04fc586SGary Hade 
4730fc44159SYasunori Goto int register_one_node(int nid)
4740fc44159SYasunori Goto {
4750fc44159SYasunori Goto 	int error = 0;
47676b67ed9SKAMEZAWA Hiroyuki 	int cpu;
4770fc44159SYasunori Goto 
4780fc44159SYasunori Goto 	if (node_online(nid)) {
4790fc44159SYasunori Goto 		int p_node = parent_node(nid);
4800fc44159SYasunori Goto 		struct node *parent = NULL;
4810fc44159SYasunori Goto 
4820fc44159SYasunori Goto 		if (p_node != nid)
4830fc44159SYasunori Goto 			parent = &node_devices[p_node];
4840fc44159SYasunori Goto 
4850fc44159SYasunori Goto 		error = register_node(&node_devices[nid], nid, parent);
48676b67ed9SKAMEZAWA Hiroyuki 
48776b67ed9SKAMEZAWA Hiroyuki 		/* link cpu under this node */
48876b67ed9SKAMEZAWA Hiroyuki 		for_each_present_cpu(cpu) {
48976b67ed9SKAMEZAWA Hiroyuki 			if (cpu_to_node(cpu) == nid)
49076b67ed9SKAMEZAWA Hiroyuki 				register_cpu_under_node(cpu, nid);
49176b67ed9SKAMEZAWA Hiroyuki 		}
492c04fc586SGary Hade 
493c04fc586SGary Hade 		/* link memory sections under this node */
494c04fc586SGary Hade 		error = link_mem_sections(nid);
49539da08cbSLee Schermerhorn 
49639da08cbSLee Schermerhorn 		/* initialize work queue for memory hot plug */
49739da08cbSLee Schermerhorn 		init_node_hugetlb_work(nid);
4980fc44159SYasunori Goto 	}
4990fc44159SYasunori Goto 
5000fc44159SYasunori Goto 	return error;
5010fc44159SYasunori Goto 
5020fc44159SYasunori Goto }
5030fc44159SYasunori Goto 
5040fc44159SYasunori Goto void unregister_one_node(int nid)
5050fc44159SYasunori Goto {
5060fc44159SYasunori Goto 	unregister_node(&node_devices[nid]);
5070fc44159SYasunori Goto }
5080fc44159SYasunori Goto 
509bde631a5SLee Schermerhorn /*
510bde631a5SLee Schermerhorn  * node states attributes
511bde631a5SLee Schermerhorn  */
512bde631a5SLee Schermerhorn 
513bde631a5SLee Schermerhorn static ssize_t print_nodes_state(enum node_states state, char *buf)
514bde631a5SLee Schermerhorn {
515bde631a5SLee Schermerhorn 	int n;
516bde631a5SLee Schermerhorn 
517bde631a5SLee Schermerhorn 	n = nodelist_scnprintf(buf, PAGE_SIZE, node_states[state]);
518bde631a5SLee Schermerhorn 	if (n > 0 && PAGE_SIZE > n + 1) {
519bde631a5SLee Schermerhorn 		*(buf + n++) = '\n';
520bde631a5SLee Schermerhorn 		*(buf + n++) = '\0';
521bde631a5SLee Schermerhorn 	}
522bde631a5SLee Schermerhorn 	return n;
523bde631a5SLee Schermerhorn }
524bde631a5SLee Schermerhorn 
525bde631a5SLee Schermerhorn static ssize_t print_nodes_possible(struct sysdev_class *class, char *buf)
526bde631a5SLee Schermerhorn {
527bde631a5SLee Schermerhorn 	return print_nodes_state(N_POSSIBLE, buf);
528bde631a5SLee Schermerhorn }
529bde631a5SLee Schermerhorn 
530bde631a5SLee Schermerhorn static ssize_t print_nodes_online(struct sysdev_class *class, char *buf)
531bde631a5SLee Schermerhorn {
532bde631a5SLee Schermerhorn 	return print_nodes_state(N_ONLINE, buf);
533bde631a5SLee Schermerhorn }
534bde631a5SLee Schermerhorn 
535bde631a5SLee Schermerhorn static ssize_t print_nodes_has_normal_memory(struct sysdev_class *class,
536bde631a5SLee Schermerhorn 						char *buf)
537bde631a5SLee Schermerhorn {
538bde631a5SLee Schermerhorn 	return print_nodes_state(N_NORMAL_MEMORY, buf);
539bde631a5SLee Schermerhorn }
540bde631a5SLee Schermerhorn 
541bde631a5SLee Schermerhorn static ssize_t print_nodes_has_cpu(struct sysdev_class *class, char *buf)
542bde631a5SLee Schermerhorn {
543bde631a5SLee Schermerhorn 	return print_nodes_state(N_CPU, buf);
544bde631a5SLee Schermerhorn }
545bde631a5SLee Schermerhorn 
546bde631a5SLee Schermerhorn static SYSDEV_CLASS_ATTR(possible, 0444, print_nodes_possible, NULL);
547bde631a5SLee Schermerhorn static SYSDEV_CLASS_ATTR(online, 0444, print_nodes_online, NULL);
548bde631a5SLee Schermerhorn static SYSDEV_CLASS_ATTR(has_normal_memory, 0444, print_nodes_has_normal_memory,
549bde631a5SLee Schermerhorn 									NULL);
550bde631a5SLee Schermerhorn static SYSDEV_CLASS_ATTR(has_cpu, 0444, print_nodes_has_cpu, NULL);
551bde631a5SLee Schermerhorn 
552bde631a5SLee Schermerhorn #ifdef CONFIG_HIGHMEM
553bde631a5SLee Schermerhorn static ssize_t print_nodes_has_high_memory(struct sysdev_class *class,
554bde631a5SLee Schermerhorn 						 char *buf)
555bde631a5SLee Schermerhorn {
556bde631a5SLee Schermerhorn 	return print_nodes_state(N_HIGH_MEMORY, buf);
557bde631a5SLee Schermerhorn }
558bde631a5SLee Schermerhorn 
559bde631a5SLee Schermerhorn static SYSDEV_CLASS_ATTR(has_high_memory, 0444, print_nodes_has_high_memory,
560bde631a5SLee Schermerhorn 									 NULL);
561bde631a5SLee Schermerhorn #endif
562bde631a5SLee Schermerhorn 
563bde631a5SLee Schermerhorn struct sysdev_class_attribute *node_state_attr[] = {
564bde631a5SLee Schermerhorn 	&attr_possible,
565bde631a5SLee Schermerhorn 	&attr_online,
566bde631a5SLee Schermerhorn 	&attr_has_normal_memory,
567bde631a5SLee Schermerhorn #ifdef CONFIG_HIGHMEM
568bde631a5SLee Schermerhorn 	&attr_has_high_memory,
569bde631a5SLee Schermerhorn #endif
570bde631a5SLee Schermerhorn 	&attr_has_cpu,
571bde631a5SLee Schermerhorn };
572bde631a5SLee Schermerhorn 
573bde631a5SLee Schermerhorn static int node_states_init(void)
574bde631a5SLee Schermerhorn {
575bde631a5SLee Schermerhorn 	int i;
576bde631a5SLee Schermerhorn 	int err = 0;
577bde631a5SLee Schermerhorn 
578bde631a5SLee Schermerhorn 	for (i = 0;  i < NR_NODE_STATES; i++) {
579bde631a5SLee Schermerhorn 		int ret;
580bde631a5SLee Schermerhorn 		ret = sysdev_class_create_file(&node_class, node_state_attr[i]);
581bde631a5SLee Schermerhorn 		if (!err)
582bde631a5SLee Schermerhorn 			err = ret;
583bde631a5SLee Schermerhorn 	}
584bde631a5SLee Schermerhorn 	return err;
585bde631a5SLee Schermerhorn }
586bde631a5SLee Schermerhorn 
5874faf8d95SLee Schermerhorn #define NODE_CALLBACK_PRI	2	/* lower than SLAB */
5884b45099bSKeiichiro Tokunaga static int __init register_node_type(void)
5891da177e4SLinus Torvalds {
590bde631a5SLee Schermerhorn 	int ret;
591bde631a5SLee Schermerhorn 
592bde631a5SLee Schermerhorn 	ret = sysdev_class_register(&node_class);
5934faf8d95SLee Schermerhorn 	if (!ret) {
594bde631a5SLee Schermerhorn 		ret = node_states_init();
5954faf8d95SLee Schermerhorn 		hotplug_memory_notifier(node_memory_callback,
5964faf8d95SLee Schermerhorn 					NODE_CALLBACK_PRI);
5974faf8d95SLee Schermerhorn 	}
598bde631a5SLee Schermerhorn 
599bde631a5SLee Schermerhorn 	/*
600bde631a5SLee Schermerhorn 	 * Note:  we're not going to unregister the node class if we fail
601bde631a5SLee Schermerhorn 	 * to register the node state class attribute files.
602bde631a5SLee Schermerhorn 	 */
603bde631a5SLee Schermerhorn 	return ret;
6041da177e4SLinus Torvalds }
6051da177e4SLinus Torvalds postcore_initcall(register_node_type);
606