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) \ 33static 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) \ 40static 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) \ 47static 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 58define_id_show_func(physical_package_id); 59static DEVICE_ATTR_RO(physical_package_id); 60 61define_id_show_func(core_id); 62static DEVICE_ATTR_RO(core_id); 63 64define_siblings_show_func(thread_siblings, sibling_cpumask); 65static DEVICE_ATTR_RO(thread_siblings); 66static DEVICE_ATTR_RO(thread_siblings_list); 67 68define_siblings_show_func(core_siblings, core_cpumask); 69static DEVICE_ATTR_RO(core_siblings); 70static DEVICE_ATTR_RO(core_siblings_list); 71 72#ifdef CONFIG_SCHED_BOOK 73define_id_show_func(book_id); 74static DEVICE_ATTR_RO(book_id); 75define_siblings_show_func(book_siblings, book_cpumask); 76static DEVICE_ATTR_RO(book_siblings); 77static DEVICE_ATTR_RO(book_siblings_list); 78#endif 79 80static 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 95static struct attribute_group topology_attr_group = { 96 .attrs = default_attrs, 97 .name = "topology" 98}; 99 100/* Add/Remove cpu_topology interface for CPU device */ 101static 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 108static 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 115static 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 136static 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 150out: 151 cpu_notifier_register_done(); 152 return rc; 153} 154 155device_initcall(topology_sysfs_init); 156