2019-05-27 09:55:05 +03:00
/* SPDX-License-Identifier: GPL-2.0-or-later */
2005-04-17 02:20:36 +04:00
/*
* IBM ASM Service Processor Device Driver
*
* Copyright ( C ) IBM Corporation , 2004
*
2011-12-30 02:09:01 +04:00
* Author : Max Asböck < amax @ us . ibm . com >
2005-04-17 02:20:36 +04:00
*/
# include <linux/kernel.h>
# include <linux/types.h>
# include <linux/errno.h>
# include <linux/list.h>
# include <linux/wait.h>
# include <linux/spinlock.h>
# include <linux/slab.h>
# include <linux/module.h>
# include <linux/interrupt.h>
2007-12-04 07:16:20 +03:00
# include <linux/kref.h>
2005-04-17 02:20:36 +04:00
# include <linux/device.h>
2005-06-22 04:16:34 +04:00
# include <linux/input.h>
2016-02-10 07:32:02 +03:00
# include <linux/time64.h>
2005-04-17 02:20:36 +04:00
/* Driver identification */
# define DRIVER_NAME "ibmasm"
2005-06-22 04:16:34 +04:00
# define DRIVER_VERSION "1.0"
# define DRIVER_AUTHOR "Max Asbock <masbock@us.ibm.com>, Vernon Mauery <vernux@us.ibm.com>"
2005-04-17 02:20:36 +04:00
# define DRIVER_DESC "IBM ASM Service Processor Driver"
# define err(msg) printk(KERN_ERR "%s: " msg "\n", DRIVER_NAME)
# define info(msg) printk(KERN_INFO "%s: " msg "\n", DRIVER_NAME)
2005-06-22 04:16:34 +04:00
extern int ibmasm_debug ;
# define dbg(STR, ARGS...) \
do { \
if ( ibmasm_debug ) \
printk ( KERN_DEBUG STR , # # ARGS ) ; \
} while ( 0 )
static inline char * get_timestamp ( char * buf )
{
2016-02-10 07:32:02 +03:00
struct timespec64 now ;
ktime_get_real_ts64 ( & now ) ;
sprintf ( buf , " %llu.%.08lu " , ( long long ) now . tv_sec ,
now . tv_nsec / NSEC_PER_USEC ) ;
2005-06-22 04:16:34 +04:00
return buf ;
}
2005-04-17 02:20:36 +04:00
2007-07-17 15:03:58 +04:00
# define IBMASM_CMD_PENDING 0
# define IBMASM_CMD_COMPLETE 1
2005-04-17 02:20:36 +04:00
# define IBMASM_CMD_FAILED 2
# define IBMASM_CMD_TIMEOUT_NORMAL 45
# define IBMASM_CMD_TIMEOUT_EXTRA 240
2005-06-22 04:16:32 +04:00
# define IBMASM_CMD_MAX_BUFFER_SIZE 0x8000
2005-04-17 02:20:36 +04:00
# define REVERSE_HEARTBEAT_TIMEOUT 120
# define HEARTBEAT_BUFFER_SIZE 0x400
# ifdef IA64
# define IBMASM_DRIVER_VPD "Lin64 6.08 "
# else
# define IBMASM_DRIVER_VPD "Lin32 6.08 "
# endif
# define SYSTEM_STATE_OS_UP 5
# define SYSTEM_STATE_OS_DOWN 4
# define IBMASM_NAME_SIZE 16
# define IBMASM_NUM_EVENTS 10
# define IBMASM_EVENT_MAX_SIZE 2048u
struct command {
struct list_head queue_node ;
wait_queue_head_t wait ;
unsigned char * buffer ;
size_t buffer_size ;
int status ;
2007-12-04 07:16:20 +03:00
struct kref kref ;
2005-06-22 04:16:36 +04:00
spinlock_t * lock ;
2005-04-17 02:20:36 +04:00
} ;
2007-12-04 07:16:20 +03:00
# define to_command(c) container_of(c, struct command, kref)
2005-04-17 02:20:36 +04:00
2007-12-04 07:16:20 +03:00
void ibmasm_free_command ( struct kref * kref ) ;
2005-04-17 02:20:36 +04:00
static inline void command_put ( struct command * cmd )
{
2005-06-22 04:16:36 +04:00
unsigned long flags ;
2006-03-10 04:33:48 +03:00
spinlock_t * lock = cmd - > lock ;
2005-06-22 04:16:36 +04:00
2006-03-10 04:33:48 +03:00
spin_lock_irqsave ( lock , flags ) ;
2007-12-04 07:16:20 +03:00
kref_put ( & cmd - > kref , ibmasm_free_command ) ;
2006-03-10 04:33:48 +03:00
spin_unlock_irqrestore ( lock , flags ) ;
2005-04-17 02:20:36 +04:00
}
static inline void command_get ( struct command * cmd )
{
2007-12-04 07:16:20 +03:00
kref_get ( & cmd - > kref ) ;
2005-04-17 02:20:36 +04:00
}
struct ibmasm_event {
unsigned int serial_number ;
unsigned int data_size ;
unsigned char data [ IBMASM_EVENT_MAX_SIZE ] ;
} ;
struct event_buffer {
struct ibmasm_event events [ IBMASM_NUM_EVENTS ] ;
unsigned int next_serial_number ;
unsigned int next_index ;
struct list_head readers ;
} ;
struct event_reader {
2005-06-22 04:16:33 +04:00
int cancelled ;
2005-04-17 02:20:36 +04:00
unsigned int next_serial_number ;
wait_queue_head_t wait ;
struct list_head node ;
unsigned int data_size ;
unsigned char data [ IBMASM_EVENT_MAX_SIZE ] ;
} ;
struct reverse_heartbeat {
wait_queue_head_t wait ;
unsigned int stopped ;
} ;
2005-06-22 04:16:34 +04:00
struct ibmasm_remote {
2006-01-07 19:35:05 +03:00
struct input_dev * keybd_dev ;
struct input_dev * mouse_dev ;
2005-04-17 02:20:36 +04:00
} ;
struct service_processor {
struct list_head node ;
spinlock_t lock ;
void __iomem * base_address ;
unsigned int irq ;
struct command * current_command ;
struct command * heartbeat ;
struct list_head command_queue ;
struct event_buffer * event_buffer ;
char dirname [ IBMASM_NAME_SIZE ] ;
char devname [ IBMASM_NAME_SIZE ] ;
unsigned int number ;
2006-01-07 19:35:05 +03:00
struct ibmasm_remote remote ;
2005-04-17 02:20:36 +04:00
int serial_line ;
struct device * dev ;
} ;
/* command processing */
2007-07-17 15:04:00 +04:00
struct command * ibmasm_new_command ( struct service_processor * sp , size_t buffer_size ) ;
void ibmasm_exec_command ( struct service_processor * sp , struct command * cmd ) ;
void ibmasm_wait_for_response ( struct command * cmd , int timeout ) ;
void ibmasm_receive_command_response ( struct service_processor * sp , void * response , size_t size ) ;
2005-04-17 02:20:36 +04:00
/* event processing */
2007-07-17 15:04:00 +04:00
int ibmasm_event_buffer_init ( struct service_processor * sp ) ;
void ibmasm_event_buffer_exit ( struct service_processor * sp ) ;
void ibmasm_receive_event ( struct service_processor * sp , void * data , unsigned int data_size ) ;
void ibmasm_event_reader_register ( struct service_processor * sp , struct event_reader * reader ) ;
void ibmasm_event_reader_unregister ( struct service_processor * sp , struct event_reader * reader ) ;
int ibmasm_get_next_event ( struct service_processor * sp , struct event_reader * reader ) ;
void ibmasm_cancel_next_event ( struct event_reader * reader ) ;
2005-04-17 02:20:36 +04:00
/* heartbeat - from SP to OS */
2007-07-17 15:04:00 +04:00
void ibmasm_register_panic_notifier ( void ) ;
void ibmasm_unregister_panic_notifier ( void ) ;
int ibmasm_heartbeat_init ( struct service_processor * sp ) ;
void ibmasm_heartbeat_exit ( struct service_processor * sp ) ;
void ibmasm_receive_heartbeat ( struct service_processor * sp , void * message , size_t size ) ;
2005-04-17 02:20:36 +04:00
/* reverse heartbeat - from OS to SP */
2007-07-17 15:04:00 +04:00
void ibmasm_init_reverse_heartbeat ( struct service_processor * sp , struct reverse_heartbeat * rhb ) ;
int ibmasm_start_reverse_heartbeat ( struct service_processor * sp , struct reverse_heartbeat * rhb ) ;
void ibmasm_stop_reverse_heartbeat ( struct reverse_heartbeat * rhb ) ;
2005-04-17 02:20:36 +04:00
/* dot commands */
2007-07-17 15:04:00 +04:00
void ibmasm_receive_message ( struct service_processor * sp , void * data , int data_size ) ;
int ibmasm_send_driver_vpd ( struct service_processor * sp ) ;
int ibmasm_send_os_state ( struct service_processor * sp , int os_state ) ;
2005-04-17 02:20:36 +04:00
/* low level message processing */
2007-07-17 15:04:00 +04:00
int ibmasm_send_i2o_message ( struct service_processor * sp ) ;
irqreturn_t ibmasm_interrupt_handler ( int irq , void * dev_id ) ;
2005-04-17 02:20:36 +04:00
/* remote console */
2007-07-17 15:04:00 +04:00
void ibmasm_handle_mouse_interrupt ( struct service_processor * sp ) ;
int ibmasm_init_remote_input_dev ( struct service_processor * sp ) ;
void ibmasm_free_remote_input_dev ( struct service_processor * sp ) ;
2005-04-17 02:20:36 +04:00
/* file system */
2007-07-17 15:04:00 +04:00
int ibmasmfs_register ( void ) ;
void ibmasmfs_unregister ( void ) ;
void ibmasmfs_add_sp ( struct service_processor * sp ) ;
2005-04-17 02:20:36 +04:00
/* uart */
2015-10-27 16:02:24 +03:00
# if IS_ENABLED(CONFIG_SERIAL_8250)
2007-07-17 15:04:00 +04:00
void ibmasm_register_uart ( struct service_processor * sp ) ;
void ibmasm_unregister_uart ( struct service_processor * sp ) ;
2005-04-17 02:20:36 +04:00
# else
# define ibmasm_register_uart(sp) do { } while(0)
# define ibmasm_unregister_uart(sp) do { } while(0)
# endif