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++) { 30647504980SRoel Kluin 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