IPMI: A few minor fixes and some cosmetic changes.
Nothing big here, but some minor things that people have found and some minor reworks for names and include files. Thanks, -corey -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE/Q1c5nzg9ZpmiCaGYfOMkJGb/4EFAl2Dp3wACgkQYfOMkJGb /4HKIA/+N0zGXn4Hgp7FJPobpZvlUCswHGUUmk7+Wibf8qXqObClvDLsu4nsblbX n8tmAVV8OzjZvyx1L49Lan8yBB4rtMg1Y4+WC8hWi2j6eB1JY2jNjHKIRIVFZMIX z2uHGIRxyL/vPbyDkUFLQxmxqjuGzQHivkGyaPopI/Z7N+LCZMhfTiUHt1lJkxcj Uka+XgVNfe1OOkBSeVQcIzwppQH83i2j6NL0BrZ3Cu9vTMJTqiP8TRrgendxGyxb Tk/zTrE9Ct7tz3pD2/nqtyo5xAL4uLPoxJmM916ucYvS5nkUfYDhuJxWDrcjWsZe jV2/knCNIJn90aIFNs/lQOKb+OzeitGz7IdlHzJyi/cU7VhcpsrxfBTADR6ydTMk bmr1vvPOhN0PekSH6r9ly5FECTOWIEhoy6XWpoDGYtWvHj5OEtk4vDdJYE4aw5cd tZMM+x7x3P427rb7Dna0MgyFuAipJhQMzr+AzWEOGNQw505iZP5/C1UbkUFE6lWJ nr3tBVr6ZkJdTaO/aY2bA02loDJyEL5m8W/XaU2PSlKZkGZk1pLiOiB1v88upSpz ZpJ5w+ItjqZFRnVaRxTjPUwaieAm6iswXUvXCpKUPfnOSKAkPpAFDIsEpmNIUtfD slvFfztFFS7o1VrguTIqIgZ6p4xJETNrlZqNhr7In/Z3p5jg13Y= =5uQL -----END PGP SIGNATURE----- Merge tag 'for-linus-5.4-1' of git://github.com/cminyard/linux-ipmi Pull IPMI updates from Corey Minyard: "A few minor fixes and some cosmetic changes. Nothing big here, but some minor things that people have found and some minor reworks for names and include files" * tag 'for-linus-5.4-1' of git://github.com/cminyard/linux-ipmi: ipmi_si_intf: Fix race in timer shutdown handling ipmi: move message error checking to avoid deadlock ipmi_ssif: avoid registering duplicate ssif interface ipmi: Free receive messages when in an oops ipmi_si: Only schedule continuously in the thread in maintenance mode ipmi_si: Remove ipmi_ from the device attr names ipmi_si: Convert device attr permissions to octal ipmi_si: Rework some include files ipmi_si: Convert timespec64 to timespecalistair/sunxi64-5.4-dsi
commit
a9f8b38a07
|
@ -12,7 +12,6 @@
|
||||||
#include <linux/dmi.h>
|
#include <linux/dmi.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/property.h>
|
#include <linux/property.h>
|
||||||
#include "ipmi_si_sm.h"
|
|
||||||
#include "ipmi_dmi.h"
|
#include "ipmi_dmi.h"
|
||||||
#include "ipmi_plat_data.h"
|
#include "ipmi_plat_data.h"
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
/*
|
/*
|
||||||
* DMI defines for use by IPMI
|
* DMI defines for use by IPMI
|
||||||
*/
|
*/
|
||||||
|
#include "ipmi_si.h"
|
||||||
|
|
||||||
#ifdef CONFIG_IPMI_DMI_DECODE
|
#ifdef CONFIG_IPMI_DMI_DECODE
|
||||||
int ipmi_dmi_get_slave_addr(enum si_type si_type, unsigned int space,
|
int ipmi_dmi_get_slave_addr(enum si_type si_type, unsigned int space,
|
||||||
|
|
|
@ -904,12 +904,14 @@ static int deliver_response(struct ipmi_smi *intf, struct ipmi_recv_msg *msg)
|
||||||
rv = -EINVAL;
|
rv = -EINVAL;
|
||||||
}
|
}
|
||||||
ipmi_free_recv_msg(msg);
|
ipmi_free_recv_msg(msg);
|
||||||
} else if (!oops_in_progress) {
|
} else if (oops_in_progress) {
|
||||||
/*
|
/*
|
||||||
* If we are running in the panic context, calling the
|
* If we are running in the panic context, calling the
|
||||||
* receive handler doesn't much meaning and has a deadlock
|
* receive handler doesn't much meaning and has a deadlock
|
||||||
* risk. At this moment, simply skip it in that case.
|
* risk. At this moment, simply skip it in that case.
|
||||||
*/
|
*/
|
||||||
|
ipmi_free_recv_msg(msg);
|
||||||
|
} else {
|
||||||
int index;
|
int index;
|
||||||
struct ipmi_user *user = acquire_ipmi_user(msg->user, &index);
|
struct ipmi_user *user = acquire_ipmi_user(msg->user, &index);
|
||||||
|
|
||||||
|
@ -2220,7 +2222,8 @@ static int i_ipmi_request(struct ipmi_user *user,
|
||||||
else {
|
else {
|
||||||
smi_msg = ipmi_alloc_smi_msg();
|
smi_msg = ipmi_alloc_smi_msg();
|
||||||
if (smi_msg == NULL) {
|
if (smi_msg == NULL) {
|
||||||
ipmi_free_recv_msg(recv_msg);
|
if (!supplied_recv)
|
||||||
|
ipmi_free_recv_msg(recv_msg);
|
||||||
rv = -ENOMEM;
|
rv = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -4215,7 +4218,53 @@ static int handle_one_recv_msg(struct ipmi_smi *intf,
|
||||||
int chan;
|
int chan;
|
||||||
|
|
||||||
ipmi_debug_msg("Recv:", msg->rsp, msg->rsp_size);
|
ipmi_debug_msg("Recv:", msg->rsp, msg->rsp_size);
|
||||||
if (msg->rsp_size < 2) {
|
|
||||||
|
if ((msg->data_size >= 2)
|
||||||
|
&& (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2))
|
||||||
|
&& (msg->data[1] == IPMI_SEND_MSG_CMD)
|
||||||
|
&& (msg->user_data == NULL)) {
|
||||||
|
|
||||||
|
if (intf->in_shutdown)
|
||||||
|
goto free_msg;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the local response to a command send, start
|
||||||
|
* the timer for these. The user_data will not be
|
||||||
|
* NULL if this is a response send, and we will let
|
||||||
|
* response sends just go through.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for errors, if we get certain errors (ones
|
||||||
|
* that mean basically we can try again later), we
|
||||||
|
* ignore them and start the timer. Otherwise we
|
||||||
|
* report the error immediately.
|
||||||
|
*/
|
||||||
|
if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0)
|
||||||
|
&& (msg->rsp[2] != IPMI_NODE_BUSY_ERR)
|
||||||
|
&& (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR)
|
||||||
|
&& (msg->rsp[2] != IPMI_BUS_ERR)
|
||||||
|
&& (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR)) {
|
||||||
|
int ch = msg->rsp[3] & 0xf;
|
||||||
|
struct ipmi_channel *chans;
|
||||||
|
|
||||||
|
/* Got an error sending the message, handle it. */
|
||||||
|
|
||||||
|
chans = READ_ONCE(intf->channel_list)->c;
|
||||||
|
if ((chans[ch].medium == IPMI_CHANNEL_MEDIUM_8023LAN)
|
||||||
|
|| (chans[ch].medium == IPMI_CHANNEL_MEDIUM_ASYNC))
|
||||||
|
ipmi_inc_stat(intf, sent_lan_command_errs);
|
||||||
|
else
|
||||||
|
ipmi_inc_stat(intf, sent_ipmb_command_errs);
|
||||||
|
intf_err_seq(intf, msg->msgid, msg->rsp[2]);
|
||||||
|
} else
|
||||||
|
/* The message was sent, start the timer. */
|
||||||
|
intf_start_seq_timer(intf, msg->msgid);
|
||||||
|
free_msg:
|
||||||
|
requeue = 0;
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
} else if (msg->rsp_size < 2) {
|
||||||
/* Message is too small to be correct. */
|
/* Message is too small to be correct. */
|
||||||
dev_warn(intf->si_dev,
|
dev_warn(intf->si_dev,
|
||||||
"BMC returned too small a message for netfn %x cmd %x, got %d bytes\n",
|
"BMC returned too small a message for netfn %x cmd %x, got %d bytes\n",
|
||||||
|
@ -4472,62 +4521,16 @@ void ipmi_smi_msg_received(struct ipmi_smi *intf,
|
||||||
unsigned long flags = 0; /* keep us warning-free. */
|
unsigned long flags = 0; /* keep us warning-free. */
|
||||||
int run_to_completion = intf->run_to_completion;
|
int run_to_completion = intf->run_to_completion;
|
||||||
|
|
||||||
if ((msg->data_size >= 2)
|
/*
|
||||||
&& (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2))
|
* To preserve message order, we keep a queue and deliver from
|
||||||
&& (msg->data[1] == IPMI_SEND_MSG_CMD)
|
* a tasklet.
|
||||||
&& (msg->user_data == NULL)) {
|
*/
|
||||||
|
if (!run_to_completion)
|
||||||
if (intf->in_shutdown)
|
spin_lock_irqsave(&intf->waiting_rcv_msgs_lock, flags);
|
||||||
goto free_msg;
|
list_add_tail(&msg->link, &intf->waiting_rcv_msgs);
|
||||||
|
if (!run_to_completion)
|
||||||
/*
|
spin_unlock_irqrestore(&intf->waiting_rcv_msgs_lock,
|
||||||
* This is the local response to a command send, start
|
flags);
|
||||||
* the timer for these. The user_data will not be
|
|
||||||
* NULL if this is a response send, and we will let
|
|
||||||
* response sends just go through.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check for errors, if we get certain errors (ones
|
|
||||||
* that mean basically we can try again later), we
|
|
||||||
* ignore them and start the timer. Otherwise we
|
|
||||||
* report the error immediately.
|
|
||||||
*/
|
|
||||||
if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0)
|
|
||||||
&& (msg->rsp[2] != IPMI_NODE_BUSY_ERR)
|
|
||||||
&& (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR)
|
|
||||||
&& (msg->rsp[2] != IPMI_BUS_ERR)
|
|
||||||
&& (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR)) {
|
|
||||||
int ch = msg->rsp[3] & 0xf;
|
|
||||||
struct ipmi_channel *chans;
|
|
||||||
|
|
||||||
/* Got an error sending the message, handle it. */
|
|
||||||
|
|
||||||
chans = READ_ONCE(intf->channel_list)->c;
|
|
||||||
if ((chans[ch].medium == IPMI_CHANNEL_MEDIUM_8023LAN)
|
|
||||||
|| (chans[ch].medium == IPMI_CHANNEL_MEDIUM_ASYNC))
|
|
||||||
ipmi_inc_stat(intf, sent_lan_command_errs);
|
|
||||||
else
|
|
||||||
ipmi_inc_stat(intf, sent_ipmb_command_errs);
|
|
||||||
intf_err_seq(intf, msg->msgid, msg->rsp[2]);
|
|
||||||
} else
|
|
||||||
/* The message was sent, start the timer. */
|
|
||||||
intf_start_seq_timer(intf, msg->msgid);
|
|
||||||
|
|
||||||
free_msg:
|
|
||||||
ipmi_free_smi_msg(msg);
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* To preserve message order, we keep a queue and deliver from
|
|
||||||
* a tasklet.
|
|
||||||
*/
|
|
||||||
if (!run_to_completion)
|
|
||||||
spin_lock_irqsave(&intf->waiting_rcv_msgs_lock, flags);
|
|
||||||
list_add_tail(&msg->link, &intf->waiting_rcv_msgs);
|
|
||||||
if (!run_to_completion)
|
|
||||||
spin_unlock_irqrestore(&intf->waiting_rcv_msgs_lock,
|
|
||||||
flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!run_to_completion)
|
if (!run_to_completion)
|
||||||
spin_lock_irqsave(&intf->xmit_msgs_lock, flags);
|
spin_lock_irqsave(&intf->xmit_msgs_lock, flags);
|
||||||
|
|
|
@ -6,14 +6,65 @@
|
||||||
* etc) to the base ipmi system interface code.
|
* etc) to the base ipmi system interface code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef __IPMI_SI_H__
|
||||||
|
#define __IPMI_SI_H__
|
||||||
|
|
||||||
|
#include <linux/ipmi.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include "ipmi_si_sm.h"
|
|
||||||
|
#define SI_DEVICE_NAME "ipmi_si"
|
||||||
|
|
||||||
#define DEFAULT_REGSPACING 1
|
#define DEFAULT_REGSPACING 1
|
||||||
#define DEFAULT_REGSIZE 1
|
#define DEFAULT_REGSIZE 1
|
||||||
|
|
||||||
#define DEVICE_NAME "ipmi_si"
|
enum si_type {
|
||||||
|
SI_TYPE_INVALID, SI_KCS, SI_SMIC, SI_BT
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ipmi_addr_space {
|
||||||
|
IPMI_IO_ADDR_SPACE, IPMI_MEM_ADDR_SPACE
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The structure for doing I/O in the state machine. The state
|
||||||
|
* machine doesn't have the actual I/O routines, they are done through
|
||||||
|
* this interface.
|
||||||
|
*/
|
||||||
|
struct si_sm_io {
|
||||||
|
unsigned char (*inputb)(const struct si_sm_io *io, unsigned int offset);
|
||||||
|
void (*outputb)(const struct si_sm_io *io,
|
||||||
|
unsigned int offset,
|
||||||
|
unsigned char b);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generic info used by the actual handling routines, the
|
||||||
|
* state machine shouldn't touch these.
|
||||||
|
*/
|
||||||
|
void __iomem *addr;
|
||||||
|
unsigned int regspacing;
|
||||||
|
unsigned int regsize;
|
||||||
|
unsigned int regshift;
|
||||||
|
enum ipmi_addr_space addr_space;
|
||||||
|
unsigned long addr_data;
|
||||||
|
enum ipmi_addr_src addr_source; /* ACPI, PCI, SMBIOS, hardcode, etc. */
|
||||||
|
void (*addr_source_cleanup)(struct si_sm_io *io);
|
||||||
|
void *addr_source_data;
|
||||||
|
union ipmi_smi_info_union addr_info;
|
||||||
|
|
||||||
|
int (*io_setup)(struct si_sm_io *info);
|
||||||
|
void (*io_cleanup)(struct si_sm_io *info);
|
||||||
|
unsigned int io_size;
|
||||||
|
|
||||||
|
int irq;
|
||||||
|
int (*irq_setup)(struct si_sm_io *io);
|
||||||
|
void *irq_handler_data;
|
||||||
|
void (*irq_cleanup)(struct si_sm_io *io);
|
||||||
|
|
||||||
|
u8 slave_addr;
|
||||||
|
enum si_type si_type;
|
||||||
|
struct device *dev;
|
||||||
|
};
|
||||||
|
|
||||||
int ipmi_si_add_smi(struct si_sm_io *io);
|
int ipmi_si_add_smi(struct si_sm_io *io);
|
||||||
irqreturn_t ipmi_si_irq_handler(int irq, void *data);
|
irqreturn_t ipmi_si_irq_handler(int irq, void *data);
|
||||||
|
@ -50,3 +101,5 @@ static inline void ipmi_si_parisc_shutdown(void) { }
|
||||||
|
|
||||||
int ipmi_si_port_setup(struct si_sm_io *io);
|
int ipmi_si_port_setup(struct si_sm_io *io);
|
||||||
int ipmi_si_mem_setup(struct si_sm_io *io);
|
int ipmi_si_mem_setup(struct si_sm_io *io);
|
||||||
|
|
||||||
|
#endif /* __IPMI_SI_H__ */
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include <linux/ipmi.h>
|
#include <linux/ipmi.h>
|
||||||
#include <linux/ipmi_smi.h>
|
#include <linux/ipmi_smi.h>
|
||||||
#include "ipmi_si.h"
|
#include "ipmi_si.h"
|
||||||
|
#include "ipmi_si_sm.h"
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/ctype.h>
|
#include <linux/ctype.h>
|
||||||
|
|
||||||
|
@ -221,6 +222,9 @@ struct smi_info {
|
||||||
*/
|
*/
|
||||||
bool irq_enable_broken;
|
bool irq_enable_broken;
|
||||||
|
|
||||||
|
/* Is the driver in maintenance mode? */
|
||||||
|
bool in_maintenance_mode;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Did we get an attention that we did not handle?
|
* Did we get an attention that we did not handle?
|
||||||
*/
|
*/
|
||||||
|
@ -261,10 +265,10 @@ static void cleanup_ipmi_si(void);
|
||||||
#ifdef DEBUG_TIMING
|
#ifdef DEBUG_TIMING
|
||||||
void debug_timestamp(char *msg)
|
void debug_timestamp(char *msg)
|
||||||
{
|
{
|
||||||
struct timespec64 t;
|
struct timespec t;
|
||||||
|
|
||||||
ktime_get_ts64(&t);
|
ktime_get_ts(&t);
|
||||||
pr_debug("**%s: %lld.%9.9ld\n", msg, (long long) t.tv_sec, t.tv_nsec);
|
pr_debug("**%s: %ld.%9.9ld\n", msg, (long) t.tv_sec, t.tv_nsec);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#define debug_timestamp(x)
|
#define debug_timestamp(x)
|
||||||
|
@ -935,18 +939,18 @@ static void set_run_to_completion(void *send_info, bool i_run_to_completion)
|
||||||
* we are spinning in kipmid looking for something and not delaying
|
* we are spinning in kipmid looking for something and not delaying
|
||||||
* between checks
|
* between checks
|
||||||
*/
|
*/
|
||||||
static inline void ipmi_si_set_not_busy(struct timespec64 *ts)
|
static inline void ipmi_si_set_not_busy(struct timespec *ts)
|
||||||
{
|
{
|
||||||
ts->tv_nsec = -1;
|
ts->tv_nsec = -1;
|
||||||
}
|
}
|
||||||
static inline int ipmi_si_is_busy(struct timespec64 *ts)
|
static inline int ipmi_si_is_busy(struct timespec *ts)
|
||||||
{
|
{
|
||||||
return ts->tv_nsec != -1;
|
return ts->tv_nsec != -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int ipmi_thread_busy_wait(enum si_sm_result smi_result,
|
static inline bool ipmi_thread_busy_wait(enum si_sm_result smi_result,
|
||||||
const struct smi_info *smi_info,
|
const struct smi_info *smi_info,
|
||||||
struct timespec64 *busy_until)
|
struct timespec *busy_until)
|
||||||
{
|
{
|
||||||
unsigned int max_busy_us = 0;
|
unsigned int max_busy_us = 0;
|
||||||
|
|
||||||
|
@ -955,18 +959,18 @@ static inline int ipmi_thread_busy_wait(enum si_sm_result smi_result,
|
||||||
if (max_busy_us == 0 || smi_result != SI_SM_CALL_WITH_DELAY)
|
if (max_busy_us == 0 || smi_result != SI_SM_CALL_WITH_DELAY)
|
||||||
ipmi_si_set_not_busy(busy_until);
|
ipmi_si_set_not_busy(busy_until);
|
||||||
else if (!ipmi_si_is_busy(busy_until)) {
|
else if (!ipmi_si_is_busy(busy_until)) {
|
||||||
ktime_get_ts64(busy_until);
|
ktime_get_ts(busy_until);
|
||||||
timespec64_add_ns(busy_until, max_busy_us*NSEC_PER_USEC);
|
timespec_add_ns(busy_until, max_busy_us * NSEC_PER_USEC);
|
||||||
} else {
|
} else {
|
||||||
struct timespec64 now;
|
struct timespec now;
|
||||||
|
|
||||||
ktime_get_ts64(&now);
|
ktime_get_ts(&now);
|
||||||
if (unlikely(timespec64_compare(&now, busy_until) > 0)) {
|
if (unlikely(timespec_compare(&now, busy_until) > 0)) {
|
||||||
ipmi_si_set_not_busy(busy_until);
|
ipmi_si_set_not_busy(busy_until);
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -984,7 +988,7 @@ static int ipmi_thread(void *data)
|
||||||
struct smi_info *smi_info = data;
|
struct smi_info *smi_info = data;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
enum si_sm_result smi_result;
|
enum si_sm_result smi_result;
|
||||||
struct timespec64 busy_until;
|
struct timespec busy_until = { 0, 0 };
|
||||||
|
|
||||||
ipmi_si_set_not_busy(&busy_until);
|
ipmi_si_set_not_busy(&busy_until);
|
||||||
set_user_nice(current, MAX_NICE);
|
set_user_nice(current, MAX_NICE);
|
||||||
|
@ -1007,11 +1011,20 @@ static int ipmi_thread(void *data)
|
||||||
spin_unlock_irqrestore(&(smi_info->si_lock), flags);
|
spin_unlock_irqrestore(&(smi_info->si_lock), flags);
|
||||||
busy_wait = ipmi_thread_busy_wait(smi_result, smi_info,
|
busy_wait = ipmi_thread_busy_wait(smi_result, smi_info,
|
||||||
&busy_until);
|
&busy_until);
|
||||||
if (smi_result == SI_SM_CALL_WITHOUT_DELAY)
|
if (smi_result == SI_SM_CALL_WITHOUT_DELAY) {
|
||||||
; /* do nothing */
|
; /* do nothing */
|
||||||
else if (smi_result == SI_SM_CALL_WITH_DELAY && busy_wait)
|
} else if (smi_result == SI_SM_CALL_WITH_DELAY && busy_wait) {
|
||||||
schedule();
|
/*
|
||||||
else if (smi_result == SI_SM_IDLE) {
|
* In maintenance mode we run as fast as
|
||||||
|
* possible to allow firmware updates to
|
||||||
|
* complete as fast as possible, but normally
|
||||||
|
* don't bang on the scheduler.
|
||||||
|
*/
|
||||||
|
if (smi_info->in_maintenance_mode)
|
||||||
|
schedule();
|
||||||
|
else
|
||||||
|
usleep_range(100, 200);
|
||||||
|
} else if (smi_result == SI_SM_IDLE) {
|
||||||
if (atomic_read(&smi_info->need_watch)) {
|
if (atomic_read(&smi_info->need_watch)) {
|
||||||
schedule_timeout_interruptible(100);
|
schedule_timeout_interruptible(100);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1019,8 +1032,9 @@ static int ipmi_thread(void *data)
|
||||||
__set_current_state(TASK_INTERRUPTIBLE);
|
__set_current_state(TASK_INTERRUPTIBLE);
|
||||||
schedule();
|
schedule();
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
schedule_timeout_interruptible(1);
|
schedule_timeout_interruptible(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1198,6 +1212,7 @@ static void set_maintenance_mode(void *send_info, bool enable)
|
||||||
|
|
||||||
if (!enable)
|
if (!enable)
|
||||||
atomic_set(&smi_info->req_events, 0);
|
atomic_set(&smi_info->req_events, 0);
|
||||||
|
smi_info->in_maintenance_mode = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void shutdown_smi(void *send_info);
|
static void shutdown_smi(void *send_info);
|
||||||
|
@ -1266,12 +1281,12 @@ int ipmi_std_irq_setup(struct si_sm_io *io)
|
||||||
rv = request_irq(io->irq,
|
rv = request_irq(io->irq,
|
||||||
ipmi_si_irq_handler,
|
ipmi_si_irq_handler,
|
||||||
IRQF_SHARED,
|
IRQF_SHARED,
|
||||||
DEVICE_NAME,
|
SI_DEVICE_NAME,
|
||||||
io->irq_handler_data);
|
io->irq_handler_data);
|
||||||
if (rv) {
|
if (rv) {
|
||||||
dev_warn(io->dev, "%s unable to claim interrupt %d,"
|
dev_warn(io->dev, "%s unable to claim interrupt %d,"
|
||||||
" running polled\n",
|
" running polled\n",
|
||||||
DEVICE_NAME, io->irq);
|
SI_DEVICE_NAME, io->irq);
|
||||||
io->irq = 0;
|
io->irq = 0;
|
||||||
} else {
|
} else {
|
||||||
io->irq_cleanup = std_irq_cleanup;
|
io->irq_cleanup = std_irq_cleanup;
|
||||||
|
@ -1586,37 +1601,37 @@ out:
|
||||||
}
|
}
|
||||||
|
|
||||||
#define IPMI_SI_ATTR(name) \
|
#define IPMI_SI_ATTR(name) \
|
||||||
static ssize_t ipmi_##name##_show(struct device *dev, \
|
static ssize_t name##_show(struct device *dev, \
|
||||||
struct device_attribute *attr, \
|
struct device_attribute *attr, \
|
||||||
char *buf) \
|
char *buf) \
|
||||||
{ \
|
{ \
|
||||||
struct smi_info *smi_info = dev_get_drvdata(dev); \
|
struct smi_info *smi_info = dev_get_drvdata(dev); \
|
||||||
\
|
\
|
||||||
return snprintf(buf, 10, "%u\n", smi_get_stat(smi_info, name)); \
|
return snprintf(buf, 10, "%u\n", smi_get_stat(smi_info, name)); \
|
||||||
} \
|
} \
|
||||||
static DEVICE_ATTR(name, S_IRUGO, ipmi_##name##_show, NULL)
|
static DEVICE_ATTR(name, 0444, name##_show, NULL)
|
||||||
|
|
||||||
static ssize_t ipmi_type_show(struct device *dev,
|
static ssize_t type_show(struct device *dev,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
struct smi_info *smi_info = dev_get_drvdata(dev);
|
struct smi_info *smi_info = dev_get_drvdata(dev);
|
||||||
|
|
||||||
return snprintf(buf, 10, "%s\n", si_to_str[smi_info->io.si_type]);
|
return snprintf(buf, 10, "%s\n", si_to_str[smi_info->io.si_type]);
|
||||||
}
|
}
|
||||||
static DEVICE_ATTR(type, S_IRUGO, ipmi_type_show, NULL);
|
static DEVICE_ATTR(type, 0444, type_show, NULL);
|
||||||
|
|
||||||
static ssize_t ipmi_interrupts_enabled_show(struct device *dev,
|
static ssize_t interrupts_enabled_show(struct device *dev,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
struct smi_info *smi_info = dev_get_drvdata(dev);
|
struct smi_info *smi_info = dev_get_drvdata(dev);
|
||||||
int enabled = smi_info->io.irq && !smi_info->interrupt_disabled;
|
int enabled = smi_info->io.irq && !smi_info->interrupt_disabled;
|
||||||
|
|
||||||
return snprintf(buf, 10, "%d\n", enabled);
|
return snprintf(buf, 10, "%d\n", enabled);
|
||||||
}
|
}
|
||||||
static DEVICE_ATTR(interrupts_enabled, S_IRUGO,
|
static DEVICE_ATTR(interrupts_enabled, 0444,
|
||||||
ipmi_interrupts_enabled_show, NULL);
|
interrupts_enabled_show, NULL);
|
||||||
|
|
||||||
IPMI_SI_ATTR(short_timeouts);
|
IPMI_SI_ATTR(short_timeouts);
|
||||||
IPMI_SI_ATTR(long_timeouts);
|
IPMI_SI_ATTR(long_timeouts);
|
||||||
|
@ -1630,9 +1645,9 @@ IPMI_SI_ATTR(events);
|
||||||
IPMI_SI_ATTR(watchdog_pretimeouts);
|
IPMI_SI_ATTR(watchdog_pretimeouts);
|
||||||
IPMI_SI_ATTR(incoming_messages);
|
IPMI_SI_ATTR(incoming_messages);
|
||||||
|
|
||||||
static ssize_t ipmi_params_show(struct device *dev,
|
static ssize_t params_show(struct device *dev,
|
||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
struct smi_info *smi_info = dev_get_drvdata(dev);
|
struct smi_info *smi_info = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
@ -1647,7 +1662,7 @@ static ssize_t ipmi_params_show(struct device *dev,
|
||||||
smi_info->io.irq,
|
smi_info->io.irq,
|
||||||
smi_info->io.slave_addr);
|
smi_info->io.slave_addr);
|
||||||
}
|
}
|
||||||
static DEVICE_ATTR(params, S_IRUGO, ipmi_params_show, NULL);
|
static DEVICE_ATTR(params, 0444, params_show, NULL);
|
||||||
|
|
||||||
static struct attribute *ipmi_si_dev_attrs[] = {
|
static struct attribute *ipmi_si_dev_attrs[] = {
|
||||||
&dev_attr_type.attr,
|
&dev_attr_type.attr,
|
||||||
|
@ -1828,8 +1843,7 @@ static inline void stop_timer_and_thread(struct smi_info *smi_info)
|
||||||
}
|
}
|
||||||
|
|
||||||
smi_info->timer_can_start = false;
|
smi_info->timer_can_start = false;
|
||||||
if (smi_info->timer_running)
|
del_timer_sync(&smi_info->si_timer);
|
||||||
del_timer_sync(&smi_info->si_timer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct smi_info *find_dup_si(struct smi_info *info)
|
static struct smi_info *find_dup_si(struct smi_info *info)
|
||||||
|
|
|
@ -118,7 +118,7 @@ int ipmi_si_mem_setup(struct si_sm_io *io)
|
||||||
*/
|
*/
|
||||||
for (idx = 0; idx < io->io_size; idx++) {
|
for (idx = 0; idx < io->io_size; idx++) {
|
||||||
if (request_mem_region(addr + idx * io->regspacing,
|
if (request_mem_region(addr + idx * io->regspacing,
|
||||||
io->regsize, DEVICE_NAME) == NULL) {
|
io->regsize, SI_DEVICE_NAME) == NULL) {
|
||||||
/* Undo allocations */
|
/* Undo allocations */
|
||||||
mem_region_cleanup(io, idx);
|
mem_region_cleanup(io, idx);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
|
@ -150,7 +150,7 @@ static const struct pci_device_id ipmi_pci_devices[] = {
|
||||||
MODULE_DEVICE_TABLE(pci, ipmi_pci_devices);
|
MODULE_DEVICE_TABLE(pci, ipmi_pci_devices);
|
||||||
|
|
||||||
static struct pci_driver ipmi_pci_driver = {
|
static struct pci_driver ipmi_pci_driver = {
|
||||||
.name = DEVICE_NAME,
|
.name = SI_DEVICE_NAME,
|
||||||
.id_table = ipmi_pci_devices,
|
.id_table = ipmi_pci_devices,
|
||||||
.probe = ipmi_pci_probe,
|
.probe = ipmi_pci_probe,
|
||||||
.remove = ipmi_pci_remove,
|
.remove = ipmi_pci_remove,
|
||||||
|
|
|
@ -457,7 +457,7 @@ static const struct platform_device_id si_plat_ids[] = {
|
||||||
|
|
||||||
struct platform_driver ipmi_platform_driver = {
|
struct platform_driver ipmi_platform_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = DEVICE_NAME,
|
.name = SI_DEVICE_NAME,
|
||||||
.of_match_table = of_ipmi_match,
|
.of_match_table = of_ipmi_match,
|
||||||
.acpi_match_table = ACPI_PTR(acpi_ipmi_match),
|
.acpi_match_table = ACPI_PTR(acpi_ipmi_match),
|
||||||
},
|
},
|
||||||
|
|
|
@ -99,7 +99,7 @@ int ipmi_si_port_setup(struct si_sm_io *io)
|
||||||
*/
|
*/
|
||||||
for (idx = 0; idx < io->io_size; idx++) {
|
for (idx = 0; idx < io->io_size; idx++) {
|
||||||
if (request_region(addr + idx * io->regspacing,
|
if (request_region(addr + idx * io->regspacing,
|
||||||
io->regsize, DEVICE_NAME) == NULL) {
|
io->regsize, SI_DEVICE_NAME) == NULL) {
|
||||||
/* Undo allocations */
|
/* Undo allocations */
|
||||||
while (idx--)
|
while (idx--)
|
||||||
release_region(addr + idx * io->regspacing,
|
release_region(addr + idx * io->regspacing,
|
||||||
|
|
|
@ -14,7 +14,10 @@
|
||||||
* Copyright 2002 MontaVista Software Inc.
|
* Copyright 2002 MontaVista Software Inc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/ipmi.h>
|
#ifndef __IPMI_SI_SM_H__
|
||||||
|
#define __IPMI_SI_SM_H__
|
||||||
|
|
||||||
|
#include "ipmi_si.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is defined by the state machines themselves, it is an opaque
|
* This is defined by the state machines themselves, it is an opaque
|
||||||
|
@ -22,54 +25,6 @@
|
||||||
*/
|
*/
|
||||||
struct si_sm_data;
|
struct si_sm_data;
|
||||||
|
|
||||||
enum si_type {
|
|
||||||
SI_TYPE_INVALID, SI_KCS, SI_SMIC, SI_BT
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ipmi_addr_space {
|
|
||||||
IPMI_IO_ADDR_SPACE, IPMI_MEM_ADDR_SPACE
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The structure for doing I/O in the state machine. The state
|
|
||||||
* machine doesn't have the actual I/O routines, they are done through
|
|
||||||
* this interface.
|
|
||||||
*/
|
|
||||||
struct si_sm_io {
|
|
||||||
unsigned char (*inputb)(const struct si_sm_io *io, unsigned int offset);
|
|
||||||
void (*outputb)(const struct si_sm_io *io,
|
|
||||||
unsigned int offset,
|
|
||||||
unsigned char b);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Generic info used by the actual handling routines, the
|
|
||||||
* state machine shouldn't touch these.
|
|
||||||
*/
|
|
||||||
void __iomem *addr;
|
|
||||||
unsigned int regspacing;
|
|
||||||
unsigned int regsize;
|
|
||||||
unsigned int regshift;
|
|
||||||
enum ipmi_addr_space addr_space;
|
|
||||||
unsigned long addr_data;
|
|
||||||
enum ipmi_addr_src addr_source; /* ACPI, PCI, SMBIOS, hardcode, etc. */
|
|
||||||
void (*addr_source_cleanup)(struct si_sm_io *io);
|
|
||||||
void *addr_source_data;
|
|
||||||
union ipmi_smi_info_union addr_info;
|
|
||||||
|
|
||||||
int (*io_setup)(struct si_sm_io *info);
|
|
||||||
void (*io_cleanup)(struct si_sm_io *info);
|
|
||||||
unsigned int io_size;
|
|
||||||
|
|
||||||
int irq;
|
|
||||||
int (*irq_setup)(struct si_sm_io *io);
|
|
||||||
void *irq_handler_data;
|
|
||||||
void (*irq_cleanup)(struct si_sm_io *io);
|
|
||||||
|
|
||||||
u8 slave_addr;
|
|
||||||
enum si_type si_type;
|
|
||||||
struct device *dev;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Results of SMI events. */
|
/* Results of SMI events. */
|
||||||
enum si_sm_result {
|
enum si_sm_result {
|
||||||
SI_SM_CALL_WITHOUT_DELAY, /* Call the driver again immediately */
|
SI_SM_CALL_WITHOUT_DELAY, /* Call the driver again immediately */
|
||||||
|
@ -146,3 +101,4 @@ extern const struct si_sm_handlers kcs_smi_handlers;
|
||||||
extern const struct si_sm_handlers smic_smi_handlers;
|
extern const struct si_sm_handlers smic_smi_handlers;
|
||||||
extern const struct si_sm_handlers bt_smi_handlers;
|
extern const struct si_sm_handlers bt_smi_handlers;
|
||||||
|
|
||||||
|
#endif /* __IPMI_SI_SM_H__ */
|
||||||
|
|
|
@ -52,7 +52,6 @@
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/ctype.h>
|
#include <linux/ctype.h>
|
||||||
#include <linux/time64.h>
|
#include <linux/time64.h>
|
||||||
#include "ipmi_si_sm.h"
|
|
||||||
#include "ipmi_dmi.h"
|
#include "ipmi_dmi.h"
|
||||||
|
|
||||||
#define DEVICE_NAME "ipmi_ssif"
|
#define DEVICE_NAME "ipmi_ssif"
|
||||||
|
@ -1428,6 +1427,10 @@ static struct ssif_addr_info *ssif_info_find(unsigned short addr,
|
||||||
restart:
|
restart:
|
||||||
list_for_each_entry(info, &ssif_infos, link) {
|
list_for_each_entry(info, &ssif_infos, link) {
|
||||||
if (info->binfo.addr == addr) {
|
if (info->binfo.addr == addr) {
|
||||||
|
if (info->addr_src == SI_SMBIOS)
|
||||||
|
info->adapter_name = kstrdup(adapter_name,
|
||||||
|
GFP_KERNEL);
|
||||||
|
|
||||||
if (info->adapter_name || adapter_name) {
|
if (info->adapter_name || adapter_name) {
|
||||||
if (!info->adapter_name != !adapter_name) {
|
if (!info->adapter_name != !adapter_name) {
|
||||||
/* One is NULL and one is not */
|
/* One is NULL and one is not */
|
||||||
|
@ -1603,6 +1606,60 @@ out_no_multi_part:
|
||||||
#define GLOBAL_ENABLES_MASK (IPMI_BMC_EVT_MSG_BUFF | IPMI_BMC_RCV_MSG_INTR | \
|
#define GLOBAL_ENABLES_MASK (IPMI_BMC_EVT_MSG_BUFF | IPMI_BMC_RCV_MSG_INTR | \
|
||||||
IPMI_BMC_EVT_MSG_INTR)
|
IPMI_BMC_EVT_MSG_INTR)
|
||||||
|
|
||||||
|
static void ssif_remove_dup(struct i2c_client *client)
|
||||||
|
{
|
||||||
|
struct ssif_info *ssif_info = i2c_get_clientdata(client);
|
||||||
|
|
||||||
|
ipmi_unregister_smi(ssif_info->intf);
|
||||||
|
kfree(ssif_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ssif_add_infos(struct i2c_client *client)
|
||||||
|
{
|
||||||
|
struct ssif_addr_info *info;
|
||||||
|
|
||||||
|
info = kzalloc(sizeof(*info), GFP_KERNEL);
|
||||||
|
if (!info)
|
||||||
|
return -ENOMEM;
|
||||||
|
info->addr_src = SI_ACPI;
|
||||||
|
info->client = client;
|
||||||
|
info->adapter_name = kstrdup(client->adapter->name, GFP_KERNEL);
|
||||||
|
info->binfo.addr = client->addr;
|
||||||
|
list_add_tail(&info->link, &ssif_infos);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prefer ACPI over SMBIOS, if both are available.
|
||||||
|
* So if we get an ACPI interface and have already registered a SMBIOS
|
||||||
|
* interface at the same address, remove the SMBIOS and add the ACPI one.
|
||||||
|
*/
|
||||||
|
static int ssif_check_and_remove(struct i2c_client *client,
|
||||||
|
struct ssif_info *ssif_info)
|
||||||
|
{
|
||||||
|
struct ssif_addr_info *info;
|
||||||
|
|
||||||
|
list_for_each_entry(info, &ssif_infos, link) {
|
||||||
|
if (!info->client)
|
||||||
|
return 0;
|
||||||
|
if (!strcmp(info->adapter_name, client->adapter->name) &&
|
||||||
|
info->binfo.addr == client->addr) {
|
||||||
|
if (info->addr_src == SI_ACPI)
|
||||||
|
return -EEXIST;
|
||||||
|
|
||||||
|
if (ssif_info->addr_source == SI_ACPI &&
|
||||||
|
info->addr_src == SI_SMBIOS) {
|
||||||
|
dev_info(&client->dev,
|
||||||
|
"Removing %s-specified SSIF interface in favor of ACPI\n",
|
||||||
|
ipmi_addr_src_to_str(info->addr_src));
|
||||||
|
ssif_remove_dup(info->client);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
unsigned char msg[3];
|
unsigned char msg[3];
|
||||||
|
@ -1614,13 +1671,17 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||||
u8 slave_addr = 0;
|
u8 slave_addr = 0;
|
||||||
struct ssif_addr_info *addr_info = NULL;
|
struct ssif_addr_info *addr_info = NULL;
|
||||||
|
|
||||||
|
mutex_lock(&ssif_infos_mutex);
|
||||||
resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
|
resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
|
||||||
if (!resp)
|
if (!resp) {
|
||||||
|
mutex_unlock(&ssif_infos_mutex);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
ssif_info = kzalloc(sizeof(*ssif_info), GFP_KERNEL);
|
ssif_info = kzalloc(sizeof(*ssif_info), GFP_KERNEL);
|
||||||
if (!ssif_info) {
|
if (!ssif_info) {
|
||||||
kfree(resp);
|
kfree(resp);
|
||||||
|
mutex_unlock(&ssif_infos_mutex);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1639,6 +1700,19 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rv = ssif_check_and_remove(client, ssif_info);
|
||||||
|
/* If rv is 0 and addr source is not SI_ACPI, continue probing */
|
||||||
|
if (!rv && ssif_info->addr_source == SI_ACPI) {
|
||||||
|
rv = ssif_add_infos(client);
|
||||||
|
if (rv) {
|
||||||
|
dev_err(&client->dev, "Out of memory!, exiting ..\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
} else if (rv) {
|
||||||
|
dev_err(&client->dev, "Not probing, Interface already present\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
slave_addr = find_slave_address(client, slave_addr);
|
slave_addr = find_slave_address(client, slave_addr);
|
||||||
|
|
||||||
dev_info(&client->dev,
|
dev_info(&client->dev,
|
||||||
|
@ -1851,6 +1925,7 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||||
kfree(ssif_info);
|
kfree(ssif_info);
|
||||||
}
|
}
|
||||||
kfree(resp);
|
kfree(resp);
|
||||||
|
mutex_unlock(&ssif_infos_mutex);
|
||||||
return rv;
|
return rv;
|
||||||
|
|
||||||
out_remove_attr:
|
out_remove_attr:
|
||||||
|
|
Loading…
Reference in New Issue