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, sibling_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 #ifdef CONFIG_SCHED_DRAWER 81 define_id_show_func(drawer_id); 82 static DEVICE_ATTR_RO(drawer_id); 83 define_siblings_show_func(drawer_siblings, drawer_cpumask); 84 static DEVICE_ATTR_RO(drawer_siblings); 85 static DEVICE_ATTR_RO(drawer_siblings_list); 86 #endif 87 88 static struct attribute *default_attrs[] = { 89 &dev_attr_physical_package_id.attr, 90 &dev_attr_core_id.attr, 91 &dev_attr_thread_siblings.attr, 92 &dev_attr_thread_siblings_list.attr, 93 &dev_attr_core_siblings.attr, 94 &dev_attr_core_siblings_list.attr, 95 #ifdef CONFIG_SCHED_BOOK 96 &dev_attr_book_id.attr, 97 &dev_attr_book_siblings.attr, 98 &dev_attr_book_siblings_list.attr, 99 #endif 100 #ifdef CONFIG_SCHED_DRAWER 101 &dev_attr_drawer_id.attr, 102 &dev_attr_drawer_siblings.attr, 103 &dev_attr_drawer_siblings_list.attr, 104 #endif 105 NULL 106 }; 107 108 static struct attribute_group topology_attr_group = { 109 .attrs = default_attrs, 110 .name = "topology" 111 }; 112 113 /* Add/Remove cpu_topology interface for CPU device */ 114 static int topology_add_dev(unsigned int cpu) 115 { 116 struct device *dev = get_cpu_device(cpu); 117 118 return sysfs_create_group(&dev->kobj, &topology_attr_group); 119 } 120 121 static void topology_remove_dev(unsigned int cpu) 122 { 123 struct device *dev = get_cpu_device(cpu); 124 125 sysfs_remove_group(&dev->kobj, &topology_attr_group); 126 } 127 128 static int topology_cpu_callback(struct notifier_block *nfb, 129 unsigned long action, void *hcpu) 130 { 131 unsigned int cpu = (unsigned long)hcpu; 132 int rc = 0; 133 134 switch (action) { 135 case CPU_UP_PREPARE: 136 case CPU_UP_PREPARE_FROZEN: 137 rc = topology_add_dev(cpu); 138 break; 139 case CPU_UP_CANCELED: 140 case CPU_UP_CANCELED_FROZEN: 141 case CPU_DEAD: 142 case CPU_DEAD_FROZEN: 143 topology_remove_dev(cpu); 144 break; 145 } 146 return notifier_from_errno(rc); 147 } 148 149 static int topology_sysfs_init(void) 150 { 151 int cpu; 152 int rc = 0; 153 154 cpu_notifier_register_begin(); 155 156 for_each_online_cpu(cpu) { 157 rc = topology_add_dev(cpu); 158 if (rc) 159 goto out; 160 } 161 __hotcpu_notifier(topology_cpu_callback, 0); 162 163 out: 164 cpu_notifier_register_done(); 165 return rc; 166 } 167 168 device_initcall(topology_sysfs_init); 169