linux/drivers/char/ipmi/ipmi_si_intf.c

// SPDX-License-Identifier: GPL-2.0+
/*
 * ipmi_si.c
 *
 * The interface to the IPMI driver for the system interfaces (KCS, SMIC,
 * BT).
 *
 * Author: MontaVista Software, Inc.
 *         Corey Minyard <[email protected]>
 *         [email protected]
 *
 * Copyright 2002 MontaVista Software Inc.
 * Copyright 2006 IBM Corp., Christian Krafft <[email protected]>
 */

/*
 * This file holds the "policy" for the interface to the SMI state
 * machine.  It does the configuration, handles timers and interrupts,
 * and drives the real SMI state machine.
 */

#define pr_fmt(fmt)

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/sched.h>
#include <linux/seq_file.h>
#include <linux/timer.h>
#include <linux/errno.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/list.h>
#include <linux/notifier.h>
#include <linux/mutex.h>
#include <linux/kthread.h>
#include <asm/irq.h>
#include <linux/interrupt.h>
#include <linux/rcupdate.h>
#include <linux/ipmi.h>
#include <linux/ipmi_smi.h>
#include "ipmi_si.h"
#include "ipmi_si_sm.h"
#include <linux/string.h>
#include <linux/ctype.h>

/* Measure times between events in the driver. */
#undef DEBUG_TIMING

/* Call every 10 ms. */
#define SI_TIMEOUT_TIME_USEC
#define SI_USEC_PER_JIFFY
#define SI_TIMEOUT_JIFFIES
#define SI_SHORT_TIMEOUT_USEC

enum si_intf_state {};

/* Some BT-specific defines we need here. */
#define IPMI_BT_INTMASK_REG
#define IPMI_BT_INTMASK_CLEAR_IRQ_BIT
#define IPMI_BT_INTMASK_ENABLE_IRQ_BIT

/* 'invalid' to allow a firmware-specified interface to be disabled */
const char *const si_to_str[] =;

static bool initialized;

/*
 * Indexes into stats[] in smi_info below.
 */
enum si_stat_indexes {};

struct smi_info {};

#define smi_inc_stat(smi, stat)
#define smi_get_stat(smi, stat)

#define IPMI_MAX_INTFS
static int force_kipmid[IPMI_MAX_INTFS];
static int num_force_kipmid;

static unsigned int kipmid_max_busy_us[IPMI_MAX_INTFS];
static int num_max_busy_us;

static bool unload_when_empty =;

static int try_smi_init(struct smi_info *smi);
static void cleanup_one_si(struct smi_info *smi_info);
static void cleanup_ipmi_si(void);

#ifdef DEBUG_TIMING
void debug_timestamp(struct smi_info *smi_info, char *msg)
{
	struct timespec64 t;

	ktime_get_ts64(&t);
	dev_dbg(smi_info->io.dev, "**%s: %lld.%9.9ld\n",
		msg, t.tv_sec, t.tv_nsec);
}
#else
#define debug_timestamp(smi_info, x)
#endif

static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list);
static int register_xaction_notifier(struct notifier_block *nb)
{}

static void deliver_recv_msg(struct smi_info *smi_info,
			     struct ipmi_smi_msg *msg)
{}

static void return_hosed_msg(struct smi_info *smi_info, int cCode)
{}

static enum si_sm_result start_next_msg(struct smi_info *smi_info)
{}

static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val)
{}

/*
 * Start a new message and (re)start the timer and thread.
 */
static void start_new_msg(struct smi_info *smi_info, unsigned char *msg,
			  unsigned int size)
{}

static void start_check_enables(struct smi_info *smi_info)
{}

static void start_clear_flags(struct smi_info *smi_info)
{}

static void start_getting_msg_queue(struct smi_info *smi_info)
{}

static void start_getting_events(struct smi_info *smi_info)
{}

/*
 * When we have a situtaion where we run out of memory and cannot
 * allocate messages, we just leave them in the BMC and run the system
 * polled until we can allocate some memory.  Once we have some
 * memory, we will re-enable the interrupt.
 *
 * Note that we cannot just use disable_irq(), since the interrupt may
 * be shared.
 */
static inline bool disable_si_irq(struct smi_info *smi_info)
{}

static inline bool enable_si_irq(struct smi_info *smi_info)
{}

/*
 * Allocate a message.  If unable to allocate, start the interrupt
 * disable process and return NULL.  If able to allocate but
 * interrupts are disabled, free the message and return NULL after
 * starting the interrupt enable process.
 */
static struct ipmi_smi_msg *alloc_msg_handle_irq(struct smi_info *smi_info)
{}

static void handle_flags(struct smi_info *smi_info)
{}

/*
 * Global enables we care about.
 */
#define GLOBAL_ENABLES_MASK

