xref: /openbmc/linux/drivers/base/node.c (revision c07e02db)
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>
141da177e4SLinus Torvalds 
151da177e4SLinus Torvalds static struct sysdev_class node_class = {
161da177e4SLinus Torvalds 	set_kset_name("node"),
171da177e4SLinus Torvalds };
181da177e4SLinus Torvalds 
191da177e4SLinus Torvalds 
201da177e4SLinus Torvalds static ssize_t node_read_cpumap(struct sys_device * dev, char * buf)
211da177e4SLinus Torvalds {
221da177e4SLinus Torvalds 	struct node *node_dev = to_node(dev);
231da177e4SLinus Torvalds 	cpumask_t mask = node_to_cpumask(node_dev->sysdev.id);
241da177e4SLinus Torvalds 	int len;
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds 	/* 2004/06/03: buf currently PAGE_SIZE, need > 1 char per 4 bits. */
271da177e4SLinus Torvalds 	BUILD_BUG_ON(MAX_NUMNODES/4 > PAGE_SIZE/2);
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds 	len = cpumask_scnprintf(buf, PAGE_SIZE-1, mask);
301da177e4SLinus Torvalds 	len += sprintf(buf + len, "\n");
311da177e4SLinus Torvalds 	return len;
321da177e4SLinus Torvalds }
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds static SYSDEV_ATTR(cpumap, S_IRUGO, node_read_cpumap, NULL);
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds #define K(x) ((x) << (PAGE_SHIFT - 10))
371da177e4SLinus Torvalds static ssize_t node_read_meminfo(struct sys_device * dev, char * buf)
381da177e4SLinus Torvalds {
391da177e4SLinus Torvalds 	int n;
401da177e4SLinus Torvalds 	int nid = dev->id;
411da177e4SLinus Torvalds 	struct sysinfo i;
42c07e02dbSMartin Hicks 	struct page_state ps;
431da177e4SLinus Torvalds 	unsigned long inactive;
441da177e4SLinus Torvalds 	unsigned long active;
451da177e4SLinus Torvalds 	unsigned long free;
461da177e4SLinus Torvalds 
471da177e4SLinus Torvalds 	si_meminfo_node(&i, nid);
48c07e02dbSMartin Hicks 	get_page_state_node(&ps, nid);
491da177e4SLinus Torvalds 	__get_zone_counts(&active, &inactive, &free, NODE_DATA(nid));
501da177e4SLinus Torvalds 
51c07e02dbSMartin Hicks 	/* Check for negative values in these approximate counters */
52c07e02dbSMartin Hicks 	if ((long)ps.nr_dirty < 0)
53c07e02dbSMartin Hicks 		ps.nr_dirty = 0;
54c07e02dbSMartin Hicks 	if ((long)ps.nr_writeback < 0)
55c07e02dbSMartin Hicks 		ps.nr_writeback = 0;
56c07e02dbSMartin Hicks 	if ((long)ps.nr_mapped < 0)
57c07e02dbSMartin Hicks 		ps.nr_mapped = 0;
58c07e02dbSMartin Hicks 	if ((long)ps.nr_slab < 0)
59c07e02dbSMartin Hicks 		ps.nr_slab = 0;
60c07e02dbSMartin Hicks 
611da177e4SLinus Torvalds 	n = sprintf(buf, "\n"
621da177e4SLinus Torvalds 		       "Node %d MemTotal:     %8lu kB\n"
631da177e4SLinus Torvalds 		       "Node %d MemFree:      %8lu kB\n"
641da177e4SLinus Torvalds 		       "Node %d MemUsed:      %8lu kB\n"
651da177e4SLinus Torvalds 		       "Node %d Active:       %8lu kB\n"
661da177e4SLinus Torvalds 		       "Node %d Inactive:     %8lu kB\n"
671da177e4SLinus Torvalds 		       "Node %d HighTotal:    %8lu kB\n"
681da177e4SLinus Torvalds 		       "Node %d HighFree:     %8lu kB\n"
691da177e4SLinus Torvalds 		       "Node %d LowTotal:     %8lu kB\n"
70c07e02dbSMartin Hicks 		       "Node %d LowFree:      %8lu kB\n"
71c07e02dbSMartin Hicks 		       "Node %d Dirty:        %8lu kB\n"
72c07e02dbSMartin Hicks 		       "Node %d Writeback:    %8lu kB\n"
73c07e02dbSMartin Hicks 		       "Node %d Mapped:       %8lu kB\n"
74c07e02dbSMartin Hicks 		       "Node %d Slab:         %8lu kB\n",
751da177e4SLinus Torvalds 		       nid, K(i.totalram),
761da177e4SLinus Torvalds 		       nid, K(i.freeram),
771da177e4SLinus Torvalds 		       nid, K(i.totalram - i.freeram),
781da177e4SLinus Torvalds 		       nid, K(active),
791da177e4SLinus Torvalds 		       nid, K(inactive),
801da177e4SLinus Torvalds 		       nid, K(i.totalhigh),
811da177e4SLinus Torvalds 		       nid, K(i.freehigh),
821da177e4SLinus Torvalds 		       nid, K(i.totalram - i.totalhigh),
83c07e02dbSMartin Hicks 		       nid, K(i.freeram - i.freehigh),
84c07e02dbSMartin Hicks 		       nid, K(ps.nr_dirty),
85c07e02dbSMartin Hicks 		       nid, K(ps.nr_writeback),
86c07e02dbSMartin Hicks 		       nid, K(ps.nr_mapped),
87c07e02dbSMartin Hicks 		       nid, K(ps.nr_slab));
881da177e4SLinus Torvalds 	n += hugetlb_report_node_meminfo(nid, buf + n);
891da177e4SLinus Torvalds 	return n;
901da177e4SLinus Torvalds }
911da177e4SLinus Torvalds 
921da177e4SLinus Torvalds #undef K
931da177e4SLinus Torvalds static SYSDEV_ATTR(meminfo, S_IRUGO, node_read_meminfo, NULL);
941da177e4SLinus Torvalds 
951da177e4SLinus Torvalds static ssize_t node_read_numastat(struct sys_device * dev, char * buf)
961da177e4SLinus Torvalds {
971da177e4SLinus Torvalds 	unsigned long numa_hit, numa_miss, interleave_hit, numa_foreign;
981da177e4SLinus Torvalds 	unsigned long local_node, other_node;
991da177e4SLinus Torvalds 	int i, cpu;
1001da177e4SLinus Torvalds 	pg_data_t *pg = NODE_DATA(dev->id);
1011da177e4SLinus Torvalds 	numa_hit = 0;
1021da177e4SLinus Torvalds 	numa_miss = 0;
1031da177e4SLinus Torvalds 	interleave_hit = 0;
1041da177e4SLinus Torvalds 	numa_foreign = 0;
1051da177e4SLinus Torvalds 	local_node = 0;
1061da177e4SLinus Torvalds 	other_node = 0;
1071da177e4SLinus Torvalds 	for (i = 0; i < MAX_NR_ZONES; i++) {
1081da177e4SLinus Torvalds 		struct zone *z = &pg->node_zones[i];
1091da177e4SLinus Torvalds 		for (cpu = 0; cpu < NR_CPUS; cpu++) {
110e7c8d5c9SChristoph Lameter 			struct per_cpu_pageset *ps = zone_pcp(z,cpu);
1111da177e4SLinus Torvalds 			numa_hit += ps->numa_hit;
1121da177e4SLinus Torvalds 			numa_miss += ps->numa_miss;
1131da177e4SLinus Torvalds 			numa_foreign += ps->numa_foreign;
1141da177e4SLinus Torvalds 			interleave_hit += ps->interleave_hit;
1151da177e4SLinus Torvalds 			local_node += ps->local_node;
1161da177e4SLinus Torvalds 			other_node += ps->other_node;
1171da177e4SLinus Torvalds 		}
1181da177e4SLinus Torvalds 	}
1191da177e4SLinus Torvalds 	return sprintf(buf,
1201da177e4SLinus Torvalds 		       "numa_hit %lu\n"
1211da177e4SLinus Torvalds 		       "numa_miss %lu\n"
1221da177e4SLinus Torvalds 		       "numa_foreign %lu\n"
1231da177e4SLinus Torvalds 		       "interleave_hit %lu\n"
1241da177e4SLinus Torvalds 		       "local_node %lu\n"
1251da177e4SLinus Torvalds 		       "other_node %lu\n",
1261da177e4SLinus Torvalds 		       numa_hit,
1271da177e4SLinus Torvalds 		       numa_miss,
1281da177e4SLinus Torvalds 		       numa_foreign,
1291da177e4SLinus Torvalds 		       interleave_hit,
1301da177e4SLinus Torvalds 		       local_node,
1311da177e4SLinus Torvalds 		       other_node);
1321da177e4SLinus Torvalds }
1331da177e4SLinus Torvalds static SYSDEV_ATTR(numastat, S_IRUGO, node_read_numastat, NULL);
1341da177e4SLinus Torvalds 
1351da177e4SLinus Torvalds static ssize_t node_read_distance(struct sys_device * dev, char * buf)
1361da177e4SLinus Torvalds {
1371da177e4SLinus Torvalds 	int nid = dev->id;
1381da177e4SLinus Torvalds 	int len = 0;
1391da177e4SLinus Torvalds 	int i;
1401da177e4SLinus Torvalds 
1411da177e4SLinus Torvalds 	/* buf currently PAGE_SIZE, need ~4 chars per node */
1421da177e4SLinus Torvalds 	BUILD_BUG_ON(MAX_NUMNODES*4 > PAGE_SIZE/2);
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds 	for_each_online_node(i)
1451da177e4SLinus Torvalds 		len += sprintf(buf + len, "%s%d", i ? " " : "", node_distance(nid, i));
1461da177e4SLinus Torvalds 
1471da177e4SLinus Torvalds 	len += sprintf(buf + len, "\n");
1481da177e4SLinus Torvalds 	return len;
1491da177e4SLinus Torvalds }
1501da177e4SLinus Torvalds static SYSDEV_ATTR(distance, S_IRUGO, node_read_distance, NULL);
1511da177e4SLinus Torvalds 
1521da177e4SLinus Torvalds 
1531da177e4SLinus Torvalds /*
1541da177e4SLinus Torvalds  * register_node - Setup a driverfs device for a node.
1551da177e4SLinus Torvalds  * @num - Node number to use when creating the device.
1561da177e4SLinus Torvalds  *
1571da177e4SLinus Torvalds  * Initialize and register the node device.
1581da177e4SLinus Torvalds  */
1594b45099bSKeiichiro Tokunaga int register_node(struct node *node, int num, struct node *parent)
1601da177e4SLinus Torvalds {
1611da177e4SLinus Torvalds 	int error;
1621da177e4SLinus Torvalds 
1631da177e4SLinus Torvalds 	node->sysdev.id = num;
1641da177e4SLinus Torvalds 	node->sysdev.cls = &node_class;
1651da177e4SLinus Torvalds 	error = sysdev_register(&node->sysdev);
1661da177e4SLinus Torvalds 
1671da177e4SLinus Torvalds 	if (!error){
1681da177e4SLinus Torvalds 		sysdev_create_file(&node->sysdev, &attr_cpumap);
1691da177e4SLinus Torvalds 		sysdev_create_file(&node->sysdev, &attr_meminfo);
1701da177e4SLinus Torvalds 		sysdev_create_file(&node->sysdev, &attr_numastat);
1711da177e4SLinus Torvalds 		sysdev_create_file(&node->sysdev, &attr_distance);
1721da177e4SLinus Torvalds 	}
1731da177e4SLinus Torvalds 	return error;
1741da177e4SLinus Torvalds }
1751da177e4SLinus Torvalds 
1764b45099bSKeiichiro Tokunaga /**
1774b45099bSKeiichiro Tokunaga  * unregister_node - unregister a node device
1784b45099bSKeiichiro Tokunaga  * @node: node going away
1794b45099bSKeiichiro Tokunaga  *
1804b45099bSKeiichiro Tokunaga  * Unregisters a node device @node.  All the devices on the node must be
1814b45099bSKeiichiro Tokunaga  * unregistered before calling this function.
1824b45099bSKeiichiro Tokunaga  */
1834b45099bSKeiichiro Tokunaga void unregister_node(struct node *node)
1844b45099bSKeiichiro Tokunaga {
1854b45099bSKeiichiro Tokunaga 	sysdev_remove_file(&node->sysdev, &attr_cpumap);
1864b45099bSKeiichiro Tokunaga 	sysdev_remove_file(&node->sysdev, &attr_meminfo);
1874b45099bSKeiichiro Tokunaga 	sysdev_remove_file(&node->sysdev, &attr_numastat);
1884b45099bSKeiichiro Tokunaga 	sysdev_remove_file(&node->sysdev, &attr_distance);
1891da177e4SLinus Torvalds 
1904b45099bSKeiichiro Tokunaga 	sysdev_unregister(&node->sysdev);
1914b45099bSKeiichiro Tokunaga }
1924b45099bSKeiichiro Tokunaga 
1934b45099bSKeiichiro Tokunaga static int __init register_node_type(void)
1941da177e4SLinus Torvalds {
1951da177e4SLinus Torvalds 	return sysdev_class_register(&node_class);
1961da177e4SLinus Torvalds }
1971da177e4SLinus Torvalds postcore_initcall(register_node_type);
198