1 /* 2 * driver/base/topology.c - Populate sysfs with cpu topology information 3 * 4 * Written by: Zhang Yanmin, Intel Corporation 5 * 6 * Copyright (C) 2006, Intel Corp. 7 * 8 * All rights reserved. 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, but 16 * WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 18 * NON INFRINGEMENT. See the GNU General Public License for more 19 * details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program; if not, write to the Free Software 23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 24 * 25 */ 26 #include <linux/mm.h> 27 #include <linux/cpu.h> 28 #include <linux/module.h> 29 #include <linux/hardirq.h> 30 #include <linux/topology.h> 31 32 #define define_id_show_func(name) \ 33 static ssize_t name##_show(struct device *dev, \ 34 struct device_attribute *attr, char *buf) \ 35 { \ 36 return sprintf(buf, "%d\n", topology_##name(dev->id)); \ 37 } 38 39 #define define_siblings_show_map(name, mask) \ 40 static ssize_t name##_show(struct device *dev, \ 41 struct device_attribute *attr, char *buf) \ 42 { \ 43 return cpumap_print_to_pagebuf(false, buf, topology_##mask(dev->id));\ 44 } 45 46 #define define_siblings_show_list(name, mask) \ 47 static ssize_t name##_list_show(struct device *dev, \ 48 struct device_attribute *attr, \ 49 char *buf) \ 50 { \ 51 return cpumap_print_to_pagebuf(true, buf, topology_##mask(dev->id));\ 52 } 53 54 #define define_siblings_show_func(name, mask) \ 55 define_siblings_show_map(name, mask); \ 56 define_siblings_show_list(name, mask) 57 58 define_id_show_func(physical_package_id); 59 static DEVICE_ATTR_RO(physical_package_id); 60 61 define_id_show_func(core_id); 62 static DEVICE_ATTR_RO(core_id); 63 64 define_siblings_show_func(thread_siblings, thread_cpumask); 65 static DEVICE_ATTR_RO(thread_siblings); 66 static DEVICE_ATTR_RO(thread_siblings_list); 67 68 define_siblings_show_func(core_siblings, core_cpumask); 69 static DEVICE_ATTR_RO(core_siblings); 70 static DEVICE_ATTR_RO(core_siblings_list); 71 72 #ifdef CONFIG_SCHED_BOOK 73 define_id_show_func(book_id); 74 static DEVICE_ATTR_RO(book_id); 75 define_siblings_show_func(book_siblings, book_cpumask); 76 static DEVICE_ATTR_RO(book_siblings); 77 static DEVICE_ATTR_RO(book_siblings_list); 78 #endif 79 80 static struct attribute *default_attrs[] = { 81 &dev_attr_physical_package_id.attr, 82 &dev_attr_core_id.attr, 83 &dev_attr_thread_siblings.attr, 84 &dev_attr_thread_siblings_list.attr, 85 &dev_attr_core_siblings.attr, 86 &dev_attr_core_siblings_list.attr, 87 #ifdef CONFIG_SCHED_BOOK 88 &dev_attr_book_id.attr, 89 &dev_attr_book_siblings.attr, 90 &dev_attr_book_siblings_list.attr, 91 #endif 92 NULL 93 }; 94 95 static struct attribute_group topology_attr_group = { 96 .attrs = default_attrs, 97 .name = "topology" 98 }; 99 100 /* Add/Remove cpu_topology interface for CPU device */ 101 static int topology_add_dev(unsigned int cpu) 102 { 103 struct device *dev = get_cpu_device(cpu); 104 105 return sysfs_create_group(&dev->kobj, &topology_attr_group); 106 } 107 108 static void topology_remove_dev(unsigned int cpu) 109 { 110 struct device *dev = get_cpu_device(cpu); 111 112 sysfs_remove_group(&dev->kobj, &topology_attr_group); 113 } 114 115 static int topology_cpu_callback(struct notifier_block *nfb, 116 unsigned long action, void *hcpu) 117 { 118 unsigned int cpu = (unsigned long)hcpu; 119 int rc = 0; 120 121 switch (action) { 122 case CPU_UP_PREPARE: 123 case CPU_UP_PREPARE_FROZEN: 124 rc = topology_add_dev(cpu); 125 break; 126 case CPU_UP_CANCELED: 127 case CPU_UP_CANCELED_FROZEN: 128 case CPU_DEAD: 129 case CPU_DEAD_FROZEN: 130 topology_remove_dev(cpu); 131 break; 132 } 133 return notifier_from_errno(rc); 134 } 135 136 static int topology_sysfs_init(void) 137 { 138 int cpu; 139 int rc = 0; 140 141 cpu_notifier_register_begin(); 142 143 for_each_online_cpu(cpu) { 144 rc = topology_add_dev(cpu); 145 if (rc) 146 goto out; 147 } 148 __hotcpu_notifier(topology_cpu_callback, 0); 149 150 out: 151 cpu_notifier_register_done(); 152 return rc; 153 } 154 155 device_initcall(topology_sysfs_init); 156