210 lines · c
1/* SPDX-License-Identifier: GPL-2.0-or-later */2 3/*4 * IBM ASM Service Processor Device Driver5 *6 * Copyright (C) IBM Corporation, 20047 *8 * Author: Max Asböck <amax@us.ibm.com>9 */10 11#include <linux/kernel.h>12#include <linux/types.h>13#include <linux/errno.h>14#include <linux/list.h>15#include <linux/wait.h>16#include <linux/spinlock.h>17#include <linux/slab.h>18#include <linux/module.h>19#include <linux/interrupt.h>20#include <linux/kref.h>21#include <linux/device.h>22#include <linux/input.h>23#include <linux/time64.h>24 25/* Driver identification */26#define DRIVER_NAME "ibmasm"27#define DRIVER_VERSION "1.0"28#define DRIVER_AUTHOR "Max Asbock <masbock@us.ibm.com>, Vernon Mauery <vernux@us.ibm.com>"29#define DRIVER_DESC "IBM ASM Service Processor Driver"30 31#define err(msg) printk(KERN_ERR "%s: " msg "\n", DRIVER_NAME)32#define info(msg) printk(KERN_INFO "%s: " msg "\n", DRIVER_NAME)33 34extern int ibmasm_debug;35#define dbg(STR, ARGS...) \36 do { \37 if (ibmasm_debug) \38 printk(KERN_DEBUG STR , ##ARGS); \39 } while (0)40 41static inline char *get_timestamp(char *buf)42{43 struct timespec64 now;44 45 ktime_get_real_ts64(&now);46 sprintf(buf, "%llu.%.08lu", (long long)now.tv_sec,47 now.tv_nsec / NSEC_PER_USEC);48 return buf;49}50 51#define IBMASM_CMD_PENDING 052#define IBMASM_CMD_COMPLETE 153#define IBMASM_CMD_FAILED 254 55#define IBMASM_CMD_TIMEOUT_NORMAL 4556#define IBMASM_CMD_TIMEOUT_EXTRA 24057 58#define IBMASM_CMD_MAX_BUFFER_SIZE 0x800059 60#define REVERSE_HEARTBEAT_TIMEOUT 12061 62#define HEARTBEAT_BUFFER_SIZE 0x40063 64#ifdef IA6465#define IBMASM_DRIVER_VPD "Lin64 6.08 "66#else67#define IBMASM_DRIVER_VPD "Lin32 6.08 "68#endif69 70#define SYSTEM_STATE_OS_UP 571#define SYSTEM_STATE_OS_DOWN 472 73#define IBMASM_NAME_SIZE 1674 75#define IBMASM_NUM_EVENTS 1076#define IBMASM_EVENT_MAX_SIZE 2048u77 78 79struct command {80 struct list_head queue_node;81 wait_queue_head_t wait;82 unsigned char *buffer;83 size_t buffer_size;84 int status;85 struct kref kref;86 spinlock_t *lock;87};88#define to_command(c) container_of(c, struct command, kref)89 90void ibmasm_free_command(struct kref *kref);91static inline void command_put(struct command *cmd)92{93 unsigned long flags;94 spinlock_t *lock = cmd->lock;95 96 spin_lock_irqsave(lock, flags);97 kref_put(&cmd->kref, ibmasm_free_command);98 spin_unlock_irqrestore(lock, flags);99}100 101static inline void command_get(struct command *cmd)102{103 kref_get(&cmd->kref);104}105 106 107struct ibmasm_event {108 unsigned int serial_number;109 unsigned int data_size;110 unsigned char data[IBMASM_EVENT_MAX_SIZE];111};112 113struct event_buffer {114 struct ibmasm_event events[IBMASM_NUM_EVENTS];115 unsigned int next_serial_number;116 unsigned int next_index;117 struct list_head readers;118};119 120struct event_reader {121 int cancelled;122 unsigned int next_serial_number;123 wait_queue_head_t wait;124 struct list_head node;125 unsigned int data_size;126 unsigned char data[IBMASM_EVENT_MAX_SIZE];127};128 129struct reverse_heartbeat {130 wait_queue_head_t wait;131 unsigned int stopped;132};133 134struct ibmasm_remote {135 struct input_dev *keybd_dev;136 struct input_dev *mouse_dev;137};138 139struct service_processor {140 struct list_head node;141 spinlock_t lock;142 void __iomem *base_address;143 unsigned int irq;144 struct command *current_command;145 struct command *heartbeat;146 struct list_head command_queue;147 struct event_buffer *event_buffer;148 char dirname[IBMASM_NAME_SIZE];149 char devname[IBMASM_NAME_SIZE];150 unsigned int number;151 struct ibmasm_remote remote;152 int serial_line;153 struct device *dev;154};155 156/* command processing */157struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_size);158void ibmasm_exec_command(struct service_processor *sp, struct command *cmd);159void ibmasm_wait_for_response(struct command *cmd, int timeout);160void ibmasm_receive_command_response(struct service_processor *sp, void *response, size_t size);161 162/* event processing */163int ibmasm_event_buffer_init(struct service_processor *sp);164void ibmasm_event_buffer_exit(struct service_processor *sp);165void ibmasm_receive_event(struct service_processor *sp, void *data, unsigned int data_size);166void ibmasm_event_reader_register(struct service_processor *sp, struct event_reader *reader);167void ibmasm_event_reader_unregister(struct service_processor *sp, struct event_reader *reader);168int ibmasm_get_next_event(struct service_processor *sp, struct event_reader *reader);169void ibmasm_cancel_next_event(struct event_reader *reader);170 171/* heartbeat - from SP to OS */172void ibmasm_register_panic_notifier(void);173void ibmasm_unregister_panic_notifier(void);174int ibmasm_heartbeat_init(struct service_processor *sp);175void ibmasm_heartbeat_exit(struct service_processor *sp);176void ibmasm_receive_heartbeat(struct service_processor *sp, void *message, size_t size);177 178/* reverse heartbeat - from OS to SP */179void ibmasm_init_reverse_heartbeat(struct service_processor *sp, struct reverse_heartbeat *rhb);180int ibmasm_start_reverse_heartbeat(struct service_processor *sp, struct reverse_heartbeat *rhb);181void ibmasm_stop_reverse_heartbeat(struct reverse_heartbeat *rhb);182 183/* dot commands */184void ibmasm_receive_message(struct service_processor *sp, void *data, int data_size);185int ibmasm_send_driver_vpd(struct service_processor *sp);186int ibmasm_send_os_state(struct service_processor *sp, int os_state);187 188/* low level message processing */189int ibmasm_send_i2o_message(struct service_processor *sp);190irqreturn_t ibmasm_interrupt_handler(int irq, void * dev_id);191 192/* remote console */193void ibmasm_handle_mouse_interrupt(struct service_processor *sp);194int ibmasm_init_remote_input_dev(struct service_processor *sp);195void ibmasm_free_remote_input_dev(struct service_processor *sp);196 197/* file system */198int ibmasmfs_register(void);199void ibmasmfs_unregister(void);200void ibmasmfs_add_sp(struct service_processor *sp);201 202/* uart */203#if IS_ENABLED(CONFIG_SERIAL_8250)204void ibmasm_register_uart(struct service_processor *sp);205void ibmasm_unregister_uart(struct service_processor *sp);206#else207#define ibmasm_register_uart(sp) do { } while(0)208#define ibmasm_unregister_uart(sp) do { } while(0)209#endif210