xref: /openbmc/linux/drivers/base/node.c (revision c04fc586)
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);
27c5f59f08SMike Travis 	node_to_cpumask_ptr(mask, 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"
757b854121SLee Schermerhorn #ifdef CONFIG_UNEVICTABLE_LRU
765344b7e6SNick Piggin 		       "Node %d Unevictable:    %8lu kB\n"
775344b7e6SNick Piggin 		       "Node %d Mlocked:        %8lu kB\n"
787b854121SLee Schermerhorn #endif
79182e8e23SChristoph Lameter #ifdef CONFIG_HIGHMEM
801da177e4SLinus Torvalds 		       "Node %d HighTotal:      %8lu kB\n"
811da177e4SLinus Torvalds 		       "Node %d HighFree:       %8lu kB\n"
821da177e4SLinus Torvalds 		       "Node %d LowTotal:       %8lu kB\n"
83c07e02dbSMartin Hicks 		       "Node %d LowFree:        %8lu kB\n"
84182e8e23SChristoph Lameter #endif
85c07e02dbSMartin Hicks 		       "Node %d Dirty:          %8lu kB\n"
86c07e02dbSMartin Hicks 		       "Node %d Writeback:      %8lu kB\n"
87347ce434SChristoph Lameter 		       "Node %d FilePages:      %8lu kB\n"
88c07e02dbSMartin Hicks 		       "Node %d Mapped:         %8lu kB\n"
89f3dbd344SChristoph Lameter 		       "Node %d AnonPages:      %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 #ifdef CONFIG_UNEVICTABLE_LRU
1097b854121SLee Schermerhorn 		       nid, K(node_page_state(nid, NR_UNEVICTABLE)),
1105344b7e6SNick Piggin 		       nid, K(node_page_state(nid, NR_MLOCK)),
1117b854121SLee Schermerhorn #endif
112182e8e23SChristoph Lameter #ifdef CONFIG_HIGHMEM
1131da177e4SLinus Torvalds 		       nid, K(i.totalhigh),
1141da177e4SLinus Torvalds 		       nid, K(i.freehigh),
1151da177e4SLinus Torvalds 		       nid, K(i.totalram - i.totalhigh),
116c07e02dbSMartin Hicks 		       nid, K(i.freeram - i.freehigh),
117182e8e23SChristoph Lameter #endif
118b1e7a8fdSChristoph Lameter 		       nid, K(node_page_state(nid, NR_FILE_DIRTY)),
119ce866b34SChristoph Lameter 		       nid, K(node_page_state(nid, NR_WRITEBACK)),
120347ce434SChristoph Lameter 		       nid, K(node_page_state(nid, NR_FILE_PAGES)),
12165ba55f5SChristoph Lameter 		       nid, K(node_page_state(nid, NR_FILE_MAPPED)),
122f3dbd344SChristoph Lameter 		       nid, K(node_page_state(nid, NR_ANON_PAGES)),
123df849a15SChristoph Lameter 		       nid, K(node_page_state(nid, NR_PAGETABLE)),
124fd39fc85SChristoph Lameter 		       nid, K(node_page_state(nid, NR_UNSTABLE_NFS)),
125d2c5e30cSChristoph Lameter 		       nid, K(node_page_state(nid, NR_BOUNCE)),
126fc3ba692SMiklos Szeredi 		       nid, K(node_page_state(nid, NR_WRITEBACK_TEMP)),
127972d1a7bSChristoph Lameter 		       nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE) +
128972d1a7bSChristoph Lameter 				node_page_state(nid, NR_SLAB_UNRECLAIMABLE)),
129972d1a7bSChristoph Lameter 		       nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE)),
130972d1a7bSChristoph Lameter 		       nid, K(node_page_state(nid, NR_SLAB_UNRECLAIMABLE)));
1311da177e4SLinus Torvalds 	n += hugetlb_report_node_meminfo(nid, buf + n);
1321da177e4SLinus Torvalds 	return n;
1331da177e4SLinus Torvalds }
1341da177e4SLinus Torvalds 
1351da177e4SLinus Torvalds #undef K
1361da177e4SLinus Torvalds static SYSDEV_ATTR(meminfo, S_IRUGO, node_read_meminfo, NULL);
1371da177e4SLinus Torvalds 
1384a0b2b4dSAndi Kleen static ssize_t node_read_numastat(struct sys_device * dev,
1394a0b2b4dSAndi Kleen 				struct sysdev_attribute *attr, char * buf)
1401da177e4SLinus Torvalds {
1411da177e4SLinus Torvalds 	return sprintf(buf,
1421da177e4SLinus Torvalds 		       "numa_hit %lu\n"
1431da177e4SLinus Torvalds 		       "numa_miss %lu\n"
1441da177e4SLinus Torvalds 		       "numa_foreign %lu\n"
1451da177e4SLinus Torvalds 		       "interleave_hit %lu\n"
1461da177e4SLinus Torvalds 		       "local_node %lu\n"
1471da177e4SLinus Torvalds 		       "other_node %lu\n",
148ca889e6cSChristoph Lameter 		       node_page_state(dev->id, NUMA_HIT),
149ca889e6cSChristoph Lameter 		       node_page_state(dev->id, NUMA_MISS),
150ca889e6cSChristoph Lameter 		       node_page_state(dev->id, NUMA_FOREIGN),
151ca889e6cSChristoph Lameter 		       node_page_state(dev->id, NUMA_INTERLEAVE_HIT),
152ca889e6cSChristoph Lameter 		       node_page_state(dev->id, NUMA_LOCAL),
153ca889e6cSChristoph Lameter 		       node_page_state(dev->id, NUMA_OTHER));
1541da177e4SLinus Torvalds }
1551da177e4SLinus Torvalds static SYSDEV_ATTR(numastat, S_IRUGO, node_read_numastat, NULL);
1561da177e4SLinus Torvalds 
1574a0b2b4dSAndi Kleen static ssize_t node_read_distance(struct sys_device * dev,
1584a0b2b4dSAndi Kleen 			struct sysdev_attribute *attr, char * buf)
1591da177e4SLinus Torvalds {
1601da177e4SLinus Torvalds 	int nid = dev->id;
1611da177e4SLinus Torvalds 	int len = 0;
1621da177e4SLinus Torvalds 	int i;
1631da177e4SLinus Torvalds 
1641da177e4SLinus Torvalds 	/* buf currently PAGE_SIZE, need ~4 chars per node */
1651da177e4SLinus Torvalds 	BUILD_BUG_ON(MAX_NUMNODES*4 > PAGE_SIZE/2);
1661da177e4SLinus Torvalds 
1671da177e4SLinus Torvalds 	for_each_online_node(i)
1681da177e4SLinus Torvalds 		len += sprintf(buf + len, "%s%d", i ? " " : "", node_distance(nid, i));
1691da177e4SLinus Torvalds 
1701da177e4SLinus Torvalds 	len += sprintf(buf + len, "\n");
1711da177e4SLinus Torvalds 	return len;
1721da177e4SLinus Torvalds }
1731da177e4SLinus Torvalds static SYSDEV_ATTR(distance, S_IRUGO, node_read_distance, NULL);
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds 
1761da177e4SLinus Torvalds /*
177405ae7d3SRobert P. J. Day  * register_node - Setup a sysfs device for a node.
1781da177e4SLinus Torvalds  * @num - Node number to use when creating the device.
1791da177e4SLinus Torvalds  *
1801da177e4SLinus Torvalds  * Initialize and register the node device.
1811da177e4SLinus Torvalds  */
1824b45099bSKeiichiro Tokunaga int register_node(struct node *node, int num, struct node *parent)
1831da177e4SLinus Torvalds {
1841da177e4SLinus Torvalds 	int error;
1851da177e4SLinus Torvalds 
1861da177e4SLinus Torvalds 	node->sysdev.id = num;
1871da177e4SLinus Torvalds 	node->sysdev.cls = &node_class;
1881da177e4SLinus Torvalds 	error = sysdev_register(&node->sysdev);
1891da177e4SLinus Torvalds 
1901da177e4SLinus Torvalds 	if (!error){
1911da177e4SLinus Torvalds 		sysdev_create_file(&node->sysdev, &attr_cpumap);
19239106dcfSMike Travis 		sysdev_create_file(&node->sysdev, &attr_cpulist);
1931da177e4SLinus Torvalds 		sysdev_create_file(&node->sysdev, &attr_meminfo);
1941da177e4SLinus Torvalds 		sysdev_create_file(&node->sysdev, &attr_numastat);
1951da177e4SLinus Torvalds 		sysdev_create_file(&node->sysdev, &attr_distance);
196af936a16SLee Schermerhorn 
197af936a16SLee Schermerhorn 		scan_unevictable_register_node(node);
1981da177e4SLinus Torvalds 	}
1991da177e4SLinus Torvalds 	return error;
2001da177e4SLinus Torvalds }
2011da177e4SLinus Torvalds 
2024b45099bSKeiichiro Tokunaga /**
2034b45099bSKeiichiro Tokunaga  * unregister_node - unregister a node device
2044b45099bSKeiichiro Tokunaga  * @node: node going away
2054b45099bSKeiichiro Tokunaga  *
2064b45099bSKeiichiro Tokunaga  * Unregisters a node device @node.  All the devices on the node must be
2074b45099bSKeiichiro Tokunaga  * unregistered before calling this function.
2084b45099bSKeiichiro Tokunaga  */
2094b45099bSKeiichiro Tokunaga void unregister_node(struct node *node)
2104b45099bSKeiichiro Tokunaga {
2114b45099bSKeiichiro Tokunaga 	sysdev_remove_file(&node->sysdev, &attr_cpumap);
21239106dcfSMike Travis 	sysdev_remove_file(&node->sysdev, &attr_cpulist);
2134b45099bSKeiichiro Tokunaga 	sysdev_remove_file(&node->sysdev, &attr_meminfo);
2144b45099bSKeiichiro Tokunaga 	sysdev_remove_file(&node->sysdev, &attr_numastat);
2154b45099bSKeiichiro Tokunaga 	sysdev_remove_file(&node->sysdev, &attr_distance);
2161da177e4SLinus Torvalds 
217af936a16SLee Schermerhorn 	scan_unevictable_unregister_node(node);
218af936a16SLee Schermerhorn 
2194b45099bSKeiichiro Tokunaga 	sysdev_unregister(&node->sysdev);
2204b45099bSKeiichiro Tokunaga }
2214b45099bSKeiichiro Tokunaga 
2220fc44159SYasunori Goto struct node node_devices[MAX_NUMNODES];
2230fc44159SYasunori Goto 
22476b67ed9SKAMEZAWA Hiroyuki /*
22576b67ed9SKAMEZAWA Hiroyuki  * register cpu under node
22676b67ed9SKAMEZAWA Hiroyuki  */
22776b67ed9SKAMEZAWA Hiroyuki int register_cpu_under_node(unsigned int cpu, unsigned int nid)
22876b67ed9SKAMEZAWA Hiroyuki {
22976b67ed9SKAMEZAWA Hiroyuki 	if (node_online(nid)) {
23076b67ed9SKAMEZAWA Hiroyuki 		struct sys_device *obj = get_cpu_sysdev(cpu);
23176b67ed9SKAMEZAWA Hiroyuki 		if (!obj)
23276b67ed9SKAMEZAWA Hiroyuki 			return 0;
23376b67ed9SKAMEZAWA Hiroyuki 		return sysfs_create_link(&node_devices[nid].sysdev.kobj,
23476b67ed9SKAMEZAWA Hiroyuki 					 &obj->kobj,
23576b67ed9SKAMEZAWA Hiroyuki 					 kobject_name(&obj->kobj));
23676b67ed9SKAMEZAWA Hiroyuki 	 }
23776b67ed9SKAMEZAWA Hiroyuki 
23876b67ed9SKAMEZAWA Hiroyuki 	return 0;
23976b67ed9SKAMEZAWA Hiroyuki }
24076b67ed9SKAMEZAWA Hiroyuki 
24176b67ed9SKAMEZAWA Hiroyuki int unregister_cpu_under_node(unsigned int cpu, unsigned int nid)
24276b67ed9SKAMEZAWA Hiroyuki {
24376b67ed9SKAMEZAWA Hiroyuki 	if (node_online(nid)) {
24476b67ed9SKAMEZAWA Hiroyuki 		struct sys_device *obj = get_cpu_sysdev(cpu);
24576b67ed9SKAMEZAWA Hiroyuki 		if (obj)
24676b67ed9SKAMEZAWA Hiroyuki 			sysfs_remove_link(&node_devices[nid].sysdev.kobj,
24776b67ed9SKAMEZAWA Hiroyuki 					 kobject_name(&obj->kobj));
24876b67ed9SKAMEZAWA Hiroyuki 	}
24976b67ed9SKAMEZAWA Hiroyuki 	return 0;
25076b67ed9SKAMEZAWA Hiroyuki }
25176b67ed9SKAMEZAWA Hiroyuki 
252c04fc586SGary Hade #ifdef CONFIG_MEMORY_HOTPLUG_SPARSE
253c04fc586SGary Hade #define page_initialized(page)  (page->lru.next)
254c04fc586SGary Hade 
255c04fc586SGary Hade static int get_nid_for_pfn(unsigned long pfn)
256c04fc586SGary Hade {
257c04fc586SGary Hade 	struct page *page;
258c04fc586SGary Hade 
259c04fc586SGary Hade 	if (!pfn_valid_within(pfn))
260c04fc586SGary Hade 		return -1;
261c04fc586SGary Hade 	page = pfn_to_page(pfn);
262c04fc586SGary Hade 	if (!page_initialized(page))
263c04fc586SGary Hade 		return -1;
264c04fc586SGary Hade 	return pfn_to_nid(pfn);
265c04fc586SGary Hade }
266c04fc586SGary Hade 
267c04fc586SGary Hade /* register memory section under specified node if it spans that node */
268c04fc586SGary Hade int register_mem_sect_under_node(struct memory_block *mem_blk, int nid)
269c04fc586SGary Hade {
270c04fc586SGary Hade 	unsigned long pfn, sect_start_pfn, sect_end_pfn;
271c04fc586SGary Hade 
272c04fc586SGary Hade 	if (!mem_blk)
273c04fc586SGary Hade 		return -EFAULT;
274c04fc586SGary Hade 	if (!node_online(nid))
275c04fc586SGary Hade 		return 0;
276c04fc586SGary Hade 	sect_start_pfn = section_nr_to_pfn(mem_blk->phys_index);
277c04fc586SGary Hade 	sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1;
278c04fc586SGary Hade 	for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) {
279c04fc586SGary Hade 		int page_nid;
280c04fc586SGary Hade 
281c04fc586SGary Hade 		page_nid = get_nid_for_pfn(pfn);
282c04fc586SGary Hade 		if (page_nid < 0)
283c04fc586SGary Hade 			continue;
284c04fc586SGary Hade 		if (page_nid != nid)
285c04fc586SGary Hade 			continue;
286c04fc586SGary Hade 		return sysfs_create_link_nowarn(&node_devices[nid].sysdev.kobj,
287c04fc586SGary Hade 					&mem_blk->sysdev.kobj,
288c04fc586SGary Hade 					kobject_name(&mem_blk->sysdev.kobj));
289c04fc586SGary Hade 	}
290c04fc586SGary Hade 	/* mem section does not span the specified node */
291c04fc586SGary Hade 	return 0;
292c04fc586SGary Hade }
293c04fc586SGary Hade 
294c04fc586SGary Hade /* unregister memory section under all nodes that it spans */
295c04fc586SGary Hade int unregister_mem_sect_under_nodes(struct memory_block *mem_blk)
296c04fc586SGary Hade {
297c04fc586SGary Hade 	nodemask_t unlinked_nodes;
298c04fc586SGary Hade 	unsigned long pfn, sect_start_pfn, sect_end_pfn;
299c04fc586SGary Hade 
300c04fc586SGary Hade 	if (!mem_blk)
301c04fc586SGary Hade 		return -EFAULT;
302c04fc586SGary Hade 	nodes_clear(unlinked_nodes);
303c04fc586SGary Hade 	sect_start_pfn = section_nr_to_pfn(mem_blk->phys_index);
304c04fc586SGary Hade 	sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1;
305c04fc586SGary Hade 	for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) {
306c04fc586SGary Hade 		unsigned int nid;
307c04fc586SGary Hade 
308c04fc586SGary Hade 		nid = get_nid_for_pfn(pfn);
309c04fc586SGary Hade 		if (nid < 0)
310c04fc586SGary Hade 			continue;
311c04fc586SGary Hade 		if (!node_online(nid))
312c04fc586SGary Hade 			continue;
313c04fc586SGary Hade 		if (node_test_and_set(nid, unlinked_nodes))
314c04fc586SGary Hade 			continue;
315c04fc586SGary Hade 		sysfs_remove_link(&node_devices[nid].sysdev.kobj,
316c04fc586SGary Hade 			 kobject_name(&mem_blk->sysdev.kobj));
317c04fc586SGary Hade 	}
318c04fc586SGary Hade 	return 0;
319c04fc586SGary Hade }
320c04fc586SGary Hade 
321c04fc586SGary Hade static int link_mem_sections(int nid)
322c04fc586SGary Hade {
323c04fc586SGary Hade 	unsigned long start_pfn = NODE_DATA(nid)->node_start_pfn;
324c04fc586SGary Hade 	unsigned long end_pfn = start_pfn + NODE_DATA(nid)->node_spanned_pages;
325c04fc586SGary Hade 	unsigned long pfn;
326c04fc586SGary Hade 	int err = 0;
327c04fc586SGary Hade 
328c04fc586SGary Hade 	for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
329c04fc586SGary Hade 		unsigned long section_nr = pfn_to_section_nr(pfn);
330c04fc586SGary Hade 		struct mem_section *mem_sect;
331c04fc586SGary Hade 		struct memory_block *mem_blk;
332c04fc586SGary Hade 		int ret;
333c04fc586SGary Hade 
334c04fc586SGary Hade 		if (!present_section_nr(section_nr))
335c04fc586SGary Hade 			continue;
336c04fc586SGary Hade 		mem_sect = __nr_to_section(section_nr);
337c04fc586SGary Hade 		mem_blk = find_memory_block(mem_sect);
338c04fc586SGary Hade 		ret = register_mem_sect_under_node(mem_blk, nid);
339c04fc586SGary Hade 		if (!err)
340c04fc586SGary Hade 			err = ret;
341c04fc586SGary Hade 
342c04fc586SGary Hade 		/* discard ref obtained in find_memory_block() */
343c04fc586SGary Hade 		kobject_put(&mem_blk->sysdev.kobj);
344c04fc586SGary Hade 	}
345c04fc586SGary Hade 	return err;
346c04fc586SGary Hade }
347c04fc586SGary Hade #else
348c04fc586SGary Hade static int link_mem_sections(int nid) { return 0; }
349c04fc586SGary Hade #endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */
350c04fc586SGary Hade 
3510fc44159SYasunori Goto int register_one_node(int nid)
3520fc44159SYasunori Goto {
3530fc44159SYasunori Goto 	int error = 0;
35476b67ed9SKAMEZAWA Hiroyuki 	int cpu;
3550fc44159SYasunori Goto 
3560fc44159SYasunori Goto 	if (node_online(nid)) {
3570fc44159SYasunori Goto 		int p_node = parent_node(nid);
3580fc44159SYasunori Goto 		struct node *parent = NULL;
3590fc44159SYasunori Goto 
3600fc44159SYasunori Goto 		if (p_node != nid)
3610fc44159SYasunori Goto 			parent = &node_devices[p_node];
3620fc44159SYasunori Goto 
3630fc44159SYasunori Goto 		error = register_node(&node_devices[nid], nid, parent);
36476b67ed9SKAMEZAWA Hiroyuki 
36576b67ed9SKAMEZAWA Hiroyuki 		/* link cpu under this node */
36676b67ed9SKAMEZAWA Hiroyuki 		for_each_present_cpu(cpu) {
36776b67ed9SKAMEZAWA Hiroyuki 			if (cpu_to_node(cpu) == nid)
36876b67ed9SKAMEZAWA Hiroyuki 				register_cpu_under_node(cpu, nid);
36976b67ed9SKAMEZAWA Hiroyuki 		}
370c04fc586SGary Hade 
371c04fc586SGary Hade 		/* link memory sections under this node */
372c04fc586SGary Hade 		error = link_mem_sections(nid);
3730fc44159SYasunori Goto 	}
3740fc44159SYasunori Goto 
3750fc44159SYasunori Goto 	return error;
3760fc44159SYasunori Goto 
3770fc44159SYasunori Goto }
3780fc44159SYasunori Goto 
3790fc44159SYasunori Goto void unregister_one_node(int nid)
3800fc44159SYasunori Goto {
3810fc44159SYasunori Goto 	unregister_node(&node_devices[nid]);
3820fc44159SYasunori Goto }
3830fc44159SYasunori Goto 
384bde631a5SLee Schermerhorn /*
385bde631a5SLee Schermerhorn  * node states attributes
386bde631a5SLee Schermerhorn  */
387bde631a5SLee Schermerhorn 
388bde631a5SLee Schermerhorn static ssize_t print_nodes_state(enum node_states state, char *buf)
389bde631a5SLee Schermerhorn {
390bde631a5SLee Schermerhorn 	int n;
391bde631a5SLee Schermerhorn 
392bde631a5SLee Schermerhorn 	n = nodelist_scnprintf(buf, PAGE_SIZE, node_states[state]);
393bde631a5SLee Schermerhorn 	if (n > 0 && PAGE_SIZE > n + 1) {
394bde631a5SLee Schermerhorn 		*(buf + n++) = '\n';
395bde631a5SLee Schermerhorn 		*(buf + n++) = '\0';
396bde631a5SLee Schermerhorn 	}
397bde631a5SLee Schermerhorn 	return n;
398bde631a5SLee Schermerhorn }
399bde631a5SLee Schermerhorn 
400bde631a5SLee Schermerhorn static ssize_t print_nodes_possible(struct sysdev_class *class, char *buf)
401bde631a5SLee Schermerhorn {
402bde631a5SLee Schermerhorn 	return print_nodes_state(N_POSSIBLE, buf);
403bde631a5SLee Schermerhorn }
404bde631a5SLee Schermerhorn 
405bde631a5SLee Schermerhorn static ssize_t print_nodes_online(struct sysdev_class *class, char *buf)
406bde631a5SLee Schermerhorn {
407bde631a5SLee Schermerhorn 	return print_nodes_state(N_ONLINE, buf);
408bde631a5SLee Schermerhorn }
409bde631a5SLee Schermerhorn 
410bde631a5SLee Schermerhorn static ssize_t print_nodes_has_normal_memory(struct sysdev_class *class,
411bde631a5SLee Schermerhorn 						char *buf)
412bde631a5SLee Schermerhorn {
413bde631a5SLee Schermerhorn 	return print_nodes_state(N_NORMAL_MEMORY, buf);
414bde631a5SLee Schermerhorn }
415bde631a5SLee Schermerhorn 
416bde631a5SLee Schermerhorn static ssize_t print_nodes_has_cpu(struct sysdev_class *class, char *buf)
417bde631a5SLee Schermerhorn {
418bde631a5SLee Schermerhorn 	return print_nodes_state(N_CPU, buf);
419bde631a5SLee Schermerhorn }
420bde631a5SLee Schermerhorn 
421bde631a5SLee Schermerhorn static SYSDEV_CLASS_ATTR(possible, 0444, print_nodes_possible, NULL);
422bde631a5SLee Schermerhorn static SYSDEV_CLASS_ATTR(online, 0444, print_nodes_online, NULL);
423bde631a5SLee Schermerhorn static SYSDEV_CLASS_ATTR(has_normal_memory, 0444, print_nodes_has_normal_memory,
424bde631a5SLee Schermerhorn 									NULL);
425bde631a5SLee Schermerhorn static SYSDEV_CLASS_ATTR(has_cpu, 0444, print_nodes_has_cpu, NULL);
426bde631a5SLee Schermerhorn 
427bde631a5SLee Schermerhorn #ifdef CONFIG_HIGHMEM
428bde631a5SLee Schermerhorn static ssize_t print_nodes_has_high_memory(struct sysdev_class *class,
429bde631a5SLee Schermerhorn 						 char *buf)
430bde631a5SLee Schermerhorn {
431bde631a5SLee Schermerhorn 	return print_nodes_state(N_HIGH_MEMORY, buf);
432bde631a5SLee Schermerhorn }
433bde631a5SLee Schermerhorn 
434bde631a5SLee Schermerhorn static SYSDEV_CLASS_ATTR(has_high_memory, 0444, print_nodes_has_high_memory,
435bde631a5SLee Schermerhorn 									 NULL);
436bde631a5SLee Schermerhorn #endif
437bde631a5SLee Schermerhorn 
438bde631a5SLee Schermerhorn struct sysdev_class_attribute *node_state_attr[] = {
439bde631a5SLee Schermerhorn 	&attr_possible,
440bde631a5SLee Schermerhorn 	&attr_online,
441bde631a5SLee Schermerhorn 	&attr_has_normal_memory,
442bde631a5SLee Schermerhorn #ifdef CONFIG_HIGHMEM
443bde631a5SLee Schermerhorn 	&attr_has_high_memory,
444bde631a5SLee Schermerhorn #endif
445bde631a5SLee Schermerhorn 	&attr_has_cpu,
446bde631a5SLee Schermerhorn };
447bde631a5SLee Schermerhorn 
448bde631a5SLee Schermerhorn static int node_states_init(void)
449bde631a5SLee Schermerhorn {
450bde631a5SLee Schermerhorn 	int i;
451bde631a5SLee Schermerhorn 	int err = 0;
452bde631a5SLee Schermerhorn 
453bde631a5SLee Schermerhorn 	for (i = 0;  i < NR_NODE_STATES; i++) {
454bde631a5SLee Schermerhorn 		int ret;
455bde631a5SLee Schermerhorn 		ret = sysdev_class_create_file(&node_class, node_state_attr[i]);
456bde631a5SLee Schermerhorn 		if (!err)
457bde631a5SLee Schermerhorn 			err = ret;
458bde631a5SLee Schermerhorn 	}
459bde631a5SLee Schermerhorn 	return err;
460bde631a5SLee Schermerhorn }
461bde631a5SLee Schermerhorn 
4624b45099bSKeiichiro Tokunaga static int __init register_node_type(void)
4631da177e4SLinus Torvalds {
464bde631a5SLee Schermerhorn 	int ret;
465bde631a5SLee Schermerhorn 
466bde631a5SLee Schermerhorn 	ret = sysdev_class_register(&node_class);
467bde631a5SLee Schermerhorn 	if (!ret)
468bde631a5SLee Schermerhorn 		ret = node_states_init();
469bde631a5SLee Schermerhorn 
470bde631a5SLee Schermerhorn 	/*
471bde631a5SLee Schermerhorn 	 * Note:  we're not going to unregister the node class if we fail
472bde631a5SLee Schermerhorn 	 * to register the node state class attribute files.
473bde631a5SLee Schermerhorn 	 */
474bde631a5SLee Schermerhorn 	return ret;
4751da177e4SLinus Torvalds }
4761da177e4SLinus Torvalds postcore_initcall(register_node_type);
477