From 2885e25c422fb68208f677f944a45fce8eda2a3c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 2 Feb 2012 10:36:33 -0800 Subject: driver core: cpu: remove kernel warning when removing a cpu With the movement of the cpu sysdev code to be real stuct devices, now when we remove a cpu from the system, the driver core rightfully complains that there is not a release method for this device. For now, paper over this issue by quieting the driver core, but comment this in detail. This will be resolved in future kernels to be solved properly. Reported-by: Konrad Rzeszutek Wilk Tested-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- drivers/base/cpu.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers/base') diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index db87e78d745..23f2c4cd48d 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -208,6 +208,25 @@ static ssize_t print_cpus_offline(struct device *dev, } static DEVICE_ATTR(offline, 0444, print_cpus_offline, NULL); +static void cpu_device_release(struct device *dev) +{ + /* + * This is an empty function to prevent the driver core from spitting a + * warning at us. Yes, I know this is directly opposite of what the + * documentation for the driver core and kobjects say, and the author + * of this code has already been publically ridiculed for doing + * something as foolish as this. However, at this point in time, it is + * the only way to handle the issue of statically allocated cpu + * devices. The different architectures will have their cpu device + * code reworked to properly handle this in the near future, so this + * function will then be changed to correctly free up the memory held + * by the cpu device. + * + * Never copy this way of doing things, or you too will be made fun of + * on the linux-kerenl list, you have been warned. + */ +} + /* * register_cpu - Setup a sysfs device for a CPU. * @cpu - cpu->hotpluggable field set to 1 will generate a control file in @@ -223,6 +242,7 @@ int __cpuinit register_cpu(struct cpu *cpu, int num) cpu->node_id = cpu_to_node(num); cpu->dev.id = num; cpu->dev.bus = &cpu_subsys; + cpu->dev.release = cpu_device_release; error = device_register(&cpu->dev); if (!error && cpu->hotpluggable) register_cpu_control(cpu); -- cgit v1.2.3-70-g09d2 From 321bf4ed5ff5f7c62ef59f33b7eec5b154391f0a Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Mon, 30 Jan 2012 13:57:12 -0800 Subject: drivers/base/memory.c: fix memory_dev_init() long delay One system with 2048g ram, reported soft lockup on recent kernel. [ 34.426749] cpu_dev_init done [ 61.166399] BUG: soft lockup - CPU#0 stuck for 22s! [swapper/0:1] [ 61.166733] Modules linked in: [ 61.166904] irq event stamp: 1935610 [ 61.178431] hardirqs last enabled at (1935609): [] mutex_lock_nested+0x299/0x2b4 [ 61.178923] hardirqs last disabled at (1935610): [] apic_timer_interrupt+0x6b/0x80 [ 61.198767] softirqs last enabled at (1935476): [] __do_softirq+0x195/0x1ab [ 61.218604] softirqs last disabled at (1935471): [] call_softirq+0x1c/0x30 [ 61.238408] CPU 0 [ 61.238549] Modules linked in: [ 61.238744] [ 61.238825] Pid: 1, comm: swapper/0 Not tainted 3.3.0-rc1-tip-yh-02076-g962f689-dirty #171 [ 61.278212] RIP: 0010:[] [] lock_release+0x90/0x9c [ 61.278627] RSP: 0018:ffff883f64dbfd70 EFLAGS: 00000246 [ 61.298287] RAX: ffff883f64dc0000 RBX: 0000000000000000 RCX: 000000000000008b [ 61.298690] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000 [ 61.318383] RBP: ffff883f64dbfda0 R08: 0000000000000001 R09: 000000000000008b [ 61.338215] R10: 0000000000000000 R11: 0000000000000000 R12: ffff883f64dbfd10 [ 61.338610] R13: ffff883f64dc0708 R14: ffff883f64dc0708 R15: ffffffff81095657 [ 61.358299] FS: 0000000000000000(0000) GS:ffff883f7d600000(0000) knlGS:0000000000000000 [ 61.378118] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 61.378450] CR2: 0000000000000000 CR3: 00000000024af000 CR4: 00000000000007f0 [ 61.398144] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 61.417918] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 [ 61.418260] Process swapper/0 (pid: 1, threadinfo ffff883f64dbe000, task ffff883f64dc0000) [ 61.445358] Stack: [ 61.445511] 0000000000000002 ffff897f649ba168 ffff883f64dbfe10 ffff88ff64bb57a8 [ 61.458040] 0000000000000000 0000000000000000 ffff883f64dbfdc0 ffffffff81ceb1b4 [ 61.458491] 000000000011608c ffff88ff64bb58a8 ffff883f64dbfdf0 ffffffff81c57638 [ 61.478215] Call Trace: [ 61.478367] [] _raw_spin_unlock+0x21/0x2e [ 61.497994] [] klist_next+0x9e/0xbc [ 61.498264] [] next_device+0xe/0x1e [ 61.517867] [] subsys_find_device_by_id+0xb7/0xd6 [ 61.518197] [] find_memory_block_hinted+0x3d/0x66 [ 61.537927] [] find_memory_block+0x10/0x12 [ 61.538193] [] add_memory_section+0x35/0x9e [ 61.557932] [] memory_dev_init+0x68/0xda [ 61.558227] [] driver_init+0x97/0xa7 [ 61.577853] [] kernel_init+0xf6/0x1c0 [ 61.578140] [] kernel_thread_helper+0x4/0x10 [ 61.597850] [] ? retint_restore_args+0xe/0xe [ 61.598144] [] ? start_kernel+0x3ab/0x3ab [ 61.617826] [] ? gs_change+0xb/0xb [ 61.618060] Code: 10 48 83 3b 00 eb e8 4c 89 f2 44 89 fe 4c 89 ef e8 e1 fe ff ff 65 48 8b 04 25 40 bc 00 00 c7 80 cc 06 00 00 00 00 00 00 41 54 9d <5e> 5b 41 5c 41 5d 41 5e 41 5f 5d c3 55 48 89 e5 41 57 41 89 cf [ 89.285380] memory_dev_init done Finally it takes about 55s to create 16400 memory entries. Root cause: for x86_64, 2048g (with 2g hole at [2g,4g), and TOP2 will be 2050g), will have 16400 memory block. find_memory_block/subsys_find_device_by_id will be expensive with that many entries. Actually, we don't need to find that memory block for BOOT path. Skip that finding make it get back to normal. [ 34.466696] cpu_dev_init done [ 35.290080] memory_dev_init done Also solved the delay with topology_init when sections_per_block is not 1. Signed-off-by: Yinghai Lu Cc: Kay Sievers Cc: Nathan Fontenot Cc: Robin Holt Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/base/memory.c | 31 ++++++++++++++++++++++++++----- drivers/base/node.c | 8 ++++++++ 2 files changed, 34 insertions(+), 5 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/memory.c b/drivers/base/memory.c index ed5de58c340..9e60dbe9fd9 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -572,19 +572,36 @@ static int init_memory_block(struct memory_block **memory, } static int add_memory_section(int nid, struct mem_section *section, + struct memory_block **mem_p, unsigned long state, enum mem_add_context context) { - struct memory_block *mem; + struct memory_block *mem = NULL; + int scn_nr = __section_nr(section); int ret = 0; mutex_lock(&mem_sysfs_mutex); - mem = find_memory_block(section); + if (context == BOOT) { + /* same memory block ? */ + if (mem_p && *mem_p) + if (scn_nr >= (*mem_p)->start_section_nr && + scn_nr <= (*mem_p)->end_section_nr) { + mem = *mem_p; + kobject_get(&mem->dev.kobj); + } + } else + mem = find_memory_block(section); + if (mem) { mem->section_count++; kobject_put(&mem->dev.kobj); - } else + } else { ret = init_memory_block(&mem, section, state); + /* store memory_block pointer for next loop */ + if (!ret && context == BOOT) + if (mem_p) + *mem_p = mem; + } if (!ret) { if (context == HOTPLUG && @@ -627,7 +644,7 @@ int remove_memory_block(unsigned long node_id, struct mem_section *section, */ int register_new_memory(int nid, struct mem_section *section) { - return add_memory_section(nid, section, MEM_OFFLINE, HOTPLUG); + return add_memory_section(nid, section, NULL, MEM_OFFLINE, HOTPLUG); } int unregister_memory_section(struct mem_section *section) @@ -647,6 +664,7 @@ int __init memory_dev_init(void) int ret; int err; unsigned long block_sz; + struct memory_block *mem = NULL; ret = subsys_system_register(&memory_subsys, NULL); if (ret) @@ -662,7 +680,10 @@ int __init memory_dev_init(void) for (i = 0; i < NR_MEM_SECTIONS; i++) { if (!present_section_nr(i)) continue; - err = add_memory_section(0, __nr_to_section(i), MEM_ONLINE, + /* don't need to reuse memory_block if only one per block */ + err = add_memory_section(0, __nr_to_section(i), + (sections_per_block == 1) ? NULL : &mem, + MEM_ONLINE, BOOT); if (!ret) ret = err; diff --git a/drivers/base/node.c b/drivers/base/node.c index 44f427a6611..90aa2a11a93 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -456,7 +456,15 @@ static int link_mem_sections(int nid) if (!present_section_nr(section_nr)) continue; mem_sect = __nr_to_section(section_nr); + + /* same memblock ? */ + if (mem_blk) + if ((section_nr >= mem_blk->start_section_nr) && + (section_nr <= mem_blk->end_section_nr)) + continue; + mem_blk = find_memory_block_hinted(mem_sect, mem_blk); + ret = register_mem_sect_under_node(mem_blk, nid); if (!err) err = ret; -- cgit v1.2.3-70-g09d2 From 29bb5d4fd3140a7d5d02d858118c74a45f15c296 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 8 Feb 2012 15:11:17 -0800 Subject: driver-core: cpu: fix kobject warning when hotplugging a cpu Due to the sysdev conversion to struct device, the cpu objects get reused when adding a cpu after offlining it, which causes a big warning that the kobject portion is not properly initialized. So clear out the object before we register it again, so all is quiet. Reported-by: Konrad Rzeszutek Wilk Tested-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- drivers/base/cpu.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/base') diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 23f2c4cd48d..4dabf5077c4 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -240,6 +240,7 @@ int __cpuinit register_cpu(struct cpu *cpu, int num) int error; cpu->node_id = cpu_to_node(num); + memset(&cpu->dev, 0x00, sizeof(struct device)); cpu->dev.id = num; cpu->dev.bus = &cpu_subsys; cpu->dev.release = cpu_device_release; -- cgit v1.2.3-70-g09d2 From 61cddc57dc14a5dffa0921d9a24fd68edbb374ac Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 15 Feb 2012 10:23:25 +0100 Subject: regmap: Fix cache defaults initialization from raw cache defaults Currently registers with a value of 0 are ignored when initializing the register defaults from raw defaults. This worked in the past, because registers without a explicit default were assumed to have a default value of 0. This was changed in commit b03622a8 ("regmap: Ensure rbtree syncs registers set to zero properly"). As a result registers, which have a raw default value of 0 are now assumed to have no default. This again can result in unnecessary writes when syncing the cache. It will also result in unnecessary reads for e.g. the first update operation. In the case where readback is not possible this will even let the update operation fail, if the register has not been written to before. So this patch removes the check. Instead it adds a check to ignore raw defaults for registers which are volatile, since those registers are not cached. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/base/regmap/regcache.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/base') diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index 1ead66186b7..d1daa5e9fad 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -53,7 +53,7 @@ static int regcache_hw_init(struct regmap *map) for (count = 0, i = 0; i < map->num_reg_defaults_raw; i++) { val = regcache_get_val(map->reg_defaults_raw, i, map->cache_word_size); - if (!val) + if (regmap_volatile(map, i)) continue; count++; } @@ -70,7 +70,7 @@ static int regcache_hw_init(struct regmap *map) for (i = 0, j = 0; i < map->num_reg_defaults_raw; i++) { val = regcache_get_val(map->reg_defaults_raw, i, map->cache_word_size); - if (!val) + if (regmap_volatile(map, i)) continue; map->reg_defaults[j].reg = i; map->reg_defaults[j].def = val; -- cgit v1.2.3-70-g09d2