LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* RE: [BUILD BREAK] usb: gadget: fsl_mxc_udc can't compile on current v3.8-rc3
From: Chen Peter-B29397 @ 2013-01-11  8:35 UTC (permalink / raw)
  To: balbi@ti.com, kernel@pengutronix.de
  Cc: Greg KH, linux-usb@vger.kernel.org, linuxppc-dev@lists.ozlabs.org,
	Li Yang-R58472
In-Reply-To: <20130111082731.GA11085@arwen.pp.htv.fi>

=20
> > >
> >
> > I am working on it, but there are two versions, this one and chipidea's=
.
> >
> > Anyway, I will send a patch to fix this problem.
>=20
> if you're already using chipidea, then send me a patch removing this
> driver and focus your effort on chipidea.
>=20
Added Sascha

Now, not all of FSL i.mx USB can move to use chipidea due to some platform =
and USB
PHY problem.

> --
> balbi

^ permalink raw reply

* Re: [BUILD BREAK] usb: gadget: fsl_mxc_udc can't compile on current v3.8-rc3
From: Felipe Balbi @ 2013-01-11  8:27 UTC (permalink / raw)
  To: Chen Peter-B29397
  Cc: Greg KH, linux-usb@vger.kernel.org, linuxppc-dev@lists.ozlabs.org,
	Li Yang-R58472, Felipe Balbi
In-Reply-To: <F281D0F91ED19E4D8E63A7504E8A649803D63ACE@039-SN2MPN1-022.039d.mgd.msft.net>

[-- Attachment #1: Type: text/plain, Size: 690 bytes --]

On Fri, Jan 11, 2013 at 03:23:59AM +0000, Chen Peter-B29397 wrote:
>  
> > > >
> > > > Some recent patch has caused fsl_mxc_udc.c driver to fail compilation
> > > > because it can't find <mach/hardware.h> anymore.
> > > >
> > > > I would like this to be fixed still during this -rc cycle.
> > >
> > > Me too, who's sending a patch?  :)
> > 
> > Hi Peter,
> > 
> > Who is currently working on the i.mx USB?
> > 
> 
> I am working on it, but there are two versions, this one and chipidea's.
> 
> Anyway, I will send a patch to fix this problem.

if you're already using chipidea, then send me a patch removing this
driver and focus your effort on chipidea.

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Interrupt handler not executed
From: R.Patil @ 2013-01-11  7:36 UTC (permalink / raw)
  To: linuxppc-dev

Hello,

We are working on board based on Freescale MPC8313ERDB. We have ported linu=
x 3.0.46 kernel on it. In one of device driver written by us, we need to ta=
ke some action upon asserting IRQ0 interrupt. For this we have written inte=
rrupt handler which takes care of this. We are able register interrupt hand=
ler successfully with the help of 'request=5Firq'. We confirmed this by che=
cking respective entry in '/proc/interrupts'. We have also confirmed assert=
ion of interrupt line (IRQ0) on oscilloscope. The problem is, interrupt han=
dler does not execute upon asserting the interrupt line.    =20

Interesting part is, we have similar requirement in other drivers but for d=
ifferent interrupt lines. The interrupt handler for them executes successfu=
lly. What could be the possible reasons for this behaviour (not invoking IR=
Q0 interrupt handler)? If anybody could give a hint to solve or debug the p=
roblem?

Kind Regards,
Rahul PatilEmail Disclaimer:
  ---------------------------

This e-mail and any files transmitted with it are for the sole use of the i=
ntended recipient(s) and may contain confidential and  privileged informati=
on. Computer viruses can be transmitted via email.The recipient should chec=
k this email and any  attachments for the presence of viruses. The company =
accepts no liability for any damage caused by any virus transmitted by this=
 email.

^ permalink raw reply

* [PATCH] powerpc: added DSCR support to ptrace
From: Alexey Kardashevskiy @ 2013-01-11  6:29 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Alexey Kardashevskiy, Michael Neuling, linuxppc-dev, linux-kernel

The DSCR (aka Data Stream Control Register) is supported on some
server PowerPC chips and allow some control over the prefetch
of data streams.

The kernel already supports DSCR value per thread but there is also
a need in a ability to change it from an external process for
the specific pid.

The patch adds new register index PT_DSCR (index=44) which can be
set/get by:
  ptrace(PTRACE_POKEUSER, traced_process, PT_DSCR << 3, dscr);
  dscr = ptrace(PTRACE_PEEKUSER, traced_process, PT_DSCR << 3, NULL);

The patch does not increase PT_REGS_COUNT as the pt_regs struct has not
been changed.

Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
---
 arch/powerpc/include/uapi/asm/ptrace.h |    1 +
 arch/powerpc/kernel/ptrace.c           |   29 +++++++++++++++++++++++++++++
 2 files changed, 30 insertions(+)

diff --git a/arch/powerpc/include/uapi/asm/ptrace.h b/arch/powerpc/include/uapi/asm/ptrace.h
index ee67a2b..5a4863c 100644
--- a/arch/powerpc/include/uapi/asm/ptrace.h
+++ b/arch/powerpc/include/uapi/asm/ptrace.h
@@ -108,6 +108,7 @@ struct pt_regs {
 #define PT_DAR	41
 #define PT_DSISR 42
 #define PT_RESULT 43
+#define PT_DSCR 44
 #define PT_REGS_COUNT 44
 
 #define PT_FPR0	48	/* each FP reg occupies 2 slots in this space */
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index d4afccc..245c1b6 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -179,6 +179,30 @@ static int set_user_msr(struct task_struct *task, unsigned long msr)
 	return 0;
 }
 
+#ifdef CONFIG_PPC64
+static unsigned long get_user_dscr(struct task_struct *task)
+{
+	return task->thread.dscr;
+}
+
+static int set_user_dscr(struct task_struct *task, unsigned long dscr)
+{
+	task->thread.dscr = dscr;
+	task->thread.dscr_inherit = 1;
+	return 0;
+}
+#else
+static unsigned long get_user_dscr(struct task_struct *task)
+{
+	return -EIO;
+}
+
+static int set_user_dscr(struct task_struct *task, unsigned long dscr)
+{
+	return -EIO;
+}
+#endif
+
 /*
  * We prevent mucking around with the reserved area of trap
  * which are used internally by the kernel.
@@ -200,6 +224,9 @@ unsigned long ptrace_get_reg(struct task_struct *task, int regno)
 	if (regno == PT_MSR)
 		return get_user_msr(task);
 
+	if (regno == PT_DSCR)
+		return get_user_dscr(task);
+
 	if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long)))
 		return ((unsigned long *)task->thread.regs)[regno];
 
@@ -218,6 +245,8 @@ int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data)
 		return set_user_msr(task, data);
 	if (regno == PT_TRAP)
 		return set_user_trap(task, data);
+	if (regno == PT_DSCR)
+		return set_user_dscr(task, data);
 
 	if (regno <= PT_MAX_PUT_REG) {
 		((unsigned long *)task->thread.regs)[regno] = data;
-- 
1.7.10.4

^ permalink raw reply related

* Re: linux-next: build failure after merge of the final tree (powerpc tree related)
From: Michael Neuling @ 2013-01-11  6:04 UTC (permalink / raw)
  To: Stephen Rothwell; +Cc: linux-next, Paul Mackerras, linuxppc-dev, linux-kernel
In-Reply-To: <20130111165241.44a5ede6b24c997810be74e1@canb.auug.org.au>

Stephen Rothwell <sfr@canb.auug.org.au> wrote:

> Hi all,
> 
> After merging the final tree, today's linux-next build (powerpc
> allyesconfig) failed like this:
> 
> arch/powerpc/kernel/kgdb.c: In function 'kgdb_arch_exit':
> arch/powerpc/kernel/kgdb.c:492:2: error: '__debugger_breakx_match' undeclared (first use in this function)
> 
> Caused by commit 9422de3e953d ("powerpc: Hardware breakpoints rewrite to
> handle non DABR breakpoint registers").  I applied "powerpc: Fix typo in
> breakpoint kgdb code" from Mikey for this.
> 
> arch/powerpc/kernel/exceptions-64s.S: Assembler messages:
> arch/powerpc/kernel/exceptions-64s.S:1204: Error: attempt to move .org backwards
> 
> Not sure what caused that - probably a combination of patches adding code
> low down.  I have just left this broken for today.

FWIW I posted this earlier

http://patchwork.ozlabs.org/patch/211184/

Mikey

^ permalink raw reply

* RE: [PATCH] Added device tree binding for TDM and TDM phy
From: Singh Sandeep-B37400 @ 2013-01-11  6:01 UTC (permalink / raw)
  To: Wood Scott-B07421
  Cc: linuxppc-dev@ozlabs.org, devicetree-discuss@lists.ozlabs.org,
	Aggrwal Poonam-B10812
In-Reply-To: <1357847318.27576.9@snotra>

> -----Original Message-----
> From: Wood Scott-B07421
> Sent: Friday, January 11, 2013 1:19 AM
> To: Singh Sandeep-B37400
> Cc: Wood Scott-B07421; devicetree-discuss@lists.ozlabs.org; linuxppc-
> dev@ozlabs.org; Aggrwal Poonam-B10812
> Subject: Re: [PATCH] Added device tree binding for TDM and TDM phy
>=20
> On 01/10/2013 03:24:21 AM, Singh Sandeep-B37400 wrote:
> > > > > +- compatible
> > > > > +    Value type: <string>
> > > > > +    Definition: Should contain generic compatibility like
> > > > "tdm-phy-slic"
> > > > > or
> > > > > +    "tdm-phy-e1" or "tdm-phy-t1".
> > >
> > > Does this "generic" string (plus the other properties) tell you all
> > you
> > > need to know about the device?  If there are other possible
> > "generic"
> > > compatibles, they should be listed or else different people will
> > make up
> > > different strings for the same thing.
> >
> > This property will describe the type of device, and will help TDM
> > framework to know if it is E1/T1/SLIC device. Further details can be
> > extracted from other compatible strings.
> > There are only three generic compatibles field types, which are
> > already mentioned in definition. Do I need to make this thing more
> > clear.
>=20
> The word "like" suggests that there are other possibilites.  It would be
> clearer as:
>=20
> Definition: One of "tdm-phy-slic", "tdm-phy-e1", or "tdm-phy-t1".
>=20
> -Scott
Ok, thanks for your comments.

^ permalink raw reply

* linux-next: build failure after merge of the final tree (powerpc tree related)
From: Stephen Rothwell @ 2013-01-11  5:52 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Paul Mackerras, linuxppc-dev
  Cc: Michael Neuling, linux-next, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 818 bytes --]

Hi all,

After merging the final tree, today's linux-next build (powerpc
allyesconfig) failed like this:

arch/powerpc/kernel/kgdb.c: In function 'kgdb_arch_exit':
arch/powerpc/kernel/kgdb.c:492:2: error: '__debugger_breakx_match' undeclared (first use in this function)

Caused by commit 9422de3e953d ("powerpc: Hardware breakpoints rewrite to
handle non DABR breakpoint registers").  I applied "powerpc: Fix typo in
breakpoint kgdb code" from Mikey for this.

arch/powerpc/kernel/exceptions-64s.S: Assembler messages:
arch/powerpc/kernel/exceptions-64s.S:1204: Error: attempt to move .org backwards

Not sure what caused that - probably a combination of patches adding code
low down.  I have just left this broken for today.

-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* [PATCH] powerpc: added DSCR support to ptrace
From: Alexey Kardashevskiy @ 2013-01-11  4:18 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Alexey Kardashevskiy, linuxppc-dev, Paul Mackerras, linux-kernel

The DSCR (aka Data Stream Control Register) is supported on some
server PowerPC chips and allow some control over the prefetch
of data streams.

The kernel already supports DSCR value per thread but there is also
a need in a ability to change it from an external process for
the specific pid.

The patch adds new register index PT_DSCR (index=44) which can be
set/get by:
  ptrace(PTRACE_POKEUSER, traced_process, PT_DSCR << 3, dscr);
  dscr = ptrace(PTRACE_PEEKUSER, traced_process, PT_DSCR << 3, NULL);

Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
---
 arch/powerpc/include/asm/ptrace.h |    3 +++
 arch/powerpc/kernel/ptrace.c      |   23 ++++++++++++++++++++++-
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h
index 48223f9..85eefa8 100644
--- a/arch/powerpc/include/asm/ptrace.h
+++ b/arch/powerpc/include/asm/ptrace.h
@@ -261,6 +261,9 @@ static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
 #define PT_DAR	41
 #define PT_DSISR 42
 #define PT_RESULT 43
+#ifdef __powerpc64__
+#define PT_DSCR 44
+#endif
 #define PT_REGS_COUNT 44
 
 #define PT_FPR0	48	/* each FP reg occupies 2 slots in this space */
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 05b7dd2..444f22a 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -182,6 +182,20 @@ static int set_user_msr(struct task_struct *task, unsigned long msr)
 	return 0;
 }
 
+#ifdef CONFIG_PPC64
+static unsigned long get_user_dscr(struct task_struct *task)
+{
+	return task->thread.dscr;
+}
+
+static int set_user_dscr(struct task_struct *task, unsigned long dscr)
+{
+	task->thread.dscr = dscr;
+	task->thread.dscr_inherit = 1;
+	return 0;
+}
+#endif
+
 /*
  * We prevent mucking around with the reserved area of trap
  * which are used internally by the kernel.
@@ -203,6 +217,10 @@ unsigned long ptrace_get_reg(struct task_struct *task, int regno)
 	if (regno == PT_MSR)
 		return get_user_msr(task);
 
+#ifdef CONFIG_PPC64
+	if (regno == PT_DSCR)
+		return get_user_dscr(task);
+#endif
 	if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long)))
 		return ((unsigned long *)task->thread.regs)[regno];
 
@@ -221,7 +239,10 @@ int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data)
 		return set_user_msr(task, data);
 	if (regno == PT_TRAP)
 		return set_user_trap(task, data);
-
+#ifdef CONFIG_PPC64
+	if (regno == PT_DSCR)
+		return set_user_dscr(task, data);
+#endif
 	if (regno <= PT_MAX_PUT_REG) {
 		((unsigned long *)task->thread.regs)[regno] = data;
 		return 0;
-- 
1.7.10.4

^ permalink raw reply related

* RE: [BUILD BREAK] usb: gadget: fsl_mxc_udc can't compile on current v3.8-rc3
From: Chen Peter-B29397 @ 2013-01-11  3:23 UTC (permalink / raw)
  To: Li Yang-R58472, Greg KH, Felipe Balbi
  Cc: linux-usb@vger.kernel.org, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <94F013E7935FF44C83EBE7784D62AD3F09526763@039-SN2MPN1-023.039d.mgd.msft.net>

=20
> > >
> > > Some recent patch has caused fsl_mxc_udc.c driver to fail compilation
> > > because it can't find <mach/hardware.h> anymore.
> > >
> > > I would like this to be fixed still during this -rc cycle.
> >
> > Me too, who's sending a patch?  :)
>=20
> Hi Peter,
>=20
> Who is currently working on the i.mx USB?
>=20

I am working on it, but there are two versions, this one and chipidea's.

Anyway, I will send a patch to fix this problem.

> Regards,
> Leo

^ permalink raw reply

* RE: [BUILD BREAK] usb: gadget: fsl_mxc_udc can't compile on current v3.8-rc3
From: Li Yang-R58472 @ 2013-01-11  3:21 UTC (permalink / raw)
  To: Chen Peter-B29397, Greg KH, Felipe Balbi
  Cc: linux-usb@vger.kernel.org, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <20130110143006.GC15787@kroah.com>

> -----Original Message-----
> From: Greg KH [mailto:gregkh@linuxfoundation.org]
> Sent: Thursday, January 10, 2013 10:30 PM
> To: Felipe Balbi
> Cc: Li Yang-R58472; linux-usb@vger.kernel.org; linuxppc-
> dev@lists.ozlabs.org
> Subject: Re: [BUILD BREAK] usb: gadget: fsl_mxc_udc can't compile on
> current v3.8-rc3
>=20
> On Thu, Jan 10, 2013 at 12:08:35PM +0200, Felipe Balbi wrote:
> > Hi,
> >
> > Some recent patch has caused fsl_mxc_udc.c driver to fail compilation
> > because it can't find <mach/hardware.h> anymore.
> >
> > I would like this to be fixed still during this -rc cycle.
>=20
> Me too, who's sending a patch?  :)

Hi Peter,

Who is currently working on the i.mx USB?

Regards,
Leo

^ permalink raw reply

* [PATCH] powerpc: Fix typo in breakpoint kgdb code.
From: Michael Neuling @ 2013-01-11  2:11 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, linuxppc-dev, Ian Munsie
In-Reply-To: <1356048405-20560-7-git-send-email-mikey@neuling.org>

Currently we are getting: 
 arch/powerpc/kernel/kgdb.c: In function 'kgdb_arch_exit':
 arch/powerpc/kernel/kgdb.c:492:2: error: '__debugger_breakx_match' undeclared (first use in this function)
 arch/powerpc/kernel/kgdb.c:492:2: note: each undeclared identifier is reported only once for each function it appears in

Fix the typo.

Signed-off-by: Michael Neuling <mikey@neuling.org>
---
Stupid error.  I guess my defconfigs didn't compile this
code... sorry.

diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c
index a05f0e4..8747447 100644
--- a/arch/powerpc/kernel/kgdb.c
+++ b/arch/powerpc/kernel/kgdb.c
@@ -489,6 +489,6 @@ void kgdb_arch_exit(void)
 	__debugger_bpt = old__debugger_bpt;
 	__debugger_sstep = old__debugger_sstep;
 	__debugger_iabr_match = old__debugger_iabr_match;
-	__debugger_breakx_match = old__debugger_break_match;
+	__debugger_break_match = old__debugger_break_match;
 	__debugger_fault_handler = old__debugger_fault_handler;
 }

^ permalink raw reply related

* Re: [BUILD BREAK] usb: gadget: fsl_mxc_udc can't compile on current v3.8-rc3
From: Peter Chen @ 2013-01-11  1:37 UTC (permalink / raw)
  To: Greg KH; +Cc: linuxppc-dev, linux-usb, Felipe Balbi
In-Reply-To: <20130110143006.GC15787@kroah.com>

On Thu, Jan 10, 2013 at 06:30:06AM -0800, Greg KH wrote:
> On Thu, Jan 10, 2013 at 12:08:35PM +0200, Felipe Balbi wrote:
> > Hi,
> > 
> > Some recent patch has caused fsl_mxc_udc.c driver to fail compilation
> > because it can't find <mach/hardware.h> anymore.
> > 
> > I would like this to be fixed still during this -rc cycle.
> 
> Me too, who's sending a patch?  :)
Let me have a look, and try to send a patch as soon as possible
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

-- 

Best Regards,
Peter Chen

^ permalink raw reply

* [PATCH] powerpc: rename set_break to avoid naming conflict
From: Michael Neuling @ 2013-01-11  0:25 UTC (permalink / raw)
  To: benh; +Cc: Linux PPC dev, Fengguang Wu
In-Reply-To: <20130110105513.GA19224@localhost>

With allmodconfig we are getting:
  drivers/tty/synclink_gt.c:160:12: error: conflicting types for 'set_break'
  arch/powerpc/include/asm/debug.h:49:5: note: previous declaration of 'set_break' was here

  drivers/tty/synclinkmp.c:526:12: error: conflicting types for 'set_break'
  arch/powerpc/include/asm/debug.h:49:5: note: previous declaration of 'set_break' was here

This renames set_break to set_breakpoint to avoid this naming conflict

Signed-off-by: Michael Neuling <mikey@neuling.org>
Reported-by: Fengguang Wu <fengguang.wu@intel.com>

diff --git a/arch/powerpc/include/asm/debug.h b/arch/powerpc/include/asm/debug.h
index 8d85ffb..d251630 100644
--- a/arch/powerpc/include/asm/debug.h
+++ b/arch/powerpc/include/asm/debug.h
@@ -46,7 +46,7 @@ static inline int debugger_break_match(struct pt_regs *regs) { return 0; }
 static inline int debugger_fault_handler(struct pt_regs *regs) { return 0; }
 #endif
 
-int set_break(struct arch_hw_breakpoint *brk);
+int set_breakpoint(struct arch_hw_breakpoint *brk);
 #ifdef CONFIG_PPC_ADV_DEBUG_REGS
 extern void do_send_trap(struct pt_regs *regs, unsigned long address,
 			 unsigned long error_code, int signal_code, int brkpt);
diff --git a/arch/powerpc/include/asm/hw_breakpoint.h b/arch/powerpc/include/asm/hw_breakpoint.h
index 2c91faf..96437e5 100644
--- a/arch/powerpc/include/asm/hw_breakpoint.h
+++ b/arch/powerpc/include/asm/hw_breakpoint.h
@@ -81,7 +81,7 @@ static inline void hw_breakpoint_disable(void)
 	brk.address = 0;
 	brk.type = 0;
 	brk.len = 0;
-	set_break(&brk);
+	set_breakpoint(&brk);
 }
 extern void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs);
 
diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c
index c7483d0..2a3e8dd 100644
--- a/arch/powerpc/kernel/hw_breakpoint.c
+++ b/arch/powerpc/kernel/hw_breakpoint.c
@@ -73,7 +73,7 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
 	 * If so, DABR will be populated in single_step_dabr_instruction().
 	 */
 	if (current->thread.last_hit_ubp != bp)
-		set_break(info);
+		set_breakpoint(info);
 
 	return 0;
 }
@@ -191,7 +191,7 @@ void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs)
 
 	info = counter_arch_bp(tsk->thread.last_hit_ubp);
 	regs->msr &= ~MSR_SE;
-	set_break(info);
+	set_breakpoint(info);
 	tsk->thread.last_hit_ubp = NULL;
 }
 
@@ -276,7 +276,7 @@ int __kprobes hw_breakpoint_handler(struct die_args *args)
 	if (!(info->type & HW_BRK_TYPE_EXTRANEOUS_IRQ))
 		perf_bp_event(bp, regs);
 
-	set_break(info);
+	set_breakpoint(info);
 out:
 	rcu_read_unlock();
 	return rc;
@@ -308,7 +308,7 @@ int __kprobes single_step_dabr_instruction(struct die_args *args)
 	if (!(info->type & HW_BRK_TYPE_EXTRANEOUS_IRQ))
 		perf_bp_event(bp, regs);
 
-	set_break(info);
+	set_breakpoint(info);
 	current->thread.last_hit_ubp = NULL;
 
 	/*
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 8d56452..99550d3 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -366,7 +366,7 @@ static void set_debug_reg_defaults(struct thread_struct *thread)
 {
 	thread->hw_brk.address = 0;
 	thread->hw_brk.type = 0;
-	set_break(&thread->hw_brk);
+	set_breakpoint(&thread->hw_brk);
 }
 #endif /* !CONFIG_HAVE_HW_BREAKPOINT */
 #endif	/* CONFIG_PPC_ADV_DEBUG_REGS */
@@ -427,7 +427,7 @@ static inline int set_dawr(struct arch_hw_breakpoint *brk)
 	return 0;
 }
 
-int set_break(struct arch_hw_breakpoint *brk)
+int set_breakpoint(struct arch_hw_breakpoint *brk)
 {
 	__get_cpu_var(current_brk) = *brk;
 
@@ -538,7 +538,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
  */
 #ifndef CONFIG_HAVE_HW_BREAKPOINT
 	if (unlikely(hw_brk_match(&__get_cpu_var(current_brk), &new->thread.hw_brk)))
-		set_break(&new->thread.hw_brk);
+		set_breakpoint(&new->thread.hw_brk);
 #endif /* CONFIG_HAVE_HW_BREAKPOINT */
 #endif
 
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c
index 1f26956..3003d89 100644
--- a/arch/powerpc/kernel/signal.c
+++ b/arch/powerpc/kernel/signal.c
@@ -132,7 +132,7 @@ static int do_signal(struct pt_regs *regs)
 	 */
 	if (current->thread.hw_brk.address &&
 		current->thread.hw_brk.type)
-		set_break(&current->thread.hw_brk);
+		set_breakpoint(&current->thread.hw_brk);
 #endif
 	/* Re-enable the breakpoints for the signal stack */
 	thread_change_pc(current, regs);
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 529c1ed..13f85de 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -747,7 +747,7 @@ static void insert_cpu_bpts(void)
 		brk.address = dabr.address;
 		brk.type = (dabr.enabled & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
 		brk.len = 8;
-		set_break(&brk);
+		set_breakpoint(&brk);
 	}
 	if (iabr && cpu_has_feature(CPU_FTR_IABR))
 		mtspr(SPRN_IABR, iabr->address

^ permalink raw reply related

* [RFC PATCH v2 05/12] mm: Add memory hotplug handlers
From: Toshi Kani @ 2013-01-10 23:40 UTC (permalink / raw)
  To: rjw, lenb, gregkh, akpm
  Cc: linux-s390, Toshi Kani, jiang.liu, wency, linux-mm, yinghai,
	linux-kernel, linux-acpi, isimatu.yasuaki, srivatsa.bhat,
	guohanjun, bhelgaas, linuxppc-dev
In-Reply-To: <1357861230-29549-1-git-send-email-toshi.kani@hp.com>

Added memory hotplug handlers.  mm_add_execute() onlines requested
memory ranges for hot-add & online operations, and mm_del_execute()
offlines them for hot-delete & offline operations.  They are also
used for rollback as well.

mm_del_validate() fails a hot-delete request if a requested memory
range is non-movable when del_movable_only is set.

Signed-off-by: Toshi Kani <toshi.kani@hp.com>
---
 mm/memory_hotplug.c |  101 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 101 insertions(+)

diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index d04ed87..ed3d829 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -29,6 +29,8 @@
 #include <linux/suspend.h>
 #include <linux/mm_inline.h>
 #include <linux/firmware-map.h>
+#include <linux/module.h>
+#include <linux/sys_hotplug.h>
 
 #include <asm/tlbflush.h>
 
@@ -45,6 +47,13 @@ static void generic_online_page(struct page *page);
 
 static online_page_callback_t online_page_callback = generic_online_page;
 
+static int mm_add_execute(struct shp_request *req, int rollback);
+static int mm_del_execute(struct shp_request *req, int rollback);
+
+static int del_movable_only = 0;
+module_param(del_movable_only, int, 0644);
+MODULE_PARM_DESC(del_movable_only, "Restrict hot-remove to movable memory only");
+
 DEFINE_MUTEX(mem_hotplug_mutex);
 
 void lock_memory_hotplug(void)
@@ -1431,3 +1440,95 @@ int remove_memory(u64 start, u64 size)
 }
 #endif /* CONFIG_MEMORY_HOTREMOVE */
 EXPORT_SYMBOL_GPL(remove_memory);
+
+static int mm_add_execute(struct shp_request *req, int rollback)
+{
+	struct shp_device *shp_dev;
+	struct shp_memory *shp_mem;
+	int ret;
+
+	if (rollback)
+		return mm_del_execute(req, 0);
+
+	list_for_each_entry(shp_dev, &req->dev_list, list) {
+		if (shp_dev->class != SHP_CLS_MEMORY)
+			continue;
+
+		shp_mem = &shp_dev->info.mem;
+
+		ret = add_memory(shp_mem->node,
+				shp_mem->start_addr, shp_mem->length);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int mm_del_validate(struct shp_request *req, int rollback)
+{
+	struct shp_device *shp_dev;
+	struct shp_memory *shp_mem;
+	unsigned long start_pfn, nr_pages;
+
+	if (rollback || !del_movable_only)
+		return 0;
+
+	list_for_each_entry(shp_dev, &req->dev_list, list) {
+		if (shp_dev->class != SHP_CLS_MEMORY)
+			continue;
+
+		shp_mem = &shp_dev->info.mem;
+		start_pfn = shp_mem->start_addr >> PAGE_SHIFT;
+		nr_pages = PAGE_ALIGN(shp_mem->length) >> PAGE_SHIFT;
+
+		/*
+		 * Check if this memory range is removable.  This check is
+		 * enabled when del_movable_only is set.
+		 */
+		if (is_mem_section_removable(start_pfn, nr_pages)) {
+			pr_info("Memory [%#010llx-%#010llx] not removable\n",
+				shp_mem->start_addr,
+				shp_mem->start_addr + shp_mem->length-1);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int mm_del_execute(struct shp_request *req, int rollback)
+{
+	struct shp_device *shp_dev;
+	struct shp_memory *shp_mem;
+	int ret;
+
+	if (rollback)
+		return mm_add_execute(req, 0);
+
+	list_for_each_entry(shp_dev, &req->dev_list, list) {
+		if (shp_dev->class != SHP_CLS_MEMORY)
+			continue;
+
+		shp_mem = &shp_dev->info.mem;
+
+		ret = remove_memory(shp_mem->start_addr, shp_mem->length);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int __init mm_shp_init(void)
+{
+	shp_register_handler(SHP_ADD_EXECUTE, mm_add_execute,
+				SHP_MEM_ADD_EXECUTE_ORDER);
+	shp_register_handler(SHP_DEL_VALIDATE, mm_del_validate,
+				SHP_MEM_DEL_VALIDATE_ORDER);
+	shp_register_handler(SHP_DEL_EXECUTE, mm_del_execute,
+				SHP_MEM_DEL_EXECUTE_ORDER);
+
+	return 0;
+}
+module_init(mm_shp_init);

^ permalink raw reply related

* [RFC PATCH v2 00/12] System device hot-plug framework
From: Toshi Kani @ 2013-01-10 23:40 UTC (permalink / raw)
  To: rjw, lenb, gregkh, akpm
  Cc: linux-s390, Toshi Kani, jiang.liu, wency, linux-mm, yinghai,
	linux-kernel, linux-acpi, isimatu.yasuaki, srivatsa.bhat,
	guohanjun, bhelgaas, linuxppc-dev

This patchset is a prototype of proposed system device hot-plug framework
for design review.  Unlike other hot-plug environments, such as USB and
PCI, there is no common framework for system device hot-plug [1].
Therefore, this patchset is designed to provide a common framework for
hot-plugging and online/offline operations of system devices, such as CPU,
Memory and Node.  While this patchset only supports ACPI-based hot-plug
operations, the framework itself is designed to be platform-neural and
can support other FW architectures as necessary.

This patchset is based on Linus's tree (3.8-rc3).

I have seen a few stability issues with 3.8-rc3 in my testing and will
look into their solutions.

[1] System device hot-plug frameworks for ppc and s390 are implemented
    for specific platforms and products.


Background: System Device Initialization
========================================
System devices, such as CPU and memory, must be initialized during early
boot sequence as they are the essential components to provide low-level
services, ex. scheduling, memory allocation and interrupts, which are
the foundations of the kernel services.  start_kernel() and kernel_init()
manage the boot-up sequence to initialize system devices and low-level
services in pre-defined order as shown below. 

  start_kernel()
    boot_cpu_init()          // init cpu0
    setup_arch()
      efi_init()             // init EFI memory map
      initmem_init()         // init NUMA
      x86_init.paging.pagetable_init() // init page table
      acpi_boot_init()       // parse ACPI MADT table
        :
  kernel_init()
    kernel_init_freeable()
      smp_init()             // init other CPUs
        :
      do_basic_setup()
        driver_init()
          cpu_dev_init()     // build system/cpu tree
          memory_dev_init()  // build system/memory tree
        do_initcalls()
          acpi_init()        // build ACPI device tree

Note that drivers are initialized at the end of the boot sequence as they
depend on the kernel services from system devices.  Hence, while system
devices may be exposed to sysfs with their pseudo drivers, their
initialization may not be fully integrated into the driver structures.  

Overview of the System Device Hot-plug Framework
================================================
Similar to the boot-up sequence, the system device hot-plug framework
provides a sequencer that calls all registered handlers in pre-defined
order for hot-add and hot-delete of system devices.  It allows any modules
initializing system devices in the boot-up sequence to participate in
the hot-plug operations as well.  In high-level, there are two types of
handlers, 1) FW-dependent (ex. ACPI) handlers that enumerate or eject
system devices, and 2) system device (ex. CPU, Memory) management handlers
that online or offline the enumerated system devices.  Online/offline
operations are sub-set of hot-add/delete operations.  The ordering of the
handlers are symmetric between hot-add (online) and hot-delete (offline)
operations.

        hot-add    online
           |    ^    :    ^
  HW Enum/ |    |    :    :
    Eject  |    |    :    :
           |    |    :    :
  Online/  |    |    |    |
  Offline  |    |    |    |
           V    |    V    |
             hot-del   offline

The handlers may not call other handlers directly to exceed their role.
Therefore, the role of the handlers in their modules remains consistent
with their role at the boot-up sequence.  For instance, the ACPI module
may not perform online or offline of system devices.

System Device Hot-plug Operation
================================

Serialized Startup
------------------
The framework provides an interface (hp_submit_req) to request a hot-plug
operation.  All requests are queued to and run on a single work queue.
The framework assures that there is only a single hot-plug or online/
offline operation running at a time.  A single request may however target
to multiple devices.  This makes the execution context of handlers to be
consistent with the boot-up sequence and enables code sharing.

Phased Execution
----------------
The framework proceeds hot-plug and online/offline operations in the 
following three phases.  The modules can register their handlers to each
phase.  The framework also initiates a roll-back operation if any hander
failed in the validate or execute phase.

1) Validate Phase - Handlers validate if they support a given request
without making any changes to target device(s).  They check any known
restrictions and/or prerequisite conditions to their modules, and fail
an unsupported request before making any changes.  For instance, the
memory module may check if a hot-remove request is targeted to movable
ranges.

2) Execute Phase - Handlers make requested change within the scope that
its roll-back is possible in case of a failure.  Execute handlers must
implement their roll-back procedures.

3) Commit Phase - Handlers make the final change that cannot be rolled-back.
For instance, the ACPI module invokes _EJ0 for a hot-remove operation.

System Device Management Modules
================================

CPU Handlers
------------
CPU handlers are provided by the CPU driver in drivers/base/cpu.c, and
perform CPU online/offline procedures when CPU device(s) is added or
deleted during an operation.

Memory Handlers
---------------
Memory handlers are provided by the memory module in mm/memory_hotplug.c,
and perform Memory online/offline procedure when memory device(s) is
added or deleted during an operation.

FW-dependent Modules
====================

ACPI Bus Handlers
-----------------
ACPI bus handlers are provided by the ACPI core in drivers/acpi/bus.c,
and construct/destruct acpi_device object(s) during a hot-plug operation.

ACPI Resource Handlers
----------------------
ACPI resource handlers are provided by the ACPI core in
drivers/acpi/hp_resource.c, and set device resource information to
a request during a hot-plug operation.  This device resource information
is then consumed by the system device management modules for their
online/offline procedure.

ACPI Drivers
------------
ACPI drivers are called from the ACPI core during a hot-plug operation
through the following interfaces.  ACPI drivers are not called from the
framework directly, and remain internal to the ACPI core.  ACPI drivers
may not initiate online/offline of a device.

.add - Construct device-specific information to a given acpi_device.
Called at boot, hot-add and sysfs bind.

.remove - Destruct device-specific information to a given acpi_device.
Called at hot-remove and sysfs unbind.

.resource - Set device-specific resource information to a given hot-plug
request.  Called at hot-add and hot-remove.

---
v2:
 - Documented that system devices may not be initialized through the driver
   structures.
 - Clarified that the framework is for "system device" hotplug by changing
   file name, prefix and documentation.
 - Removed the use of CONFIG_HOTPLUG.
 - Moved ACPI specific definitions to include/acpi/sys_hotplug.h.
 - Implemented shp_unregister_handler() and added locking.
 - Added module parameters, shp_trace and del_movable_only.

---
Toshi Kani (12):
 Add sys_hotplug.h for system device hotplug framework
 ACPI: Add sys_hotplug.h for system device hotplug framework
 drivers/base: Add system device hotplug framework 
 cpu: Add cpu hotplug handlers
 mm: Add memory hotplug handlers
 ACPI: Add ACPI bus hotplug handlers
 ACPI: Add ACPI resource hotplug handler
 ACPI: Update processor driver for hotplug framework
 ACPI: Update memory driver for hotplug framework
 ACPI: Update container driver for hotplug framework
 cpu: Update sysfs cpu/online for hotplug framework
 ACPI: Update sysfs eject for hotplug framework

---
 drivers/acpi/Makefile           |   1 +
 drivers/acpi/acpi_memhotplug.c  | 271 ++++++++++++----------------------
 drivers/acpi/bus.c              | 134 +++++++++++++++++
 drivers/acpi/container.c        |  95 +++++-------
 drivers/acpi/internal.h         |   1 +
 drivers/acpi/processor_driver.c | 150 +++++++++----------
 drivers/acpi/scan.c             | 122 +++-------------
 drivers/acpi/shp_resource.c     |  86 +++++++++++
 drivers/base/Makefile           |   1 +
 drivers/base/cpu.c              | 147 +++++++++++++++++--
 drivers/base/sys_hotplug.c      | 313 ++++++++++++++++++++++++++++++++++++++++
 include/acpi/acpi_bus.h         |   8 +-
 include/acpi/sys_hotplug.h      |  48 ++++++
 include/linux/sys_hotplug.h     | 181 +++++++++++++++++++++++
 mm/memory_hotplug.c             | 101 +++++++++++++
 15 files changed, 1224 insertions(+), 435 deletions(-)

^ permalink raw reply

* [RFC PATCH v2 11/12] cpu: Update sysfs cpu/online for hotplug framework
From: Toshi Kani @ 2013-01-10 23:40 UTC (permalink / raw)
  To: rjw, lenb, gregkh, akpm
  Cc: linux-s390, Toshi Kani, jiang.liu, wency, linux-mm, yinghai,
	linux-kernel, linux-acpi, isimatu.yasuaki, srivatsa.bhat,
	guohanjun, bhelgaas, linuxppc-dev
In-Reply-To: <1357861230-29549-1-git-send-email-toshi.kani@hp.com>

Changed store_online() to request a cpu online or offline
operation by calling shp_submit_req().  It sets a target cpu
device information with shp_add_dev_info() for the request.

Signed-off-by: Toshi Kani <toshi.kani@hp.com>
---
 drivers/base/cpu.c |   40 ++++++++++++++++++++++++++++------------
 1 file changed, 28 insertions(+), 12 deletions(-)

diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 05534ad..cd1cbdc 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -41,27 +41,43 @@ static ssize_t __ref store_online(struct device *dev,
 				  const char *buf, size_t count)
 {
 	struct cpu *cpu = container_of(dev, struct cpu, dev);
-	ssize_t ret;
+	struct shp_request *shp_req;
+	struct shp_device *shp_dev;
+	enum shp_operation operation;
+	ssize_t ret = count;
 
-	cpu_hotplug_driver_lock();
 	switch (buf[0]) {
 	case '0':
-		ret = cpu_down(cpu->dev.id);
-		if (!ret)
-			kobject_uevent(&dev->kobj, KOBJ_OFFLINE);
+		operation = SHP_ONLINE_DEL;
 		break;
 	case '1':
-		ret = cpu_up(cpu->dev.id);
-		if (!ret)
-			kobject_uevent(&dev->kobj, KOBJ_ONLINE);
+		operation = SHP_ONLINE_ADD;
 		break;
 	default:
-		ret = -EINVAL;
+		return -EINVAL;
+	}
+
+	shp_req = shp_alloc_request(operation);
+	if (!shp_req)
+		return -ENOMEM;
+
+	shp_dev = kzalloc(sizeof(*shp_dev), GFP_KERNEL);
+	if (!shp_dev) {
+		kfree(shp_req);
+		return -ENOMEM;
+	}
+
+	shp_dev->device = dev;
+	shp_dev->class = SHP_CLS_CPU;
+	shp_dev->info.cpu.cpu_id = cpu->dev.id;
+	shp_add_dev_info(shp_req, shp_dev);
+
+	if (shp_submit_req(shp_req)) {
+		kfree(shp_dev);
+		kfree(shp_req);
+		return -EINVAL;
 	}
-	cpu_hotplug_driver_unlock();
 
-	if (ret >= 0)
-		ret = count;
 	return ret;
 }
 static DEVICE_ATTR(online, 0644, show_online, store_online);

^ permalink raw reply related

* [RFC PATCH v2 04/12] cpu: Add cpu hotplug handlers
From: Toshi Kani @ 2013-01-10 23:40 UTC (permalink / raw)
  To: rjw, lenb, gregkh, akpm
  Cc: linux-s390, Toshi Kani, jiang.liu, wency, linux-mm, yinghai,
	linux-kernel, linux-acpi, isimatu.yasuaki, srivatsa.bhat,
	guohanjun, bhelgaas, linuxppc-dev
In-Reply-To: <1357861230-29549-1-git-send-email-toshi.kani@hp.com>

Added cpu hotplug handlers.  cpu_add_execute() onlines requested
cpus for hot-add & online operations, and cpu_del_execute()
offlines them for hot-delete & offline operations.  They are
also used for rollback as well.

cpu_del_validate() fails a request if cpu0 is requested to delete.

Signed-off-by: Toshi Kani <toshi.kani@hp.com>
---
 drivers/base/cpu.c |  107 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 107 insertions(+)

diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 6345294..05534ad 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -13,6 +13,8 @@
 #include <linux/gfp.h>
 #include <linux/slab.h>
 #include <linux/percpu.h>
+#include <linux/list.h>
+#include <linux/sys_hotplug.h>
 
 #include "base.h"
 
@@ -324,10 +326,115 @@ static void __init cpu_dev_register_generic(void)
 #endif
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static int cpu_del_execute(struct shp_request *req, int rollback);
+
+static int cpu_add_execute(struct shp_request *req, int rollback)
+{
+	struct shp_device *shp_dev;
+	u32 cpu;
+	int ret;
+
+	if (rollback)
+		return cpu_del_execute(req, 0);
+
+	list_for_each_entry(shp_dev, &req->dev_list, list) {
+		if (shp_dev->class != SHP_CLS_CPU)
+			continue;
+
+		cpu = shp_dev->info.cpu.cpu_id;
+
+		if (cpu_online(cpu))
+			continue;
+
+		ret = cpu_up(cpu);
+		if (!ret) {
+			/* REVISIT: need a way to set a cpu dev for hot-plug */
+			if (shp_is_online_op(req->operation))
+				kobject_uevent(&shp_dev->device->kobj,
+							KOBJ_ONLINE);
+		} else {
+			pr_err("cpu: Failed to online cpu %d\n", cpu);
+			/* fall-thru */
+		}
+	}
+
+	return 0;
+}
+
+static int cpu_del_validate(struct shp_request *req, int rollback)
+{
+	struct shp_device *shp_dev;
+
+	if (rollback)
+		return 0;
+
+	list_for_each_entry(shp_dev, &req->dev_list, list) {
+		if (shp_dev->class != SHP_CLS_CPU)
+			continue;
+
+		/*
+		 * cpu 0 cannot be offlined.  This check can be removed when
+		 * cpu 0 offline is supported.
+		 */
+		if (shp_dev->info.cpu.cpu_id == 0)
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cpu_del_execute(struct shp_request *req, int rollback)
+{
+	struct shp_device *shp_dev;
+	u32 cpu;
+	int ret;
+
+	if (rollback)
+		return cpu_add_execute(req, 0);
+
+	list_for_each_entry(shp_dev, &req->dev_list, list) {
+		if (shp_dev->class != SHP_CLS_CPU)
+			continue;
+
+		cpu = shp_dev->info.cpu.cpu_id;
+
+		if (!cpu_online(cpu))
+			continue;
+
+		ret = cpu_down(cpu);
+		if (!ret) {
+			/* REVISIT: need a way to set a cpu dev for hot-plug */
+			if (shp_is_online_op(req->operation))
+				kobject_uevent(&shp_dev->device->kobj,
+							KOBJ_OFFLINE);
+		} else {
+			pr_err("cpu: Failed to offline cpu %d\n", cpu);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void __init cpu_shp_init(void)
+{
+	shp_register_handler(SHP_ADD_EXECUTE, cpu_add_execute,
+				SHP_CPU_ADD_EXECUTE_ORDER);
+	shp_register_handler(SHP_DEL_VALIDATE, cpu_del_validate,
+				SHP_CPU_DEL_VALIDATE_ORDER);
+	shp_register_handler(SHP_DEL_EXECUTE, cpu_del_execute,
+				SHP_CPU_DEL_EXECUTE_ORDER);
+}
+#endif	/* CONFIG_HOTPLUG_CPU */
+
 void __init cpu_dev_init(void)
 {
 	if (subsys_system_register(&cpu_subsys, cpu_root_attr_groups))
 		panic("Failed to register CPU subsystem");
 
 	cpu_dev_register_generic();
+#ifdef CONFIG_HOTPLUG_CPU
+	cpu_shp_init();
+#endif
 }

^ permalink raw reply related

* [RFC PATCH v2 03/12] drivers/base: Add system device hotplug framework
From: Toshi Kani @ 2013-01-10 23:40 UTC (permalink / raw)
  To: rjw, lenb, gregkh, akpm
  Cc: linux-s390, Toshi Kani, jiang.liu, wency, linux-mm, yinghai,
	linux-kernel, linux-acpi, isimatu.yasuaki, srivatsa.bhat,
	guohanjun, bhelgaas, linuxppc-dev
In-Reply-To: <1357861230-29549-1-git-send-email-toshi.kani@hp.com>

Added sys_hotplug.c, which is the system device hotplug framework code.

shp_register_handler() allows modules to register their hotplug handlers
to the framework.  shp_submit_req() provides the interface to submit
a hotplug or online/offline request of system devices.  The request is
then put into hp_workqueue.  shp_start_req() calls all registered handlers
in ascending order for each phase.  If any handler failed in validate or
execute phase, shp_start_req() initiates its rollback procedure.

Signed-off-by: Toshi Kani <toshi.kani@hp.com>
---
 drivers/base/Makefile      |    1 
 drivers/base/sys_hotplug.c |  313 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 314 insertions(+)
 create mode 100644 drivers/base/sys_hotplug.c

diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 5aa2d70..2e9b2f1 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -21,6 +21,7 @@ endif
 obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o
 obj-$(CONFIG_REGMAP)	+= regmap/
 obj-$(CONFIG_SOC_BUS) += soc.o
+obj-y			+= sys_hotplug.o
 
 ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
 
diff --git a/drivers/base/sys_hotplug.c b/drivers/base/sys_hotplug.c
new file mode 100644
index 0000000..c5f5285
--- /dev/null
+++ b/drivers/base/sys_hotplug.c
@@ -0,0 +1,313 @@
+/*
+ * sys_hotplug.c - System device hot-plug framework
+ *
+ * Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
+ *	Toshi Kani <toshi.kani@hp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/workqueue.h>
+#include <linux/sys_hotplug.h>
+#include <linux/kallsyms.h>
+
+/*
+ * Hot-plug handler list
+ */
+struct shp_handler {
+	struct list_head	shp_list;
+	int			shp_order;
+	shp_func		shp_func;
+};
+
+LIST_HEAD(shp_add_list_head);
+LIST_HEAD(shp_del_list_head);
+
+static DEFINE_MUTEX(shp_hdr_list_lock);
+
+#define SHP_VALIDATE_ORDER_BASE		(SHP_ORDER_MAX+1)
+#define SHP_EXECUTE_ORDER_BASE		((SHP_ORDER_MAX+1) << 1)
+#define SHP_COMMIT_ORDER_BASE		((SHP_ORDER_MAX+1) << 2)
+
+/*
+ * Hot-plug request work queue
+ */
+struct shp_work {
+	struct shp_request	*request;
+	struct work_struct	work;
+};
+
+static struct workqueue_struct *shp_workqueue;
+
+/* trace messages */
+static int shp_trace = 1;
+static char shp_ksym_buf[KSYM_NAME_LEN];
+module_param(shp_trace, int, 0644);
+MODULE_PARM_DESC(shp_trace, "Enable system device hot-plug trace messages");
+
+static char *shp_operation_string(enum shp_operation operation)
+{
+	switch (operation) {
+	case SHP_HOTPLUG_ADD:
+		return "Hot-Add";
+	case SHP_HOTPLUG_DEL:
+		return "Hot-Delete";
+	case SHP_ONLINE_ADD:
+		return "Online";
+	case SHP_ONLINE_DEL:
+		return "Offline";
+	}
+
+	return "n/a";
+}
+
+static u32 shp_get_order_base(enum shp_phase phase)
+{
+	switch (phase) {
+	case SHP_ADD_VALIDATE:
+	case SHP_DEL_VALIDATE:
+		return SHP_VALIDATE_ORDER_BASE;
+	case SHP_ADD_EXECUTE:
+	case SHP_DEL_EXECUTE:
+		return SHP_EXECUTE_ORDER_BASE;
+	case SHP_ADD_COMMIT:
+	case SHP_DEL_COMMIT:
+		return SHP_COMMIT_ORDER_BASE;
+	}
+
+	return 0;
+}
+
+/**
+ * shp_register_handler - register a hot-plug handler to the framework
+ * @phase: hot-plug phase
+ * @func: Hot-plug function
+ * @order: Pre-defined order value
+ */
+int shp_register_handler(enum shp_phase phase, shp_func func, u32 order)
+{
+	struct list_head *head;
+	struct shp_handler *hdr, *cur;
+	u32 order_base;
+	int insert = 0;
+
+	if (!func || order > SHP_ORDER_MAX)
+		return -EINVAL;
+
+	if (shp_is_add_phase(phase))
+		head = &shp_add_list_head;
+	else
+		head = &shp_del_list_head;
+
+	order_base = shp_get_order_base(phase);
+
+	hdr = kzalloc(sizeof(*hdr), GFP_KERNEL);
+	if (!hdr)
+		return -ENOMEM;
+
+	hdr->shp_order = order + order_base;
+	hdr->shp_func = func;
+
+	/*
+	 * Add this handler to the list in ascending order
+	 */
+	mutex_lock(&shp_hdr_list_lock);
+	if (list_empty(head)) {
+		list_add(&hdr->shp_list, head);
+	} else {
+		list_for_each_entry(cur, head, shp_list)
+			if (cur->shp_order > hdr->shp_order) {
+				insert = 1;
+				break;
+			}
+
+		if (insert)
+			__list_add(&hdr->shp_list,
+				cur->shp_list.prev, &cur->shp_list);
+		else
+			list_add_tail(&hdr->shp_list, head);
+	}
+	mutex_unlock(&shp_hdr_list_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(shp_register_handler);
+
+/**
+ * shp_unregister_handler - unregister a hot-plug handler from the framework
+ * @phase: hot-plug phase
+ * @func: Hot-plug function
+ */
+int shp_unregister_handler(enum shp_phase phase, shp_func func)
+{
+	struct list_head *head;
+	struct shp_handler *cur;
+
+	if (!func)
+		return -EINVAL;
+
+	if (shp_is_add_phase(phase))
+		head = &shp_add_list_head;
+	else
+		head = &shp_del_list_head;
+
+	/*
+	 * Delete this handler from the list
+	 */
+	mutex_lock(&shp_hdr_list_lock);
+	list_for_each_entry(cur, head, shp_list)
+		if (cur->shp_func == func) {
+			list_del(&cur->shp_list);
+			kfree(cur);
+			break;
+		}
+	mutex_unlock(&shp_hdr_list_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(shp_unregister_handler);
+
+static void shp_start_req(struct work_struct *work)
+{
+	struct shp_work *shp_work = container_of(work, struct shp_work, work);
+	struct shp_request *req = shp_work->request;
+	struct shp_handler *hdr;
+	struct shp_device *shp_dev, *tmp;
+	struct list_head *head;
+	int rollback = 0;
+	int ret;
+
+	if (shp_is_add_op(req->operation))
+		head = &shp_add_list_head;
+	else
+		head = &shp_del_list_head;
+
+	if (shp_trace)
+		pr_info("Starting %s Operation\n",
+				shp_operation_string(req->operation));
+
+	/*
+	 * Call hot-plug handlers in the list
+	 */
+	mutex_lock(&shp_hdr_list_lock);
+	list_for_each_entry(hdr, head, shp_list) {
+		if (shp_trace)
+			pr_info("-> %s\n",
+				kallsyms_lookup((unsigned long)hdr->shp_func,
+					NULL, NULL, NULL, shp_ksym_buf));
+
+		ret = hdr->shp_func(req, 0);
+		if (ret) {
+			if (hdr->shp_order < SHP_COMMIT_ORDER_BASE) {
+				if (shp_trace)
+					pr_info("Initiating Rollback\n");
+				rollback = 1;
+				break;
+			} else {
+				pr_err("Commit handler failed: continuing\n");
+				continue;
+			}
+		}
+	}
+
+	/*
+	 * If rollback is requested, call hot-plug handlers in the reversed
+	 * order from the failed handler.  The failed handler is not called
+	 * again.
+	 */
+	if (rollback) {
+		list_for_each_entry_continue_reverse(hdr, head, shp_list) {
+			if (shp_trace)
+				pr_info("RB-> %s\n",
+					kallsyms_lookup(
+					   (unsigned long)hdr->shp_func,
+					   NULL, NULL, NULL, shp_ksym_buf));
+
+			ret = hdr->shp_func(req, 1);
+			if (ret)
+				pr_err("Rollback handler failed: continuing\n");
+		}
+	}
+	mutex_unlock(&shp_hdr_list_lock);
+
+	/* free up the hot-plug request information */
+	list_for_each_entry_safe(shp_dev, tmp, &req->dev_list, list) {
+		list_del(&shp_dev->list);
+		kfree(shp_dev);
+	}
+	kfree(req);
+	kfree(shp_work);
+}
+
+/**
+ * shp_submit_req - submit a hot-plug request
+ * @req: Hot-plug request pointer
+ */
+int shp_submit_req(struct shp_request *req)
+{
+	struct shp_work *shp_work;
+
+	shp_work = kzalloc(sizeof(*shp_work), GFP_KERNEL);
+	if (!shp_work)
+		return -ENOMEM;
+
+	shp_work->request = req;
+	INIT_WORK(&shp_work->work, shp_start_req);
+
+	if (!queue_work(shp_workqueue, &shp_work->work)) {
+		kfree(shp_work);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(shp_submit_req);
+
+/**
+ * shp_alloc_request - allocate a hot-plug request
+ * @operation: Hot-plug operation
+ */
+struct shp_request *shp_alloc_request(enum shp_operation operation)
+{
+	struct shp_request *shp_req;
+
+	shp_req = kzalloc(sizeof(*shp_req), GFP_KERNEL);
+	if (!shp_req)
+		return NULL;
+
+	shp_req->operation = operation;
+	INIT_LIST_HEAD(&shp_req->dev_list);
+
+	return shp_req;
+}
+EXPORT_SYMBOL(shp_alloc_request);
+
+/**
+ * shp_add_dev_info - add shp_device to the hotplug request
+ * @shp_req: hot-plug request pointer
+ * @shp_dev: hot-plug device info pointer
+ */
+void shp_add_dev_info(struct shp_request *shp_req, struct shp_device *shp_dev)
+{
+	list_add_tail(&shp_dev->list, &shp_req->dev_list);
+}
+EXPORT_SYMBOL(shp_add_dev_info);
+
+static int __init shp_init(void)
+{
+	/*
+	 * Allocate shp_workqueue with max_active set to 1.  This serializes
+	 * hot-plug and online/offline operations on the workqueue.
+	 */
+	shp_workqueue = alloc_workqueue("hotplug", 0, 1);
+
+	return 0;
+}
+device_initcall(shp_init);

^ permalink raw reply related

* [RFC PATCH v2 07/12] ACPI: Add ACPI resource hotplug handler
From: Toshi Kani @ 2013-01-10 23:40 UTC (permalink / raw)
  To: rjw, lenb, gregkh, akpm
  Cc: linux-s390, Toshi Kani, jiang.liu, wency, linux-mm, yinghai,
	linux-kernel, linux-acpi, isimatu.yasuaki, srivatsa.bhat,
	guohanjun, bhelgaas, linuxppc-dev
In-Reply-To: <1357861230-29549-1-git-send-email-toshi.kani@hp.com>

Added ACPI resource handler for hotplug operations.  The handler,
acpi_set_shp_device(), sets device resource information to a hotplug
request, which is consumed by the CPU and memory handlers.
For setting the device resource information, acpi_scan_shp_devices()
walks the acpi_device tree from a target device, and calls .resource
of ACPI drivers.

For hot-add, acpi_set_shp_device() is called right after the ACPI bus
handler so that it can walk through new acpi_device objects.  For
hot-delete, it is called at the begging of the validate phase so that
other validate handlers can use the device resource information for
their validations.

Signed-off-by: Toshi Kani <toshi.kani@hp.com>
---
 drivers/acpi/Makefile       |    1 +
 drivers/acpi/bus.c          |    1 +
 drivers/acpi/internal.h     |    1 +
 drivers/acpi/shp_resource.c |   86 +++++++++++++++++++++++++++++++++++++++++++
 include/acpi/acpi_bus.h     |    4 ++
 5 files changed, 93 insertions(+)
 create mode 100644 drivers/acpi/shp_resource.c

diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 2a4502b..205be23 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -34,6 +34,7 @@ acpi-$(CONFIG_ACPI_SLEEP)	+= proc.o
 acpi-y				+= bus.o glue.o
 acpi-y				+= scan.o
 acpi-y				+= resource.o
+acpi-y				+= shp_resource.o
 acpi-y				+= processor_core.o
 acpi-y				+= ec.o
 acpi-$(CONFIG_ACPI_DOCK)	+= dock.o
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 31a1911..69b5edb 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -1236,6 +1236,7 @@ static int __init acpi_init(void)
 	acpi_sleep_proc_init();
 	acpi_wakeup_device_init();
 	acpi_shp_init();
+	acpi_shp_res_init();
 	return 0;
 }
 
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 3c407cd..51aa740 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -26,6 +26,7 @@
 int init_acpi_device_notify(void);
 int acpi_scan_init(void);
 int acpi_sysfs_init(void);
+void acpi_shp_res_init(void);
 
 #ifdef CONFIG_DEBUG_FS
 extern struct dentry *acpi_debugfs_dir;
diff --git a/drivers/acpi/shp_resource.c b/drivers/acpi/shp_resource.c
new file mode 100644
index 0000000..51ab968
--- /dev/null
+++ b/drivers/acpi/shp_resource.c
@@ -0,0 +1,86 @@
+/*
+ * shp_resource.c - Setup system device hot-plug resource information
+ *
+ * Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
+ *	Toshi Kani <toshi.kani@hp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/acpi.h>
+#include <acpi/sys_hotplug.h>
+
+#include "internal.h"
+
+static int
+acpi_set_shp_device(struct acpi_device *device, struct shp_request *req)
+{
+	int ret;
+
+	if (!device->driver) {
+		dev_dbg(&device->dev, "driver not bound\n");
+		return 0;
+	}
+
+	if (!device->driver->ops.resource)
+		return 0;
+
+	ret = device->driver->ops.resource(device, req);
+	if (ret) {
+		dev_err(&device->dev, "ops.resource failed (%d)\n", ret);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
+acpi_scan_shp_devices(struct acpi_device *device, struct shp_request *req)
+{
+	struct acpi_device *child = NULL;
+
+	if (acpi_set_shp_device(device, req))
+		return 0;
+
+	list_for_each_entry(child, &device->children, node)
+		acpi_scan_shp_devices(child, req);
+
+	return 0;
+}
+
+static int acpi_set_shp_resources(struct shp_request *req, int rollback)
+{
+	acpi_handle handle = (acpi_handle) req->handle;
+	struct acpi_device *device = NULL;
+
+	if (rollback)
+		return 0;
+
+	/* only handle hot-plug operation */
+	if (!shp_is_hotplug_op(req->operation))
+		return 0;
+
+	if (acpi_bus_get_device(handle, &device)) {
+		acpi_handle_err(handle, "acpi_bus_get_device failed\n");
+		return -EINVAL;
+	}
+
+	acpi_scan_shp_devices(device, req);
+
+	return 0;
+}
+
+void __init acpi_shp_res_init(void)
+{
+	shp_register_handler(SHP_ADD_EXECUTE, acpi_set_shp_resources,
+				SHP_ACPI_RES_ADD_EXECUTE_ORDER);
+	shp_register_handler(SHP_DEL_VALIDATE, acpi_set_shp_resources,
+				SHP_ACPI_RES_DEL_VALIDATE_ORDER);
+}
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 7ced5dc..6bf002e 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -27,6 +27,7 @@
 #define __ACPI_BUS_H__
 
 #include <linux/device.h>
+#include <acpi/sys_hotplug.h>
 
 #include <acpi/acpi.h>
 
@@ -94,6 +95,8 @@ typedef int (*acpi_op_start) (struct acpi_device * device);
 typedef int (*acpi_op_bind) (struct acpi_device * device);
 typedef int (*acpi_op_unbind) (struct acpi_device * device);
 typedef void (*acpi_op_notify) (struct acpi_device * device, u32 event);
+typedef int (*acpi_op_resource) (struct acpi_device *device,
+			struct shp_request *shp_req);
 
 struct acpi_bus_ops {
 	u32 acpi_op_add:1;
@@ -107,6 +110,7 @@ struct acpi_device_ops {
 	acpi_op_bind bind;
 	acpi_op_unbind unbind;
 	acpi_op_notify notify;
+	acpi_op_resource resource;
 };
 
 #define ACPI_DRIVER_ALL_NOTIFY_EVENTS	0x1	/* system AND device events */

^ permalink raw reply related

* [RFC PATCH v2 06/12] ACPI: Add ACPI bus hotplug handlers
From: Toshi Kani @ 2013-01-10 23:40 UTC (permalink / raw)
  To: rjw, lenb, gregkh, akpm
  Cc: linux-s390, Toshi Kani, jiang.liu, wency, linux-mm, yinghai,
	linux-kernel, linux-acpi, isimatu.yasuaki, srivatsa.bhat,
	guohanjun, bhelgaas, linuxppc-dev
In-Reply-To: <1357861230-29549-1-git-send-email-toshi.kani@hp.com>

Added ACPI bus hotplug handlers.  acpi_add_execute() calls
acpi_bus_add() to construct new acpi_device objects for hot-add
operation, and acpi_del_execute() calls acpi_bus_trim() to destruct
them for hot-delete operation.  They are also used for rollback
as well.

acpi_del_commit() calls _EJ0 to eject a target object for hot-delete.

acpi_validate_ost() calls _OST to inform FW that a hot-plug operation
completed with error in case of rollback.

Signed-off-by: Toshi Kani <toshi.kani@hp.com>
---
 drivers/acpi/bus.c |  133 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 133 insertions(+)

diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 1f0d457..31a1911 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -42,6 +42,7 @@
 #include <acpi/apei.h>
 #include <linux/dmi.h>
 #include <linux/suspend.h>
+#include <acpi/sys_hotplug.h>
 
 #include "internal.h"
 
@@ -52,6 +53,9 @@ struct acpi_device *acpi_root;
 struct proc_dir_entry *acpi_root_dir;
 EXPORT_SYMBOL(acpi_root_dir);
 
+static int acpi_add_execute(struct shp_request *req, int rollback);
+static int acpi_del_execute(struct shp_request *req, int rollback);
+
 #define STRUCT_TO_INT(s)	(*((int*)&s))
 
 
@@ -859,6 +863,134 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
 }
 
 /* --------------------------------------------------------------------------
+			Hot-plug Handling
+   -------------------------------------------------------------------------- */
+
+static int acpi_validate_ost(struct shp_request *req, int rollback)
+{
+	/* If hotplug request failed, inform firmware with error */
+	if (rollback && shp_is_hotplug_op(req->operation))
+		(void) acpi_evaluate_hotplug_ost(req->handle, req->event,
+				ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
+
+	return 0;
+}
+
+static int acpi_add_execute(struct shp_request *req, int rollback)
+{
+	acpi_handle handle = (acpi_handle) req->handle;
+	acpi_handle phandle;
+	struct acpi_device *device = NULL;
+	struct acpi_device *pdev;
+	int ret;
+
+	if (rollback)
+		return acpi_del_execute(req, 0);
+
+	/* only handle hot-plug operation */
+	if (!shp_is_hotplug_op(req->operation))
+		return 0;
+
+	if (acpi_get_parent(handle, &phandle))
+		return -ENODEV;
+
+	if (acpi_bus_get_device(phandle, &pdev))
+		return -ENODEV;
+
+	ret = acpi_bus_add(&device, pdev, handle, ACPI_BUS_TYPE_DEVICE);
+
+	return ret;
+}
+
+static int acpi_add_commit(struct shp_request *req, int rollback)
+{
+	/* Inform firmware that the hotplug operation has completed */
+	(void) acpi_evaluate_hotplug_ost(req->handle, req->event,
+					ACPI_OST_SC_SUCCESS, NULL);
+
+	return 0;
+}
+
+static int acpi_del_execute(struct shp_request *req, int rollback)
+{
+	acpi_handle handle = (acpi_handle) req->handle;
+	struct acpi_device *device;
+
+	if (rollback)
+		return acpi_add_execute(req, 0);
+
+	/* only handle hot-plug operation */
+	if (!shp_is_hotplug_op(req->operation))
+		return 0;
+
+	if (acpi_bus_get_device(handle, &device)) {
+		acpi_handle_err(handle, "Failed to obtain device\n");
+		return -EINVAL;
+	}
+
+	if (acpi_bus_trim(device, 1)) {
+		dev_err(&device->dev, "Removing device failed\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int acpi_del_commit(struct shp_request *req, int rollback)
+{
+	acpi_handle handle = (acpi_handle) req->handle;
+	acpi_handle temp;
+	struct acpi_object_list arg_list;
+	union acpi_object arg;
+	acpi_status status;
+
+	/* only handle hot-plug operation */
+	if (!shp_is_hotplug_op(req->operation))
+		return 0;
+
+	/* power off device */
+	status = acpi_evaluate_object(handle, "_PS3", NULL, NULL);
+	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
+		acpi_handle_warn(handle, "Power-off device failed\n");
+
+	if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &temp))) {
+		arg_list.count = 1;
+		arg_list.pointer = &arg;
+		arg.type = ACPI_TYPE_INTEGER;
+		arg.integer.value = 0;
+		acpi_evaluate_object(handle, "_LCK", &arg_list, NULL);
+	}
+
+	arg_list.count = 1;
+	arg_list.pointer = &arg;
+	arg.type = ACPI_TYPE_INTEGER;
+	arg.integer.value = 1;
+
+	status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
+	if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND))
+			acpi_handle_warn(handle, "Eject device failed\n");
+
+	return 0;
+}
+
+static void __init acpi_shp_init(void)
+{
+	shp_register_handler(SHP_ADD_VALIDATE, acpi_validate_ost,
+				SHP_ACPI_BUS_ADD_VALIDATE_ORDER);
+	shp_register_handler(SHP_ADD_EXECUTE, acpi_add_execute,
+				SHP_ACPI_BUS_ADD_EXECUTE_ORDER);
+	shp_register_handler(SHP_ADD_COMMIT, acpi_add_commit,
+				SHP_ACPI_BUS_ADD_COMMIT_ORDER);
+
+	shp_register_handler(SHP_DEL_VALIDATE, acpi_validate_ost,
+				SHP_ACPI_BUS_DEL_VALIDATE_ORDER);
+	shp_register_handler(SHP_DEL_EXECUTE, acpi_del_execute,
+				SHP_ACPI_BUS_DEL_EXECUTE_ORDER);
+	shp_register_handler(SHP_DEL_COMMIT, acpi_del_commit,
+				SHP_ACPI_BUS_DEL_COMMIT_ORDER);
+}
+
+/* --------------------------------------------------------------------------
                              Initialization/Cleanup
    -------------------------------------------------------------------------- */
 
@@ -1103,6 +1235,7 @@ static int __init acpi_init(void)
 	acpi_debugfs_init();
 	acpi_sleep_proc_init();
 	acpi_wakeup_device_init();
+	acpi_shp_init();
 	return 0;
 }
 

^ permalink raw reply related

* [RFC PATCH v2 01/12] Add sys_hotplug.h for system device hotplug framework
From: Toshi Kani @ 2013-01-10 23:40 UTC (permalink / raw)
  To: rjw, lenb, gregkh, akpm
  Cc: linux-s390, Toshi Kani, jiang.liu, wency, linux-mm, yinghai,
	linux-kernel, linux-acpi, isimatu.yasuaki, srivatsa.bhat,
	guohanjun, bhelgaas, linuxppc-dev
In-Reply-To: <1357861230-29549-1-git-send-email-toshi.kani@hp.com>

Added include/linux/sys_hotplug.h, which defines the system device
hotplug framework interfaces used by the framework itself and
handlers.

The order values define the calling sequence of handlers.  For add
execute, the ordering is ACPI->MEM->CPU.  Memory is onlined before
CPU so that threads on new CPUs can start using their local memory.
The ordering of the delete execute is symmetric to the add execute.

struct shp_request defines a hot-plug request information.  The
device resource information is managed with a list so that a single
request may target to multiple devices.

Signed-off-by: Toshi Kani <toshi.kani@hp.com>
---
 include/linux/sys_hotplug.h |  181 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 181 insertions(+)
 create mode 100644 include/linux/sys_hotplug.h

diff --git a/include/linux/sys_hotplug.h b/include/linux/sys_hotplug.h
new file mode 100644
index 0000000..86674dd
--- /dev/null
+++ b/include/linux/sys_hotplug.h
@@ -0,0 +1,181 @@
+/*
+ * sys_hotplug.h - System device hot-plug framework
+ *
+ * Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
+ *	Toshi Kani <toshi.kani@hp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _LINUX_SYS_HOTPLUG_H
+#define _LINUX_SYS_HOTPLUG_H
+
+#include <linux/list.h>
+#include <linux/device.h>
+
+/*
+ * System device hot-plug operation proceeds in the following order.
+ *   Validate phase -> Execute phase -> Commit phase
+ *
+ * The order values below define the calling sequence of platform
+ * neutral handlers for each phase in ascending order.  The order
+ * values of firmware-specific handlers are defined in sys_hotplug.h
+ * under firmware specific directories.
+ */
+
+/* All order values must be smaller than this value */
+#define SHP_ORDER_MAX				0xffffff
+
+/* Add Validate order values */
+
+/* Add Execute order values */
+#define SHP_MEM_ADD_EXECUTE_ORDER		100
+#define SHP_CPU_ADD_EXECUTE_ORDER		110
+
+/* Add Commit order values */
+
+/* Delete Validate order values */
+#define SHP_CPU_DEL_VALIDATE_ORDER		100
+#define SHP_MEM_DEL_VALIDATE_ORDER		110
+
+/* Delete Execute order values */
+#define SHP_CPU_DEL_EXECUTE_ORDER		10
+#define SHP_MEM_DEL_EXECUTE_ORDER		20
+
+/* Delete Commit order values */
+
+/*
+ * Hot-plug request types
+ */
+#define SHP_REQ_ADD		0x000000
+#define SHP_REQ_DELETE		0x000001
+#define SHP_REQ_MASK		0x0000ff
+
+/*
+ * Hot-plug phase types
+ */
+#define SHP_PH_VALIDATE		0x000000
+#define SHP_PH_EXECUTE		0x000100
+#define SHP_PH_COMMIT		0x000200
+#define SHP_PH_MASK		0x00ff00
+
+/*
+ * Hot-plug operation types
+ */
+#define SHP_OP_HOTPLUG		0x000000
+#define SHP_OP_ONLINE		0x010000
+#define SHP_OP_MASK		0xff0000
+
+/*
+ * Hot-plug phases
+ */
+enum shp_phase {
+	SHP_ADD_VALIDATE	= (SHP_REQ_ADD|SHP_PH_VALIDATE),
+	SHP_ADD_EXECUTE		= (SHP_REQ_ADD|SHP_PH_EXECUTE),
+	SHP_ADD_COMMIT		= (SHP_REQ_ADD|SHP_PH_COMMIT),
+	SHP_DEL_VALIDATE	= (SHP_REQ_DELETE|SHP_PH_VALIDATE),
+	SHP_DEL_EXECUTE		= (SHP_REQ_DELETE|SHP_PH_EXECUTE),
+	SHP_DEL_COMMIT		= (SHP_REQ_DELETE|SHP_PH_COMMIT)
+};
+
+/*
+ * Hot-plug operations
+ */
+enum shp_operation {
+	SHP_HOTPLUG_ADD		= (SHP_OP_HOTPLUG|SHP_REQ_ADD),
+	SHP_HOTPLUG_DEL		= (SHP_OP_HOTPLUG|SHP_REQ_DELETE),
+	SHP_ONLINE_ADD		= (SHP_OP_ONLINE|SHP_REQ_ADD),
+	SHP_ONLINE_DEL		= (SHP_OP_ONLINE|SHP_REQ_DELETE)
+};
+
+/*
+ * Hot-plug device classes
+ */
+enum shp_class {
+	SHP_CLS_INVALID		= 0,
+	SHP_CLS_CPU		= 1,
+	SHP_CLS_MEMORY		= 2,
+	SHP_CLS_HOSTBRIDGE	= 3,
+	SHP_CLS_CONTAINER	= 4,
+};
+
+/*
+ * Hot-plug device information
+ */
+union shp_dev_info {
+	struct shp_cpu {
+		u32		cpu_id;
+	} cpu;
+
+	struct shp_memory {
+		int		node;
+		u64		start_addr;
+		u64		length;
+	} mem;
+
+	struct shp_hostbridge {
+	} hb;
+
+	struct shp_node {
+	} node;
+};
+
+struct shp_device {
+	struct list_head	list;
+	struct device		*device;
+	enum shp_class		class;
+	union shp_dev_info	info;
+};
+
+/*
+ * Hot-plug request
+ */
+struct shp_request {
+	/* common info */
+	enum shp_operation	operation;	/* operation */
+
+	/* hot-plug event info: only valid for hot-plug operations */
+	void			*handle;	/* FW handle */
+	u32			event;		/* FW event */
+
+	/* device resource info */
+	struct list_head	dev_list;	/* shp_device list */
+};
+
+/*
+ * Inline Utility Functions
+ */
+static inline bool shp_is_hotplug_op(enum shp_operation operation)
+{
+	return (operation & SHP_OP_MASK) == SHP_OP_HOTPLUG;
+}
+
+static inline bool shp_is_online_op(enum shp_operation operation)
+{
+	return (operation & SHP_OP_MASK) == SHP_OP_ONLINE;
+}
+
+static inline bool shp_is_add_op(enum shp_operation operation)
+{
+	return (operation & SHP_REQ_MASK) == SHP_REQ_ADD;
+}
+
+static inline bool shp_is_add_phase(enum shp_phase phase)
+{
+	return (phase & SHP_REQ_MASK) == SHP_REQ_ADD;
+}
+
+/*
+ * Externs
+ */
+typedef int (*shp_func)(struct shp_request *req, int rollback);
+extern int shp_register_handler(enum shp_phase phase, shp_func func, u32 order);
+extern int shp_unregister_handler(enum shp_phase phase, shp_func func);
+extern int shp_submit_req(struct shp_request *req);
+extern struct shp_request *shp_alloc_request(enum shp_operation operation);
+extern void shp_add_dev_info(struct shp_request *shp_req,
+		struct shp_device *shp_dev);
+
+#endif	/* _LINUX_SYS_HOTPLUG_H */

^ permalink raw reply related

* [RFC PATCH v2 08/12] ACPI: Update processor driver for hotplug framework
From: Toshi Kani @ 2013-01-10 23:40 UTC (permalink / raw)
  To: rjw, lenb, gregkh, akpm
  Cc: linux-s390, Toshi Kani, jiang.liu, wency, linux-mm, yinghai,
	linux-kernel, linux-acpi, isimatu.yasuaki, srivatsa.bhat,
	guohanjun, bhelgaas, linuxppc-dev
In-Reply-To: <1357861230-29549-1-git-send-email-toshi.kani@hp.com>

Added acpi_processor_resource() for the .resource() interface,
which sets CPU information to a hotplug request.

Changed acpi_processor_hotplug_notify() to request a hotplug
operation by calling shp_submit_req().  It no longer initiates
hot-add or hot-delete operation by calling acpi_bus_add() or
acpi_bus_hot_remove_device() directly.

acpi_processor_handle_eject() is changed not to call cpu_down()
since .add() / .remove() may not online / offline a device.

Signed-off-by: Toshi Kani <toshi.kani@hp.com>
---
 drivers/acpi/processor_driver.c |  150 ++++++++++++++++++---------------------
 1 file changed, 70 insertions(+), 80 deletions(-)

diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index e83311b..f630c2c 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -57,6 +57,7 @@
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 #include <acpi/processor.h>
+#include <acpi/sys_hotplug.h>
 
 #define PREFIX "ACPI: "
 
@@ -83,6 +84,8 @@ MODULE_LICENSE("GPL");
 static int acpi_processor_add(struct acpi_device *device);
 static int acpi_processor_remove(struct acpi_device *device, int type);
 static void acpi_processor_notify(struct acpi_device *device, u32 event);
+static int acpi_processor_resource(struct acpi_device *device,
+		struct shp_request *shp_req);
 static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr);
 static int acpi_processor_handle_eject(struct acpi_processor *pr);
 static int acpi_processor_start(struct acpi_processor *pr);
@@ -105,6 +108,7 @@ static struct acpi_driver acpi_processor_driver = {
 		.add = acpi_processor_add,
 		.remove = acpi_processor_remove,
 		.notify = acpi_processor_notify,
+		.resource = acpi_processor_resource,
 		},
 	.drv.pm = &acpi_processor_pm,
 };
@@ -649,6 +653,33 @@ free:
 	return 0;
 }
 
+static int
+acpi_processor_resource(struct acpi_device *device, struct shp_request *shp_req)
+{
+	struct acpi_processor *pr;
+	struct shp_device *shp_dev;
+
+	pr = acpi_driver_data(device);
+	if (!pr) {
+		dev_err(&device->dev, "Driver data missing\n");
+		return -EINVAL;
+	}
+
+	shp_dev = kzalloc(sizeof(*shp_dev), GFP_KERNEL);
+	if (!shp_dev) {
+		dev_err(&device->dev, "Failed to allocate shp_dev\n");
+		return -EINVAL;
+	}
+
+	shp_dev->device = &device->dev;
+	shp_dev->class = SHP_CLS_CPU;
+	shp_dev->info.cpu.cpu_id = pr->id;
+
+	shp_add_dev_info(shp_req, shp_dev);
+
+	return 0;
+}
+
 #ifdef CONFIG_ACPI_HOTPLUG_CPU
 /****************************************************************************
  * 	Acpi processor hotplug support 				       	    *
@@ -677,97 +708,68 @@ static int is_processor_present(acpi_handle handle)
 	return 0;
 }
 
-static
-int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device)
-{
-	acpi_handle phandle;
-	struct acpi_device *pdev;
-
-
-	if (acpi_get_parent(handle, &phandle)) {
-		return -ENODEV;
-	}
-
-	if (acpi_bus_get_device(phandle, &pdev)) {
-		return -ENODEV;
-	}
-
-	if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_PROCESSOR)) {
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
 static void acpi_processor_hotplug_notify(acpi_handle handle,
 					  u32 event, void *data)
 {
 	struct acpi_device *device = NULL;
-	struct acpi_eject_event *ej_event = NULL;
+	struct shp_request *shp_req;
+	enum shp_operation shp_op;
 	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
-	int result;
 
 	switch (event) {
 	case ACPI_NOTIFY_BUS_CHECK:
 	case ACPI_NOTIFY_DEVICE_CHECK:
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-		"Processor driver received %s event\n",
-		       (event == ACPI_NOTIFY_BUS_CHECK) ?
-		       "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK"));
-
-		if (!is_processor_present(handle))
-			break;
-
-		if (!acpi_bus_get_device(handle, &device))
-			break;
+		if (!is_processor_present(handle)) {
+			acpi_handle_err(handle, "Device not enabled\n");
+			goto err;
+		}
 
-		result = acpi_processor_device_add(handle, &device);
-		if (result) {
-			acpi_handle_err(handle, "Unable to add the device\n");
-			break;
+		if (!acpi_bus_get_device(handle, &device)) {
+			acpi_handle_err(handle, "Device added already\n");
+			goto err;
 		}
 
-		ost_code = ACPI_OST_SC_SUCCESS;
+		shp_op = SHP_HOTPLUG_ADD;
 		break;
 
 	case ACPI_NOTIFY_EJECT_REQUEST:
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-				  "received ACPI_NOTIFY_EJECT_REQUEST\n"));
-
 		if (acpi_bus_get_device(handle, &device)) {
-			acpi_handle_err(handle,
-				"Device don't exist, dropping EJECT\n");
-			break;
+			acpi_handle_err(handle, "Device not added yet\n");
+			goto err;
 		}
 		if (!acpi_driver_data(device)) {
-			acpi_handle_err(handle,
-				"Driver data is NULL, dropping EJECT\n");
-			break;
+			acpi_handle_err(handle, "Driver data missing\n");
+			goto err;
 		}
 
-		ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
-		if (!ej_event) {
-			acpi_handle_err(handle, "No memory, dropping EJECT\n");
-			break;
-		}
-
-		ej_event->handle = handle;
-		ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
-		acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
-					(void *)ej_event);
-
-		/* eject is performed asynchronously */
-		return;
+		shp_op = SHP_HOTPLUG_DEL;
+		break;
 
 	default:
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				  "Unsupported event [0x%x]\n", event));
-
-		/* non-hotplug event; possibly handled by other handler */
 		return;
 	}
 
-	/* Inform firmware that the hotplug operation has completed */
+	shp_req = shp_alloc_request(shp_op);
+	if (!shp_req) {
+		acpi_handle_err(handle, "No memory to request hotplug\n");
+		goto err;
+	}
+
+	shp_req->handle = (void *)handle;
+	shp_req->event = event;
+
+	if (shp_submit_req(shp_req)) {
+		acpi_handle_err(handle, "Failed to request hotplug\n");
+		kfree(shp_req);
+		goto err;
+	}
+
+	return;
+
+err:
+	/* Inform firmware that the hotplug operation completed w/ error */
 	(void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL);
 	return;
 }
@@ -865,25 +867,13 @@ static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr)
 
 static int acpi_processor_handle_eject(struct acpi_processor *pr)
 {
-	if (cpu_online(pr->id))
-		cpu_down(pr->id);
-
-	get_online_cpus();
-	/*
-	 * The cpu might become online again at this point. So we check whether
-	 * the cpu has been onlined or not. If the cpu became online, it means
-	 * that someone wants to use the cpu. So acpi_processor_handle_eject()
-	 * returns -EAGAIN.
-	 */
-	if (unlikely(cpu_online(pr->id))) {
-		put_online_cpus();
-		pr_warn("Failed to remove CPU %d, because other task "
-			"brought the CPU back online\n", pr->id);
-		return -EAGAIN;
+	if (cpu_online(pr->id)) {
+		pr_err("ACPI: cpu %d not off-lined\n", pr->id);
+		return -EINVAL;
 	}
+
 	arch_unregister_cpu(pr->id);
 	acpi_unmap_lsapic(pr->id);
-	put_online_cpus();
 	return (0);
 }
 #else

^ permalink raw reply related

* [RFC PATCH v2 02/12] ACPI: Add sys_hotplug.h for system device hotplug framework
From: Toshi Kani @ 2013-01-10 23:40 UTC (permalink / raw)
  To: rjw, lenb, gregkh, akpm
  Cc: linux-s390, Toshi Kani, jiang.liu, wency, linux-mm, yinghai,
	linux-kernel, linux-acpi, isimatu.yasuaki, srivatsa.bhat,
	guohanjun, bhelgaas, linuxppc-dev
In-Reply-To: <1357861230-29549-1-git-send-email-toshi.kani@hp.com>

Added include/acpi/sys_hotplug.h, which is ACPI-specific system
device hotplug header and defines the order values of ACPI-specific
handlers.

Signed-off-by: Toshi Kani <toshi.kani@hp.com>
---
 include/acpi/sys_hotplug.h |   48 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)
 create mode 100644 include/acpi/sys_hotplug.h

diff --git a/include/acpi/sys_hotplug.h b/include/acpi/sys_hotplug.h
new file mode 100644
index 0000000..ad80f61
--- /dev/null
+++ b/include/acpi/sys_hotplug.h
@@ -0,0 +1,48 @@
+/*
+ * sys_hotplug.h - ACPI System device hot-plug framework
+ *
+ * Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
+ *	Toshi Kani <toshi.kani@hp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _ACPI_SYS_HOTPLUG_H
+#define _ACPI_SYS_HOTPLUG_H
+
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/sys_hotplug.h>
+
+/*
+ * System device hot-plug operation proceeds in the following order.
+ *   Validate phase -> Execute phase -> Commit phase
+ *
+ * The order values below define the calling sequence of ACPI-specific
+ * handlers for each phase in ascending order.  The order value of
+ * platform-neutral handlers are defined in <linux/sys_hotplug.h>.
+ */
+
+/* Add Validate order values */
+#define SHP_ACPI_BUS_ADD_VALIDATE_ORDER		0	/* must be first */
+
+/* Add Execute order values */
+#define SHP_ACPI_BUS_ADD_EXECUTE_ORDER		10
+#define SHP_ACPI_RES_ADD_EXECUTE_ORDER		20
+
+/* Add Commit order values */
+#define SHP_ACPI_BUS_ADD_COMMIT_ORDER		10
+
+/* Delete Validate order values */
+#define SHP_ACPI_BUS_DEL_VALIDATE_ORDER		0	/* must be first */
+#define SHP_ACPI_RES_DEL_VALIDATE_ORDER		10
+
+/* Delete Execute order values */
+#define SHP_ACPI_BUS_DEL_EXECUTE_ORDER		100
+
+/* Delete Commit order values */
+#define SHP_ACPI_BUS_DEL_COMMIT_ORDER		100
+
+#endif	/* _ACPI_SYS_HOTPLUG_H */

^ permalink raw reply related

* [RFC PATCH v2 10/12] ACPI: Update container driver for hotplug framework
From: Toshi Kani @ 2013-01-10 23:40 UTC (permalink / raw)
  To: rjw, lenb, gregkh, akpm
  Cc: linux-s390, Toshi Kani, jiang.liu, wency, linux-mm, yinghai,
	linux-kernel, linux-acpi, isimatu.yasuaki, srivatsa.bhat,
	guohanjun, bhelgaas, linuxppc-dev
In-Reply-To: <1357861230-29549-1-git-send-email-toshi.kani@hp.com>

Changed container_notify_cb() to request a hotplug operation by
calling shp_submit_req().  It no longer initiates hot-add by calling
acpi_bus_add().  Also, it no longer sets device->flags.eject_pending
and generates KOBJ_OFFLINE event for hot-delete.

Signed-off-by: Toshi Kani <toshi.kani@hp.com>
---
 drivers/acpi/container.c |   95 ++++++++++++++++++----------------------------
 1 file changed, 37 insertions(+), 58 deletions(-)

diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
index 811910b..89af4fc 100644
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -35,6 +35,7 @@
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 #include <acpi/container.h>
+#include <acpi/sys_hotplug.h>
 
 #define PREFIX "ACPI: "
 
@@ -135,77 +136,37 @@ static int acpi_container_remove(struct acpi_device *device, int type)
 	return status;
 }
 
-static int container_device_add(struct acpi_device **device, acpi_handle handle)
-{
-	acpi_handle phandle;
-	struct acpi_device *pdev;
-	int result;
-
-
-	if (acpi_get_parent(handle, &phandle)) {
-		return -ENODEV;
-	}
-
-	if (acpi_bus_get_device(phandle, &pdev)) {
-		return -ENODEV;
-	}
-
-	if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_DEVICE)) {
-		return -ENODEV;
-	}
-
-	result = acpi_bus_start(*device);
-
-	return result;
-}
-
-static void container_notify_cb(acpi_handle handle, u32 type, void *context)
+static void container_notify_cb(acpi_handle handle, u32 event, void *context)
 {
 	struct acpi_device *device = NULL;
-	int result;
-	int present;
-	acpi_status status;
+	struct shp_request *shp_req;
+	enum shp_operation shp_op;
 	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
 
-	switch (type) {
+	switch (event) {
 	case ACPI_NOTIFY_BUS_CHECK:
 		/* Fall through */
 	case ACPI_NOTIFY_DEVICE_CHECK:
-		pr_debug("Container driver received %s event\n",
-		       (type == ACPI_NOTIFY_BUS_CHECK) ?
-		       "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK");
-
-		present = is_device_present(handle);
-		status = acpi_bus_get_device(handle, &device);
-		if (!present) {
-			if (ACPI_SUCCESS(status)) {
-				/* device exist and this is a remove request */
-				device->flags.eject_pending = 1;
-				kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
-				return;
-			}
-			break;
+		if (!is_device_present(handle)) {
+			acpi_handle_err(handle, "Device not enabled\n");
+			goto err;
 		}
 
-		if (!ACPI_FAILURE(status) || device)
-			break;
-
-		result = container_device_add(&device, handle);
-		if (result) {
-			acpi_handle_warn(handle, "Failed to add container\n");
-			break;
+		if (!acpi_bus_get_device(handle, &device)) {
+			acpi_handle_err(handle, "Device added already\n");
+			goto err;
 		}
 
-		kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
-		ost_code = ACPI_OST_SC_SUCCESS;
+		shp_op = SHP_HOTPLUG_ADD;
 		break;
 
 	case ACPI_NOTIFY_EJECT_REQUEST:
-		if (!acpi_bus_get_device(handle, &device) && device) {
-			device->flags.eject_pending = 1;
-			kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
-			return;
+		if (acpi_bus_get_device(handle, &device)) {
+			acpi_handle_err(handle, "Device not added yet\n");
+			goto err;
 		}
+
+		shp_op = SHP_HOTPLUG_DEL;
 		break;
 
 	default:
@@ -213,8 +174,26 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
 		return;
 	}
 
-	/* Inform firmware that the hotplug operation has completed */
-	(void) acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
+	shp_req = shp_alloc_request(shp_op);
+	if (!shp_req) {
+		acpi_handle_err(handle, "No memory to request hotplug\n");
+		goto err;
+	}
+
+	shp_req->handle = (void *)handle;
+	shp_req->event = event;
+
+	if (shp_submit_req(shp_req)) {
+		acpi_handle_err(handle, "Failed to request hotplug\n");
+		kfree(shp_req);
+		goto err;
+	}
+
+	return;
+
+err:
+	/* Inform firmware that the hotplug operation completed w/ error */
+	(void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL);
 	return;
 }
 

^ permalink raw reply related

* [RFC PATCH v2 12/12] ACPI: Update sysfs eject for hotplug framework
From: Toshi Kani @ 2013-01-10 23:40 UTC (permalink / raw)
  To: rjw, lenb, gregkh, akpm
  Cc: linux-s390, Toshi Kani, jiang.liu, wency, linux-mm, yinghai,
	linux-kernel, linux-acpi, isimatu.yasuaki, srivatsa.bhat,
	guohanjun, bhelgaas, linuxppc-dev
In-Reply-To: <1357861230-29549-1-git-send-email-toshi.kani@hp.com>

Changed acpi_eject_store() to request a hot-delete operation by
calling shp_submit_req().  It no longer initiates a hot-delete
operation by calling acpi_bus_hot_remove_device().

Deleted acpi_bus_hot_remove_device() since it no longer has any
caller and should not be called for hot-delete.

Deleted eject_pending bit from acpi_device_flags since the ACPI
container driver no longer sets it for hot-delete, and sysfs
eject no longer checks it in acpi_bus_hot_remove_device().

Signed-off-by: Toshi Kani <toshi.kani@hp.com>
---
 drivers/acpi/scan.c     |  122 ++++++++---------------------------------------
 include/acpi/acpi_bus.h |    4 --
 2 files changed, 23 insertions(+), 103 deletions(-)

diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index c88be6c..5e47b49 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -13,6 +13,7 @@
 #include <linux/nls.h>
 
 #include <acpi/acpi_drivers.h>
+#include <acpi/sys_hotplug.h>
 
 #include "internal.h"
 
@@ -105,85 +106,6 @@ acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, cha
 }
 static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
 
-/**
- * acpi_bus_hot_remove_device: hot-remove a device and its children
- * @context: struct acpi_eject_event pointer (freed in this func)
- *
- * Hot-remove a device and its children. This function frees up the
- * memory space passed by arg context, so that the caller may call
- * this function asynchronously through acpi_os_hotplug_execute().
- */
-void acpi_bus_hot_remove_device(void *context)
-{
-	struct acpi_eject_event *ej_event = (struct acpi_eject_event *) context;
-	struct acpi_device *device;
-	acpi_handle handle = ej_event->handle;
-	acpi_handle temp;
-	struct acpi_object_list arg_list;
-	union acpi_object arg;
-	acpi_status status = AE_OK;
-	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
-
-	if (acpi_bus_get_device(handle, &device))
-		goto err_out;
-
-	if (!device)
-		goto err_out;
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-		"Hot-removing device %s...\n", dev_name(&device->dev)));
-
-	if (acpi_bus_trim(device, 1)) {
-		printk(KERN_ERR PREFIX
-				"Removing device failed\n");
-		goto err_out;
-	}
-
-	/* device has been freed */
-	device = NULL;
-
-	/* power off device */
-	status = acpi_evaluate_object(handle, "_PS3", NULL, NULL);
-	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
-		printk(KERN_WARNING PREFIX
-				"Power-off device failed\n");
-
-	if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &temp))) {
-		arg_list.count = 1;
-		arg_list.pointer = &arg;
-		arg.type = ACPI_TYPE_INTEGER;
-		arg.integer.value = 0;
-		acpi_evaluate_object(handle, "_LCK", &arg_list, NULL);
-	}
-
-	arg_list.count = 1;
-	arg_list.pointer = &arg;
-	arg.type = ACPI_TYPE_INTEGER;
-	arg.integer.value = 1;
-
-	/*
-	 * TBD: _EJD support.
-	 */
-	status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
-	if (ACPI_FAILURE(status)) {
-		if (status != AE_NOT_FOUND)
-			printk(KERN_WARNING PREFIX
-					"Eject device failed\n");
-		goto err_out;
-	}
-
-	kfree(context);
-	return;
-
-err_out:
-	/* Inform firmware the hot-remove operation has completed w/ error */
-	(void) acpi_evaluate_hotplug_ost(handle,
-				ej_event->event, ost_code, NULL);
-	kfree(context);
-	return;
-}
-EXPORT_SYMBOL(acpi_bus_hot_remove_device);
-
 static ssize_t
 acpi_eject_store(struct device *d, struct device_attribute *attr,
 		const char *buf, size_t count)
