From eff3414b7277c4792debfa227f5408238d925f16 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 2 Jun 2007 14:41:44 -0700 Subject: [SPARC64]: Move topology init code into new file, sysfs.c Also, use per-cpu data for struct cpu. Calling kmalloc for each cpu in topology_init() is just plain clumsy. Signed-off-by: David S. Miller diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index d8d1909..f964bf2 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.70 2002/02/09 19:49:30 davem Exp $ +# # Makefile for the linux kernel. # @@ -8,7 +8,7 @@ EXTRA_CFLAGS := -Werror extra-y := head.o init_task.o vmlinux.lds obj-y := process.o setup.o cpu.o idprom.o \ - traps.o auxio.o una_asm.o \ + traps.o auxio.o una_asm.o sysfs.o \ irq.o ptrace.o time.o sys_sparc.o signal.o \ unaligned.o central.o pci.o starfire.o semaphore.o \ power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \ diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index de9b4c1..7490cc6 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -513,22 +513,3 @@ void sun_do_break(void) int serial_console = -1; int stop_a_enabled = 1; - -static int __init topology_init(void) -{ - int i, err; - - err = -ENOMEM; - - for_each_possible_cpu(i) { - struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL); - if (p) { - register_cpu(p, i); - err = 0; - } - } - - return err; -} - -subsys_initcall(topology_init); diff --git a/arch/sparc64/kernel/sysfs.c b/arch/sparc64/kernel/sysfs.c new file mode 100644 index 0000000..0808c21 --- /dev/null +++ b/arch/sparc64/kernel/sysfs.c @@ -0,0 +1,26 @@ +/* sysfs.c: Toplogy sysfs support code for sparc64. + * + * Copyright (C) 2007 David S. Miller + */ +#include +#include +#include +#include +#include + +static DEFINE_PER_CPU(struct cpu, cpu_devices); + +static int __init topology_init(void) +{ + int cpu; + + for_each_possible_cpu(cpu) { + struct cpu *c = &per_cpu(cpu_devices, cpu); + + register_cpu(c, cpu); + } + + return 0; +} + +subsys_initcall(topology_init); -- cgit v0.10.2 From d1f253e60aefe4d3a3e708b3c2a082f3ec1be6f4 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 2 Jun 2007 20:46:36 -0700 Subject: [SPARC64]: Export basic cpu properties via sysfs. Cache sizes, udelay_val, and clock_tick. Signed-off-by: David S. Miller diff --git a/arch/sparc64/kernel/sysfs.c b/arch/sparc64/kernel/sysfs.c index 0808c21..a684a79 100644 --- a/arch/sparc64/kernel/sysfs.c +++ b/arch/sparc64/kernel/sysfs.c @@ -10,14 +10,100 @@ static DEFINE_PER_CPU(struct cpu, cpu_devices); +#define SHOW_ULONG_NAME(NAME, MEMBER) \ +static ssize_t show_##NAME(struct sys_device *dev, char *buf) \ +{ \ + struct cpu *cpu = container_of(dev, struct cpu, sysdev); \ + cpuinfo_sparc *c = &cpu_data(cpu->sysdev.id); \ + return sprintf(buf, "%lu\n", c->MEMBER); \ +} + +#define SHOW_UINT_NAME(NAME, MEMBER) \ +static ssize_t show_##NAME(struct sys_device *dev, char *buf) \ +{ \ + struct cpu *cpu = container_of(dev, struct cpu, sysdev); \ + cpuinfo_sparc *c = &cpu_data(cpu->sysdev.id); \ + return sprintf(buf, "%u\n", c->MEMBER); \ +} + +SHOW_ULONG_NAME(clock_tick, clock_tick); +SHOW_ULONG_NAME(udelay_val, udelay_val); +SHOW_UINT_NAME(l1_dcache_size, dcache_size); +SHOW_UINT_NAME(l1_dcache_line_size, dcache_line_size); +SHOW_UINT_NAME(l1_icache_size, icache_size); +SHOW_UINT_NAME(l1_icache_line_size, icache_line_size); +SHOW_UINT_NAME(l2_cache_size, ecache_size); +SHOW_UINT_NAME(l2_cache_line_size, ecache_line_size); + +static struct sysdev_attribute cpu_core_attrs[] = { + _SYSDEV_ATTR(clock_tick, 0444, show_clock_tick, NULL), + _SYSDEV_ATTR(udelay_val, 0444, show_udelay_val, NULL), + _SYSDEV_ATTR(l1_dcache_size, 0444, show_l1_dcache_size, NULL), + _SYSDEV_ATTR(l1_dcache_line_size, 0444, show_l1_dcache_line_size, NULL), + _SYSDEV_ATTR(l1_icache_size, 0444, show_l1_icache_size, NULL), + _SYSDEV_ATTR(l1_icache_line_size, 0444, show_l1_icache_line_size, NULL), + _SYSDEV_ATTR(l2_cache_size, 0444, show_l2_cache_size, NULL), + _SYSDEV_ATTR(l2_cache_line_size, 0444, show_l2_cache_line_size, NULL), +}; + +static void register_cpu_online(unsigned int cpu) +{ + struct cpu *c = &per_cpu(cpu_devices, cpu); + struct sys_device *s = &c->sysdev; + int i; + + for (i = 0; i < ARRAY_SIZE(cpu_core_attrs); i++) + sysdev_create_file(s, &cpu_core_attrs[i]); +} + +#ifdef CONFIG_HOTPLUG_CPU +static void unregister_cpu_online(unsigned int cpu) +{ + struct cpu *c = &per_cpu(cpu_devices, cpu); + struct sys_device *s = &c->sysdev; + int i; + + for (i = 0; i < ARRAY_SIZE(cpu_core_attrs); i++) + sysdev_remove_file(s, &cpu_core_attrs[i]); +} +#endif + +static int __cpuinit sysfs_cpu_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned int)(long)hcpu; + + switch (action) { + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: + register_cpu_online(cpu); + break; +#ifdef CONFIG_HOTPLUG_CPU + case CPU_DEAD: + case CPU_DEAD_FROZEN: + unregister_cpu_online(cpu); + break; +#endif + } + return NOTIFY_OK; +} + +static struct notifier_block __cpuinitdata sysfs_cpu_nb = { + .notifier_call = sysfs_cpu_notify, +}; + static int __init topology_init(void) { int cpu; + register_cpu_notifier(&sysfs_cpu_nb); + for_each_possible_cpu(cpu) { struct cpu *c = &per_cpu(cpu_devices, cpu); register_cpu(c, cpu); + if (cpu_online(cpu)) + register_cpu_online(cpu); } return 0; -- cgit v0.10.2 From 48b67356400dd7866c035024aeaa2f804de7cead Mon Sep 17 00:00:00 2001 From: David Miller Date: Sun, 3 Jun 2007 19:07:32 -0700 Subject: [SPARC64]: Fix service channel hypervisor function names. sed 's/scv/svc/' Signed-off-by: David S. Miller diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index ed712e0..5b28315 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -2514,9 +2514,9 @@ sun4v_ncs_request: nop .size sun4v_ncs_request, .-sun4v_ncs_request - .globl sun4v_scv_send - .type sun4v_scv_send,#function -sun4v_scv_send: + .globl sun4v_svc_send + .type sun4v_svc_send,#function +sun4v_svc_send: save %sp, -192, %sp mov %i0, %o0 mov %i1, %o1 @@ -2526,11 +2526,11 @@ sun4v_scv_send: stx %o1, [%i3] ret restore - .size sun4v_scv_send, .-sun4v_scv_send + .size sun4v_svc_send, .-sun4v_svc_send - .globl sun4v_scv_recv - .type sun4v_scv_recv,#function -sun4v_scv_recv: + .globl sun4v_svc_recv + .type sun4v_svc_recv,#function +sun4v_svc_recv: save %sp, -192, %sp mov %i0, %o0 mov %i1, %o1 @@ -2540,33 +2540,33 @@ sun4v_scv_recv: stx %o1, [%i3] ret restore - .size sun4v_scv_recv, .-sun4v_scv_recv + .size sun4v_svc_recv, .-sun4v_svc_recv - .globl sun4v_scv_getstatus - .type sun4v_scv_getstatus,#function -sun4v_scv_getstatus: + .globl sun4v_svc_getstatus + .type sun4v_svc_getstatus,#function +sun4v_svc_getstatus: mov HV_FAST_SVC_GETSTATUS, %o5 mov %o1, %o4 ta HV_FAST_TRAP stx %o1, [%o4] retl nop - .size sun4v_scv_getstatus, .-sun4v_scv_getstatus + .size sun4v_svc_getstatus, .-sun4v_svc_getstatus - .globl sun4v_scv_setstatus - .type sun4v_scv_setstatus,#function -sun4v_scv_setstatus: + .globl sun4v_svc_setstatus + .type sun4v_svc_setstatus,#function +sun4v_svc_setstatus: mov HV_FAST_SVC_SETSTATUS, %o5 ta HV_FAST_TRAP retl nop - .size sun4v_scv_setstatus, .-sun4v_scv_setstatus + .size sun4v_svc_setstatus, .-sun4v_svc_setstatus - .globl sun4v_scv_clrstatus - .type sun4v_scv_clrstatus,#function -sun4v_scv_clrstatus: + .globl sun4v_svc_clrstatus + .type sun4v_svc_clrstatus,#function +sun4v_svc_clrstatus: mov HV_FAST_SVC_CLRSTATUS, %o5 ta HV_FAST_TRAP retl nop - .size sun4v_scv_clrstatus, .-sun4v_scv_clrstatus + .size sun4v_svc_clrstatus, .-sun4v_svc_clrstatus -- cgit v0.10.2 From d887ab3a9b1899f88b8cfba531e726b5fb2ebd14 Mon Sep 17 00:00:00 2001 From: David Miller Date: Sun, 3 Jun 2007 23:38:09 -0700 Subject: [SPARC64]: Provide mmu statistics via sysfs. If the system supports hypervisor based statistics, allow them to be fetched, enabled, and disabled via sysfs. Enable and disable via the boolean: /sys/devices/systems/cpu/cpuN/mmustat_enable Statistic values are provided under: /sys/devices/systems/cpu/cpuN/mmu_status/ Signed-off-by: David S. Miller diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index 5b28315..7d1a118 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -2570,3 +2570,25 @@ sun4v_svc_clrstatus: retl nop .size sun4v_svc_clrstatus, .-sun4v_svc_clrstatus + + .globl sun4v_mmustat_conf + .type sun4v_mmustat_conf,#function +sun4v_mmustat_conf: + mov %o1, %o4 + mov HV_FAST_MMUSTAT_CONF, %o5 + ta HV_FAST_TRAP + stx %o1, [%o4] + retl + nop + .size sun4v_mmustat_conf, .-sun4v_mmustat_conf + + .globl sun4v_mmustat_info + .type sun4v_mmustat_info,#function +sun4v_mmustat_info: + mov %o0, %o4 + mov HV_FAST_MMUSTAT_INFO, %o5 + ta HV_FAST_TRAP + stx %o1, [%o4] + retl + nop + .size sun4v_mmustat_info, .-sun4v_mmustat_info diff --git a/arch/sparc64/kernel/sysfs.c b/arch/sparc64/kernel/sysfs.c index a684a79..cdb1477 100644 --- a/arch/sparc64/kernel/sysfs.c +++ b/arch/sparc64/kernel/sysfs.c @@ -8,32 +8,198 @@ #include #include -static DEFINE_PER_CPU(struct cpu, cpu_devices); +#include +#include + +static DEFINE_PER_CPU(struct hv_mmu_statistics, mmu_stats) __attribute__((aligned(64))); -#define SHOW_ULONG_NAME(NAME, MEMBER) \ +#define SHOW_MMUSTAT_ULONG(NAME) \ static ssize_t show_##NAME(struct sys_device *dev, char *buf) \ { \ - struct cpu *cpu = container_of(dev, struct cpu, sysdev); \ - cpuinfo_sparc *c = &cpu_data(cpu->sysdev.id); \ + struct hv_mmu_statistics *p = &per_cpu(mmu_stats, dev->id); \ + return sprintf(buf, "%lu\n", p->NAME); \ +} \ +static SYSDEV_ATTR(NAME, 0444, show_##NAME, NULL) + +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_8k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_8k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_64k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_64k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_4mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_4mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctx0_256mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctx0_256mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_8k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_8k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_64k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_64k_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_4mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_4mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_hits_ctxnon0_256mb_tte); +SHOW_MMUSTAT_ULONG(immu_tsb_ticks_ctxnon0_256mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_8k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_8k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_64k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_64k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_4mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_4mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctx0_256mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctx0_256mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_8k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_8k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_64k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_64k_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_4mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_4mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_hits_ctxnon0_256mb_tte); +SHOW_MMUSTAT_ULONG(dmmu_tsb_ticks_ctxnon0_256mb_tte); + +static struct attribute *mmu_stat_attrs[] = { + &attr_immu_tsb_hits_ctx0_8k_tte.attr, + &attr_immu_tsb_ticks_ctx0_8k_tte.attr, + &attr_immu_tsb_hits_ctx0_64k_tte.attr, + &attr_immu_tsb_ticks_ctx0_64k_tte.attr, + &attr_immu_tsb_hits_ctx0_4mb_tte.attr, + &attr_immu_tsb_ticks_ctx0_4mb_tte.attr, + &attr_immu_tsb_hits_ctx0_256mb_tte.attr, + &attr_immu_tsb_ticks_ctx0_256mb_tte.attr, + &attr_immu_tsb_hits_ctxnon0_8k_tte.attr, + &attr_immu_tsb_ticks_ctxnon0_8k_tte.attr, + &attr_immu_tsb_hits_ctxnon0_64k_tte.attr, + &attr_immu_tsb_ticks_ctxnon0_64k_tte.attr, + &attr_immu_tsb_hits_ctxnon0_4mb_tte.attr, + &attr_immu_tsb_ticks_ctxnon0_4mb_tte.attr, + &attr_immu_tsb_hits_ctxnon0_256mb_tte.attr, + &attr_immu_tsb_ticks_ctxnon0_256mb_tte.attr, + &attr_dmmu_tsb_hits_ctx0_8k_tte.attr, + &attr_dmmu_tsb_ticks_ctx0_8k_tte.attr, + &attr_dmmu_tsb_hits_ctx0_64k_tte.attr, + &attr_dmmu_tsb_ticks_ctx0_64k_tte.attr, + &attr_dmmu_tsb_hits_ctx0_4mb_tte.attr, + &attr_dmmu_tsb_ticks_ctx0_4mb_tte.attr, + &attr_dmmu_tsb_hits_ctx0_256mb_tte.attr, + &attr_dmmu_tsb_ticks_ctx0_256mb_tte.attr, + &attr_dmmu_tsb_hits_ctxnon0_8k_tte.attr, + &attr_dmmu_tsb_ticks_ctxnon0_8k_tte.attr, + &attr_dmmu_tsb_hits_ctxnon0_64k_tte.attr, + &attr_dmmu_tsb_ticks_ctxnon0_64k_tte.attr, + &attr_dmmu_tsb_hits_ctxnon0_4mb_tte.attr, + &attr_dmmu_tsb_ticks_ctxnon0_4mb_tte.attr, + &attr_dmmu_tsb_hits_ctxnon0_256mb_tte.attr, + &attr_dmmu_tsb_ticks_ctxnon0_256mb_tte.attr, + NULL, +}; + +static struct attribute_group mmu_stat_group = { + .attrs = mmu_stat_attrs, + .name = "mmu_stats", +}; + +/* XXX convert to rusty's on_one_cpu */ +static unsigned long run_on_cpu(unsigned long cpu, + unsigned long (*func)(unsigned long), + unsigned long arg) +{ + cpumask_t old_affinity = current->cpus_allowed; + unsigned long ret; + + /* should return -EINVAL to userspace */ + if (set_cpus_allowed(current, cpumask_of_cpu(cpu))) + return 0; + + ret = func(arg); + + set_cpus_allowed(current, old_affinity); + + return ret; +} + +static unsigned long read_mmustat_enable(unsigned long junk) +{ + unsigned long ra = 0; + + sun4v_mmustat_info(&ra); + + return ra != 0; +} + +static unsigned long write_mmustat_enable(unsigned long val) +{ + unsigned long ra, orig_ra; + + if (val) + ra = __pa(&per_cpu(mmu_stats, smp_processor_id())); + else + ra = 0UL; + + return sun4v_mmustat_conf(ra, &orig_ra); +} + +static ssize_t show_mmustat_enable(struct sys_device *s, char *buf) +{ + unsigned long val = run_on_cpu(s->id, read_mmustat_enable, 0); + return sprintf(buf, "%lx\n", val); +} + +static ssize_t store_mmustat_enable(struct sys_device *s, const char *buf, size_t count) +{ + unsigned long val, err; + int ret = sscanf(buf, "%ld", &val); + + if (ret != 1) + return -EINVAL; + + err = run_on_cpu(s->id, write_mmustat_enable, val); + if (err) + return -EIO; + + return count; +} + +static SYSDEV_ATTR(mmustat_enable, 0644, show_mmustat_enable, store_mmustat_enable); + +static int mmu_stats_supported; + +static int register_mmu_stats(struct sys_device *s) +{ + if (!mmu_stats_supported) + return 0; + sysdev_create_file(s, &attr_mmustat_enable); + return sysfs_create_group(&s->kobj, &mmu_stat_group); +} + +#ifdef CONFIG_HOTPLUG_CPU +static void unregister_mmu_stats(struct sys_device *s) +{ + if (!mmu_stats_supported) + return; + sysfs_remove_group(&s->kobj, &mmu_stat_group); + sysdev_remove_file(s, &attr_mmustat_enable); +} +#endif + +#define SHOW_CPUDATA_ULONG_NAME(NAME, MEMBER) \ +static ssize_t show_##NAME(struct sys_device *dev, char *buf) \ +{ \ + cpuinfo_sparc *c = &cpu_data(dev->id); \ return sprintf(buf, "%lu\n", c->MEMBER); \ } -#define SHOW_UINT_NAME(NAME, MEMBER) \ +#define SHOW_CPUDATA_UINT_NAME(NAME, MEMBER) \ static ssize_t show_##NAME(struct sys_device *dev, char *buf) \ { \ - struct cpu *cpu = container_of(dev, struct cpu, sysdev); \ - cpuinfo_sparc *c = &cpu_data(cpu->sysdev.id); \ + cpuinfo_sparc *c = &cpu_data(dev->id); \ return sprintf(buf, "%u\n", c->MEMBER); \ } -SHOW_ULONG_NAME(clock_tick, clock_tick); -SHOW_ULONG_NAME(udelay_val, udelay_val); -SHOW_UINT_NAME(l1_dcache_size, dcache_size); -SHOW_UINT_NAME(l1_dcache_line_size, dcache_line_size); -SHOW_UINT_NAME(l1_icache_size, icache_size); -SHOW_UINT_NAME(l1_icache_line_size, icache_line_size); -SHOW_UINT_NAME(l2_cache_size, ecache_size); -SHOW_UINT_NAME(l2_cache_line_size, ecache_line_size); +SHOW_CPUDATA_ULONG_NAME(clock_tick, clock_tick); +SHOW_CPUDATA_ULONG_NAME(udelay_val, udelay_val); +SHOW_CPUDATA_UINT_NAME(l1_dcache_size, dcache_size); +SHOW_CPUDATA_UINT_NAME(l1_dcache_line_size, dcache_line_size); +SHOW_CPUDATA_UINT_NAME(l1_icache_size, icache_size); +SHOW_CPUDATA_UINT_NAME(l1_icache_line_size, icache_line_size); +SHOW_CPUDATA_UINT_NAME(l2_cache_size, ecache_size); +SHOW_CPUDATA_UINT_NAME(l2_cache_line_size, ecache_line_size); static struct sysdev_attribute cpu_core_attrs[] = { _SYSDEV_ATTR(clock_tick, 0444, show_clock_tick, NULL), @@ -46,6 +212,8 @@ static struct sysdev_attribute cpu_core_attrs[] = { _SYSDEV_ATTR(l2_cache_line_size, 0444, show_l2_cache_line_size, NULL), }; +static DEFINE_PER_CPU(struct cpu, cpu_devices); + static void register_cpu_online(unsigned int cpu) { struct cpu *c = &per_cpu(cpu_devices, cpu); @@ -54,6 +222,8 @@ static void register_cpu_online(unsigned int cpu) for (i = 0; i < ARRAY_SIZE(cpu_core_attrs); i++) sysdev_create_file(s, &cpu_core_attrs[i]); + + register_mmu_stats(s); } #ifdef CONFIG_HOTPLUG_CPU @@ -63,6 +233,7 @@ static void unregister_cpu_online(unsigned int cpu) struct sys_device *s = &c->sysdev; int i; + unregister_mmu_stats(s); for (i = 0; i < ARRAY_SIZE(cpu_core_attrs); i++) sysdev_remove_file(s, &cpu_core_attrs[i]); } @@ -92,10 +263,24 @@ static struct notifier_block __cpuinitdata sysfs_cpu_nb = { .notifier_call = sysfs_cpu_notify, }; +static void __init check_mmu_stats(void) +{ + unsigned long dummy1, err; + + if (tlb_type != hypervisor) + return; + + err = sun4v_mmustat_info(&dummy1); + if (!err) + mmu_stats_supported = 1; +} + static int __init topology_init(void) { int cpu; + check_mmu_stats(); + register_cpu_notifier(&sysfs_cpu_nb); for_each_possible_cpu(cpu) { diff --git a/include/asm-sparc64/hypervisor.h b/include/asm-sparc64/hypervisor.h index 4a43075..5c2f9d4 100644 --- a/include/asm-sparc64/hypervisor.h +++ b/include/asm-sparc64/hypervisor.h @@ -2798,6 +2798,11 @@ struct hv_mmu_statistics { */ #define HV_FAST_MMUSTAT_INFO 0x103 +#ifndef __ASSEMBLY__ +extern unsigned long sun4v_mmustat_conf(unsigned long ra, unsigned long *orig_ra); +extern unsigned long sun4v_mmustat_info(unsigned long *ra); +#endif + /* NCS crypto services */ /* ncs_request() sub-function numbers */ -- cgit v0.10.2 From f78eae2e6f5d1eb05f76a45486286445b916bd92 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 4 Jun 2007 17:01:39 -0700 Subject: [SPARC64]: Proper multi-core scheduling support. The scheduling domain hierarchy is: all cpus --> cpus that share an instruction cache --> cpus that share an integer execution unit Signed-off-by: David S. Miller diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index bd00f89..89a1b46 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -396,6 +396,15 @@ config SCHED_SMT when dealing with UltraSPARC cpus at a cost of slightly increased overhead in some places. If unsure say N here. +config SCHED_MC + bool "Multi-core scheduler support" + depends on SMP + default y + help + Multi-core scheduler support improves the CPU scheduler's decision + making when dealing with multi-core CPU chips at a cost of slightly + increased overhead in some places. If unsure say N here. + source "kernel/Kconfig.preempt" config CMDLINE_BOOL diff --git a/arch/sparc64/kernel/mdesc.c b/arch/sparc64/kernel/mdesc.c index 9246c2c..1b5db4b 100644 --- a/arch/sparc64/kernel/mdesc.c +++ b/arch/sparc64/kernel/mdesc.c @@ -473,6 +473,53 @@ static void __init set_core_ids(void) } } +static void __init mark_proc_ids(struct mdesc_node *mp, int proc_id) +{ + int i; + + for (i = 0; i < mp->num_arcs; i++) { + struct mdesc_node *t = mp->arcs[i].arc; + const u64 *id; + + if (strcmp(mp->arcs[i].name, "back")) + continue; + + if (strcmp(t->name, "cpu")) + continue; + + id = md_get_property(t, "id", NULL); + if (*id < NR_CPUS) + cpu_data(*id).proc_id = proc_id; + } +} + +static void __init __set_proc_ids(const char *exec_unit_name) +{ + struct mdesc_node *mp; + int idx; + + idx = 0; + md_for_each_node_by_name(mp, exec_unit_name) { + const char *type; + int len; + + type = md_get_property(mp, "type", &len); + if (!find_in_proplist(type, "int", len) && + !find_in_proplist(type, "integer", len)) + continue; + + mark_proc_ids(mp, idx); + + idx++; + } +} + +static void __init set_proc_ids(void) +{ + __set_proc_ids("exec_unit"); + __set_proc_ids("exec-unit"); +} + static void __init get_one_mondo_bits(const u64 *p, unsigned int *mask, unsigned char def) { u64 val; @@ -574,9 +621,11 @@ static void __init mdesc_fill_in_cpu_data(void) #endif c->core_id = 0; + c->proc_id = -1; } set_core_ids(); + set_proc_ids(); smp_fill_in_sib_core_maps(); } diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index dad4b3b..928aba3d 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -1800,6 +1800,7 @@ static void __init of_fill_in_cpu_data(void) cpu_data(cpuid).core_id = 0; } + cpu_data(cpuid).proc_id = -1; #ifdef CONFIG_SMP cpu_set(cpuid, cpu_present_map); diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index c550bba..68a45ac 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -51,6 +51,8 @@ cpumask_t cpu_online_map __read_mostly = CPU_MASK_NONE; cpumask_t phys_cpu_present_map __read_mostly = CPU_MASK_NONE; cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = CPU_MASK_NONE }; +cpumask_t cpu_core_map[NR_CPUS] __read_mostly = + { [0 ... NR_CPUS-1] = CPU_MASK_NONE }; static cpumask_t smp_commenced_mask; static cpumask_t cpu_callout_map; @@ -1217,13 +1219,28 @@ void __devinit smp_fill_in_sib_core_maps(void) unsigned int j; if (cpu_data(i).core_id == 0) { - cpu_set(i, cpu_sibling_map[i]); + cpu_set(i, cpu_core_map[i]); continue; } for_each_possible_cpu(j) { if (cpu_data(i).core_id == cpu_data(j).core_id) + cpu_set(j, cpu_core_map[i]); + } + } + + for_each_possible_cpu(i) { + unsigned int j; + + if (cpu_data(i).proc_id == -1) { + cpu_set(i, cpu_sibling_map[i]); + continue; + } + + for_each_possible_cpu(j) { + if (cpu_data(i).proc_id == + cpu_data(j).proc_id) cpu_set(j, cpu_sibling_map[i]); } } diff --git a/include/asm-sparc64/cpudata.h b/include/asm-sparc64/cpudata.h index 03c385d..445026f 100644 --- a/include/asm-sparc64/cpudata.h +++ b/include/asm-sparc64/cpudata.h @@ -31,7 +31,7 @@ typedef struct { unsigned int ecache_size; unsigned int ecache_line_size; int core_id; - unsigned int __pad3; + int proc_id; } cpuinfo_sparc; DECLARE_PER_CPU(cpuinfo_sparc, __cpu_data); diff --git a/include/asm-sparc64/smp.h b/include/asm-sparc64/smp.h index f76e149..5400212 100644 --- a/include/asm-sparc64/smp.h +++ b/include/asm-sparc64/smp.h @@ -33,6 +33,7 @@ extern cpumask_t phys_cpu_present_map; #define cpu_possible_map phys_cpu_present_map extern cpumask_t cpu_sibling_map[NR_CPUS]; +extern cpumask_t cpu_core_map[NR_CPUS]; /* * General functions that each host system must provide. diff --git a/include/asm-sparc64/topology.h b/include/asm-sparc64/topology.h index e0d450d..4880f7c 100644 --- a/include/asm-sparc64/topology.h +++ b/include/asm-sparc64/topology.h @@ -1,12 +1,19 @@ #ifndef _ASM_SPARC64_TOPOLOGY_H #define _ASM_SPARC64_TOPOLOGY_H +#ifdef CONFIG_SMP #include -#define smt_capable() (tlb_type == hypervisor) - -#include +#define topology_physical_package_id(cpu) (cpu_data(cpu).proc_id) #define topology_core_id(cpu) (cpu_data(cpu).core_id) +#define topology_core_siblings(cpu) (cpu_core_map[cpu]) #define topology_thread_siblings(cpu) (cpu_sibling_map[cpu]) +#define mc_capable() (tlb_type == hypervisor) +#define smt_capable() (tlb_type == hypervisor) +#endif /* CONFIG_SMP */ + +#include + +#define cpu_coregroup_map(cpu) (cpu_core_map[cpu]) #endif /* _ASM_SPARC64_TOPOLOGY_H */ -- cgit v0.10.2 From 5cd342df96e911fb8135fb3d58f33c2c5af9ffab Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 4 Jun 2007 21:35:18 -0700 Subject: [SPARC64]: Make core and sibling groups equal on UltraSPARC-IV. Signed-off-by: David S. Miller diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index 928aba3d..172387d 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -1781,6 +1781,7 @@ static void __init of_fill_in_cpu_data(void) } cpu_data(cpuid).core_id = portid + 1; + cpu_data(cpuid).proc_id = portid; } else { cpu_data(cpuid).dcache_size = of_getintprop_default(dp, "dcache-size", 16 * 1024); @@ -1799,8 +1800,8 @@ static void __init of_fill_in_cpu_data(void) of_getintprop_default(dp, "ecache-line-size", 64); cpu_data(cpuid).core_id = 0; + cpu_data(cpuid).proc_id = -1; } - cpu_data(cpuid).proc_id = -1; #ifdef CONFIG_SMP cpu_set(cpuid, cpu_present_map); -- cgit v0.10.2 From a2f9f6bbb30e60ee9f9f83cede960123a65876a2 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 4 Jun 2007 21:48:33 -0700 Subject: [SPARC64]: Fix {mc,smt}_capable(). It's not just sun4v hypervisor platforms that should return true for this, sun4u with UltraSPARC-IV should return true too. Signed-off-by: David S. Miller diff --git a/arch/sparc64/kernel/mdesc.c b/arch/sparc64/kernel/mdesc.c index 1b5db4b..f0e16045 100644 --- a/arch/sparc64/kernel/mdesc.c +++ b/arch/sparc64/kernel/mdesc.c @@ -624,6 +624,10 @@ static void __init mdesc_fill_in_cpu_data(void) c->proc_id = -1; } +#ifdef CONFIG_SMP + sparc64_multi_core = 1; +#endif + set_core_ids(); set_proc_ids(); diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index 172387d..6f4a528 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -1782,6 +1782,9 @@ static void __init of_fill_in_cpu_data(void) cpu_data(cpuid).core_id = portid + 1; cpu_data(cpuid).proc_id = portid; +#ifdef CONFIG_SMP + sparc64_multi_core = 1; +#endif } else { cpu_data(cpuid).dcache_size = of_getintprop_default(dp, "dcache-size", 16 * 1024); diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 68a45ac..4dcd7d0 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -44,6 +44,8 @@ extern void calibrate_delay(void); +int sparc64_multi_core __read_mostly; + /* Please don't make this stuff initdata!!! --DaveM */ unsigned char boot_cpu_id; diff --git a/include/asm-sparc64/smp.h b/include/asm-sparc64/smp.h index 5400212..4fb8c4b 100644 --- a/include/asm-sparc64/smp.h +++ b/include/asm-sparc64/smp.h @@ -34,6 +34,7 @@ extern cpumask_t phys_cpu_present_map; extern cpumask_t cpu_sibling_map[NR_CPUS]; extern cpumask_t cpu_core_map[NR_CPUS]; +extern int sparc64_multi_core; /* * General functions that each host system must provide. diff --git a/include/asm-sparc64/topology.h b/include/asm-sparc64/topology.h index 4880f7c..290ac75 100644 --- a/include/asm-sparc64/topology.h +++ b/include/asm-sparc64/topology.h @@ -2,14 +2,12 @@ #define _ASM_SPARC64_TOPOLOGY_H #ifdef CONFIG_SMP -#include - #define topology_physical_package_id(cpu) (cpu_data(cpu).proc_id) #define topology_core_id(cpu) (cpu_data(cpu).core_id) #define topology_core_siblings(cpu) (cpu_core_map[cpu]) #define topology_thread_siblings(cpu) (cpu_sibling_map[cpu]) -#define mc_capable() (tlb_type == hypervisor) -#define smt_capable() (tlb_type == hypervisor) +#define mc_capable() (sparc64_multi_core) +#define smt_capable() (sparc64_multi_core) #endif /* CONFIG_SMP */ #include -- cgit v0.10.2 From f04dbac2623439e8e15abf55742769af0280c919 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 4 Jun 2007 23:32:23 -0700 Subject: [SPARC64]: Fill in gaps in non-PCI dma_*() NOP implementation. Signed-off-by: David S. Miller diff --git a/include/asm-sparc64/dma-mapping.h b/include/asm-sparc64/dma-mapping.h index 9329429..4e21c2f 100644 --- a/include/asm-sparc64/dma-mapping.h +++ b/include/asm-sparc64/dma-mapping.h @@ -162,6 +162,22 @@ dma_mapping_error(dma_addr_t dma_addr) #else struct device; +struct page; +struct scatterlist; + +static inline int +dma_supported(struct device *dev, u64 mask) +{ + BUG(); + return 0; +} + +static inline int +dma_set_mask(struct device *dev, u64 dma_mask) +{ + BUG(); + return 0; +} static inline void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag) @@ -176,6 +192,52 @@ static inline void dma_free_coherent(struct device *dev, size_t size, BUG(); } +static inline dma_addr_t +dma_map_single(struct device *dev, void *cpu_addr, size_t size, + enum dma_data_direction direction) +{ + BUG(); + return 0; +} + +static inline void +dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, + enum dma_data_direction direction) +{ + BUG(); +} + +static inline dma_addr_t +dma_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + BUG(); + return 0; +} + +static inline void +dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, + enum dma_data_direction direction) +{ + BUG(); +} + +static inline int +dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction direction) +{ + BUG(); + return 0; +} + +static inline void +dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, + enum dma_data_direction direction) +{ + BUG(); +} + static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, enum dma_data_direction direction) @@ -190,6 +252,27 @@ dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t siz BUG(); } +static inline void +dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ + BUG(); +} + +static inline void +dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ + BUG(); +} + +static inline int +dma_mapping_error(dma_addr_t dma_addr) +{ + BUG(); + return 0; +} + #endif /* PCI */ -- cgit v0.10.2 From 65d8bac3df9516adb17ce9df94a955d3c2c85a51 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 4 Jun 2007 23:33:04 -0700 Subject: [ATA]: Back out bogus (SPARC64 && !PCI) Kconfig depends. Signed-off-by: David S. Miller diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 7d893a6..b4a8d60 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -8,7 +8,6 @@ menuconfig ATA depends on BLOCK depends on !(M32R || M68K) || BROKEN depends on !SUN4 || BROKEN - depends on !(SPARC64 && !PCI) select SCSI ---help--- If you want to use a ATA hard disk, ATA tape drive, ATA CD-ROM or -- cgit v0.10.2 From 353076fee81318d056c7a853b1bf6ad1f81d050d Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Mon, 4 Jun 2007 23:52:45 -0700 Subject: [VIDEO]: Fix section mismatch warning in promcon. Fix the following warnings in promcon: WARNING: o-sparc64/drivers/video/console/built-in.o(.text+0x480): Section mismatch: reference to .init.data:promfont_unitable (between 'promcon_init_unimap' and 'promcon_init') WARNING: o-sparc64/drivers/video/console/built-in.o(.text+0x488): Section mismatch: reference to .init.data:promfont_unitable (between 'promcon_init_unimap' and 'promcon_init') WARNING: o-sparc64/drivers/video/console/built-in.o(.text+0x48c): Section mismatch: reference to .init.data:promfont_unicount (between 'promcon_init_unimap' and 'promcon_init') WARNING: o-sparc64/drivers/video/console/built-in.o(.text+0x490): Section mismatch: reference to .init.data:promfont_unicount (between 'promcon_init_unimap' and 'promcon_init') The warnings happens because the function: promcon_init_unimap() references promfont_unitable and promfont_unicount which are marked __initdata by the conmakehash command in the drivers/video/console/Makefile Fix the warning by removing the __initdata marker on the two variables. Signed-off-by: Sam Ravnborg Signed-off-by: David S. Miller diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile index 9b26dda..ac46cc3 100644 --- a/drivers/video/console/Makefile +++ b/drivers/video/console/Makefile @@ -47,7 +47,7 @@ targets := promcon_tbl.c quiet_cmd_conmakehash = CNMKHSH $@ cmd_conmakehash = scripts/conmakehash $< | \ sed -e '/\#include <[^>]*>/p' -e 's/types/init/' \ - -e 's/dfont\(_uni.*\]\)/promfont\1 __initdata/' > $@ + -e 's/dfont\(_uni.*\]\)/promfont\1 /' > $@ $(obj)/promcon_tbl.c: $(src)/prom.uni $(call cmd,conmakehash) -- cgit v0.10.2 From d2fa9e05e3876198d8ab31624fe84512a0a44b45 Mon Sep 17 00:00:00 2001 From: Antonino Daplas Date: Tue, 5 Jun 2007 13:14:33 -0700 Subject: [VIDEO] ffb: The pseudo_palette is only 16 elements long The pseudo_palette is only 16 elements long. Signed-off-by: Antonino Daplas Signed-off-by: David S. Miller diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c index 1d4e835..3f6c98f 100644 --- a/drivers/video/ffb.c +++ b/drivers/video/ffb.c @@ -656,7 +656,7 @@ static int ffb_setcolreg(unsigned regno, { u32 value; - if (regno >= 256) + if (regno >= 16) return 1; red >>= 8; @@ -903,7 +903,7 @@ ffb_init_fix(struct fb_info *info) struct all_info { struct fb_info info; struct ffb_par par; - u32 pseudo_palette[256]; + u32 pseudo_palette[16]; }; static int ffb_init_one(struct of_device *op) -- cgit v0.10.2 From f2c138638687a7ffbf0d2a0e7addfec7bab9a765 Mon Sep 17 00:00:00 2001 From: Antonino Daplas Date: Tue, 5 Jun 2007 13:15:01 -0700 Subject: [VIDEO] sunxvr2500fb: Fix pseudo_palette array size - the pseudo_palette is only 16 elements long. - the pseudo_palette has only 16 elements. Do not write if regno (the array index) is more than 15. Signed-off-by: Antonino Daplas Signed-off-by: David S. Miller diff --git a/drivers/video/sunxvr2500.c b/drivers/video/sunxvr2500.c index 4316c7f..c3869a9 100644 --- a/drivers/video/sunxvr2500.c +++ b/drivers/video/sunxvr2500.c @@ -28,7 +28,7 @@ struct s3d_info { unsigned int depth; unsigned int fb_size; - u32 pseudo_palette[256]; + u32 pseudo_palette[16]; }; static int __devinit s3d_get_props(struct s3d_info *sp) @@ -52,15 +52,14 @@ static int s3d_setcolreg(unsigned regno, { u32 value; - if (regno >= 256) - return 1; + if (regno < 16) { + red >>= 8; + green >>= 8; + blue >>= 8; - red >>= 8; - green >>= 8; - blue >>= 8; - - value = (blue << 24) | (green << 16) | (red << 8); - ((u32 *)info->pseudo_palette)[regno] = value; + value = (blue << 24) | (green << 16) | (red << 8); + ((u32 *)info->pseudo_palette)[regno] = value; + } return 0; } -- cgit v0.10.2 From e7e8cc5ae63c39dbbbb5f14c5120bdf2d931fac9 Mon Sep 17 00:00:00 2001 From: Antonino Daplas Date: Tue, 5 Jun 2007 13:15:26 -0700 Subject: [VIDEO] sunxvr500fb: Fix pseudo_palette array size - the pseudo_palette is only 16 elements long. - the pseudo_palette has only 16 elements. Do not write if regno (the array index) is more than 15. Signed-off-by: Antonino Daplas Signed-off-by: David S. Miller diff --git a/drivers/video/sunxvr500.c b/drivers/video/sunxvr500.c index 08880a6..71bf3f1 100644 --- a/drivers/video/sunxvr500.c +++ b/drivers/video/sunxvr500.c @@ -50,7 +50,7 @@ struct e3d_info { u32 fb8_0_off; u32 fb8_1_off; - u32 pseudo_palette[256]; + u32 pseudo_palette[16]; }; static int __devinit e3d_get_props(struct e3d_info *ep) @@ -126,7 +126,9 @@ static int e3d_setcolreg(unsigned regno, blue_8 = blue >> 8; value = (blue_8 << 24) | (green_8 << 16) | (red_8 << 8); - ((u32 *)info->pseudo_palette)[regno] = value; + + if (info->fix.visual == FB_VISUAL_TRUECOLOR && regno < 16) + ((u32 *)info->pseudo_palette)[regno] = value; red_10 = red >> 6; -- cgit v0.10.2