xref: /openbmc/linux/drivers/base/node.c (revision b1e7a8fd)
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>
91da177e4SLinus Torvalds #include <linux/node.h>
101da177e4SLinus Torvalds #include <linux/hugetlb.h>
111da177e4SLinus Torvalds #include <linux/cpumask.h>
121da177e4SLinus Torvalds #include <linux/topology.h>
131da177e4SLinus Torvalds #include <linux/nodemask.h>
1476b67ed9SKAMEZAWA Hiroyuki #include <linux/cpu.h>
151da177e4SLinus Torvalds 
161da177e4SLinus Torvalds static struct sysdev_class node_class = {
171da177e4SLinus Torvalds 	set_kset_name("node"),
181da177e4SLinus Torvalds };
191da177e4SLinus Torvalds 
201da177e4SLinus Torvalds 
211da177e4SLinus Torvalds static ssize_t node_read_cpumap(struct sys_device * dev, char * buf)
221da177e4SLinus Torvalds {
231da177e4SLinus Torvalds 	struct node *node_dev = to_node(dev);
241da177e4SLinus Torvalds 	cpumask_t mask = node_to_cpumask(node_dev->sysdev.id);
251da177e4SLinus Torvalds 	int len;
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds 	/* 2004/06/03: buf currently PAGE_SIZE, need > 1 char per 4 bits. */
281da177e4SLinus Torvalds 	BUILD_BUG_ON(MAX_NUMNODES/4 > PAGE_SIZE/2);
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds 	len = cpumask_scnprintf(buf, PAGE_SIZE-1, mask);
311da177e4SLinus Torvalds 	len += sprintf(buf + len, "\n");
321da177e4SLinus Torvalds 	return len;
331da177e4SLinus Torvalds }
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds static SYSDEV_ATTR(cpumap, S_IRUGO, node_read_cpumap, NULL);
361da177e4SLinus Torvalds 
371da177e4SLinus Torvalds #define K(x) ((x) << (PAGE_SHIFT - 10))
381da177e4SLinus Torvalds static ssize_t node_read_meminfo(struct sys_device * dev, char * buf)
391da177e4SLinus Torvalds {
401da177e4SLinus Torvalds 	int n;
411da177e4SLinus Torvalds 	int nid = dev->id;
421da177e4SLinus Torvalds 	struct sysinfo i;
43c07e02dbSMartin Hicks 	struct page_state ps;
441da177e4SLinus Torvalds 	unsigned long inactive;
451da177e4SLinus Torvalds 	unsigned long active;
461da177e4SLinus Torvalds 	unsigned long free;
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds 	si_meminfo_node(&i, nid);
49c07e02dbSMartin Hicks 	get_page_state_node(&ps, nid);
501da177e4SLinus Torvalds 	__get_zone_counts(&active, &inactive, &free, NODE_DATA(nid));
511da177e4SLinus Torvalds 
52c07e02dbSMartin Hicks 	/* Check for negative values in these approximate counters */
53c07e02dbSMartin Hicks 	if ((long)ps.nr_writeback < 0)
54c07e02dbSMartin Hicks 		ps.nr_writeback = 0;
55c07e02dbSMartin Hicks 
561da177e4SLinus Torvalds 	n = sprintf(buf, "\n"
571da177e4SLinus Torvalds 		       "Node %d MemTotal:     %8lu kB\n"
581da177e4SLinus Torvalds 		       "Node %d MemFree:      %8lu kB\n"
591da177e4SLinus Torvalds 		       "Node %d MemUsed:      %8lu kB\n"
601da177e4SLinus Torvalds 		       "Node %d Active:       %8lu kB\n"
611da177e4SLinus Torvalds 		       "Node %d Inactive:     %8lu kB\n"
621da177e4SLinus Torvalds 		       "Node %d HighTotal:    %8lu kB\n"
631da177e4SLinus Torvalds 		       "Node %d HighFree:     %8lu kB\n"
641da177e4SLinus Torvalds 		       "Node %d LowTotal:     %8lu kB\n"
65c07e02dbSMartin Hicks 		       "Node %d LowFree:      %8lu kB\n"
66c07e02dbSMartin Hicks 		       "Node %d Dirty:        %8lu kB\n"
67c07e02dbSMartin Hicks 		       "Node %d Writeback:    %8lu kB\n"
68347ce434SChristoph Lameter 		       "Node %d FilePages:    %8lu kB\n"
69c07e02dbSMartin Hicks 		       "Node %d Mapped:       %8lu kB\n"
70f3dbd344SChristoph Lameter 		       "Node %d AnonPages:    %8lu kB\n"
71df849a15SChristoph Lameter 		       "Node %d PageTables:   %8lu kB\n"
72c07e02dbSMartin Hicks 		       "Node %d Slab:         %8lu kB\n",
731da177e4SLinus Torvalds 		       nid, K(i.totalram),
741da177e4SLinus Torvalds 		       nid, K(i.freeram),
751da177e4SLinus Torvalds 		       nid, K(i.totalram - i.freeram),
761da177e4SLinus Torvalds 		       nid, K(active),
771da177e4SLinus Torvalds 		       nid, K(inactive),
781da177e4SLinus Torvalds 		       nid, K(i.totalhigh),
791da177e4SLinus Torvalds 		       nid, K(i.freehigh),
801da177e4SLinus Torvalds 		       nid, K(i.totalram - i.totalhigh),
81c07e02dbSMartin Hicks 		       nid, K(i.freeram - i.freehigh),
82b1e7a8fdSChristoph Lameter 		       nid, K(node_page_state(nid, NR_FILE_DIRTY)),
83c07e02dbSMartin Hicks 		       nid, K(ps.nr_writeback),
84347ce434SChristoph Lameter 		       nid, K(node_page_state(nid, NR_FILE_PAGES)),
8565ba55f5SChristoph Lameter 		       nid, K(node_page_state(nid, NR_FILE_MAPPED)),
86f3dbd344SChristoph Lameter 		       nid, K(node_page_state(nid, NR_ANON_PAGES)),
87df849a15SChristoph Lameter 		       nid, K(node_page_state(nid, NR_PAGETABLE)),
889a865ffaSChristoph Lameter 		       nid, K(node_page_state(nid, NR_SLAB)));
891da177e4SLinus Torvalds 	n += hugetlb_report_node_meminfo(nid, buf + n);
901da177e4SLinus Torvalds 	return n;
911da177e4SLinus Torvalds }
921da177e4SLinus Torvalds 
931da177e4SLinus Torvalds #undef K
941da177e4SLinus Torvalds static SYSDEV_ATTR(meminfo, S_IRUGO, node_read_meminfo, NULL);
951da177e4SLinus Torvalds 
961da177e4SLinus Torvalds static ssize_t node_read_numastat(struct sys_device * dev, char * buf)
971da177e4SLinus Torvalds {
981da177e4SLinus Torvalds 	unsigned long numa_hit, numa_miss, interleave_hit, numa_foreign;
991da177e4SLinus Torvalds 	unsigned long local_node, other_node;
1001da177e4SLinus Torvalds 	int i, cpu;
1011da177e4SLinus Torvalds 	pg_data_t *pg = NODE_DATA(dev->id);
1021da177e4SLinus Torvalds 	numa_hit = 0;
1031da177e4SLinus Torvalds 	numa_miss = 0;
1041da177e4SLinus Torvalds 	interleave_hit = 0;
1051da177e4SLinus Torvalds 	numa_foreign = 0;
1061da177e4SLinus Torvalds 	local_node = 0;
1071da177e4SLinus Torvalds 	other_node = 0;
1081da177e4SLinus Torvalds 	for (i = 0; i < MAX_NR_ZONES; i++) {
1091da177e4SLinus Torvalds 		struct zone *z = &pg->node_zones[i];
11054404e72SChristoph Lameter 		for_each_online_cpu(cpu) {
111e7c8d5c9SChristoph Lameter 			struct per_cpu_pageset *ps = zone_pcp(z,cpu);
1121da177e4SLinus Torvalds 			numa_hit += ps->numa_hit;
1131da177e4SLinus Torvalds 			numa_miss += ps->numa_miss;
1141da177e4SLinus Torvalds 			numa_foreign += ps->numa_foreign;
1151da177e4SLinus Torvalds 			interleave_hit += ps->interleave_hit;
1161da177e4SLinus Torvalds 			local_node += ps->local_node;
1171da177e4SLinus Torvalds 			other_node += ps->other_node;
1181da177e4SLinus Torvalds 		}
1191da177e4SLinus Torvalds 	}
1201da177e4SLinus Torvalds 	return sprintf(buf,
1211da177e4SLinus Torvalds 		       "numa_hit %lu\n"
1221da177e4SLinus Torvalds 		       "numa_miss %lu\n"
1231da177e4SLinus Torvalds 		       "numa_foreign %lu\n"
1241da177e4SLinus Torvalds 		       "interleave_hit %lu\n"
1251da177e4SLinus Torvalds 		       "local_node %lu\n"
1261da177e4SLinus Torvalds 		       "other_node %lu\n",
1271da177e4SLinus Torvalds 		       numa_hit,
1281da177e4SLinus Torvalds 		       numa_miss,
1291da177e4SLinus Torvalds 		       numa_foreign,
1301da177e4SLinus Torvalds 		       interleave_hit,
1311da177e4SLinus Torvalds 		       local_node,
1321da177e4SLinus Torvalds 		       other_node);
1331da177e4SLinus Torvalds }
1341da177e4SLinus Torvalds static SYSDEV_ATTR(numastat, S_IRUGO, node_read_numastat, NULL);
1351da177e4SLinus Torvalds 
1361da177e4SLinus Torvalds static ssize_t node_read_distance(struct sys_device * dev, char * buf)
1371da177e4SLinus Torvalds {
1381da177e4SLinus Torvalds 	int nid = dev->id;
1391da177e4SLinus Torvalds 	int len = 0;
1401da177e4SLinus Torvalds 	int i;
1411da177e4SLinus Torvalds 
1421da177e4SLinus Torvalds 	/* buf currently PAGE_SIZE, need ~4 chars per node */
1431da177e4SLinus Torvalds 	BUILD_BUG_ON(MAX_NUMNODES*4 > PAGE_SIZE/2);
1441da177e4SLinus Torvalds 
1451da177e4SLinus Torvalds 	for_each_online_node(i)
1461da177e4SLinus Torvalds 		len += sprintf(buf + len, "%s%d", i ? " " : "", node_distance(nid, i));
1471da177e4SLinus Torvalds 
1481da177e4SLinus Torvalds 	len += sprintf(buf + len, "\n");
1491da177e4SLinus Torvalds 	return len;
1501da177e4SLinus Torvalds }
1511da177e4SLinus Torvalds static SYSDEV_ATTR(distance, S_IRUGO, node_read_distance, NULL);
1521da177e4SLinus Torvalds 
1531da177e4SLinus Torvalds 
1541da177e4SLinus Torvalds /*
1551da177e4SLinus Torvalds  * register_node - Setup a driverfs device for a node.
1561da177e4SLinus Torvalds  * @num - Node number to use when creating the device.
1571da177e4SLinus Torvalds  *
1581da177e4SLinus Torvalds  * Initialize and register the node device.
1591da177e4SLinus Torvalds  */
1604b45099bSKeiichiro Tokunaga int register_node(struct node *node, int num, struct node *parent)
1611da177e4SLinus Torvalds {
1621da177e4SLinus Torvalds 	int error;
1631da177e4SLinus Torvalds 
1641da177e4SLinus Torvalds 	node->sysdev.id = num;
1651da177e4SLinus Torvalds 	node->sysdev.cls = &node_class;
1661da177e4SLinus Torvalds 	error = sysdev_register(&node->sysdev);
1671da177e4SLinus Torvalds 
1681da177e4SLinus Torvalds 	if (!error){
1691da177e4SLinus Torvalds 		sysdev_create_file(&node->sysdev, &attr_cpumap);
1701da177e4SLinus Torvalds 		sysdev_create_file(&node->sysdev, &attr_meminfo);
1711da177e4SLinus Torvalds 		sysdev_create_file(&node->sysdev, &attr_numastat);
1721da177e4SLinus Torvalds 		sysdev_create_file(&node->sysdev, &attr_distance);
1731da177e4SLinus Torvalds 	}
1741da177e4SLinus Torvalds 	return error;
1751da177e4SLinus Torvalds }
1761da177e4SLinus Torvalds 
1774b45099bSKeiichiro Tokunaga /**
1784b45099bSKeiichiro Tokunaga  * unregister_node - unregister a node device
1794b45099bSKeiichiro Tokunaga  * @node: node going away
1804b45099bSKeiichiro Tokunaga  *
1814b45099bSKeiichiro Tokunaga  * Unregisters a node device @node.  All the devices on the node must be
1824b45099bSKeiichiro Tokunaga  * unregistered before calling this function.
1834b45099bSKeiichiro Tokunaga  */
1844b45099bSKeiichiro Tokunaga void unregister_node(struct node *node)
1854b45099bSKeiichiro Tokunaga {
1864b45099bSKeiichiro Tokunaga 	sysdev_remove_file(&node->sysdev, &attr_cpumap);
1874b45099bSKeiichiro Tokunaga 	sysdev_remove_file(&node->sysdev, &attr_meminfo);
1884b45099bSKeiichiro Tokunaga 	sysdev_remove_file(&node->sysdev, &attr_numastat);
1894b45099bSKeiichiro Tokunaga 	sysdev_remove_file(&node->sysdev, &attr_distance);
1901da177e4SLinus Torvalds 
1914b45099bSKeiichiro Tokunaga 	sysdev_unregister(&node->sysdev);
1924b45099bSKeiichiro Tokunaga }
1934b45099bSKeiichiro Tokunaga 
1940fc44159SYasunori Goto struct node node_devices[MAX_NUMNODES];
1950fc44159SYasunori Goto 
19676b67ed9SKAMEZAWA Hiroyuki /*
19776b67ed9SKAMEZAWA Hiroyuki  * register cpu under node
19876b67ed9SKAMEZAWA Hiroyuki  */
19976b67ed9SKAMEZAWA Hiroyuki int register_cpu_under_node(unsigned int cpu, unsigned int nid)
20076b67ed9SKAMEZAWA Hiroyuki {
20176b67ed9SKAMEZAWA Hiroyuki 	if (node_online(nid)) {
20276b67ed9SKAMEZAWA Hiroyuki 		struct sys_device *obj = get_cpu_sysdev(cpu);
20376b67ed9SKAMEZAWA Hiroyuki 		if (!obj)
20476b67ed9SKAMEZAWA Hiroyuki 			return 0;
20576b67ed9SKAMEZAWA Hiroyuki 		return sysfs_create_link(&node_devices[nid].sysdev.kobj,
20676b67ed9SKAMEZAWA Hiroyuki 					 &obj->kobj,
20776b67ed9SKAMEZAWA Hiroyuki 					 kobject_name(&obj->kobj));
20876b67ed9SKAMEZAWA Hiroyuki 	 }
20976b67ed9SKAMEZAWA Hiroyuki 
21076b67ed9SKAMEZAWA Hiroyuki 	return 0;
21176b67ed9SKAMEZAWA Hiroyuki }
21276b67ed9SKAMEZAWA Hiroyuki 
21376b67ed9SKAMEZAWA Hiroyuki int unregister_cpu_under_node(unsigned int cpu, unsigned int nid)
21476b67ed9SKAMEZAWA Hiroyuki {
21576b67ed9SKAMEZAWA Hiroyuki 	if (node_online(nid)) {
21676b67ed9SKAMEZAWA Hiroyuki 		struct sys_device *obj = get_cpu_sysdev(cpu);
21776b67ed9SKAMEZAWA Hiroyuki 		if (obj)
21876b67ed9SKAMEZAWA Hiroyuki 			sysfs_remove_link(&node_devices[nid].sysdev.kobj,
21976b67ed9SKAMEZAWA Hiroyuki 					 kobject_name(&obj->kobj));
22076b67ed9SKAMEZAWA Hiroyuki 	}
22176b67ed9SKAMEZAWA Hiroyuki 	return 0;
22276b67ed9SKAMEZAWA Hiroyuki }
22376b67ed9SKAMEZAWA Hiroyuki 
2240fc44159SYasunori Goto int register_one_node(int nid)
2250fc44159SYasunori Goto {
2260fc44159SYasunori Goto 	int error = 0;
22776b67ed9SKAMEZAWA Hiroyuki 	int cpu;
2280fc44159SYasunori Goto 
2290fc44159SYasunori Goto 	if (node_online(nid)) {
2300fc44159SYasunori Goto 		int p_node = parent_node(nid);
2310fc44159SYasunori Goto 		struct node *parent = NULL;
2320fc44159SYasunori Goto 
2330fc44159SYasunori Goto 		if (p_node != nid)
2340fc44159SYasunori Goto 			parent = &node_devices[p_node];
2350fc44159SYasunori Goto 
2360fc44159SYasunori Goto 		error = register_node(&node_devices[nid], nid, parent);
23776b67ed9SKAMEZAWA Hiroyuki 
23876b67ed9SKAMEZAWA Hiroyuki 		/* link cpu under this node */
23976b67ed9SKAMEZAWA Hiroyuki 		for_each_present_cpu(cpu) {
24076b67ed9SKAMEZAWA Hiroyuki 			if (cpu_to_node(cpu) == nid)
24176b67ed9SKAMEZAWA Hiroyuki 				register_cpu_under_node(cpu, nid);
24276b67ed9SKAMEZAWA Hiroyuki 		}
2430fc44159SYasunori Goto 	}
2440fc44159SYasunori Goto 
2450fc44159SYasunori Goto 	return error;
2460fc44159SYasunori Goto 
2470fc44159SYasunori Goto }
2480fc44159SYasunori Goto 
2490fc44159SYasunori Goto void unregister_one_node(int nid)
2500fc44159SYasunori Goto {
2510fc44159SYasunori Goto 	unregister_node(&node_devices[nid]);
2520fc44159SYasunori Goto }
2530fc44159SYasunori Goto 
2544b45099bSKeiichiro Tokunaga static int __init register_node_type(void)
2551da177e4SLinus Torvalds {
2561da177e4SLinus Torvalds 	return sysdev_class_register(&node_class);
2571da177e4SLinus Torvalds }
2581da177e4SLinus Torvalds postcore_initcall(register_node_type);
259