static u8 current_global_enables(struct smi_info *smi_info, u8 base,
				 bool *irq_on)
{}

static void check_bt_irq(struct smi_info *smi_info, bool irq_on)
{}

static void handle_transaction_done(struct smi_info *smi_info)
{}

/*
 * Called on timeouts and events.  Timeouts should pass the elapsed
 * time, interrupts should pass in zero.  Must be called with
 * si_lock held and interrupts disabled.
 */
static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
					   int time)
{}

static void check_start_timer_thread(struct smi_info *smi_info)
{}

static void flush_messages(void *send_info)
{}

static void sender(void                *send_info,
		   struct ipmi_smi_msg *msg)
{}

static void set_run_to_completion(void *send_info, bool i_run_to_completion)
{}

/*
 * Use -1 as a special constant to tell that we are spinning in kipmid
 * looking for something and not delaying between checks
 */
#define IPMI_TIME_NOT_BUSY
static inline bool ipmi_thread_busy_wait(enum si_sm_result smi_result,
					 const struct smi_info *smi_info,
					 ktime_t *busy_until)
{}


/*
 * A busy-waiting loop for speeding up IPMI operation.
 *
 * Lousy hardware makes this hard.  This is only enabled for systems
 * that are not BT and do not have interrupts.  It starts spinning
 * when an operation is complete or until max_busy tells it to stop
 * (if that is enabled).  See the paragraph on kimid_max_busy_us in
 * Documentation/driver-api/ipmi.rst for details.
 */
static int ipmi_thread(void *data)
{}


static void poll(void *send_info)
{}

static void request_events(void *send_info)
{}

static void set_need_watch(void *send_info, unsigned int watch_mask)
{}

static void smi_timeout(struct timer_list *t)
{}

irqreturn_t ipmi_si_irq_handler(int irq, void *data)
{}

static int smi_start_processing(void            *send_info,
				struct ipmi_smi *intf)
{}

static int get_smi_info(void *send_info, struct ipmi_smi_info *data)
{}

static void set_maintenance_mode(void *send_info, bool enable)
{}

static void shutdown_smi(void *send_info);
static const struct ipmi_smi_handlers handlers =;

static LIST_HEAD(smi_infos);
static DEFINE_MUTEX(smi_infos_lock);
static int smi_num; /* Used to sequence the SMIs */

static const char * const addr_space_to_str[] =;

module_param_array();
MODULE_PARM_DESC();
module_param(unload_when_empty, bool, 0);
MODULE_PARM_DESC();
module_param_array();
MODULE_PARM_DESC();

void ipmi_irq_finish_setup(struct si_sm_io *io)
{}

void ipmi_irq_start_cleanup(struct si_sm_io *io)
{}

static void std_irq_cleanup(struct si_sm_io *io)
{}

int ipmi_std_irq_setup(struct si_sm_io *io)
{}

static int wait_for_msg_done(struct smi_info *smi_info)
{}

static int try_get_dev_id(struct smi_info *smi_info)
{}

static int get_global_enables(struct smi_info *smi_info, u8 *enables)
{}

/*
 * Returns 1 if it gets an error from the command.
 */
static int set_global_enables(struct smi_info *smi_info, u8 enables)
{}

/*
 * Some BMCs do not support clearing the receive irq bit in the global
 * enables (even if they don't support interrupts on the BMC).  Check
 * for this and handle it properly.
 */
static void check_clr_rcv_irq(struct smi_info *smi_info)
{}

/*
 * Some BMCs do not support setting the interrupt bits in the global
 * enables even if they support interrupts.  Clearly bad, but we can
 * compensate.
 */
static void check_set_rcv_irq(struct smi_info *smi_info)
{}

static int try_enable_event_buffer(struct smi_info *smi_info)
{}

#define IPMI_SI_ATTR(name)

static ssize_t type_show(struct device *dev,
			 struct device_attribute *attr,
			 char *buf)
{}
static DEVICE_ATTR_RO(type);

static ssize_t interrupts_enabled_show(struct device *dev,
				       struct device_attribute *attr,
				       char *buf)
{}
static DEVICE_ATTR_RO(interrupts_enabled);

IPMI_SI_ATTR();
IPMI_SI_ATTR();
IPMI_SI_ATTR();
IPMI_SI_ATTR();
IPMI_SI_ATTR();
IPMI_SI_ATTR();
IPMI_SI_ATTR();
IPMI_SI_ATTR();
IPMI_SI_ATTR();
IPMI_SI_ATTR();
IPMI_SI_ATTR();

static ssize_t params_show(struct device *dev,
			   struct device_attribute *attr,
			   char *buf)
{}
static DEVICE_ATTR_RO(params);

static struct attribute *ipmi_si_dev_attrs[] =;

static const struct attribute_group ipmi_si_dev_attr_group =;

/*
 * oem_data_avail_to_receive_msg_avail
 * @info - smi_info structure with msg_flags set
 *
 * Converts flags from OEM_DATA_AVAIL to RECEIVE_MSG_AVAIL
 * Returns 1 indicating need to re-run handle_flags().
 */
static int oem_data_avail_to_receive_msg_avail(struct smi_info *smi_info)
{}

/*
 * setup_dell_poweredge_oem_data_handler
 * @info - smi_info.device_id must be populated
 *
 * Systems that match, but have firmware version < 1.40 may assert
 * OEM0_DATA_AVAIL on their own, without being told via Set Flags that
 * it's safe to do so.  Such systems will de-assert OEM1_DATA_AVAIL
 * upon receipt of IPMI_GET_MSG_CMD, so we should treat these flags
 * as RECEIVE_MSG_AVAIL instead.
 *
 * As Dell has no plans to release IPMI 1.5 firmware that *ever*
 * assert the OEM[012] bits, and if it did, the driver would have to
 * change to handle that properly, we don't actually check for the
 * firmware version.
 * Device ID = 0x20                BMC on PowerEdge 8G servers
 * Device Revision = 0x80
 * Firmware Revision1 = 0x01       BMC version 1.40
 * Firmware Revision2 = 0x40       BCD encoded
 * IPMI Version = 0x51             IPMI 1.5
 * Manufacturer ID = A2 02 00      Dell IANA
 *
 * Additionally, PowerEdge systems with IPMI < 1.5 may also assert
 * OEM0_DATA_AVAIL and needs to be treated as RECEIVE_MSG_AVAIL.
 *
 */
#define DELL_POWEREDGE_8G_BMC_DEVICE_ID
#define DELL_POWEREDGE_8G_BMC_DEVICE_REV
#define DELL_POWEREDGE_8G_BMC_IPMI_VERSION
#define DELL_IANA_MFR_ID
static void setup_dell_poweredge_oem_data_handler(struct smi_info *smi_info)
{}

#define CANNOT_RETURN_REQUESTED_LENGTH
static void return_hosed_msg_badsize(struct smi_info *smi_info)
{}

/*
 * dell_poweredge_bt_xaction_handler
 * @info - smi_info.device_id must be populated
 *
 * Dell PowerEdge servers with the BT interface (x6xx and 1750) will
 * not respond to a Get SDR command if the length of the data
 * requested is exactly 0x3A, which leads to command timeouts and no
 * data returned.  This intercepts such commands, and causes userspace
 * callers to try again with a different-sized buffer, which succeeds.
 */

#define STORAGE_NETFN
#define STORAGE_CMD_GET_SDR
static int dell_poweredge_bt_xaction_handler(struct notifier_block *self,
					     unsigned long unused,
					     void *in)
{}

static struct notifier_block dell_poweredge_bt_xaction_notifier =;

/*
 * setup_dell_poweredge_bt_xaction_handler
 * @info - smi_info.device_id must be filled in already
 *
 * Fills in smi_info.device_id.start_transaction_pre_hook
 * when we know what function to use there.
 */
static void
setup_dell_poweredge_bt_xaction_handler(struct smi_info *smi_info)
{}

/*
 * setup_oem_data_handler
 * @info - smi_info.device_id must be filled in already
 *
 * Fills in smi_info.device_id.oem_data_available_handler
 * when we know what function to use there.
 */

static void setup_oem_data_handler(struct smi_info *smi_info)
{}

static void setup_xaction_handlers(struct smi_info *smi_info)
{}

static void check_for_broken_irqs(struct smi_info *smi_info)
{}

static inline void stop_timer_and_thread(struct smi_info *smi_info)
{}

static struct smi_info *find_dup_si(struct smi_info *info)
{}

int ipmi_si_add_smi(struct si_sm_io *io)
{}

/*
 * Try to start up an interface.  Must be called with smi_infos_lock
 * held, primarily to keep smi_num consistent, we only one to do these
 * one at a time.
 */
static int try_smi_init(struct smi_info *new_smi)
{}

static int __init init_ipmi_si(void)
{}
module_init();

static void wait_msg_processed(struct smi_info *smi_info)
{}

static void shutdown_smi(void *send_info)
{}

/*
 * Must be called with smi_infos_lock held, to serialize the
 * smi_info->intf check.
 */
static void cleanup_one_si(struct smi_info *smi_info)
{}

void ipmi_si_remove_by_dev(struct device *dev)
{}

struct device *ipmi_si_remove_by_data(int addr_space, enum si_type si_type,
				      unsigned long addr)
{}

static void cleanup_ipmi_si(void)
{}
module_exit(cleanup_ipmi_si);

MODULE_ALIAS();
MODULE_LICENSE();
MODULE_AUTHOR();
MODULE_DESCRIPTION();