@@ -192,44 +114,44 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
 	acpi_status status;
 	acpi_object_type type = 0;
 	struct acpi_device *acpi_device = to_acpi_device(d);
-	struct acpi_eject_event *ej_event;
+	struct shp_request *shp_req;
 
 	if ((!count) || (buf[0] != '1')) {
 		return -EINVAL;
 	}
 #ifndef FORCE_EJECT
 	if (acpi_device->driver == NULL) {
-		ret = -ENODEV;
-		goto err;
+		return -ENODEV;
 	}
 #endif
 	status = acpi_get_type(acpi_device->handle, &type);
 	if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) {
-		ret = -ENODEV;
-		goto err;
+		return -ENODEV;
 	}
 
-	ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
-	if (!ej_event) {
-		ret = -ENOMEM;
+	shp_req = shp_alloc_request(SHP_HOTPLUG_DEL);
+	if (!shp_req)
+		return -ENOMEM;
+
+	shp_req->handle = (void *) acpi_device->handle;
+
+	/* event originated from user */
+	shp_req->event = ACPI_OST_EC_OSPM_EJECT;
+	(void) acpi_evaluate_hotplug_ost(shp_req->handle,
+			shp_req->event, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
+
+	if (shp_submit_req(shp_req)) {
+		kfree(shp_req);
 		goto err;
 	}
 
-	ej_event->handle = acpi_device->handle;
-	if (acpi_device->flags.eject_pending) {
-		/* event originated from ACPI eject notification */
-		ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
-		acpi_device->flags.eject_pending = 0;
-	} else {
-		/* event originated from user */
-		ej_event->event = ACPI_OST_EC_OSPM_EJECT;
-		(void) acpi_evaluate_hotplug_ost(ej_event->handle,
-			ej_event->event, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
-	}
+	return ret;
 
-	acpi_os_hotplug_execute(acpi_bus_hot_remove_device, (void *)ej_event);
 err:
-	return ret;
+	/* Inform firmware that the hotplug operation completed w/ error */
+	(void) acpi_evaluate_hotplug_ost(shp_req->handle,
+			shp_req->event, ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
+	return -EINVAL;
 }
 
 static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 6bf002e..ccbfef3 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -151,8 +151,7 @@ struct acpi_device_flags {
 	u32 suprise_removal_ok:1;
 	u32 power_manageable:1;
 	u32 performance_manageable:1;
-	u32 eject_pending:1;
-	u32 reserved:24;
+	u32 reserved:25;
 };
 
 /* File System */
@@ -362,7 +361,6 @@ int acpi_bus_register_driver(struct acpi_driver *driver);
 void acpi_bus_unregister_driver(struct acpi_driver *driver);
 int acpi_bus_add(struct acpi_device **child, struct acpi_device *parent,
 		 acpi_handle handle, int type);
-void acpi_bus_hot_remove_device(void *context);
 int acpi_bus_trim(struct acpi_device *start, int rmdevice);
 int acpi_bus_start(struct acpi_device *device);
 acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle * ejd);

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox