Commit f133ecca9cbb31b5e6e9bda27cbe3034fbf656df

Authored by Chris Metcalf
1 parent 7a0287df3e

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>

Showing 7 changed files with 347 additions and 28 deletions Side-by-side Diff

... ... @@ -12,6 +12,7 @@
12 12 select GENERIC_IRQ_PROBE
13 13 select GENERIC_PENDING_IRQ if SMP
14 14 select GENERIC_IRQ_SHOW
  15 + select SYS_HYPERVISOR
15 16  
16 17 # FIXME: investigate whether we need/want these options.
17 18 # select HAVE_IOREMAP_PROT
arch/tile/include/asm/hardwall.h
... ... @@ -40,6 +40,10 @@
40 40 #define HARDWALL_DEACTIVATE \
41 41 _IO(HARDWALL_IOCTL_BASE, _HARDWALL_DEACTIVATE)
42 42  
  43 +#define _HARDWALL_GET_ID 4
  44 +#define HARDWALL_GET_ID \
  45 + _IO(HARDWALL_IOCTL_BASE, _HARDWALL_GET_ID)
  46 +
43 47 #ifndef __KERNEL__
44 48  
45 49 /* This is the canonical name expected by userspace. */
... ... @@ -47,9 +51,14 @@
47 51  
48 52 #else
49 53  
50   -/* Hook for /proc/tile/hardwall. */
51   -struct seq_file;
52   -int proc_tile_hardwall_show(struct seq_file *sf, void *v);
  54 +/* /proc hooks for hardwall. */
  55 +struct proc_dir_entry;
  56 +#ifdef CONFIG_HARDWALL
  57 +void proc_tile_hardwall_init(struct proc_dir_entry *root);
  58 +int proc_pid_hardwall(struct task_struct *task, char *buffer);
  59 +#else
  60 +static inline void proc_tile_hardwall_init(struct proc_dir_entry *root) {}
  61 +#endif
53 62  
54 63 #endif
55 64  
arch/tile/kernel/Makefile
... ... @@ -5,7 +5,7 @@
5 5 extra-y := vmlinux.lds head_$(BITS).o
6 6 obj-y := backtrace.o entry.o init_task.o irq.o messaging.o \
7 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 9 intvec_$(BITS).o regs_$(BITS).o tile-desc_$(BITS).o
10 10  
11 11 obj-$(CONFIG_HARDWALL) += hardwall.o
arch/tile/kernel/hardwall.c
... ... @@ -40,16 +40,25 @@
40 40 struct hardwall_info {
41 41 struct list_head list; /* "rectangles" list */
42 42 struct list_head task_head; /* head of tasks in this hardwall */
  43 + struct cpumask cpumask; /* cpus in the rectangle */
43 44 int ulhc_x; /* upper left hand corner x coord */
44 45 int ulhc_y; /* upper left hand corner y coord */
45 46 int width; /* rectangle width */
46 47 int height; /* rectangle height */
  48 + int id; /* integer id for this hardwall */
47 49 int teardown_in_progress; /* are we tearing this one down? */
48 50 };
49 51  
50 52 /* Currently allocated hardwall rectangles */
51 53 static LIST_HEAD(rectangles);
52 54  
  55 +/* /proc/tile/hardwall */
  56 +static struct proc_dir_entry *hardwall_proc_dir;
  57 +
  58 +/* Functions to manage files in /proc/tile/hardwall. */
  59 +static void hardwall_add_proc(struct hardwall_info *rect);
  60 +static void hardwall_remove_proc(struct hardwall_info *rect);
  61 +
53 62 /*
54 63 * Guard changes to the hardwall data structures.
55 64 * This could be finer grained (e.g. one lock for the list of hardwall
... ... @@ -105,6 +114,8 @@
105 114 r->ulhc_y = cpu_y(ulhc);
106 115 r->width = cpu_x(lrhc) - r->ulhc_x + 1;
107 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 120 /* Width and height must be positive */
110 121 if (r->width <= 0 || r->height <= 0)
... ... @@ -388,6 +399,9 @@
388 399 /* Set up appropriate hardwalling on all affected cpus. */
389 400 hardwall_setup(rect);
390 401  
  402 + /* Create a /proc/tile/hardwall entry. */
  403 + hardwall_add_proc(rect);
  404 +
391 405 return rect;
392 406 }
393 407  
... ... @@ -645,6 +659,9 @@
645 659 /* Restart switch and disable firewall. */
646 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 665 /* Now free the rectangle from the list. */
649 666 spin_lock_irqsave(&hardwall_lock, flags);
650 667 BUG_ON(!list_empty(&rect->task_head));
651 668  
652 669  
653 670  
654 671  
... ... @@ -654,36 +671,58 @@
654 671 }
655 672  
656 673  
657   -/*
658   - * Dump hardwall state via /proc; initialized in arch/tile/sys/proc.c.
659   - */
660   -int proc_tile_hardwall_show(struct seq_file *sf, void *v)
  674 +static int hardwall_proc_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) {
665   - seq_printf(sf, "%dx%d 0,0 pids:\n", smp_width, smp_height);
666   - return 0;
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);
  679 + int rc = cpulist_scnprintf(buf, sizeof(buf), &rect->cpumask);
  680 + buf[rc++] = '\n';
  681 + seq_write(sf, buf, rc);
683 682 return 0;
684 683 }
685 684  
  685 +static int hardwall_proc_open(struct inode *inode,
  686 + struct file *file)
  687 +{
  688 + return single_open(file, hardwall_proc_show, PDE(inode)->data);
  689 +}
686 690  
  691 +static 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 +
  698 +static 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 +
  706 +static 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 +
  713 +int 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 +
  719 +void proc_tile_hardwall_init(struct proc_dir_entry *root)
  720 +{
  721 + if (!udn_disabled)
  722 + hardwall_proc_dir = proc_mkdir("hardwall", root);
  723 +}
  724 +
  725 +
687 726 /*
688 727 * Character device support via ioctl/close.
689 728 */
... ... @@ -715,6 +754,9 @@
715 754 if (current->thread.hardwall != rect)
716 755 return -EINVAL;
717 756 return hardwall_deactivate(current);
  757 +
  758 + case _HARDWALL_GET_ID:
  759 + return rect ? rect->id : -EINVAL;
718 760  
719 761 default:
720 762 return -EINVAL;
arch/tile/kernel/proc.c
... ... @@ -27,6 +27,7 @@
27 27 #include <asm/processor.h>
28 28 #include <asm/sections.h>
29 29 #include <asm/homecache.h>
  30 +#include <asm/hardwall.h>
30 31 #include <arch/chip.h>
31 32  
32 33  
... ... @@ -88,4 +89,76 @@
88 89 .stop = c_stop,
89 90 .show = show_cpuinfo,
90 91 };
  92 +
  93 +/*
  94 + * Support /proc/tile directory
  95 + */
  96 +
  97 +static 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 +
  108 +arch_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 */
  115 +static 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 +
  140 +static ctl_table unaligned_table[] = {
  141 + {
  142 + .procname = "unaligned_fixup",
  143 + .mode = 0555,
  144 + .child = unaligned_subtable
  145 + },
  146 + {}
  147 +};
  148 +#endif
  149 +
  150 +static struct ctl_path tile_path[] = {
  151 + { .procname = "tile" },
  152 + { }
  153 +};
  154 +
  155 +static 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 +
  163 +arch_initcall(proc_sys_tile_init);
arch/tile/kernel/sysfs.c
  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. */
  24 +static 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 +
  34 +static 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 +}
  40 +static SYSDEV_CLASS_ATTR(chip_width, 0444, chip_width_show, NULL);
  41 +
  42 +static 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 +}
  48 +static SYSDEV_CLASS_ATTR(chip_height, 0444, chip_height_show, NULL);
  49 +
  50 +static 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 +}
  56 +static SYSDEV_CLASS_ATTR(chip_serial, 0444, chip_serial_show, NULL);
  57 +
  58 +static 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 +}
  64 +static SYSDEV_CLASS_ATTR(chip_revision, 0444, chip_revision_show, NULL);
  65 +
  66 +
  67 +static 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 +}
  73 +static 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 +
  84 +HV_CONF_ATTR(version, HV_CONFSTR_HV_SW_VER)
  85 +HV_CONF_ATTR(config_version, HV_CONFSTR_HV_CONFIG_VER)
  86 +
  87 +HV_CONF_ATTR(board_part, HV_CONFSTR_BOARD_PART_NUM)
  88 +HV_CONF_ATTR(board_serial, HV_CONFSTR_BOARD_SERIAL_NUM)
  89 +HV_CONF_ATTR(board_revision, HV_CONFSTR_BOARD_REV)
  90 +HV_CONF_ATTR(board_description, HV_CONFSTR_BOARD_DESC)
  91 +HV_CONF_ATTR(mezz_part, HV_CONFSTR_MEZZ_PART_NUM)
  92 +HV_CONF_ATTR(mezz_serial, HV_CONFSTR_MEZZ_SERIAL_NUM)
  93 +HV_CONF_ATTR(mezz_revision, HV_CONFSTR_MEZZ_REV)
  94 +HV_CONF_ATTR(mezz_description, HV_CONFSTR_MEZZ_DESC)
  95 +HV_CONF_ATTR(switch_control, HV_CONFSTR_SWITCH_CONTROL)
  96 +
  97 +static 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 +
  110 +static struct attribute_group board_attr_group = {
  111 + .name = "board",
  112 + .attrs = board_attrs,
  113 +};
  114 +
  115 +
  116 +static struct bin_attribute hvconfig_bin;
  117 +
  118 +static ssize_t
  119 +hvconfig_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 +
  151 +static 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 +}
  185 +subsys_initcall(create_sysfs_entries);
... ... @@ -83,6 +83,9 @@
83 83 #include <linux/pid_namespace.h>
84 84 #include <linux/fs_struct.h>
85 85 #include <linux/slab.h>
  86 +#ifdef CONFIG_HARDWALL
  87 +#include <asm/hardwall.h>
  88 +#endif
86 89 #include "internal.h"
87 90  
88 91 /* NOTE:
... ... @@ -2894,6 +2897,9 @@
2894 2897 #ifdef CONFIG_TASK_IO_ACCOUNTING
2895 2898 INF("io", S_IRUGO, proc_tgid_io_accounting),
2896 2899 #endif
  2900 +#ifdef CONFIG_HARDWALL
  2901 + INF("hardwall", S_IRUGO, proc_pid_hardwall),
  2902 +#endif
2897 2903 };
2898 2904  
2899 2905 static int proc_tgid_base_readdir(struct file * filp,
... ... @@ -3231,6 +3237,9 @@
3231 3237 #endif
3232 3238 #ifdef CONFIG_TASK_IO_ACCOUNTING
3233 3239 INF("io", S_IRUGO, proc_tid_io_accounting),
  3240 +#endif
  3241 +#ifdef CONFIG_HARDWALL
  3242 + INF("hardwall", S_IRUGO, proc_pid_hardwall),
3234 3243 #endif
3235 3244 };
3236 3245