aboutsummaryrefslogtreecommitdiffstats
path: root/arch/tile/kernel
diff options
context:
space:
mode:
authorChris Metcalf <cmetcalf@tilera.com>2011-05-26 12:40:09 -0400
committerChris Metcalf <cmetcalf@tilera.com>2011-05-27 10:39:05 -0400
commitf133ecca9cbb31b5e6e9bda27cbe3034fbf656df (patch)
tree1887377b71ee9fc73d4e1226d1d9776ae5a5d7ad /arch/tile/kernel
parent7a0287df3e83a0012dfc496d4a8af9c1c5b126ef (diff)
arch/tile: more /proc and /sys file support
This change introduces a few of the less controversial /proc and /proc/sys interfaces for tile, along with sysfs attributes for various things that were originally proposed as /proc/tile files. It also adjusts the "hardwall" proc API. Arnd Bergmann reviewed the initial arch/tile submission, which included a complete set of all the /proc/tile and /proc/sys/tile knobs that we had added in a somewhat ad hoc way during initial development, and provided feedback on where most of them should go. One knob turned out to be similar enough to the existing /proc/sys/debug/exception-trace that it was re-implemented to use that model instead. Another knob was /proc/tile/grid, which reported the "grid" dimensions of a tile chip (e.g. 8x8 processors = 64-core chip). Arnd suggested looking at sysfs for that, so this change moves that information to a pair of sysfs attributes (chip_width and chip_height) in the /sys/devices/system/cpu directory. We also put the "chip_serial" and "chip_revision" information from our old /proc/tile/board file as attributes in /sys/devices/system/cpu. Other information collected via hypervisor APIs is now placed in /sys/hypervisor. We create a /sys/hypervisor/type file (holding the constant string "tilera") to be parallel with the Xen use of /sys/hypervisor/type holding "xen". We create three top-level files, "version" (the hypervisor's own version), "config_version" (the version of the configuration file), and "hvconfig" (the contents of the configuration file). The remaining information from our old /proc/tile/board and /proc/tile/switch files becomes an attribute group appearing under /sys/hypervisor/board/. Finally, after some feedback from Arnd Bergmann for the previous version of this patch, the /proc/tile/hardwall file is split up into two conceptual parts. First, a directory /proc/tile/hardwall/ which contains one file per active hardwall, each file named after the hardwall's ID and holding a cpulist that says which cpus are enclosed by the hardwall. Second, a /proc/PID file "hardwall" that is either empty (for non-hardwall-using processes) or contains the hardwall ID. Finally, this change pushes the /proc/sys/tile/unaligned_fixup/ directory, with knobs controlling the kernel code for handling the fixup of unaligned exceptions. Reviewed-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
Diffstat (limited to 'arch/tile/kernel')
-rw-r--r--arch/tile/kernel/Makefile2
-rw-r--r--arch/tile/kernel/hardwall.c90
-rw-r--r--arch/tile/kernel/proc.c73
-rw-r--r--arch/tile/kernel/sysfs.c185
4 files changed, 325 insertions, 25 deletions
diff --git a/arch/tile/kernel/Makefile b/arch/tile/kernel/Makefile
index b4c8e8ec45dc..b4dbc057baad 100644
--- a/arch/tile/kernel/Makefile
+++ b/arch/tile/kernel/Makefile
@@ -5,7 +5,7 @@
5extra-y := vmlinux.lds head_$(BITS).o 5extra-y := vmlinux.lds head_$(BITS).o
6obj-y := backtrace.o entry.o init_task.o irq.o messaging.o \ 6obj-y := backtrace.o entry.o init_task.o irq.o messaging.o \
7 pci-dma.o proc.o process.o ptrace.o reboot.o \ 7 pci-dma.o proc.o process.o ptrace.o reboot.o \
8 setup.o signal.o single_step.o stack.o sys.o time.o traps.o \ 8 setup.o signal.o single_step.o stack.o sys.o sysfs.o time.o traps.o \
9 intvec_$(BITS).o regs_$(BITS).o tile-desc_$(BITS).o 9 intvec_$(BITS).o regs_$(BITS).o tile-desc_$(BITS).o
10 10
11obj-$(CONFIG_HARDWALL) += hardwall.o 11obj-$(CONFIG_HARDWALL) += hardwall.o
diff --git a/arch/tile/kernel/hardwall.c b/arch/tile/kernel/hardwall.c
index 3bddef710de4..8c41891aab34 100644
--- a/arch/tile/kernel/hardwall.c
+++ b/arch/tile/kernel/hardwall.c
@@ -40,16 +40,25 @@
40struct hardwall_info { 40struct hardwall_info {
41 struct list_head list; /* "rectangles" list */ 41 struct list_head list; /* "rectangles" list */
42 struct list_head task_head; /* head of tasks in this hardwall */ 42 struct list_head task_head; /* head of tasks in this hardwall */
43 struct cpumask cpumask; /* cpus in the rectangle */
43 int ulhc_x; /* upper left hand corner x coord */ 44 int ulhc_x; /* upper left hand corner x coord */
44 int ulhc_y; /* upper left hand corner y coord */ 45 int ulhc_y; /* upper left hand corner y coord */
45 int width; /* rectangle width */ 46 int width; /* rectangle width */
46 int height; /* rectangle height */ 47 int height; /* rectangle height */
48 int id; /* integer id for this hardwall */
47 int teardown_in_progress; /* are we tearing this one down? */ 49 int teardown_in_progress; /* are we tearing this one down? */
48}; 50};
49 51
50/* Currently allocated hardwall rectangles */ 52/* Currently allocated hardwall rectangles */
51static LIST_HEAD(rectangles); 53static LIST_HEAD(rectangles);
52 54
55/* /proc/tile/hardwall */
56static struct proc_dir_entry *hardwall_proc_dir;
57
58/* Functions to manage files in /proc/tile/hardwall. */
59static void hardwall_add_proc(struct hardwall_info *rect);
60static void hardwall_remove_proc(struct hardwall_info *rect);
61
53/* 62/*
54 * Guard changes to the hardwall data structures. 63 * Guard changes to the hardwall data structures.
55 * This could be finer grained (e.g. one lock for the list of hardwall 64 * This could be finer grained (e.g. one lock for the list of hardwall
@@ -105,6 +114,8 @@ static int setup_rectangle(struct hardwall_info *r, struct cpumask *mask)
105 r->ulhc_y = cpu_y(ulhc); 114 r->ulhc_y = cpu_y(ulhc);
106 r->width = cpu_x(lrhc) - r->ulhc_x + 1; 115 r->width = cpu_x(lrhc) - r->ulhc_x + 1;
107 r->height = cpu_y(lrhc) - r->ulhc_y + 1; 116 r->height = cpu_y(lrhc) - r->ulhc_y + 1;
117 cpumask_copy(&r->cpumask, mask);
118 r->id = ulhc; /* The ulhc cpu id can be the hardwall id. */
108 119
109 /* Width and height must be positive */ 120 /* Width and height must be positive */
110 if (r->width <= 0 || r->height <= 0) 121 if (r->width <= 0 || r->height <= 0)
@@ -388,6 +399,9 @@ static struct hardwall_info *hardwall_create(
388 /* Set up appropriate hardwalling on all affected cpus. */ 399 /* Set up appropriate hardwalling on all affected cpus. */
389 hardwall_setup(rect); 400 hardwall_setup(rect);
390 401
402 /* Create a /proc/tile/hardwall entry. */
403 hardwall_add_proc(rect);
404
391 return rect; 405 return rect;
392} 406}
393 407
@@ -645,6 +659,9 @@ static void hardwall_destroy(struct hardwall_info *rect)
645 /* Restart switch and disable firewall. */ 659 /* Restart switch and disable firewall. */
646 on_each_cpu_mask(&mask, restart_udn_switch, NULL, 1); 660 on_each_cpu_mask(&mask, restart_udn_switch, NULL, 1);
647 661
662 /* Remove the /proc/tile/hardwall entry. */
663 hardwall_remove_proc(rect);
664
648 /* Now free the rectangle from the list. */ 665 /* Now free the rectangle from the list. */
649 spin_lock_irqsave(&hardwall_lock, flags); 666 spin_lock_irqsave(&hardwall_lock, flags);
650 BUG_ON(!list_empty(&rect->task_head)); 667 BUG_ON(!list_empty(&rect->task_head));
@@ -654,35 +671,57 @@ static void hardwall_destroy(struct hardwall_info *rect)
654} 671}
655 672
656 673
657/* 674static int hardwall_proc_show(struct seq_file *sf, void *v)
658 * Dump hardwall state via /proc; initialized in arch/tile/sys/proc.c.
659 */
660int proc_tile_hardwall_show(struct seq_file *sf, void *v)
661{ 675{
662 struct hardwall_info *r; 676 struct hardwall_info *rect = sf->private;
677 char buf[256];
663 678
664 if (udn_disabled) { 679 int rc = cpulist_scnprintf(buf, sizeof(buf), &rect->cpumask);
665 seq_printf(sf, "%dx%d 0,0 pids:\n", smp_width, smp_height); 680 buf[rc++] = '\n';
666 return 0; 681 seq_write(sf, buf, rc);
667 }
668
669 spin_lock_irq(&hardwall_lock);
670 list_for_each_entry(r, &rectangles, list) {
671 struct task_struct *p;
672 seq_printf(sf, "%dx%d %d,%d pids:",
673 r->width, r->height, r->ulhc_x, r->ulhc_y);
674 list_for_each_entry(p, &r->task_head, thread.hardwall_list) {
675 unsigned int cpu = cpumask_first(&p->cpus_allowed);
676 unsigned int x = cpu % smp_width;
677 unsigned int y = cpu / smp_width;
678 seq_printf(sf, " %d@%d,%d", p->pid, x, y);
679 }
680 seq_printf(sf, "\n");
681 }
682 spin_unlock_irq(&hardwall_lock);
683 return 0; 682 return 0;
684} 683}
685 684
685static int hardwall_proc_open(struct inode *inode,
686 struct file *file)
687{
688 return single_open(file, hardwall_proc_show, PDE(inode)->data);
689}
690
691static const struct file_operations hardwall_proc_fops = {
692 .open = hardwall_proc_open,
693 .read = seq_read,
694 .llseek = seq_lseek,
695 .release = single_release,
696};
697
698static void hardwall_add_proc(struct hardwall_info *rect)
699{
700 char buf[64];
701 snprintf(buf, sizeof(buf), "%d", rect->id);
702 proc_create_data(buf, 0444, hardwall_proc_dir,
703 &hardwall_proc_fops, rect);
704}
705
706static void hardwall_remove_proc(struct hardwall_info *rect)
707{
708 char buf[64];
709 snprintf(buf, sizeof(buf), "%d", rect->id);
710 remove_proc_entry(buf, hardwall_proc_dir);
711}
712
713int proc_pid_hardwall(struct task_struct *task, char *buffer)
714{
715 struct hardwall_info *rect = task->thread.hardwall;
716 return rect ? sprintf(buffer, "%d\n", rect->id) : 0;
717}
718
719void proc_tile_hardwall_init(struct proc_dir_entry *root)
720{
721 if (!udn_disabled)
722 hardwall_proc_dir = proc_mkdir("hardwall", root);
723}
724
686 725
687/* 726/*
688 * Character device support via ioctl/close. 727 * Character device support via ioctl/close.
@@ -716,6 +755,9 @@ static long hardwall_ioctl(struct file *file, unsigned int a, unsigned long b)
716 return -EINVAL; 755 return -EINVAL;
717 return hardwall_deactivate(current); 756 return hardwall_deactivate(current);
718 757
758 case _HARDWALL_GET_ID:
759 return rect ? rect->id : -EINVAL;
760
719 default: 761 default:
720 return -EINVAL; 762 return -EINVAL;
721 } 763 }
diff --git a/arch/tile/kernel/proc.c b/arch/tile/kernel/proc.c
index 2e02c41ddf3b..62d820833c68 100644
--- a/arch/tile/kernel/proc.c
+++ b/arch/tile/kernel/proc.c
@@ -27,6 +27,7 @@
27#include <asm/processor.h> 27#include <asm/processor.h>
28#include <asm/sections.h> 28#include <asm/sections.h>
29#include <asm/homecache.h> 29#include <asm/homecache.h>
30#include <asm/hardwall.h>
30#include <arch/chip.h> 31#include <arch/chip.h>
31 32
32 33
@@ -88,3 +89,75 @@ const struct seq_operations cpuinfo_op = {
88 .stop = c_stop, 89 .stop = c_stop,
89 .show = show_cpuinfo, 90 .show = show_cpuinfo,
90}; 91};
92
93/*
94 * Support /proc/tile directory
95 */
96
97static int __init proc_tile_init(void)
98{
99 struct proc_dir_entry *root = proc_mkdir("tile", NULL);
100 if (root == NULL)
101 return 0;
102
103 proc_tile_hardwall_init(root);
104
105 return 0;
106}
107
108arch_initcall(proc_tile_init);
109
110/*
111 * Support /proc/sys/tile directory
112 */
113
114#ifndef __tilegx__ /* FIXME: GX: no support for unaligned access yet */
115static ctl_table unaligned_subtable[] = {
116 {
117 .procname = "enabled",
118 .data = &unaligned_fixup,
119 .maxlen = sizeof(int),
120 .mode = 0644,
121 .proc_handler = &proc_dointvec
122 },
123 {
124 .procname = "printk",
125 .data = &unaligned_printk,
126 .maxlen = sizeof(int),
127 .mode = 0644,
128 .proc_handler = &proc_dointvec
129 },
130 {
131 .procname = "count",
132 .data = &unaligned_fixup_count,
133 .maxlen = sizeof(int),
134 .mode = 0644,
135 .proc_handler = &proc_dointvec
136 },
137 {}
138};
139
140static ctl_table unaligned_table[] = {
141 {
142 .procname = "unaligned_fixup",
143 .mode = 0555,
144 .child = unaligned_subtable
145 },
146 {}
147};
148#endif
149
150static struct ctl_path tile_path[] = {
151 { .procname = "tile" },
152 { }
153};
154
155static int __init proc_sys_tile_init(void)
156{
157#ifndef __tilegx__ /* FIXME: GX: no support for unaligned access yet */
158 register_sysctl_paths(tile_path, unaligned_table);
159#endif
160 return 0;
161}
162
163arch_initcall(proc_sys_tile_init);
diff --git a/arch/tile/kernel/sysfs.c b/arch/tile/kernel/sysfs.c
new file mode 100644
index 000000000000..b671a86f4515
--- /dev/null
+++ b/arch/tile/kernel/sysfs.c
@@ -0,0 +1,185 @@
1/*
2 * Copyright 2011 Tilera Corporation. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation, version 2.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
11 * NON INFRINGEMENT. See the GNU General Public License for
12 * more details.
13 *
14 * /sys entry support.
15 */
16
17#include <linux/sysdev.h>
18#include <linux/cpu.h>
19#include <linux/slab.h>
20#include <linux/smp.h>
21#include <hv/hypervisor.h>
22
23/* Return a string queried from the hypervisor, truncated to page size. */
24static ssize_t get_hv_confstr(char *page, int query)
25{
26 ssize_t n = hv_confstr(query, (unsigned long)page, PAGE_SIZE - 1);
27 n = n < 0 ? 0 : min(n, (ssize_t)PAGE_SIZE - 1) - 1;
28 if (n)
29 page[n++] = '\n';
30 page[n] = '\0';
31 return n;
32}
33
34static ssize_t chip_width_show(struct sysdev_class *dev,
35 struct sysdev_class_attribute *attr,
36 char *page)
37{
38 return sprintf(page, "%u\n", smp_width);
39}
40static SYSDEV_CLASS_ATTR(chip_width, 0444, chip_width_show, NULL);
41
42static ssize_t chip_height_show(struct sysdev_class *dev,
43 struct sysdev_class_attribute *attr,
44 char *page)
45{
46 return sprintf(page, "%u\n", smp_height);
47}
48static SYSDEV_CLASS_ATTR(chip_height, 0444, chip_height_show, NULL);
49
50static ssize_t chip_serial_show(struct sysdev_class *dev,
51 struct sysdev_class_attribute *attr,
52 char *page)
53{
54 return get_hv_confstr(page, HV_CONFSTR_CHIP_SERIAL_NUM);
55}
56static SYSDEV_CLASS_ATTR(chip_serial, 0444, chip_serial_show, NULL);
57
58static ssize_t chip_revision_show(struct sysdev_class *dev,
59 struct sysdev_class_attribute *attr,
60 char *page)
61{
62 return get_hv_confstr(page, HV_CONFSTR_CHIP_REV);
63}
64static SYSDEV_CLASS_ATTR(chip_revision, 0444, chip_revision_show, NULL);
65
66
67static ssize_t type_show(struct sysdev_class *dev,
68 struct sysdev_class_attribute *attr,
69 char *page)
70{
71 return sprintf(page, "tilera\n");
72}
73static SYSDEV_CLASS_ATTR(type, 0444, type_show, NULL);
74
75#define HV_CONF_ATTR(name, conf) \
76 static ssize_t name ## _show(struct sysdev_class *dev, \
77 struct sysdev_class_attribute *attr, \
78 char *page) \
79 { \
80 return get_hv_confstr(page, conf); \
81 } \
82 static SYSDEV_CLASS_ATTR(name, 0444, name ## _show, NULL);
83
84HV_CONF_ATTR(version, HV_CONFSTR_HV_SW_VER)
85HV_CONF_ATTR(config_version, HV_CONFSTR_HV_CONFIG_VER)
86
87HV_CONF_ATTR(board_part, HV_CONFSTR_BOARD_PART_NUM)
88HV_CONF_ATTR(board_serial, HV_CONFSTR_BOARD_SERIAL_NUM)
89HV_CONF_ATTR(board_revision, HV_CONFSTR_BOARD_REV)
90HV_CONF_ATTR(board_description, HV_CONFSTR_BOARD_DESC)
91HV_CONF_ATTR(mezz_part, HV_CONFSTR_MEZZ_PART_NUM)
92HV_CONF_ATTR(mezz_serial, HV_CONFSTR_MEZZ_SERIAL_NUM)
93HV_CONF_ATTR(mezz_revision, HV_CONFSTR_MEZZ_REV)
94HV_CONF_ATTR(mezz_description, HV_CONFSTR_MEZZ_DESC)
95HV_CONF_ATTR(switch_control, HV_CONFSTR_SWITCH_CONTROL)
96
97static struct attribute *board_attrs[] = {
98 &attr_board_part.attr,
99 &attr_board_serial.attr,
100 &attr_board_revision.attr,
101 &attr_board_description.attr,
102 &attr_mezz_part.attr,
103 &attr_mezz_serial.attr,
104 &attr_mezz_revision.attr,
105 &attr_mezz_description.attr,
106 &attr_switch_control.attr,
107 NULL
108};
109
110static struct attribute_group board_attr_group = {
111 .name = "board",
112 .attrs = board_attrs,
113};
114
115
116static struct bin_attribute hvconfig_bin;
117
118static ssize_t
119hvconfig_bin_read(struct file *filp, struct kobject *kobj,
120 struct bin_attribute *bin_attr,
121 char *buf, loff_t off, size_t count)
122{
123 static size_t size;
124
125 /* Lazily learn the true size (minus the trailing NUL). */
126 if (size == 0)
127 size = hv_confstr(HV_CONFSTR_HV_CONFIG, 0, 0) - 1;
128
129 /* Check and adjust input parameters. */
130 if (off > size)
131 return -EINVAL;
132 if (count > size - off)
133 count = size - off;
134
135 if (count) {
136 /* Get a copy of the hvc and copy out the relevant portion. */
137 char *hvc;
138
139 size = off + count;
140 hvc = kmalloc(size, GFP_KERNEL);
141 if (hvc == NULL)
142 return -ENOMEM;
143 hv_confstr(HV_CONFSTR_HV_CONFIG, (unsigned long)hvc, size);
144 memcpy(buf, hvc + off, count);
145 kfree(hvc);
146 }
147
148 return count;
149}
150
151static int __init create_sysfs_entries(void)
152{
153 struct sysdev_class *cls = &cpu_sysdev_class;
154 int err = 0;
155
156#define create_cpu_attr(name) \
157 if (!err) \
158 err = sysfs_create_file(&cls->kset.kobj, &attr_##name.attr);
159 create_cpu_attr(chip_width);
160 create_cpu_attr(chip_height);
161 create_cpu_attr(chip_serial);
162 create_cpu_attr(chip_revision);
163
164#define create_hv_attr(name) \
165 if (!err) \
166 err = sysfs_create_file(hypervisor_kobj, &attr_##name.attr);
167 create_hv_attr(type);
168 create_hv_attr(version);
169 create_hv_attr(config_version);
170
171 if (!err)
172 err = sysfs_create_group(hypervisor_kobj, &board_attr_group);
173
174 if (!err) {
175 sysfs_bin_attr_init(&hvconfig_bin);
176 hvconfig_bin.attr.name = "hvconfig";
177 hvconfig_bin.attr.mode = S_IRUGO;
178 hvconfig_bin.read = hvconfig_bin_read;
179 hvconfig_bin.size = PAGE_SIZE;
180 err = sysfs_create_bin_file(hypervisor_kobj, &hvconfig_bin);
181 }
182
183 return err;
184}
185subsys_initcall(create_sysfs_entries);