[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20110523170338.GP20052@erda.amd.com>
Date: Mon, 23 May 2011 19:03:38 +0200
From: Robert Richter <robert.richter@....com>
To: Dave Jones <davej@...hat.com>,
Linux Kernel <linux-kernel@...r.kernel.org>
Subject: [PATCH] oprofile, x86: Enable preemption during pci device setup in
IBS init
(modified subject)
On 20.05.11 05:47:24, Robert Richter wrote:
> On 18.05.11 15:17:06, Dave Jones wrote:
> > I just saw this when after I did a 'modprobe oprofile' on my amd64 box.
>
> Thanks for reporting this. This happens in init_ibs(). We are actually
> too strict here with disabling preemption, though we still need it.
> Will change that code.
>
> -Robert
>
> >
> > Dave
> >
> > BUG: sleeping function called from invalid context at mm/slub.c:824
> > in_atomic(): 1, irqs_disabled(): 0, pid: 32357, name: modprobe
> > INFO: lockdep is turned off.
> > Pid: 32357, comm: modprobe Not tainted 2.6.39-rc7+ #14
> > Call Trace:
> > [<ffffffff8104bdc8>] __might_sleep+0x112/0x117
> > [<ffffffff81129693>] kmem_cache_alloc_trace+0x4b/0xe7
> > [<ffffffff81278f14>] kzalloc.constprop.0+0x29/0x2b
> > [<ffffffff81278f4c>] pci_get_subsys+0x36/0x78
> > [<ffffffff81022689>] ? setup_APIC_eilvt+0xfb/0x139
> > [<ffffffff81278fa4>] pci_get_device+0x16/0x18
> > [<ffffffffa06c8b5d>] op_amd_init+0xd3/0x211 [oprofile]
> > [<ffffffffa064d000>] ? 0xffffffffa064cfff
> > [<ffffffffa064d298>] op_nmi_init+0x21e/0x26a [oprofile]
> > [<ffffffffa064d062>] oprofile_arch_init+0xe/0x26 [oprofile]
> > [<ffffffffa064d010>] oprofile_init+0x10/0x42 [oprofile]
> > [<ffffffff81002099>] do_one_initcall+0x7f/0x13a
> > [<ffffffff81096524>] sys_init_module+0x132/0x281
> > [<ffffffff814cc682>] system_call_fastpath+0x16/0x1b
Dave,
the patch below should fix this.
-Robert
>From 3d2606f42984613d324ad3047cf503bcddc3880a Mon Sep 17 00:00:00 2001
From: Robert Richter <robert.richter@....com>
Date: Fri, 20 May 2011 09:46:54 +0200
Subject: [PATCH] oprofile, x86: Enable preemption during pci device setup in
IBS init
IBS initialization is a mix of per-core register access and per-node
pci device setup. Register access should be pinned to the cpu, but pci
setup must run with preemption enabled.
This patch better separates the code into non-/preemptible sections
and fixes sleeping with preemption disabled. See bug message below.
Fixes also freeing the eilvt entry by introducing put_eilvt().
BUG: sleeping function called from invalid context at mm/slub.c:824
in_atomic(): 1, irqs_disabled(): 0, pid: 32357, name: modprobe
INFO: lockdep is turned off.
Pid: 32357, comm: modprobe Not tainted 2.6.39-rc7+ #14
Call Trace:
[<ffffffff8104bdc8>] __might_sleep+0x112/0x117
[<ffffffff81129693>] kmem_cache_alloc_trace+0x4b/0xe7
[<ffffffff81278f14>] kzalloc.constprop.0+0x29/0x2b
[<ffffffff81278f4c>] pci_get_subsys+0x36/0x78
[<ffffffff81022689>] ? setup_APIC_eilvt+0xfb/0x139
[<ffffffff81278fa4>] pci_get_device+0x16/0x18
[<ffffffffa06c8b5d>] op_amd_init+0xd3/0x211 [oprofile]
[<ffffffffa064d000>] ? 0xffffffffa064cfff
[<ffffffffa064d298>] op_nmi_init+0x21e/0x26a [oprofile]
[<ffffffffa064d062>] oprofile_arch_init+0xe/0x26 [oprofile]
[<ffffffffa064d010>] oprofile_init+0x10/0x42 [oprofile]
[<ffffffff81002099>] do_one_initcall+0x7f/0x13a
[<ffffffff81096524>] sys_init_module+0x132/0x281
[<ffffffff814cc682>] system_call_fastpath+0x16/0x1b
Reported-by: Dave Jones <davej@...hat.com>
Cc: <stable@...nel.org> [2.6.37.x]
Signed-off-by: Robert Richter <robert.richter@....com>
---
arch/x86/oprofile/op_model_amd.c | 95 +++++++++++++++++++++----------------
1 files changed, 54 insertions(+), 41 deletions(-)
diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c
index c3b8e24..9fd8a56 100644
--- a/arch/x86/oprofile/op_model_amd.c
+++ b/arch/x86/oprofile/op_model_amd.c
@@ -316,16 +316,23 @@ static void op_amd_stop_ibs(void)
wrmsrl(MSR_AMD64_IBSOPCTL, 0);
}
-static inline int eilvt_is_available(int offset)
+static inline int get_eilvt(int offset)
{
- /* check if we may assign a vector */
return !setup_APIC_eilvt(offset, 0, APIC_EILVT_MSG_NMI, 1);
}
+static inline int put_eilvt(int offset)
+{
+ return !setup_APIC_eilvt(offset, 0, 0, 1);
+}
+
static inline int ibs_eilvt_valid(void)
{
int offset;
u64 val;
+ int valid = 0;
+
+ preempt_disable();
rdmsrl(MSR_AMD64_IBSCTL, val);
offset = val & IBSCTL_LVT_OFFSET_MASK;
@@ -333,16 +340,20 @@ static inline int ibs_eilvt_valid(void)
if (!(val & IBSCTL_LVT_OFFSET_VALID)) {
pr_err(FW_BUG "cpu %d, invalid IBS interrupt offset %d (MSR%08X=0x%016llx)\n",
smp_processor_id(), offset, MSR_AMD64_IBSCTL, val);
- return 0;
+ goto out;
}
- if (!eilvt_is_available(offset)) {
+ if (!get_eilvt(offset)) {
pr_err(FW_BUG "cpu %d, IBS interrupt offset %d not available (MSR%08X=0x%016llx)\n",
smp_processor_id(), offset, MSR_AMD64_IBSCTL, val);
- return 0;
+ goto out;
}
- return 1;
+ valid = 1;
+out:
+ preempt_enable();
+
+ return valid;
}
static inline int get_ibs_offset(void)
@@ -600,67 +611,69 @@ static int setup_ibs_ctl(int ibs_eilvt_off)
static int force_ibs_eilvt_setup(void)
{
- int i;
+ int offset;
int ret;
- /* find the next free available EILVT entry */
- for (i = 1; i < 4; i++) {
- if (!eilvt_is_available(i))
- continue;
- ret = setup_ibs_ctl(i);
- if (ret)
- return ret;
- pr_err(FW_BUG "using offset %d for IBS interrupts\n", i);
- return 0;
+ /*
+ * find the next free available EILVT entry, skip offset 0,
+ * pin search to this cpu
+ */
+ preempt_disable();
+ for (offset = 1; offset < APIC_EILVT_NR_MAX; offset++) {
+ if (get_eilvt(offset))
+ break;
}
+ preempt_enable();
- printk(KERN_DEBUG "No EILVT entry available\n");
-
- return -EBUSY;
-}
-
-static int __init_ibs_nmi(void)
-{
- int ret;
-
- if (ibs_eilvt_valid())
- return 0;
+ if (offset == APIC_EILVT_NR_MAX) {
+ printk(KERN_DEBUG "No EILVT entry available\n");
+ return -EBUSY;
+ }
- ret = force_ibs_eilvt_setup();
+ ret = setup_ibs_ctl(offset);
if (ret)
- return ret;
+ goto out;
- if (!ibs_eilvt_valid())
- return -EFAULT;
+ if (!ibs_eilvt_valid()) {
+ ret = -EFAULT;
+ goto out;
+ }
+ pr_err(FW_BUG "using offset %d for IBS interrupts\n", offset);
pr_err(FW_BUG "workaround enabled for IBS LVT offset\n");
return 0;
+out:
+ preempt_disable();
+ put_eilvt(offset);
+ preempt_enable();
+ return ret;
}
/*
* check and reserve APIC extended interrupt LVT offset for IBS if
* available
- *
- * init_ibs() preforms implicitly cpu-local operations, so pin this
- * thread to its current CPU
*/
static void init_ibs(void)
{
- preempt_disable();
-
ibs_caps = get_ibs_caps();
+
if (!ibs_caps)
+ return;
+
+ if (ibs_eilvt_valid())
goto out;
- if (__init_ibs_nmi() < 0)
- ibs_caps = 0;
- else
- printk(KERN_INFO "oprofile: AMD IBS detected (0x%08x)\n", ibs_caps);
+ if (!force_ibs_eilvt_setup())
+ goto out;
+
+ /* Failed to setup ibs */
+ ibs_caps = 0;
+ return;
out:
- preempt_enable();
+ printk(KERN_INFO "oprofile: AMD IBS detected (0x%08x)\n", ibs_caps);
}
static int (*create_arch_files)(struct super_block *sb, struct dentry *root);
--
1.7.5.rc3
--
Advanced Micro Devices, Inc.
Operating System Research Center
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists