Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
cloud-kernel
提交
4b63bd35
cloud-kernel
项目概览
openanolis
/
cloud-kernel
1 年多 前同步成功
通知
160
Star
36
Fork
7
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
10
列表
看板
标记
里程碑
合并请求
2
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
cloud-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
10
Issue
10
列表
看板
标记
里程碑
合并请求
2
合并请求
2
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
4b63bd35
编写于
1月 12, 2011
作者:
L
Len Brown
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'ipmi' into release
上级
03b6e6e5
e92b297c
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
653 addition
and
4 deletion
+653
-4
Documentation/IPMI.txt
Documentation/IPMI.txt
+27
-0
drivers/acpi/Kconfig
drivers/acpi/Kconfig
+11
-0
drivers/acpi/Makefile
drivers/acpi/Makefile
+1
-0
drivers/acpi/acpi_ipmi.c
drivers/acpi/acpi_ipmi.c
+525
-0
drivers/char/ipmi/ipmi_msghandler.c
drivers/char/ipmi/ipmi_msghandler.c
+27
-0
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/ipmi/ipmi_si_intf.c
+16
-4
include/linux/ipmi.h
include/linux/ipmi.h
+38
-0
include/linux/ipmi_smi.h
include/linux/ipmi_smi.h
+8
-0
未找到文件。
Documentation/IPMI.txt
浏览文件 @
4b63bd35
...
...
@@ -533,6 +533,33 @@ completion during sending a panic event.
Other Pieces
------------
Get the detailed info related with the IPMI device
--------------------------------------------------
Some users need more detailed information about a device, like where
the address came from or the raw base device for the IPMI interface.
You can use the IPMI smi_watcher to catch the IPMI interfaces as they
come or go, and to grab the information, you can use the function
ipmi_get_smi_info(), which returns the following structure:
struct ipmi_smi_info {
enum ipmi_addr_src addr_src;
struct device *dev;
union {
struct {
void *acpi_handle;
} acpi_info;
} addr_info;
};
Currently special info for only for SI_ACPI address sources is
returned. Others may be added as necessary.
Note that the dev pointer is included in the above structure, and
assuming ipmi_smi_get_info returns success, you must call put_device
on the dev pointer.
Watchdog
--------
...
...
drivers/acpi/Kconfig
浏览文件 @
4b63bd35
...
...
@@ -207,6 +207,17 @@ config ACPI_PROCESSOR
To compile this driver as a module, choose M here:
the module will be called processor.
config ACPI_IPMI
tristate "IPMI"
depends on EXPERIMENTAL && IPMI_SI && IPMI_HANDLER
default n
help
This driver enables the ACPI to access the BMC controller. And it
uses the IPMI request/response message to communicate with BMC
controller, which can be found on on the server.
To compile this driver as a module, choose M here:
the module will be called as acpi_ipmi.
config ACPI_HOTPLUG_CPU
bool
...
...
drivers/acpi/Makefile
浏览文件 @
4b63bd35
...
...
@@ -69,5 +69,6 @@ processor-y += processor_idle.o processor_thermal.o
processor-$(CONFIG_CPU_FREQ)
+=
processor_perflib.o
obj-$(CONFIG_ACPI_PROCESSOR_AGGREGATOR)
+=
acpi_pad.o
obj-$(CONFIG_ACPI_IPMI)
+=
acpi_ipmi.o
obj-$(CONFIG_ACPI_APEI)
+=
apei/
drivers/acpi/acpi_ipmi.c
0 → 100644
浏览文件 @
4b63bd35
/*
* acpi_ipmi.c - ACPI IPMI opregion
*
* Copyright (C) 2010 Intel Corporation
* Copyright (C) 2010 Zhao Yakui <yakui.zhao@intel.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* 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.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <linux/ipmi.h>
#include <linux/device.h>
#include <linux/pnp.h>
MODULE_AUTHOR
(
"Zhao Yakui"
);
MODULE_DESCRIPTION
(
"ACPI IPMI Opregion driver"
);
MODULE_LICENSE
(
"GPL"
);
#define IPMI_FLAGS_HANDLER_INSTALL 0
#define ACPI_IPMI_OK 0
#define ACPI_IPMI_TIMEOUT 0x10
#define ACPI_IPMI_UNKNOWN 0x07
/* the IPMI timeout is 5s */
#define IPMI_TIMEOUT (5 * HZ)
struct
acpi_ipmi_device
{
/* the device list attached to driver_data.ipmi_devices */
struct
list_head
head
;
/* the IPMI request message list */
struct
list_head
tx_msg_list
;
struct
mutex
tx_msg_lock
;
acpi_handle
handle
;
struct
pnp_dev
*
pnp_dev
;
ipmi_user_t
user_interface
;
int
ipmi_ifnum
;
/* IPMI interface number */
long
curr_msgid
;
unsigned
long
flags
;
struct
ipmi_smi_info
smi_data
;
};
struct
ipmi_driver_data
{
struct
list_head
ipmi_devices
;
struct
ipmi_smi_watcher
bmc_events
;
struct
ipmi_user_hndl
ipmi_hndlrs
;
struct
mutex
ipmi_lock
;
};
struct
acpi_ipmi_msg
{
struct
list_head
head
;
/*
* General speaking the addr type should be SI_ADDR_TYPE. And
* the addr channel should be BMC.
* In fact it can also be IPMB type. But we will have to
* parse it from the Netfn command buffer. It is so complex
* that it is skipped.
*/
struct
ipmi_addr
addr
;
long
tx_msgid
;
/* it is used to track whether the IPMI message is finished */
struct
completion
tx_complete
;
struct
kernel_ipmi_msg
tx_message
;
int
msg_done
;
/* tx data . And copy it from ACPI object buffer */
u8
tx_data
[
64
];
int
tx_len
;
u8
rx_data
[
64
];
int
rx_len
;
struct
acpi_ipmi_device
*
device
;
};
/* IPMI request/response buffer per ACPI 4.0, sec 5.5.2.4.3.2 */
struct
acpi_ipmi_buffer
{
u8
status
;
u8
length
;
u8
data
[
64
];
};
static
void
ipmi_register_bmc
(
int
iface
,
struct
device
*
dev
);
static
void
ipmi_bmc_gone
(
int
iface
);
static
void
ipmi_msg_handler
(
struct
ipmi_recv_msg
*
msg
,
void
*
user_msg_data
);
static
void
acpi_add_ipmi_device
(
struct
acpi_ipmi_device
*
ipmi_device
);
static
void
acpi_remove_ipmi_device
(
struct
acpi_ipmi_device
*
ipmi_device
);
static
struct
ipmi_driver_data
driver_data
=
{
.
ipmi_devices
=
LIST_HEAD_INIT
(
driver_data
.
ipmi_devices
),
.
bmc_events
=
{
.
owner
=
THIS_MODULE
,
.
new_smi
=
ipmi_register_bmc
,
.
smi_gone
=
ipmi_bmc_gone
,
},
.
ipmi_hndlrs
=
{
.
ipmi_recv_hndl
=
ipmi_msg_handler
,
},
};
static
struct
acpi_ipmi_msg
*
acpi_alloc_ipmi_msg
(
struct
acpi_ipmi_device
*
ipmi
)
{
struct
acpi_ipmi_msg
*
ipmi_msg
;
struct
pnp_dev
*
pnp_dev
=
ipmi
->
pnp_dev
;
ipmi_msg
=
kzalloc
(
sizeof
(
struct
acpi_ipmi_msg
),
GFP_KERNEL
);
if
(
!
ipmi_msg
)
{
dev_warn
(
&
pnp_dev
->
dev
,
"Can't allocate memory for ipmi_msg
\n
"
);
return
NULL
;
}
init_completion
(
&
ipmi_msg
->
tx_complete
);
INIT_LIST_HEAD
(
&
ipmi_msg
->
head
);
ipmi_msg
->
device
=
ipmi
;
return
ipmi_msg
;
}
#define IPMI_OP_RGN_NETFN(offset) ((offset >> 8) & 0xff)
#define IPMI_OP_RGN_CMD(offset) (offset & 0xff)
static
void
acpi_format_ipmi_msg
(
struct
acpi_ipmi_msg
*
tx_msg
,
acpi_physical_address
address
,
acpi_integer
*
value
)
{
struct
kernel_ipmi_msg
*
msg
;
struct
acpi_ipmi_buffer
*
buffer
;
struct
acpi_ipmi_device
*
device
;
msg
=
&
tx_msg
->
tx_message
;
/*
* IPMI network function and command are encoded in the address
* within the IPMI OpRegion; see ACPI 4.0, sec 5.5.2.4.3.
*/
msg
->
netfn
=
IPMI_OP_RGN_NETFN
(
address
);
msg
->
cmd
=
IPMI_OP_RGN_CMD
(
address
);
msg
->
data
=
tx_msg
->
tx_data
;
/*
* value is the parameter passed by the IPMI opregion space handler.
* It points to the IPMI request message buffer
*/
buffer
=
(
struct
acpi_ipmi_buffer
*
)
value
;
/* copy the tx message data */
msg
->
data_len
=
buffer
->
length
;
memcpy
(
tx_msg
->
tx_data
,
buffer
->
data
,
msg
->
data_len
);
/*
* now the default type is SYSTEM_INTERFACE and channel type is BMC.
* If the netfn is APP_REQUEST and the cmd is SEND_MESSAGE,
* the addr type should be changed to IPMB. Then we will have to parse
* the IPMI request message buffer to get the IPMB address.
* If so, please fix me.
*/
tx_msg
->
addr
.
addr_type
=
IPMI_SYSTEM_INTERFACE_ADDR_TYPE
;
tx_msg
->
addr
.
channel
=
IPMI_BMC_CHANNEL
;
tx_msg
->
addr
.
data
[
0
]
=
0
;
/* Get the msgid */
device
=
tx_msg
->
device
;
mutex_lock
(
&
device
->
tx_msg_lock
);
device
->
curr_msgid
++
;
tx_msg
->
tx_msgid
=
device
->
curr_msgid
;
mutex_unlock
(
&
device
->
tx_msg_lock
);
}
static
void
acpi_format_ipmi_response
(
struct
acpi_ipmi_msg
*
msg
,
acpi_integer
*
value
,
int
rem_time
)
{
struct
acpi_ipmi_buffer
*
buffer
;
/*
* value is also used as output parameter. It represents the response
* IPMI message returned by IPMI command.
*/
buffer
=
(
struct
acpi_ipmi_buffer
*
)
value
;
if
(
!
rem_time
&&
!
msg
->
msg_done
)
{
buffer
->
status
=
ACPI_IPMI_TIMEOUT
;
return
;
}
/*
* If the flag of msg_done is not set or the recv length is zero, it
* means that the IPMI command is not executed correctly.
* The status code will be ACPI_IPMI_UNKNOWN.
*/
if
(
!
msg
->
msg_done
||
!
msg
->
rx_len
)
{
buffer
->
status
=
ACPI_IPMI_UNKNOWN
;
return
;
}
/*
* If the IPMI response message is obtained correctly, the status code
* will be ACPI_IPMI_OK
*/
buffer
->
status
=
ACPI_IPMI_OK
;
buffer
->
length
=
msg
->
rx_len
;
memcpy
(
buffer
->
data
,
msg
->
rx_data
,
msg
->
rx_len
);
}
static
void
ipmi_flush_tx_msg
(
struct
acpi_ipmi_device
*
ipmi
)
{
struct
acpi_ipmi_msg
*
tx_msg
,
*
temp
;
int
count
=
HZ
/
10
;
struct
pnp_dev
*
pnp_dev
=
ipmi
->
pnp_dev
;
list_for_each_entry_safe
(
tx_msg
,
temp
,
&
ipmi
->
tx_msg_list
,
head
)
{
/* wake up the sleep thread on the Tx msg */
complete
(
&
tx_msg
->
tx_complete
);
}
/* wait for about 100ms to flush the tx message list */
while
(
count
--
)
{
if
(
list_empty
(
&
ipmi
->
tx_msg_list
))
break
;
schedule_timeout
(
1
);
}
if
(
!
list_empty
(
&
ipmi
->
tx_msg_list
))
dev_warn
(
&
pnp_dev
->
dev
,
"tx msg list is not NULL
\n
"
);
}
static
void
ipmi_msg_handler
(
struct
ipmi_recv_msg
*
msg
,
void
*
user_msg_data
)
{
struct
acpi_ipmi_device
*
ipmi_device
=
user_msg_data
;
int
msg_found
=
0
;
struct
acpi_ipmi_msg
*
tx_msg
;
struct
pnp_dev
*
pnp_dev
=
ipmi_device
->
pnp_dev
;
if
(
msg
->
user
!=
ipmi_device
->
user_interface
)
{
dev_warn
(
&
pnp_dev
->
dev
,
"Unexpected response is returned. "
"returned user %p, expected user %p
\n
"
,
msg
->
user
,
ipmi_device
->
user_interface
);
ipmi_free_recv_msg
(
msg
);
return
;
}
mutex_lock
(
&
ipmi_device
->
tx_msg_lock
);
list_for_each_entry
(
tx_msg
,
&
ipmi_device
->
tx_msg_list
,
head
)
{
if
(
msg
->
msgid
==
tx_msg
->
tx_msgid
)
{
msg_found
=
1
;
break
;
}
}
mutex_unlock
(
&
ipmi_device
->
tx_msg_lock
);
if
(
!
msg_found
)
{
dev_warn
(
&
pnp_dev
->
dev
,
"Unexpected response (msg id %ld) is "
"returned.
\n
"
,
msg
->
msgid
);
ipmi_free_recv_msg
(
msg
);
return
;
}
if
(
msg
->
msg
.
data_len
)
{
/* copy the response data to Rx_data buffer */
memcpy
(
tx_msg
->
rx_data
,
msg
->
msg_data
,
msg
->
msg
.
data_len
);
tx_msg
->
rx_len
=
msg
->
msg
.
data_len
;
tx_msg
->
msg_done
=
1
;
}
complete
(
&
tx_msg
->
tx_complete
);
ipmi_free_recv_msg
(
msg
);
};
static
void
ipmi_register_bmc
(
int
iface
,
struct
device
*
dev
)
{
struct
acpi_ipmi_device
*
ipmi_device
,
*
temp
;
struct
pnp_dev
*
pnp_dev
;
ipmi_user_t
user
;
int
err
;
struct
ipmi_smi_info
smi_data
;
acpi_handle
handle
;
err
=
ipmi_get_smi_info
(
iface
,
&
smi_data
);
if
(
err
)
return
;
if
(
smi_data
.
addr_src
!=
SI_ACPI
)
{
put_device
(
smi_data
.
dev
);
return
;
}
handle
=
smi_data
.
addr_info
.
acpi_info
.
acpi_handle
;
mutex_lock
(
&
driver_data
.
ipmi_lock
);
list_for_each_entry
(
temp
,
&
driver_data
.
ipmi_devices
,
head
)
{
/*
* if the corresponding ACPI handle is already added
* to the device list, don't add it again.
*/
if
(
temp
->
handle
==
handle
)
goto
out
;
}
ipmi_device
=
kzalloc
(
sizeof
(
*
ipmi_device
),
GFP_KERNEL
);
if
(
!
ipmi_device
)
goto
out
;
pnp_dev
=
to_pnp_dev
(
smi_data
.
dev
);
ipmi_device
->
handle
=
handle
;
ipmi_device
->
pnp_dev
=
pnp_dev
;
err
=
ipmi_create_user
(
iface
,
&
driver_data
.
ipmi_hndlrs
,
ipmi_device
,
&
user
);
if
(
err
)
{
dev_warn
(
&
pnp_dev
->
dev
,
"Can't create IPMI user interface
\n
"
);
kfree
(
ipmi_device
);
goto
out
;
}
acpi_add_ipmi_device
(
ipmi_device
);
ipmi_device
->
user_interface
=
user
;
ipmi_device
->
ipmi_ifnum
=
iface
;
mutex_unlock
(
&
driver_data
.
ipmi_lock
);
memcpy
(
&
ipmi_device
->
smi_data
,
&
smi_data
,
sizeof
(
struct
ipmi_smi_info
));
return
;
out:
mutex_unlock
(
&
driver_data
.
ipmi_lock
);
put_device
(
smi_data
.
dev
);
return
;
}
static
void
ipmi_bmc_gone
(
int
iface
)
{
struct
acpi_ipmi_device
*
ipmi_device
,
*
temp
;
mutex_lock
(
&
driver_data
.
ipmi_lock
);
list_for_each_entry_safe
(
ipmi_device
,
temp
,
&
driver_data
.
ipmi_devices
,
head
)
{
if
(
ipmi_device
->
ipmi_ifnum
!=
iface
)
continue
;
acpi_remove_ipmi_device
(
ipmi_device
);
put_device
(
ipmi_device
->
smi_data
.
dev
);
kfree
(
ipmi_device
);
break
;
}
mutex_unlock
(
&
driver_data
.
ipmi_lock
);
}
/* --------------------------------------------------------------------------
* Address Space Management
* -------------------------------------------------------------------------- */
/*
* This is the IPMI opregion space handler.
* @function: indicates the read/write. In fact as the IPMI message is driven
* by command, only write is meaningful.
* @address: This contains the netfn/command of IPMI request message.
* @bits : not used.
* @value : it is an in/out parameter. It points to the IPMI message buffer.
* Before the IPMI message is sent, it represents the actual request
* IPMI message. After the IPMI message is finished, it represents
* the response IPMI message returned by IPMI command.
* @handler_context: IPMI device context.
*/
static
acpi_status
acpi_ipmi_space_handler
(
u32
function
,
acpi_physical_address
address
,
u32
bits
,
acpi_integer
*
value
,
void
*
handler_context
,
void
*
region_context
)
{
struct
acpi_ipmi_msg
*
tx_msg
;
struct
acpi_ipmi_device
*
ipmi_device
=
handler_context
;
int
err
,
rem_time
;
acpi_status
status
;
/*
* IPMI opregion message.
* IPMI message is firstly written to the BMC and system software
* can get the respsonse. So it is unmeaningful for the read access
* of IPMI opregion.
*/
if
((
function
&
ACPI_IO_MASK
)
==
ACPI_READ
)
return
AE_TYPE
;
if
(
!
ipmi_device
->
user_interface
)
return
AE_NOT_EXIST
;
tx_msg
=
acpi_alloc_ipmi_msg
(
ipmi_device
);
if
(
!
tx_msg
)
return
AE_NO_MEMORY
;
acpi_format_ipmi_msg
(
tx_msg
,
address
,
value
);
mutex_lock
(
&
ipmi_device
->
tx_msg_lock
);
list_add_tail
(
&
tx_msg
->
head
,
&
ipmi_device
->
tx_msg_list
);
mutex_unlock
(
&
ipmi_device
->
tx_msg_lock
);
err
=
ipmi_request_settime
(
ipmi_device
->
user_interface
,
&
tx_msg
->
addr
,
tx_msg
->
tx_msgid
,
&
tx_msg
->
tx_message
,
NULL
,
0
,
0
,
0
);
if
(
err
)
{
status
=
AE_ERROR
;
goto
end_label
;
}
rem_time
=
wait_for_completion_timeout
(
&
tx_msg
->
tx_complete
,
IPMI_TIMEOUT
);
acpi_format_ipmi_response
(
tx_msg
,
value
,
rem_time
);
status
=
AE_OK
;
end_label:
mutex_lock
(
&
ipmi_device
->
tx_msg_lock
);
list_del
(
&
tx_msg
->
head
);
mutex_unlock
(
&
ipmi_device
->
tx_msg_lock
);
kfree
(
tx_msg
);
return
status
;
}
static
void
ipmi_remove_space_handler
(
struct
acpi_ipmi_device
*
ipmi
)
{
if
(
!
test_bit
(
IPMI_FLAGS_HANDLER_INSTALL
,
&
ipmi
->
flags
))
return
;
acpi_remove_address_space_handler
(
ipmi
->
handle
,
ACPI_ADR_SPACE_IPMI
,
&
acpi_ipmi_space_handler
);
clear_bit
(
IPMI_FLAGS_HANDLER_INSTALL
,
&
ipmi
->
flags
);
}
static
int
ipmi_install_space_handler
(
struct
acpi_ipmi_device
*
ipmi
)
{
acpi_status
status
;
if
(
test_bit
(
IPMI_FLAGS_HANDLER_INSTALL
,
&
ipmi
->
flags
))
return
0
;
status
=
acpi_install_address_space_handler
(
ipmi
->
handle
,
ACPI_ADR_SPACE_IPMI
,
&
acpi_ipmi_space_handler
,
NULL
,
ipmi
);
if
(
ACPI_FAILURE
(
status
))
{
struct
pnp_dev
*
pnp_dev
=
ipmi
->
pnp_dev
;
dev_warn
(
&
pnp_dev
->
dev
,
"Can't register IPMI opregion space "
"handle
\n
"
);
return
-
EINVAL
;
}
set_bit
(
IPMI_FLAGS_HANDLER_INSTALL
,
&
ipmi
->
flags
);
return
0
;
}
static
void
acpi_add_ipmi_device
(
struct
acpi_ipmi_device
*
ipmi_device
)
{
INIT_LIST_HEAD
(
&
ipmi_device
->
head
);
mutex_init
(
&
ipmi_device
->
tx_msg_lock
);
INIT_LIST_HEAD
(
&
ipmi_device
->
tx_msg_list
);
ipmi_install_space_handler
(
ipmi_device
);
list_add_tail
(
&
ipmi_device
->
head
,
&
driver_data
.
ipmi_devices
);
}
static
void
acpi_remove_ipmi_device
(
struct
acpi_ipmi_device
*
ipmi_device
)
{
/*
* If the IPMI user interface is created, it should be
* destroyed.
*/
if
(
ipmi_device
->
user_interface
)
{
ipmi_destroy_user
(
ipmi_device
->
user_interface
);
ipmi_device
->
user_interface
=
NULL
;
}
/* flush the Tx_msg list */
if
(
!
list_empty
(
&
ipmi_device
->
tx_msg_list
))
ipmi_flush_tx_msg
(
ipmi_device
);
list_del
(
&
ipmi_device
->
head
);
ipmi_remove_space_handler
(
ipmi_device
);
}
static
int
__init
acpi_ipmi_init
(
void
)
{
int
result
=
0
;
if
(
acpi_disabled
)
return
result
;
mutex_init
(
&
driver_data
.
ipmi_lock
);
result
=
ipmi_smi_watcher_register
(
&
driver_data
.
bmc_events
);
return
result
;
}
static
void
__exit
acpi_ipmi_exit
(
void
)
{
struct
acpi_ipmi_device
*
ipmi_device
,
*
temp
;
if
(
acpi_disabled
)
return
;
ipmi_smi_watcher_unregister
(
&
driver_data
.
bmc_events
);
/*
* When one smi_watcher is unregistered, it is only deleted
* from the smi_watcher list. But the smi_gone callback function
* is not called. So explicitly uninstall the ACPI IPMI oregion
* handler and free it.
*/
mutex_lock
(
&
driver_data
.
ipmi_lock
);
list_for_each_entry_safe
(
ipmi_device
,
temp
,
&
driver_data
.
ipmi_devices
,
head
)
{
acpi_remove_ipmi_device
(
ipmi_device
);
put_device
(
ipmi_device
->
smi_data
.
dev
);
kfree
(
ipmi_device
);
}
mutex_unlock
(
&
driver_data
.
ipmi_lock
);
}
module_init
(
acpi_ipmi_init
);
module_exit
(
acpi_ipmi_exit
);
drivers/char/ipmi/ipmi_msghandler.c
浏览文件 @
4b63bd35
...
...
@@ -970,6 +970,33 @@ int ipmi_create_user(unsigned int if_num,
}
EXPORT_SYMBOL
(
ipmi_create_user
);
int
ipmi_get_smi_info
(
int
if_num
,
struct
ipmi_smi_info
*
data
)
{
int
rv
=
0
;
ipmi_smi_t
intf
;
struct
ipmi_smi_handlers
*
handlers
;
mutex_lock
(
&
ipmi_interfaces_mutex
);
list_for_each_entry_rcu
(
intf
,
&
ipmi_interfaces
,
link
)
{
if
(
intf
->
intf_num
==
if_num
)
goto
found
;
}
/* Not found, return an error */
rv
=
-
EINVAL
;
mutex_unlock
(
&
ipmi_interfaces_mutex
);
return
rv
;
found:
handlers
=
intf
->
handlers
;
rv
=
-
ENOSYS
;
if
(
handlers
->
get_smi_info
)
rv
=
handlers
->
get_smi_info
(
intf
->
send_info
,
data
);
mutex_unlock
(
&
ipmi_interfaces_mutex
);
return
rv
;
}
EXPORT_SYMBOL
(
ipmi_get_smi_info
);
static
void
free_user
(
struct
kref
*
ref
)
{
ipmi_user_t
user
=
container_of
(
ref
,
struct
ipmi_user
,
refcount
);
...
...
drivers/char/ipmi/ipmi_si_intf.c
浏览文件 @
4b63bd35
...
...
@@ -57,6 +57,7 @@
#include <asm/irq.h>
#include <linux/interrupt.h>
#include <linux/rcupdate.h>
#include <linux/ipmi.h>
#include <linux/ipmi_smi.h>
#include <asm/io.h>
#include "ipmi_si_sm.h"
...
...
@@ -107,10 +108,6 @@ enum si_type {
};
static
char
*
si_to_str
[]
=
{
"kcs"
,
"smic"
,
"bt"
};
enum
ipmi_addr_src
{
SI_INVALID
=
0
,
SI_HOTMOD
,
SI_HARDCODED
,
SI_SPMI
,
SI_ACPI
,
SI_SMBIOS
,
SI_PCI
,
SI_DEVICETREE
,
SI_DEFAULT
};
static
char
*
ipmi_addr_src_to_str
[]
=
{
NULL
,
"hotmod"
,
"hardcoded"
,
"SPMI"
,
"ACPI"
,
"SMBIOS"
,
"PCI"
,
"device-tree"
,
"default"
};
...
...
@@ -291,6 +288,7 @@ struct smi_info {
struct
task_struct
*
thread
;
struct
list_head
link
;
union
ipmi_smi_info_union
addr_info
;
};
#define smi_inc_stat(smi, stat) \
...
...
@@ -1186,6 +1184,18 @@ static int smi_start_processing(void *send_info,
return
0
;
}
static
int
get_smi_info
(
void
*
send_info
,
struct
ipmi_smi_info
*
data
)
{
struct
smi_info
*
smi
=
send_info
;
data
->
addr_src
=
smi
->
addr_source
;
data
->
dev
=
smi
->
dev
;
data
->
addr_info
=
smi
->
addr_info
;
get_device
(
smi
->
dev
);
return
0
;
}
static
void
set_maintenance_mode
(
void
*
send_info
,
int
enable
)
{
struct
smi_info
*
smi_info
=
send_info
;
...
...
@@ -1197,6 +1207,7 @@ static void set_maintenance_mode(void *send_info, int enable)
static
struct
ipmi_smi_handlers
handlers
=
{
.
owner
=
THIS_MODULE
,
.
start_processing
=
smi_start_processing
,
.
get_smi_info
=
get_smi_info
,
.
sender
=
sender
,
.
request_events
=
request_events
,
.
set_maintenance_mode
=
set_maintenance_mode
,
...
...
@@ -2157,6 +2168,7 @@ static int __devinit ipmi_pnp_probe(struct pnp_dev *dev,
printk
(
KERN_INFO
PFX
"probing via ACPI
\n
"
);
handle
=
acpi_dev
->
handle
;
info
->
addr_info
.
acpi_info
.
acpi_handle
=
handle
;
/* _IFT tells us the interface type: KCS, BT, etc */
status
=
acpi_evaluate_integer
(
handle
,
"_IFT"
,
NULL
,
&
tmp
);
...
...
include/linux/ipmi.h
浏览文件 @
4b63bd35
...
...
@@ -454,6 +454,44 @@ unsigned int ipmi_addr_length(int addr_type);
/* Validate that the given IPMI address is valid. */
int
ipmi_validate_addr
(
struct
ipmi_addr
*
addr
,
int
len
);
/*
* How did the IPMI driver find out about the device?
*/
enum
ipmi_addr_src
{
SI_INVALID
=
0
,
SI_HOTMOD
,
SI_HARDCODED
,
SI_SPMI
,
SI_ACPI
,
SI_SMBIOS
,
SI_PCI
,
SI_DEVICETREE
,
SI_DEFAULT
};
union
ipmi_smi_info_union
{
/*
* the acpi_info element is defined for the SI_ACPI
* address type
*/
struct
{
void
*
acpi_handle
;
}
acpi_info
;
};
struct
ipmi_smi_info
{
enum
ipmi_addr_src
addr_src
;
/*
* Base device for the interface. Don't forget to put this when
* you are done.
*/
struct
device
*
dev
;
/*
* The addr_info provides more detailed info for some IPMI
* devices, depending on the addr_src. Currently only SI_ACPI
* info is provided.
*/
union
ipmi_smi_info_union
addr_info
;
};
/* This is to get the private info of ipmi_smi_t */
extern
int
ipmi_get_smi_info
(
int
if_num
,
struct
ipmi_smi_info
*
data
);
#endif
/* __KERNEL__ */
...
...
include/linux/ipmi_smi.h
浏览文件 @
4b63bd35
...
...
@@ -39,6 +39,7 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/ipmi.h>
/* This files describes the interface for IPMI system management interface
drivers to bind into the IPMI message handler. */
...
...
@@ -86,6 +87,13 @@ struct ipmi_smi_handlers {
int
(
*
start_processing
)(
void
*
send_info
,
ipmi_smi_t
new_intf
);
/*
* Get the detailed private info of the low level interface and store
* it into the structure of ipmi_smi_data. For example: the
* ACPI device handle will be returned for the pnp_acpi IPMI device.
*/
int
(
*
get_smi_info
)(
void
*
send_info
,
struct
ipmi_smi_info
*
data
);
/* Called to enqueue an SMI message to be sent. This
operation is not allowed to fail. If an error occurs, it
should report back the error in a received message. It may
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录