2005-04-16 15:20:36 -07:00
/*
* IBM ASM Service Processor Device Driver
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*
* Copyright ( C ) IBM Corporation , 2004
*
2007-07-17 04:03:58 -07:00
* Author : Max Asb <EFBFBD> ck < amax @ us . ibm . com >
2005-04-16 15:20:36 -07:00
*
*/
2009-10-07 17:09:06 +04:00
# include <linux/sched.h>
2005-04-16 15:20:36 -07:00
# include "ibmasm.h"
2005-06-21 17:16:36 -07:00
# include "lowlevel.h"
2005-04-16 15:20:36 -07:00
static void exec_next_command ( struct service_processor * sp ) ;
2005-06-21 17:16:36 -07:00
static atomic_t command_count = ATOMIC_INIT ( 0 ) ;
2005-04-16 15:20:36 -07:00
2005-06-21 17:16:36 -07:00
struct command * ibmasm_new_command ( struct service_processor * sp , size_t buffer_size )
2005-04-16 15:20:36 -07:00
{
struct command * cmd ;
if ( buffer_size > IBMASM_CMD_MAX_BUFFER_SIZE )
return NULL ;
some kmalloc/memset ->kzalloc (tree wide)
Transform some calls to kmalloc/memset to a single kzalloc (or kcalloc).
Here is a short excerpt of the semantic patch performing
this transformation:
@@
type T2;
expression x;
identifier f,fld;
expression E;
expression E1,E2;
expression e1,e2,e3,y;
statement S;
@@
x =
- kmalloc
+ kzalloc
(E1,E2)
... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\)
- memset((T2)x,0,E1);
@@
expression E1,E2,E3;
@@
- kzalloc(E1 * E2,E3)
+ kcalloc(E1,E2,E3)
[akpm@linux-foundation.org: get kcalloc args the right way around]
Signed-off-by: Yoann Padioleau <padator@wanadoo.fr>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Acked-by: Russell King <rmk@arm.linux.org.uk>
Cc: Bryan Wu <bryan.wu@analog.com>
Acked-by: Jiri Slaby <jirislaby@gmail.com>
Cc: Dave Airlie <airlied@linux.ie>
Acked-by: Roland Dreier <rolandd@cisco.com>
Cc: Jiri Kosina <jkosina@suse.cz>
Acked-by: Dmitry Torokhov <dtor@mail.ru>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Acked-by: Pierre Ossman <drzeus-list@drzeus.cx>
Cc: Jeff Garzik <jeff@garzik.org>
Cc: "David S. Miller" <davem@davemloft.net>
Acked-by: Greg KH <greg@kroah.com>
Cc: James Bottomley <James.Bottomley@steeleye.com>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-07-19 01:49:03 -07:00
cmd = kzalloc ( sizeof ( struct command ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( cmd = = NULL )
return NULL ;
some kmalloc/memset ->kzalloc (tree wide)
Transform some calls to kmalloc/memset to a single kzalloc (or kcalloc).
Here is a short excerpt of the semantic patch performing
this transformation:
@@
type T2;
expression x;
identifier f,fld;
expression E;
expression E1,E2;
expression e1,e2,e3,y;
statement S;
@@
x =
- kmalloc
+ kzalloc
(E1,E2)
... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\)
- memset((T2)x,0,E1);
@@
expression E1,E2,E3;
@@
- kzalloc(E1 * E2,E3)
+ kcalloc(E1,E2,E3)
[akpm@linux-foundation.org: get kcalloc args the right way around]
Signed-off-by: Yoann Padioleau <padator@wanadoo.fr>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Acked-by: Russell King <rmk@arm.linux.org.uk>
Cc: Bryan Wu <bryan.wu@analog.com>
Acked-by: Jiri Slaby <jirislaby@gmail.com>
Cc: Dave Airlie <airlied@linux.ie>
Acked-by: Roland Dreier <rolandd@cisco.com>
Cc: Jiri Kosina <jkosina@suse.cz>
Acked-by: Dmitry Torokhov <dtor@mail.ru>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Acked-by: Pierre Ossman <drzeus-list@drzeus.cx>
Cc: Jeff Garzik <jeff@garzik.org>
Cc: "David S. Miller" <davem@davemloft.net>
Acked-by: Greg KH <greg@kroah.com>
Cc: James Bottomley <James.Bottomley@steeleye.com>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-07-19 01:49:03 -07:00
cmd - > buffer = kzalloc ( buffer_size , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( cmd - > buffer = = NULL ) {
kfree ( cmd ) ;
return NULL ;
}
cmd - > buffer_size = buffer_size ;
2007-12-03 21:16:20 -07:00
kref_init ( & cmd - > kref ) ;
2005-06-21 17:16:36 -07:00
cmd - > lock = & sp - > lock ;
2005-04-16 15:20:36 -07:00
cmd - > status = IBMASM_CMD_PENDING ;
init_waitqueue_head ( & cmd - > wait ) ;
INIT_LIST_HEAD ( & cmd - > queue_node ) ;
2005-06-21 17:16:36 -07:00
atomic_inc ( & command_count ) ;
dbg ( " command count: %d \n " , atomic_read ( & command_count ) ) ;
2005-04-16 15:20:36 -07:00
return cmd ;
}
2007-12-03 21:16:20 -07:00
void ibmasm_free_command ( struct kref * kref )
2005-04-16 15:20:36 -07:00
{
2007-12-03 21:16:20 -07:00
struct command * cmd = to_command ( kref ) ;
2007-07-17 04:03:58 -07:00
2005-04-16 15:20:36 -07:00
list_del ( & cmd - > queue_node ) ;
2005-06-21 17:16:36 -07:00
atomic_dec ( & command_count ) ;
dbg ( " command count: %d \n " , atomic_read ( & command_count ) ) ;
2005-04-16 15:20:36 -07:00
kfree ( cmd - > buffer ) ;
kfree ( cmd ) ;
}
static void enqueue_command ( struct service_processor * sp , struct command * cmd )
{
list_add_tail ( & cmd - > queue_node , & sp - > command_queue ) ;
}
static struct command * dequeue_command ( struct service_processor * sp )
{
struct command * cmd ;
struct list_head * next ;
if ( list_empty ( & sp - > command_queue ) )
return NULL ;
next = sp - > command_queue . next ;
list_del_init ( next ) ;
cmd = list_entry ( next , struct command , queue_node ) ;
return cmd ;
}
static inline void do_exec_command ( struct service_processor * sp )
{
2005-06-21 17:16:36 -07:00
char tsbuf [ 32 ] ;
2008-04-29 00:59:20 -07:00
dbg ( " %s:%d at %s \n " , __func__ , __LINE__ , get_timestamp ( tsbuf ) ) ;
2005-06-21 17:16:36 -07:00
2005-04-16 15:20:36 -07:00
if ( ibmasm_send_i2o_message ( sp ) ) {
sp - > current_command - > status = IBMASM_CMD_FAILED ;
2005-06-21 17:16:36 -07:00
wake_up ( & sp - > current_command - > wait ) ;
command_put ( sp - > current_command ) ;
2005-04-16 15:20:36 -07:00
exec_next_command ( sp ) ;
}
}
2007-07-17 04:03:58 -07:00
2005-04-16 15:20:36 -07:00
/**
* exec_command
* send a command to a service processor
* Commands are executed sequentially . One command ( sp - > current_command )
* is sent to the service processor . Once the interrupt handler gets a
* message of type command_response , the message is copied into
2007-07-17 04:03:58 -07:00
* the current commands buffer ,
2005-04-16 15:20:36 -07:00
*/
void ibmasm_exec_command ( struct service_processor * sp , struct command * cmd )
{
unsigned long flags ;
2005-06-21 17:16:36 -07:00
char tsbuf [ 32 ] ;
2008-04-29 00:59:20 -07:00
dbg ( " %s:%d at %s \n " , __func__ , __LINE__ , get_timestamp ( tsbuf ) ) ;
2005-04-16 15:20:36 -07:00
spin_lock_irqsave ( & sp - > lock , flags ) ;
if ( ! sp - > current_command ) {
sp - > current_command = cmd ;
2005-06-21 17:16:36 -07:00
command_get ( sp - > current_command ) ;
2005-04-16 15:20:36 -07:00
spin_unlock_irqrestore ( & sp - > lock , flags ) ;
do_exec_command ( sp ) ;
} else {
enqueue_command ( sp , cmd ) ;
spin_unlock_irqrestore ( & sp - > lock , flags ) ;
}
}
static void exec_next_command ( struct service_processor * sp )
{
unsigned long flags ;
2005-06-21 17:16:36 -07:00
char tsbuf [ 32 ] ;
2005-04-16 15:20:36 -07:00
2008-04-29 00:59:20 -07:00
dbg ( " %s:%d at %s \n " , __func__ , __LINE__ , get_timestamp ( tsbuf ) ) ;
2005-04-16 15:20:36 -07:00
spin_lock_irqsave ( & sp - > lock , flags ) ;
sp - > current_command = dequeue_command ( sp ) ;
if ( sp - > current_command ) {
command_get ( sp - > current_command ) ;
spin_unlock_irqrestore ( & sp - > lock , flags ) ;
do_exec_command ( sp ) ;
} else {
spin_unlock_irqrestore ( & sp - > lock , flags ) ;
}
}
2007-07-17 04:03:58 -07:00
/**
2005-04-16 15:20:36 -07:00
* Sleep until a command has failed or a response has been received
* and the command status been updated by the interrupt handler .
* ( see receive_response ) .
*/
void ibmasm_wait_for_response ( struct command * cmd , int timeout )
{
wait_event_interruptible_timeout ( cmd - > wait ,
cmd - > status = = IBMASM_CMD_COMPLETE | |
cmd - > status = = IBMASM_CMD_FAILED ,
timeout * HZ ) ;
}
/**
* receive_command_response
* called by the interrupt handler when a dot command of type command_response
* was received .
*/
void ibmasm_receive_command_response ( struct service_processor * sp , void * response , size_t size )
{
struct command * cmd = sp - > current_command ;
2007-07-17 04:03:58 -07:00
if ( ! sp - > current_command )
return ;
2005-04-16 15:20:36 -07:00
2005-06-21 17:16:36 -07:00
memcpy_fromio ( cmd - > buffer , response , min ( size , cmd - > buffer_size ) ) ;
2005-04-16 15:20:36 -07:00
cmd - > status = IBMASM_CMD_COMPLETE ;
2005-06-21 17:16:36 -07:00
wake_up ( & sp - > current_command - > wait ) ;
command_put ( sp - > current_command ) ;
2005-04-16 15:20:36 -07:00
exec_next_command ( sp ) ;
}