-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
yaml --- r: 88419 b: refs/heads/master c: dbd70fb h: refs/heads/master i: 88417: 3a892a9 88415: 81dc615 v: v3
- Loading branch information
Heiko Carstens
committed
Apr 17, 2008
1 parent
b4e4756
commit 03c7bdf
Showing
9 changed files
with
298 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
--- | ||
refs/heads/master: 7b758389a29cb7f456ec2d27b7a08cb3cc4e1f1c | ||
refs/heads/master: dbd70fb499952d0ba282f0159dafacfc31d50313 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,272 @@ | ||
/* | ||
* arch/s390/kernel/topology.c | ||
* | ||
* Copyright IBM Corp. 2007 | ||
* Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> | ||
*/ | ||
|
||
#include <linux/kernel.h> | ||
#include <linux/mm.h> | ||
#include <linux/init.h> | ||
#include <linux/device.h> | ||
#include <linux/bootmem.h> | ||
#include <linux/sched.h> | ||
#include <linux/workqueue.h> | ||
#include <linux/cpu.h> | ||
#include <linux/smp.h> | ||
#include <asm/delay.h> | ||
#include <asm/s390_ext.h> | ||
#include <asm/sysinfo.h> | ||
|
||
#define CPU_BITS 64 | ||
|
||
struct tl_cpu { | ||
unsigned char reserved[6]; | ||
unsigned short origin; | ||
unsigned long mask[CPU_BITS / BITS_PER_LONG]; | ||
}; | ||
|
||
struct tl_container { | ||
unsigned char reserved[8]; | ||
}; | ||
|
||
union tl_entry { | ||
unsigned char nl; | ||
struct tl_cpu cpu; | ||
struct tl_container container; | ||
}; | ||
|
||
#define NR_MAG 6 | ||
|
||
struct tl_info { | ||
unsigned char reserved0[2]; | ||
unsigned short length; | ||
unsigned char mag[NR_MAG]; | ||
unsigned char reserved1; | ||
unsigned char mnest; | ||
unsigned char reserved2[4]; | ||
union tl_entry tle[0]; | ||
}; | ||
|
||
struct core_info { | ||
struct core_info *next; | ||
cpumask_t mask; | ||
}; | ||
|
||
static void topology_work_fn(struct work_struct *work); | ||
static struct tl_info *tl_info; | ||
static struct core_info core_info; | ||
static int machine_has_topology; | ||
static int machine_has_topology_irq; | ||
static struct timer_list topology_timer; | ||
static void set_topology_timer(void); | ||
static DECLARE_WORK(topology_work, topology_work_fn); | ||
|
||
cpumask_t cpu_coregroup_map(unsigned int cpu) | ||
{ | ||
struct core_info *core = &core_info; | ||
cpumask_t mask; | ||
|
||
cpus_clear(mask); | ||
if (!machine_has_topology) | ||
return cpu_present_map; | ||
mutex_lock(&smp_cpu_state_mutex); | ||
while (core) { | ||
if (cpu_isset(cpu, core->mask)) { | ||
mask = core->mask; | ||
break; | ||
} | ||
core = core->next; | ||
} | ||
mutex_unlock(&smp_cpu_state_mutex); | ||
if (cpus_empty(mask)) | ||
mask = cpumask_of_cpu(cpu); | ||
return mask; | ||
} | ||
|
||
static void add_cpus_to_core(struct tl_cpu *tl_cpu, struct core_info *core) | ||
{ | ||
unsigned int cpu; | ||
|
||
for (cpu = find_first_bit(&tl_cpu->mask[0], CPU_BITS); | ||
cpu < CPU_BITS; | ||
cpu = find_next_bit(&tl_cpu->mask[0], CPU_BITS, cpu + 1)) | ||
{ | ||
unsigned int rcpu, lcpu; | ||
|
||
rcpu = CPU_BITS - 1 - cpu + tl_cpu->origin; | ||
for_each_present_cpu(lcpu) { | ||
if (__cpu_logical_map[lcpu] == rcpu) | ||
cpu_set(lcpu, core->mask); | ||
} | ||
} | ||
} | ||
|
||
static void clear_cores(void) | ||
{ | ||
struct core_info *core = &core_info; | ||
|
||
while (core) { | ||
cpus_clear(core->mask); | ||
core = core->next; | ||
} | ||
} | ||
|
||
static union tl_entry *next_tle(union tl_entry *tle) | ||
{ | ||
if (tle->nl) | ||
return (union tl_entry *)((struct tl_container *)tle + 1); | ||
else | ||
return (union tl_entry *)((struct tl_cpu *)tle + 1); | ||
} | ||
|
||
static void tl_to_cores(struct tl_info *info) | ||
{ | ||
union tl_entry *tle, *end; | ||
struct core_info *core = &core_info; | ||
|
||
mutex_lock(&smp_cpu_state_mutex); | ||
clear_cores(); | ||
tle = (union tl_entry *)&info->tle; | ||
end = (union tl_entry *)((unsigned long)info + info->length); | ||
while (tle < end) { | ||
switch (tle->nl) { | ||
case 5: | ||
case 4: | ||
case 3: | ||
case 2: | ||
break; | ||
case 1: | ||
core = core->next; | ||
break; | ||
case 0: | ||
add_cpus_to_core(&tle->cpu, core); | ||
break; | ||
default: | ||
clear_cores(); | ||
machine_has_topology = 0; | ||
return; | ||
} | ||
tle = next_tle(tle); | ||
} | ||
mutex_unlock(&smp_cpu_state_mutex); | ||
} | ||
|
||
static int ptf(void) | ||
{ | ||
int rc; | ||
|
||
asm volatile( | ||
" .insn rre,0xb9a20000,%1,%1\n" | ||
" ipm %0\n" | ||
" srl %0,28\n" | ||
: "=d" (rc) | ||
: "d" (2UL) : "cc"); | ||
return rc; | ||
} | ||
|
||
void arch_update_cpu_topology(void) | ||
{ | ||
struct tl_info *info = tl_info; | ||
struct sys_device *sysdev; | ||
int cpu; | ||
|
||
if (!machine_has_topology) | ||
return; | ||
ptf(); | ||
stsi(info, 15, 1, 2); | ||
tl_to_cores(info); | ||
for_each_online_cpu(cpu) { | ||
sysdev = get_cpu_sysdev(cpu); | ||
kobject_uevent(&sysdev->kobj, KOBJ_CHANGE); | ||
} | ||
} | ||
|
||
static void topology_work_fn(struct work_struct *work) | ||
{ | ||
arch_reinit_sched_domains(); | ||
} | ||
|
||
static void topology_timer_fn(unsigned long ignored) | ||
{ | ||
if (ptf()) | ||
schedule_work(&topology_work); | ||
set_topology_timer(); | ||
} | ||
|
||
static void set_topology_timer(void) | ||
{ | ||
topology_timer.function = topology_timer_fn; | ||
topology_timer.data = 0; | ||
topology_timer.expires = jiffies + 60 * HZ; | ||
add_timer(&topology_timer); | ||
} | ||
|
||
static void topology_interrupt(__u16 code) | ||
{ | ||
schedule_work(&topology_work); | ||
} | ||
|
||
static int __init init_topology_update(void) | ||
{ | ||
int rc; | ||
|
||
if (!machine_has_topology) | ||
return 0; | ||
init_timer(&topology_timer); | ||
if (machine_has_topology_irq) { | ||
rc = register_external_interrupt(0x2005, topology_interrupt); | ||
if (rc) | ||
return rc; | ||
ctl_set_bit(0, 8); | ||
} | ||
else | ||
set_topology_timer(); | ||
return 0; | ||
} | ||
__initcall(init_topology_update); | ||
|
||
void __init s390_init_cpu_topology(void) | ||
{ | ||
unsigned long long facility_bits; | ||
struct tl_info *info; | ||
struct core_info *core; | ||
int nr_cores; | ||
int i; | ||
|
||
if (stfle(&facility_bits, 1) <= 0) | ||
return; | ||
if (!(facility_bits & (1ULL << 52)) || !(facility_bits & (1ULL << 61))) | ||
return; | ||
machine_has_topology = 1; | ||
|
||
if (facility_bits & (1ULL << 51)) | ||
machine_has_topology_irq = 1; | ||
|
||
tl_info = alloc_bootmem_pages(PAGE_SIZE); | ||
if (!tl_info) | ||
goto error; | ||
info = tl_info; | ||
stsi(info, 15, 1, 2); | ||
|
||
nr_cores = info->mag[NR_MAG - 2]; | ||
for (i = 0; i < info->mnest - 2; i++) | ||
nr_cores *= info->mag[NR_MAG - 3 - i]; | ||
|
||
printk(KERN_INFO "CPU topology:"); | ||
for (i = 0; i < NR_MAG; i++) | ||
printk(" %d", info->mag[i]); | ||
printk(" / %d\n", info->mnest); | ||
|
||
core = &core_info; | ||
for (i = 0; i < nr_cores; i++) { | ||
core->next = alloc_bootmem(sizeof(struct core_info)); | ||
core = core->next; | ||
if (!core) | ||
goto error; | ||
} | ||
return; | ||
error: | ||
machine_has_topology = 0; | ||
machine_has_topology_irq = 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,20 @@ | ||
#ifndef _ASM_S390_TOPOLOGY_H | ||
#define _ASM_S390_TOPOLOGY_H | ||
|
||
#include <linux/cpumask.h> | ||
|
||
#define mc_capable() (1) | ||
|
||
cpumask_t cpu_coregroup_map(unsigned int cpu); | ||
|
||
#ifdef CONFIG_SMP | ||
void s390_init_cpu_topology(void); | ||
#else | ||
static inline void s390_init_cpu_topology(void) | ||
{ | ||
}; | ||
#endif | ||
|
||
#include <asm-generic/topology.h> | ||
|
||
#endif /* _ASM_S390_TOPOLOGY_H */ |