forked from Minki/linux
Mostly small changes, as usual.
This does add an IPMI BMC server-side driver, to allow a Linux system to act as an IPMI controller. That's the biggest change, but it is just a new driver that is fairly narrow in use. The other largish change is removing ACPI SPMI probe support, which should have never really been there in the beginning. -corey -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJaw8XOAAoJEGHzjJCRm/+BeoQQAIBokkgHSAl6y8jlmmTmu9fV gXl0GT97yAMyuTUaTvkWLdWm8GWCrSSUTAqjbcTzMWya87KRODsUg9eTO58fFw8m ODbD7ruTGmBQggJEqDaS5NHAiU22ce2aDn5I0WjJkH8vaJ3nQSa6nEgBOzXDMC1A OmaVQE6BnEAIA+nmlzbUgcuduB3iv7gTua2gy7MQSG/5jBPIAOQtpsgHtCZMA+Dt bk9LqDpOa6dZry7eIn5/u62YRVLX+iVO/DoxCgZyOxVfgnV/ykKT3PvWO9vviBQV QXXLAzLO3niDQ/ZwwpqrUWjR7oGWDKe4ntMATfnxCP7LQNrSF7LnAxz8oCcwuBxq ELrwME8LEQmMYGFg3SYcLA0k1teTP2UVWURUH6zBTft2xzo8bJN0JU7J52tTL4xa yC7JgTVeq8uQB8gkYKf43LGHlXlaxFQsnRKeCJ2JG+1yD+sOmxbZshfiLroMZ5DM nPKOuMdoqPCd7JVUMs/c0IgcDHd6vtkiDRA0jh38JdIdp9B/i+dFYs61bSzrkBD9 tXUua56QTVl5WEWy2lGX+ZH/JUJbQnTxjiaW99Q9Soml6qXqIVjR5ZvLtls0PeW0 ZytaQEGuV8758YEmOGk/1pUys/oC37mDlyjTpONGYzvAyzJqU258/YU9eJMkcQ/G FFEEkWILLuGgtFnyxwN/ =p993 -----END PGP SIGNATURE----- Merge tag 'for-linus-4.17' of git://github.com/cminyard/linux-ipmi Pull IPMI updates from Corey Minyard: "Mostly small changes, as usual. This does add an IPMI BMC server-side driver, to allow a Linux system to act as an IPMI controller. That's the biggest change, but it is just a new driver that is fairly narrow in use. The other largish change is removing ACPI SPMI probe support, which should have never really been there in the beginning" * tag 'for-linus-4.17' of git://github.com/cminyard/linux-ipmi: ipmi/parisc: Add IPMI chassis poweroff for certain HP PA-RISC and IA-64 servers ipmi_ssif: Fix kernel panic at msg_done_handler ipmi:pci: Blacklist a Realtek "IPMI" device ipmi: Remove ACPI SPMI probing from the system interface driver ipmi: Remove ACPI SPMI probing from the SSIF (I2C) driver ipmi: missing error code in try_smi_init() ipmi: use ARRAY_SIZE for poweroff_functions array sizing calculation ipmi: Consolidate cleanup code ipmi: Remove some unnecessary initializations ipmi: Fix some error cleanup issues ipmi: Add or fix SPDX-License-Identifier in all files ipmi: Re-use existing macros for built-in properties ipmi:pci: Make the PCI defines consistent with normal Linux ones ipmi: kcs_bmc: coding-style fixes and use new poll type char/ipmi: add documentation for sysfs interface ipmi: kcs_bmc: mark expected switch fall-through in kcs_bmc_handle_data ipmi: add an Aspeed KCS IPMI BMC driver ipmi: add a KCS IPMI BMC driver
This commit is contained in:
commit
cc5ada7ca3
238
Documentation/ABI/testing/sysfs-devices-platform-ipmi
Normal file
238
Documentation/ABI/testing/sysfs-devices-platform-ipmi
Normal file
@ -0,0 +1,238 @@
|
||||
What: /sys/devices/platform/ipmi_bmc.*/firmware_revision
|
||||
Date: Mar, 2006
|
||||
KernelVersion: v2.6.17
|
||||
Contact: openipmi-developer@lists.sourceforge.net
|
||||
Description:
|
||||
(RO) The major and minor revision of the firmware.
|
||||
|
||||
|
||||
What: /sys/devices/platform/ipmi_bmc.*/aux_firmware_revision
|
||||
Date: Mar, 2006
|
||||
KernelVersion: v2.6.17
|
||||
Contact: openipmi-developer@lists.sourceforge.net
|
||||
Description:
|
||||
(RO) Holds additional information about the firmware revision,
|
||||
such as boot block or internal data structure version numbers.
|
||||
The meanings of the numbers are specific to the vendor
|
||||
identified by Manufacturer ID.
|
||||
|
||||
|
||||
What: /sys/devices/platform/ipmi_bmc.*/revision
|
||||
Date: Mar, 2006
|
||||
KernelVersion: v2.6.17
|
||||
Contact: openipmi-developer@lists.sourceforge.net
|
||||
Description:
|
||||
(RO) Device revision. Useful for identifying if significant
|
||||
hardware changes have been made to the implementation of the
|
||||
management controller.
|
||||
|
||||
|
||||
What: /sys/devices/platform/ipmi_bmc.*/provides_device_sdrs
|
||||
Date: Mar, 2006
|
||||
KernelVersion: v2.6.17
|
||||
Contact: openipmi-developer@lists.sourceforge.net
|
||||
Description:
|
||||
(RO) Indicates whether device provides device sensor data
|
||||
records (1) or not (0).
|
||||
|
||||
|
||||
What: /sys/devices/platform/ipmi_bmc.*/device_id
|
||||
Date: Mar, 2006
|
||||
KernelVersion: v2.6.17
|
||||
Contact: openipmi-developer@lists.sourceforge.net
|
||||
Description:
|
||||
(RO) Device id is specified by the manufacturer identified by
|
||||
the Manufacturer ID field. This field allows controller specific
|
||||
software to identify the unique application command, OEM
|
||||
fields, and functionality that are provided by the controller
|
||||
|
||||
|
||||
What: /sys/devices/platform/ipmi_bmc.*/additional_device_support
|
||||
Date: Mar, 2006
|
||||
KernelVersion: v2.6.17
|
||||
Contact: openipmi-developer@lists.sourceforge.net
|
||||
Description:
|
||||
(RO) Lists the IPMI ‘logical device’ commands and functions
|
||||
that the controller supports that are in addition to the
|
||||
mandatory IPM and Application commands.
|
||||
|
||||
|
||||
What: /sys/devices/platform/ipmi_bmc.*/ipmi_version
|
||||
Date: Mar, 2006
|
||||
KernelVersion: v2.6.17
|
||||
Contact: openipmi-developer@lists.sourceforge.net
|
||||
Description:
|
||||
(RO) Displays the IPMI Command Specification Version.
|
||||
|
||||
|
||||
What: /sys/devices/platform/ipmi_bmc.*/manufacturer_id
|
||||
Date: Mar, 2006
|
||||
KernelVersion: v2.6.17
|
||||
Contact: openipmi-developer@lists.sourceforge.net
|
||||
Description:
|
||||
(RO) Identifies the manufacturer responsible for the
|
||||
specification of functionality of the vendor (OEM)-specific
|
||||
commands, codes, and interfaces used in the controller.
|
||||
|
||||
|
||||
What: /sys/devices/platform/ipmi_bmc.*/product_id
|
||||
Date: Mar, 2006
|
||||
KernelVersion: v2.6.17
|
||||
Contact: openipmi-developer@lists.sourceforge.net
|
||||
Description:
|
||||
(RO) Displays a number that identifies a particular system,
|
||||
module, add-in card, or board set. The number is specified
|
||||
according to the manufacturer given by Manufacturer ID.
|
||||
|
||||
For detailed definitions of the above attributes, refer to section 20.1 'Get
|
||||
Device ID Command' of the IPMI specification v2.0.
|
||||
|
||||
|
||||
What: /sys/devices/platform/ipmi_bmc.*/guid
|
||||
Date: Mar, 2006
|
||||
KernelVersion: v2.6.17
|
||||
Contact: openipmi-developer@lists.sourceforge.net
|
||||
Description:
|
||||
(RO) A GUID (Globally Unique ID), also referred to as a UUID
|
||||
(Universally Unique Identifier), for the management controller,
|
||||
as described in section 20.8 'Get Device GUID Command' of the
|
||||
IPMI specification v2.0.
|
||||
|
||||
|
||||
What: /sys/devices/platform/ipmi_si.*/type
|
||||
Date: Sep, 2017
|
||||
KernelVersion: v4.15
|
||||
Contact: openipmi-developer@lists.sourceforge.net
|
||||
Description:
|
||||
(RO) The device interface for IPMI "kcs", "smic", "bt" or
|
||||
"invalid"
|
||||
|
||||
What: /sys/devices/platform/ipmi_si.*/idles
|
||||
What: /sys/devices/platform/ipmi_si.*/watchdog_pretimeouts
|
||||
What: /sys/devices/platform/ipmi_si.*/complete_transactions
|
||||
What: /sys/devices/platform/ipmi_si.*/events
|
||||
What: /sys/devices/platform/ipmi_si.*/interrupts
|
||||
What: /sys/devices/platform/ipmi_si.*/hosed_count
|
||||
What: /sys/devices/platform/ipmi_si.*/long_timeouts
|
||||
What: /sys/devices/platform/ipmi_si.*/flag_fetches
|
||||
What: /sys/devices/platform/ipmi_si.*/attentions
|
||||
What: /sys/devices/platform/ipmi_si.*/incoming_messages
|
||||
What: /sys/devices/platform/ipmi_si.*/short_timeouts
|
||||
Date: Sep, 2017
|
||||
KernelVersion: v4.15
|
||||
Contact: openipmi-developer@lists.sourceforge.net
|
||||
Description:
|
||||
|
||||
idles: (RO) Number of times the interface was
|
||||
idle while being polled.
|
||||
|
||||
watchdog_pretimeouts: (RO) Number of watchdog pretimeouts.
|
||||
|
||||
complete_transactions: (RO) Number of completed messages.
|
||||
|
||||
events: (RO) Number of IPMI events received from
|
||||
the hardware.
|
||||
|
||||
interrupts: (RO) Number of interrupts the driver
|
||||
handled.
|
||||
|
||||
hosed_count: (RO) Number of times the hardware didn't
|
||||
follow the state machine.
|
||||
|
||||
long_timeouts: (RO) Number of times the driver
|
||||
requested a timer while nothing was in
|
||||
progress.
|
||||
|
||||
flag_fetches: (RO) Number of times the driver
|
||||
requested flags from the hardware.
|
||||
|
||||
attentions: (RO) Number of time the driver got an
|
||||
ATTN from the hardware.
|
||||
|
||||
incoming_messages: (RO) Number of asynchronous messages
|
||||
received.
|
||||
|
||||
short_timeouts: (RO) Number of times the driver
|
||||
requested a timer while an operation was
|
||||
in progress.
|
||||
|
||||
|
||||
What: /sys/devices/platform/ipmi_si.*/interrupts_enabled
|
||||
Date: Sep, 2017
|
||||
KernelVersion: v4.15
|
||||
Contact: openipmi-developer@lists.sourceforge.net
|
||||
Description:
|
||||
(RO) Indicates whether interrupts are enabled or not. The driver
|
||||
disables interrupts when it gets into a situation where it
|
||||
cannot handle messages due to lack of memory. Once that
|
||||
situation clears up, it will re-enable interrupts.
|
||||
|
||||
|
||||
What: /sys/devices/platform/ipmi_si.*/params
|
||||
Date: Sep, 2017
|
||||
KernelVersion: v4.15
|
||||
Contact: openipmi-developer@lists.sourceforge.net
|
||||
Description:
|
||||
[to be documented]
|
||||
|
||||
|
||||
What: /sys/devices/platform/dmi-ipmi-ssif.*/type
|
||||
Date: Sep, 2017
|
||||
KernelVersion: v4.15
|
||||
Contact: openipmi-developer@lists.sourceforge.net
|
||||
Description:
|
||||
(RO) Shows the IMPI device interface type - "ssif" here.
|
||||
|
||||
|
||||
What: /sys/devices/platform/dmi-ipmi-ssif.*/hosed
|
||||
What: /sys/devices/platform/dmi-ipmi-ssif.*/alerts
|
||||
What: /sys/devices/platform/dmi-ipmi-ssif.*/sent_messages
|
||||
What: /sys/devices/platform/dmi-ipmi-ssif.*/sent_messages_parts
|
||||
What: /sys/devices/platform/dmi-ipmi-ssif.*/received_messages
|
||||
What: /sys/devices/platform/dmi-ipmi-ssif.*/received_message_parts
|
||||
What: /sys/devices/platform/dmi-ipmi-ssif.*/events
|
||||
What: /sys/devices/platform/dmi-ipmi-ssif.*/watchdog_pretimeouts
|
||||
What: /sys/devices/platform/dmi-ipmi-ssif.*/flag_fetches
|
||||
What: /sys/devices/platform/dmi-ipmi-ssif.*/send_retries
|
||||
What: /sys/devices/platform/dmi-ipmi-ssif.*/receive_retries
|
||||
What: /sys/devices/platform/dmi-ipmi-ssif.*/send_errors
|
||||
What: /sys/devices/platform/dmi-ipmi-ssif.*/receive_errors
|
||||
Date: Sep, 2017
|
||||
KernelVersion: v4.15
|
||||
Contact: openipmi-developer@lists.sourceforge.net
|
||||
Description:
|
||||
hosed: (RO) Number of times the hardware didn't
|
||||
follow the state machine.
|
||||
|
||||
alerts: (RO) Number of alerts received.
|
||||
|
||||
sent_messages: (RO) Number of total messages sent.
|
||||
|
||||
sent_message_parts: (RO) Number of message parts sent.
|
||||
Messages may be broken into parts if
|
||||
they are long.
|
||||
|
||||
receieved_messages: (RO) Number of message responses
|
||||
received.
|
||||
|
||||
received_message_parts: (RO) Number of message fragments
|
||||
received.
|
||||
|
||||
events: (RO) Number of received events.
|
||||
|
||||
watchdog_pretimeouts: (RO) Number of watchdog pretimeouts.
|
||||
|
||||
flag_fetches: (RO) Number of times a flag fetch was
|
||||
requested.
|
||||
|
||||
send_retries: (RO) Number of time a message was
|
||||
retried.
|
||||
|
||||
receive_retries: (RO) Number of times the receive of a
|
||||
message was retried.
|
||||
|
||||
send_errors: (RO) Number of times the send of a
|
||||
message failed.
|
||||
|
||||
receive_errors: (RO) Number of errors in receiving
|
||||
messages.
|
25
Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt
Normal file
25
Documentation/devicetree/bindings/ipmi/aspeed-kcs-bmc.txt
Normal file
@ -0,0 +1,25 @@
|
||||
* Aspeed KCS (Keyboard Controller Style) IPMI interface
|
||||
|
||||
The Aspeed SOCs (AST2400 and AST2500) are commonly used as BMCs
|
||||
(Baseboard Management Controllers) and the KCS interface can be
|
||||
used to perform in-band IPMI communication with their host.
|
||||
|
||||
Required properties:
|
||||
- compatible : should be one of
|
||||
"aspeed,ast2400-kcs-bmc"
|
||||
"aspeed,ast2500-kcs-bmc"
|
||||
- interrupts : interrupt generated by the controller
|
||||
- kcs_chan : The LPC channel number in the controller
|
||||
- kcs_addr : The host CPU IO map address
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
kcs3: kcs3@0 {
|
||||
compatible = "aspeed,ast2500-kcs-bmc";
|
||||
reg = <0x0 0x80>;
|
||||
interrupts = <8>;
|
||||
kcs_chan = <3>;
|
||||
kcs_addr = <0xCA2>;
|
||||
status = "okay";
|
||||
};
|
@ -96,6 +96,21 @@ config IPMI_POWEROFF
|
||||
|
||||
endif # IPMI_HANDLER
|
||||
|
||||
config IPMI_KCS_BMC
|
||||
tristate
|
||||
|
||||
config ASPEED_KCS_IPMI_BMC
|
||||
depends on ARCH_ASPEED || COMPILE_TEST
|
||||
select IPMI_KCS_BMC
|
||||
select REGMAP_MMIO
|
||||
tristate "Aspeed KCS IPMI BMC driver"
|
||||
help
|
||||
Provides a driver for the KCS (Keyboard Controller Style) IPMI
|
||||
interface found on Aspeed SOCs (AST2400 and AST2500).
|
||||
|
||||
The driver implements the BMC side of the KCS contorller, it
|
||||
provides the access of KCS IO space for BMC side.
|
||||
|
||||
config ASPEED_BT_IPMI_BMC
|
||||
depends on ARCH_ASPEED || COMPILE_TEST
|
||||
depends on REGMAP && REGMAP_MMIO && MFD_SYSCON
|
||||
|
@ -21,4 +21,6 @@ obj-$(CONFIG_IPMI_SSIF) += ipmi_ssif.o
|
||||
obj-$(CONFIG_IPMI_POWERNV) += ipmi_powernv.o
|
||||
obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o
|
||||
obj-$(CONFIG_IPMI_POWEROFF) += ipmi_poweroff.o
|
||||
obj-$(CONFIG_IPMI_KCS_BMC) += kcs_bmc.o
|
||||
obj-$(CONFIG_ASPEED_BT_IPMI_BMC) += bt-bmc.o
|
||||
obj-$(CONFIG_ASPEED_KCS_IPMI_BMC) += kcs_bmc_aspeed.o
|
||||
|
@ -1,10 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2015-2016, IBM Corporation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/atomic.h>
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* ipmi_bt_sm.c
|
||||
*
|
||||
@ -5,26 +6,7 @@
|
||||
* of the driver architecture at http://sourceforge.net/projects/openipmi
|
||||
*
|
||||
* Author: Rocky Craig <first.last@hp.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* 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.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h> /* For printk. */
|
||||
#include <linux/string.h>
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* ipmi_devintf.c
|
||||
*
|
||||
@ -8,27 +9,6 @@
|
||||
* source@mvista.com
|
||||
*
|
||||
* Copyright 2002 MontaVista Software Inc.
|
||||
*
|
||||
* 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* 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.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
@ -1,4 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* A hack to create a platform device from a DMI entry. This will
|
||||
* allow autoloading of the IPMI drive based on SMBIOS entries.
|
||||
@ -29,15 +29,6 @@ static struct ipmi_dmi_info *ipmi_dmi_infos;
|
||||
|
||||
static int ipmi_dmi_nr __initdata;
|
||||
|
||||
#define set_prop_entry(_p_, _name_, type, val) \
|
||||
do { \
|
||||
struct property_entry *_p = &_p_; \
|
||||
_p->name = _name_; \
|
||||
_p->length = sizeof(type); \
|
||||
_p->is_string = false; \
|
||||
_p->value.type##_data = val; \
|
||||
} while(0)
|
||||
|
||||
static void __init dmi_add_platform_ipmi(unsigned long base_addr,
|
||||
u32 flags,
|
||||
u8 slave_addr,
|
||||
@ -85,9 +76,10 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr,
|
||||
}
|
||||
|
||||
if (si_type != SI_TYPE_INVALID)
|
||||
set_prop_entry(p[pidx++], "ipmi-type", u8, si_type);
|
||||
set_prop_entry(p[pidx++], "slave-addr", u8, slave_addr);
|
||||
set_prop_entry(p[pidx++], "addr-source", u8, SI_SMBIOS);
|
||||
p[pidx++] = PROPERTY_ENTRY_U8("ipmi-type", si_type);
|
||||
|
||||
p[pidx++] = PROPERTY_ENTRY_U8("slave-addr", slave_addr);
|
||||
p[pidx++] = PROPERTY_ENTRY_U8("addr-source", SI_SMBIOS);
|
||||
|
||||
info = kmalloc(sizeof(*info), GFP_KERNEL);
|
||||
if (!info) {
|
||||
@ -112,7 +104,7 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr,
|
||||
goto err;
|
||||
|
||||
if (type == IPMI_DMI_TYPE_SSIF) {
|
||||
set_prop_entry(p[pidx++], "i2c-addr", u16, base_addr);
|
||||
p[pidx++] = PROPERTY_ENTRY_U16("i2c-addr", base_addr);
|
||||
goto add_properties;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* DMI defines for use by IPMI
|
||||
*/
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* ipmi_kcs_sm.c
|
||||
*
|
||||
@ -8,27 +9,6 @@
|
||||
* source@mvista.com
|
||||
*
|
||||
* Copyright 2002 MontaVista Software Inc.
|
||||
*
|
||||
* 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* 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.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* ipmi_msghandler.c
|
||||
*
|
||||
@ -8,27 +9,6 @@
|
||||
* source@mvista.com
|
||||
*
|
||||
* Copyright 2002 MontaVista Software Inc.
|
||||
*
|
||||
* 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* 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.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
@ -1,12 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* PowerNV OPAL IPMI driver
|
||||
*
|
||||
* Copyright 2014 IBM Corp.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "ipmi-powernv: " fmt
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* ipmi_poweroff.c
|
||||
*
|
||||
@ -9,27 +10,6 @@
|
||||
* source@mvista.com
|
||||
*
|
||||
* Copyright 2002,2004 MontaVista Software Inc.
|
||||
*
|
||||
* 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* 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.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
@ -456,6 +436,24 @@ static int ipmi_dell_chassis_detect(ipmi_user_t user)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ipmi_hp_chassis_detect()
|
||||
* HP PA-RISC servers rp3410/rp3440, the C8000 workstation and the rx2600 and
|
||||
* zx6000 machines support IPMI vers 1 and don't set the chassis capability bit
|
||||
* but they can handle a chassis poweroff or powercycle command.
|
||||
*/
|
||||
|
||||
#define HP_IANA_MFR_ID 0x0b
|
||||
#define HP_BMC_PROD_ID 0x8201
|
||||
static int ipmi_hp_chassis_detect(ipmi_user_t user)
|
||||
{
|
||||
if (mfg_id == HP_IANA_MFR_ID
|
||||
&& prod_id == HP_BMC_PROD_ID
|
||||
&& ipmi_version == 1)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Standard chassis support
|
||||
*/
|
||||
@ -533,14 +531,16 @@ static struct poweroff_function poweroff_functions[] = {
|
||||
{ .platform_type = "chassis",
|
||||
.detect = ipmi_dell_chassis_detect,
|
||||
.poweroff_func = ipmi_poweroff_chassis },
|
||||
{ .platform_type = "chassis",
|
||||
.detect = ipmi_hp_chassis_detect,
|
||||
.poweroff_func = ipmi_poweroff_chassis },
|
||||
/* Chassis should generally be last, other things should override
|
||||
it. */
|
||||
{ .platform_type = "chassis",
|
||||
.detect = ipmi_chassis_detect,
|
||||
.poweroff_func = ipmi_poweroff_chassis },
|
||||
};
|
||||
#define NUM_PO_FUNCS (sizeof(poweroff_functions) \
|
||||
/ sizeof(struct poweroff_function))
|
||||
#define NUM_PO_FUNCS ARRAY_SIZE(poweroff_functions)
|
||||
|
||||
|
||||
/* Called on a powerdown request. */
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* ipmi_si.h
|
||||
*
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
#include <linux/moduleparam.h>
|
||||
#include "ipmi_si.h"
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* ipmi_si_hotmod.c
|
||||
*
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* ipmi_si.c
|
||||
*
|
||||
@ -10,27 +11,6 @@
|
||||
*
|
||||
* Copyright 2002 MontaVista Software Inc.
|
||||
* Copyright 2006 IBM Corp., Christian Krafft <krafft@de.ibm.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* 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.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -252,6 +232,12 @@ struct smi_info {
|
||||
/* Default driver model device. */
|
||||
struct platform_device *pdev;
|
||||
|
||||
/* Have we added the device group to the device? */
|
||||
bool dev_group_added;
|
||||
|
||||
/* Have we added the platform device? */
|
||||
bool pdev_registered;
|
||||
|
||||
/* Counters and things for the proc filesystem. */
|
||||
atomic_t stats[SI_NUM_STATS];
|
||||
|
||||
@ -275,7 +261,8 @@ static int num_max_busy_us;
|
||||
static bool unload_when_empty = true;
|
||||
|
||||
static int try_smi_init(struct smi_info *smi);
|
||||
static void cleanup_one_si(struct smi_info *to_clean);
|
||||
static void shutdown_one_si(struct smi_info *smi_info);
|
||||
static void cleanup_one_si(struct smi_info *smi_info);
|
||||
static void cleanup_ipmi_si(void);
|
||||
|
||||
#ifdef DEBUG_TIMING
|
||||
@ -2017,18 +2004,13 @@ int ipmi_si_add_smi(struct si_sm_io *io)
|
||||
ipmi_addr_src_to_str(new_smi->io.addr_source),
|
||||
si_to_str[new_smi->io.si_type]);
|
||||
|
||||
/* So we know not to free it unless we have allocated one. */
|
||||
new_smi->intf = NULL;
|
||||
new_smi->si_sm = NULL;
|
||||
new_smi->handlers = NULL;
|
||||
|
||||
list_add_tail(&new_smi->link, &smi_infos);
|
||||
|
||||
if (initialized) {
|
||||
rv = try_smi_init(new_smi);
|
||||
if (rv) {
|
||||
mutex_unlock(&smi_infos_lock);
|
||||
cleanup_one_si(new_smi);
|
||||
mutex_unlock(&smi_infos_lock);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
@ -2047,7 +2029,6 @@ static int try_smi_init(struct smi_info *new_smi)
|
||||
int rv = 0;
|
||||
int i;
|
||||
char *init_name = NULL;
|
||||
bool platform_device_registered = false;
|
||||
|
||||
pr_info(PFX "Trying %s-specified %s state machine at %s address 0x%lx, slave address 0x%x, irq %d\n",
|
||||
ipmi_addr_src_to_str(new_smi->io.addr_source),
|
||||
@ -2090,6 +2071,7 @@ static int try_smi_init(struct smi_info *new_smi)
|
||||
new_smi->intf_num);
|
||||
if (!new_smi->pdev) {
|
||||
pr_err(PFX "Unable to allocate platform device\n");
|
||||
rv = -ENOMEM;
|
||||
goto out_err;
|
||||
}
|
||||
new_smi->io.dev = &new_smi->pdev->dev;
|
||||
@ -2168,7 +2150,7 @@ static int try_smi_init(struct smi_info *new_smi)
|
||||
atomic_set(&new_smi->req_events, 1);
|
||||
}
|
||||
|
||||
if (new_smi->pdev) {
|
||||
if (new_smi->pdev && !new_smi->pdev_registered) {
|
||||
rv = platform_device_add(new_smi->pdev);
|
||||
if (rv) {
|
||||
dev_err(new_smi->io.dev,
|
||||
@ -2176,7 +2158,7 @@ static int try_smi_init(struct smi_info *new_smi)
|
||||
rv);
|
||||
goto out_err;
|
||||
}
|
||||
platform_device_registered = true;
|
||||
new_smi->pdev_registered = true;
|
||||
}
|
||||
|
||||
dev_set_drvdata(new_smi->io.dev, new_smi);
|
||||
@ -2185,8 +2167,9 @@ static int try_smi_init(struct smi_info *new_smi)
|
||||
dev_err(new_smi->io.dev,
|
||||
"Unable to add device attributes: error %d\n",
|
||||
rv);
|
||||
goto out_err_stop_timer;
|
||||
goto out_err;
|
||||
}
|
||||
new_smi->dev_group_added = true;
|
||||
|
||||
rv = ipmi_register_smi(&handlers,
|
||||
new_smi,
|
||||
@ -2196,7 +2179,7 @@ static int try_smi_init(struct smi_info *new_smi)
|
||||
dev_err(new_smi->io.dev,
|
||||
"Unable to register device: error %d\n",
|
||||
rv);
|
||||
goto out_err_remove_attrs;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IPMI_PROC_INTERFACE
|
||||
@ -2206,7 +2189,7 @@ static int try_smi_init(struct smi_info *new_smi)
|
||||
if (rv) {
|
||||
dev_err(new_smi->io.dev,
|
||||
"Unable to create proc entry: %d\n", rv);
|
||||
goto out_err_stop_timer;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
rv = ipmi_smi_add_proc_entry(new_smi->intf, "si_stats",
|
||||
@ -2215,7 +2198,7 @@ static int try_smi_init(struct smi_info *new_smi)
|
||||
if (rv) {
|
||||
dev_err(new_smi->io.dev,
|
||||
"Unable to create proc entry: %d\n", rv);
|
||||
goto out_err_stop_timer;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
rv = ipmi_smi_add_proc_entry(new_smi->intf, "params",
|
||||
@ -2224,7 +2207,7 @@ static int try_smi_init(struct smi_info *new_smi)
|
||||
if (rv) {
|
||||
dev_err(new_smi->io.dev,
|
||||
"Unable to create proc entry: %d\n", rv);
|
||||
goto out_err_stop_timer;
|
||||
goto out_err;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -2239,56 +2222,8 @@ static int try_smi_init(struct smi_info *new_smi)
|
||||
|
||||
return 0;
|
||||
|
||||
out_err_remove_attrs:
|
||||
device_remove_group(new_smi->io.dev, &ipmi_si_dev_attr_group);
|
||||
dev_set_drvdata(new_smi->io.dev, NULL);
|
||||
|
||||
out_err_stop_timer:
|
||||
stop_timer_and_thread(new_smi);
|
||||
|
||||
out_err:
|
||||
new_smi->interrupt_disabled = true;
|
||||
|
||||
if (new_smi->intf) {
|
||||
ipmi_smi_t intf = new_smi->intf;
|
||||
new_smi->intf = NULL;
|
||||
ipmi_unregister_smi(intf);
|
||||
}
|
||||
|
||||
if (new_smi->io.irq_cleanup) {
|
||||
new_smi->io.irq_cleanup(&new_smi->io);
|
||||
new_smi->io.irq_cleanup = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait until we know that we are out of any interrupt
|
||||
* handlers might have been running before we freed the
|
||||
* interrupt.
|
||||
*/
|
||||
synchronize_sched();
|
||||
|
||||
if (new_smi->si_sm) {
|
||||
if (new_smi->handlers)
|
||||
new_smi->handlers->cleanup(new_smi->si_sm);
|
||||
kfree(new_smi->si_sm);
|
||||
new_smi->si_sm = NULL;
|
||||
}
|
||||
if (new_smi->io.addr_source_cleanup) {
|
||||
new_smi->io.addr_source_cleanup(&new_smi->io);
|
||||
new_smi->io.addr_source_cleanup = NULL;
|
||||
}
|
||||
if (new_smi->io.io_cleanup) {
|
||||
new_smi->io.io_cleanup(&new_smi->io);
|
||||
new_smi->io.io_cleanup = NULL;
|
||||
}
|
||||
|
||||
if (new_smi->pdev) {
|
||||
if (platform_device_registered)
|
||||
platform_device_unregister(new_smi->pdev);
|
||||
else
|
||||
platform_device_put(new_smi->pdev);
|
||||
new_smi->pdev = NULL;
|
||||
}
|
||||
shutdown_one_si(new_smi);
|
||||
|
||||
kfree(init_name);
|
||||
|
||||
@ -2366,17 +2301,14 @@ skip_fallback_noirq:
|
||||
}
|
||||
module_init(init_ipmi_si);
|
||||
|
||||
static void cleanup_one_si(struct smi_info *to_clean)
|
||||
static void shutdown_one_si(struct smi_info *smi_info)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
if (!to_clean)
|
||||
return;
|
||||
if (smi_info->intf) {
|
||||
ipmi_smi_t intf = smi_info->intf;
|
||||
|
||||
if (to_clean->intf) {
|
||||
ipmi_smi_t intf = to_clean->intf;
|
||||
|
||||
to_clean->intf = NULL;
|
||||
smi_info->intf = NULL;
|
||||
rv = ipmi_unregister_smi(intf);
|
||||
if (rv) {
|
||||
pr_err(PFX "Unable to unregister device: errno=%d\n",
|
||||
@ -2384,49 +2316,79 @@ static void cleanup_one_si(struct smi_info *to_clean)
|
||||
}
|
||||
}
|
||||
|
||||
device_remove_group(to_clean->io.dev, &ipmi_si_dev_attr_group);
|
||||
dev_set_drvdata(to_clean->io.dev, NULL);
|
||||
|
||||
list_del(&to_clean->link);
|
||||
if (smi_info->dev_group_added) {
|
||||
device_remove_group(smi_info->io.dev, &ipmi_si_dev_attr_group);
|
||||
smi_info->dev_group_added = false;
|
||||
}
|
||||
if (smi_info->io.dev)
|
||||
dev_set_drvdata(smi_info->io.dev, NULL);
|
||||
|
||||
/*
|
||||
* Make sure that interrupts, the timer and the thread are
|
||||
* stopped and will not run again.
|
||||
*/
|
||||
if (to_clean->io.irq_cleanup)
|
||||
to_clean->io.irq_cleanup(&to_clean->io);
|
||||
stop_timer_and_thread(to_clean);
|
||||
smi_info->interrupt_disabled = true;
|
||||
if (smi_info->io.irq_cleanup) {
|
||||
smi_info->io.irq_cleanup(&smi_info->io);
|
||||
smi_info->io.irq_cleanup = NULL;
|
||||
}
|
||||
stop_timer_and_thread(smi_info);
|
||||
|
||||
/*
|
||||
* Wait until we know that we are out of any interrupt
|
||||
* handlers might have been running before we freed the
|
||||
* interrupt.
|
||||
*/
|
||||
synchronize_sched();
|
||||
|
||||
/*
|
||||
* Timeouts are stopped, now make sure the interrupts are off
|
||||
* in the BMC. Note that timers and CPU interrupts are off,
|
||||
* so no need for locks.
|
||||
*/
|
||||
while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
|
||||
poll(to_clean);
|
||||
while (smi_info->curr_msg || (smi_info->si_state != SI_NORMAL)) {
|
||||
poll(smi_info);
|
||||
schedule_timeout_uninterruptible(1);
|
||||
}
|
||||
if (to_clean->handlers)
|
||||
disable_si_irq(to_clean);
|
||||
while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
|
||||
poll(to_clean);
|
||||
if (smi_info->handlers)
|
||||
disable_si_irq(smi_info);
|
||||
while (smi_info->curr_msg || (smi_info->si_state != SI_NORMAL)) {
|
||||
poll(smi_info);
|
||||
schedule_timeout_uninterruptible(1);
|
||||
}
|
||||
if (smi_info->handlers)
|
||||
smi_info->handlers->cleanup(smi_info->si_sm);
|
||||
|
||||
if (to_clean->handlers)
|
||||
to_clean->handlers->cleanup(to_clean->si_sm);
|
||||
if (smi_info->io.addr_source_cleanup) {
|
||||
smi_info->io.addr_source_cleanup(&smi_info->io);
|
||||
smi_info->io.addr_source_cleanup = NULL;
|
||||
}
|
||||
if (smi_info->io.io_cleanup) {
|
||||
smi_info->io.io_cleanup(&smi_info->io);
|
||||
smi_info->io.io_cleanup = NULL;
|
||||
}
|
||||
|
||||
kfree(to_clean->si_sm);
|
||||
kfree(smi_info->si_sm);
|
||||
smi_info->si_sm = NULL;
|
||||
}
|
||||
|
||||
if (to_clean->io.addr_source_cleanup)
|
||||
to_clean->io.addr_source_cleanup(&to_clean->io);
|
||||
if (to_clean->io.io_cleanup)
|
||||
to_clean->io.io_cleanup(&to_clean->io);
|
||||
static void cleanup_one_si(struct smi_info *smi_info)
|
||||
{
|
||||
if (!smi_info)
|
||||
return;
|
||||
|
||||
if (to_clean->pdev)
|
||||
platform_device_unregister(to_clean->pdev);
|
||||
list_del(&smi_info->link);
|
||||
|
||||
kfree(to_clean);
|
||||
shutdown_one_si(smi_info);
|
||||
|
||||
if (smi_info->pdev) {
|
||||
if (smi_info->pdev_registered)
|
||||
platform_device_unregister(smi_info->pdev);
|
||||
else
|
||||
platform_device_put(smi_info->pdev);
|
||||
}
|
||||
|
||||
kfree(smi_info);
|
||||
}
|
||||
|
||||
int ipmi_si_remove_by_dev(struct device *dev)
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
#include <linux/io.h>
|
||||
#include "ipmi_si.h"
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <asm/hardware.h> /* for register_parisc_driver() stuff */
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* ipmi_si_pci.c
|
||||
*
|
||||
@ -17,16 +18,12 @@ module_param_named(trypci, si_trypci, bool, 0);
|
||||
MODULE_PARM_DESC(trypci, "Setting this to zero will disable the"
|
||||
" default scan of the interfaces identified via pci");
|
||||
|
||||
#define PCI_ERMC_CLASSCODE 0x0C0700
|
||||
#define PCI_ERMC_CLASSCODE_MASK 0xffffff00
|
||||
#define PCI_ERMC_CLASSCODE_TYPE_MASK 0xff
|
||||
#define PCI_ERMC_CLASSCODE_TYPE_SMIC 0x00
|
||||
#define PCI_ERMC_CLASSCODE_TYPE_KCS 0x01
|
||||
#define PCI_ERMC_CLASSCODE_TYPE_BT 0x02
|
||||
#define PCI_CLASS_SERIAL_IPMI 0x0c07
|
||||
#define PCI_CLASS_SERIAL_IPMI_SMIC 0x0c0700
|
||||
#define PCI_CLASS_SERIAL_IPMI_KCS 0x0c0701
|
||||
#define PCI_CLASS_SERIAL_IPMI_BT 0x0c0702
|
||||
|
||||
#define PCI_HP_VENDOR_ID 0x103C
|
||||
#define PCI_MMC_DEVICE_ID 0x121A
|
||||
#define PCI_MMC_ADDR_CW 0x10
|
||||
#define PCI_DEVICE_ID_HP_MMC 0x121A
|
||||
|
||||
static void ipmi_pci_cleanup(struct si_sm_io *io)
|
||||
{
|
||||
@ -65,32 +62,43 @@ static int ipmi_pci_probe_regspacing(struct si_sm_io *io)
|
||||
return DEFAULT_REGSPACING;
|
||||
}
|
||||
|
||||
static struct pci_device_id ipmi_pci_blacklist[] = {
|
||||
/*
|
||||
* This is a "Virtual IPMI device", whatever that is. It appears
|
||||
* as a KCS device by the class, but it is not one.
|
||||
*/
|
||||
{ PCI_VDEVICE(REALTEK, 0x816c) },
|
||||
{ 0, }
|
||||
};
|
||||
|
||||
static int ipmi_pci_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *ent)
|
||||
{
|
||||
int rv;
|
||||
int class_type = pdev->class & PCI_ERMC_CLASSCODE_TYPE_MASK;
|
||||
struct si_sm_io io;
|
||||
|
||||
if (pci_match_id(ipmi_pci_blacklist, pdev))
|
||||
return -ENODEV;
|
||||
|
||||
memset(&io, 0, sizeof(io));
|
||||
io.addr_source = SI_PCI;
|
||||
dev_info(&pdev->dev, "probing via PCI");
|
||||
|
||||
switch (class_type) {
|
||||
case PCI_ERMC_CLASSCODE_TYPE_SMIC:
|
||||
switch (pdev->class) {
|
||||
case PCI_CLASS_SERIAL_IPMI_SMIC:
|
||||
io.si_type = SI_SMIC;
|
||||
break;
|
||||
|
||||
case PCI_ERMC_CLASSCODE_TYPE_KCS:
|
||||
case PCI_CLASS_SERIAL_IPMI_KCS:
|
||||
io.si_type = SI_KCS;
|
||||
break;
|
||||
|
||||
case PCI_ERMC_CLASSCODE_TYPE_BT:
|
||||
case PCI_CLASS_SERIAL_IPMI_BT:
|
||||
io.si_type = SI_BT;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_info(&pdev->dev, "Unknown IPMI type: %d\n", class_type);
|
||||
dev_info(&pdev->dev, "Unknown IPMI class: %x\n", pdev->class);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@ -138,8 +146,10 @@ static void ipmi_pci_remove(struct pci_dev *pdev)
|
||||
}
|
||||
|
||||
static const struct pci_device_id ipmi_pci_devices[] = {
|
||||
{ PCI_DEVICE(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID) },
|
||||
{ PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE_MASK) },
|
||||
{ PCI_VDEVICE(HP, PCI_DEVICE_ID_HP_MMC) },
|
||||
{ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_IPMI_SMIC, ~0) },
|
||||
{ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_IPMI_KCS, ~0) },
|
||||
{ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_IPMI_BT, ~0) },
|
||||
{ 0, }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, ipmi_pci_devices);
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* ipmi_si_platform.c
|
||||
*
|
||||
@ -50,14 +51,6 @@ MODULE_PARM_DESC(trydmi, "Setting this to zero will disable the"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
|
||||
/*
|
||||
* Once we get an ACPI failure, we don't try any more, because we go
|
||||
* through the tables sequentially. Once we don't find a table, there
|
||||
* are no more.
|
||||
*/
|
||||
static int acpi_failure;
|
||||
|
||||
/* For GPE-type interrupts. */
|
||||
static u32 ipmi_acpi_gpe(acpi_handle gpe_device,
|
||||
u32 gpe_number, void *context)
|
||||
@ -102,146 +95,6 @@ static int acpi_gpe_irq_setup(struct si_sm_io *io)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Defined at
|
||||
* http://h21007.www2.hp.com/portal/download/files/unprot/hpspmi.pdf
|
||||
*/
|
||||
struct SPMITable {
|
||||
s8 Signature[4];
|
||||
u32 Length;
|
||||
u8 Revision;
|
||||
u8 Checksum;
|
||||
s8 OEMID[6];
|
||||
s8 OEMTableID[8];
|
||||
s8 OEMRevision[4];
|
||||
s8 CreatorID[4];
|
||||
s8 CreatorRevision[4];
|
||||
u8 InterfaceType;
|
||||
u8 IPMIlegacy;
|
||||
s16 SpecificationRevision;
|
||||
|
||||
/*
|
||||
* Bit 0 - SCI interrupt supported
|
||||
* Bit 1 - I/O APIC/SAPIC
|
||||
*/
|
||||
u8 InterruptType;
|
||||
|
||||
/*
|
||||
* If bit 0 of InterruptType is set, then this is the SCI
|
||||
* interrupt in the GPEx_STS register.
|
||||
*/
|
||||
u8 GPE;
|
||||
|
||||
s16 Reserved;
|
||||
|
||||
/*
|
||||
* If bit 1 of InterruptType is set, then this is the I/O
|
||||
* APIC/SAPIC interrupt.
|
||||
*/
|
||||
u32 GlobalSystemInterrupt;
|
||||
|
||||
/* The actual register address. */
|
||||
struct acpi_generic_address addr;
|
||||
|
||||
u8 UID[4];
|
||||
|
||||
s8 spmi_id[1]; /* A '\0' terminated array starts here. */
|
||||
};
|
||||
|
||||
static int try_init_spmi(struct SPMITable *spmi)
|
||||
{
|
||||
struct si_sm_io io;
|
||||
|
||||
if (spmi->IPMIlegacy != 1) {
|
||||
pr_info(PFX "Bad SPMI legacy %d\n", spmi->IPMIlegacy);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
memset(&io, 0, sizeof(io));
|
||||
io.addr_source = SI_SPMI;
|
||||
pr_info(PFX "probing via SPMI\n");
|
||||
|
||||
/* Figure out the interface type. */
|
||||
switch (spmi->InterfaceType) {
|
||||
case 1: /* KCS */
|
||||
io.si_type = SI_KCS;
|
||||
break;
|
||||
case 2: /* SMIC */
|
||||
io.si_type = SI_SMIC;
|
||||
break;
|
||||
case 3: /* BT */
|
||||
io.si_type = SI_BT;
|
||||
break;
|
||||
case 4: /* SSIF, just ignore */
|
||||
return -EIO;
|
||||
default:
|
||||
pr_info(PFX "Unknown ACPI/SPMI SI type %d\n",
|
||||
spmi->InterfaceType);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (spmi->InterruptType & 1) {
|
||||
/* We've got a GPE interrupt. */
|
||||
io.irq = spmi->GPE;
|
||||
io.irq_setup = acpi_gpe_irq_setup;
|
||||
} else if (spmi->InterruptType & 2) {
|
||||
/* We've got an APIC/SAPIC interrupt. */
|
||||
io.irq = spmi->GlobalSystemInterrupt;
|
||||
io.irq_setup = ipmi_std_irq_setup;
|
||||
} else {
|
||||
/* Use the default interrupt setting. */
|
||||
io.irq = 0;
|
||||
io.irq_setup = NULL;
|
||||
}
|
||||
|
||||
if (spmi->addr.bit_width) {
|
||||
/* A (hopefully) properly formed register bit width. */
|
||||
io.regspacing = spmi->addr.bit_width / 8;
|
||||
} else {
|
||||
io.regspacing = DEFAULT_REGSPACING;
|
||||
}
|
||||
io.regsize = io.regspacing;
|
||||
io.regshift = spmi->addr.bit_offset;
|
||||
|
||||
if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
|
||||
io.addr_type = IPMI_MEM_ADDR_SPACE;
|
||||
} else if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
|
||||
io.addr_type = IPMI_IO_ADDR_SPACE;
|
||||
} else {
|
||||
pr_warn(PFX "Unknown ACPI I/O Address type\n");
|
||||
return -EIO;
|
||||
}
|
||||
io.addr_data = spmi->addr.address;
|
||||
|
||||
pr_info("ipmi_si: SPMI: %s %#lx regsize %d spacing %d irq %d\n",
|
||||
(io.addr_type == IPMI_IO_ADDR_SPACE) ? "io" : "mem",
|
||||
io.addr_data, io.regsize, io.regspacing, io.irq);
|
||||
|
||||
return ipmi_si_add_smi(&io);
|
||||
}
|
||||
|
||||
static void spmi_find_bmc(void)
|
||||
{
|
||||
acpi_status status;
|
||||
struct SPMITable *spmi;
|
||||
int i;
|
||||
|
||||
if (acpi_disabled)
|
||||
return;
|
||||
|
||||
if (acpi_failure)
|
||||
return;
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
status = acpi_get_table(ACPI_SIG_SPMI, i+1,
|
||||
(struct acpi_table_header **)&spmi);
|
||||
if (status != AE_OK)
|
||||
return;
|
||||
|
||||
try_init_spmi(spmi);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct resource *
|
||||
@ -579,12 +432,6 @@ void ipmi_si_platform_init(void)
|
||||
int rv = platform_driver_register(&ipmi_platform_driver);
|
||||
if (rv)
|
||||
pr_err(PFX "Unable to register driver: %d\n", rv);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
if (si_tryacpi)
|
||||
spmi_find_bmc();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void ipmi_si_platform_shutdown(void)
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
#include <linux/io.h>
|
||||
#include "ipmi_si.h"
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* ipmi_si_sm.h
|
||||
*
|
||||
@ -11,27 +12,6 @@
|
||||
* source@mvista.com
|
||||
*
|
||||
* Copyright 2002 MontaVista Software Inc.
|
||||
*
|
||||
* 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* 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.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/ipmi.h>
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* ipmi_smic_sm.c
|
||||
*
|
||||
@ -18,28 +19,7 @@
|
||||
* copyright notice:
|
||||
* (c) Copyright 2001 Grant Grundler (c) Copyright
|
||||
* 2001 Hewlett-Packard Company
|
||||
*
|
||||
*
|
||||
* 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* 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.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h> /* For printk. */
|
||||
#include <linux/string.h>
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* ipmi_ssif.c
|
||||
*
|
||||
@ -13,11 +14,6 @@
|
||||
*
|
||||
* Copyright 2003 Intel Corporation
|
||||
* Copyright 2005 MontaVista Software
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -761,7 +757,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
|
||||
ssif_info->ssif_state = SSIF_NORMAL;
|
||||
ipmi_ssif_unlock_cond(ssif_info, flags);
|
||||
pr_warn(PFX "Error getting flags: %d %d, %x\n",
|
||||
result, len, data[2]);
|
||||
result, len, (len >= 3) ? data[2] : 0);
|
||||
} else if (data[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2
|
||||
|| data[1] != IPMI_GET_MSG_FLAGS_CMD) {
|
||||
/*
|
||||
@ -783,7 +779,7 @@ static void msg_done_handler(struct ssif_info *ssif_info, int result,
|
||||
if ((result < 0) || (len < 3) || (data[2] != 0)) {
|
||||
/* Error clearing flags */
|
||||
pr_warn(PFX "Error clearing flags: %d %d, %x\n",
|
||||
result, len, data[2]);
|
||||
result, len, (len >= 3) ? data[2] : 0);
|
||||
} else if (data[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2
|
||||
|| data[1] != IPMI_CLEAR_MSG_FLAGS_CMD) {
|
||||
pr_warn(PFX "Invalid response clearing flags: %x %x\n",
|
||||
@ -1906,108 +1902,6 @@ static const struct acpi_device_id ssif_acpi_match[] = {
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, ssif_acpi_match);
|
||||
|
||||
/*
|
||||
* Once we get an ACPI failure, we don't try any more, because we go
|
||||
* through the tables sequentially. Once we don't find a table, there
|
||||
* are no more.
|
||||
*/
|
||||
static int acpi_failure;
|
||||
|
||||
/*
|
||||
* Defined in the IPMI 2.0 spec.
|
||||
*/
|
||||
struct SPMITable {
|
||||
s8 Signature[4];
|
||||
u32 Length;
|
||||
u8 Revision;
|
||||
u8 Checksum;
|
||||
s8 OEMID[6];
|
||||
s8 OEMTableID[8];
|
||||
s8 OEMRevision[4];
|
||||
s8 CreatorID[4];
|
||||
s8 CreatorRevision[4];
|
||||
u8 InterfaceType;
|
||||
u8 IPMIlegacy;
|
||||
s16 SpecificationRevision;
|
||||
|
||||
/*
|
||||
* Bit 0 - SCI interrupt supported
|
||||
* Bit 1 - I/O APIC/SAPIC
|
||||
*/
|
||||
u8 InterruptType;
|
||||
|
||||
/*
|
||||
* If bit 0 of InterruptType is set, then this is the SCI
|
||||
* interrupt in the GPEx_STS register.
|
||||
*/
|
||||
u8 GPE;
|
||||
|
||||
s16 Reserved;
|
||||
|
||||
/*
|
||||
* If bit 1 of InterruptType is set, then this is the I/O
|
||||
* APIC/SAPIC interrupt.
|
||||
*/
|
||||
u32 GlobalSystemInterrupt;
|
||||
|
||||
/* The actual register address. */
|
||||
struct acpi_generic_address addr;
|
||||
|
||||
u8 UID[4];
|
||||
|
||||
s8 spmi_id[1]; /* A '\0' terminated array starts here. */
|
||||
};
|
||||
|
||||
static int try_init_spmi(struct SPMITable *spmi)
|
||||
{
|
||||
unsigned short myaddr;
|
||||
|
||||
if (num_addrs >= MAX_SSIF_BMCS)
|
||||
return -1;
|
||||
|
||||
if (spmi->IPMIlegacy != 1) {
|
||||
pr_warn("IPMI: Bad SPMI legacy: %d\n", spmi->IPMIlegacy);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (spmi->InterfaceType != 4)
|
||||
return -ENODEV;
|
||||
|
||||
if (spmi->addr.space_id != ACPI_ADR_SPACE_SMBUS) {
|
||||
pr_warn(PFX "Invalid ACPI SSIF I/O Address type: %d\n",
|
||||
spmi->addr.space_id);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
myaddr = spmi->addr.address & 0x7f;
|
||||
|
||||
return new_ssif_client(myaddr, NULL, 0, 0, SI_SPMI, NULL);
|
||||
}
|
||||
|
||||
static void spmi_find_bmc(void)
|
||||
{
|
||||
acpi_status status;
|
||||
struct SPMITable *spmi;
|
||||
int i;
|
||||
|
||||
if (acpi_disabled)
|
||||
return;
|
||||
|
||||
if (acpi_failure)
|
||||
return;
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
status = acpi_get_table(ACPI_SIG_SPMI, i+1,
|
||||
(struct acpi_table_header **)&spmi);
|
||||
if (status != AE_OK)
|
||||
return;
|
||||
|
||||
try_init_spmi(spmi);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void spmi_find_bmc(void) { }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DMI
|
||||
@ -2112,9 +2006,6 @@ static int init_ipmi_ssif(void)
|
||||
ssif_i2c_driver.driver.acpi_match_table =
|
||||
ACPI_PTR(ssif_acpi_match);
|
||||
|
||||
if (ssif_tryacpi)
|
||||
spmi_find_bmc();
|
||||
|
||||
if (ssif_trydmi) {
|
||||
rv = platform_driver_register(&ipmi_driver);
|
||||
if (rv)
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* ipmi_watchdog.c
|
||||
*
|
||||
@ -8,27 +9,6 @@
|
||||
* source@mvista.com
|
||||
*
|
||||
* Copyright 2002 MontaVista Software Inc.
|
||||
*
|
||||
* 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* 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.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
467
drivers/char/ipmi/kcs_bmc.c
Normal file
467
drivers/char/ipmi/kcs_bmc.c
Normal file
@ -0,0 +1,467 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2015-2018, Intel Corporation.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "kcs-bmc: " fmt
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ipmi_bmc.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "kcs_bmc.h"
|
||||
|
||||
#define KCS_MSG_BUFSIZ 1000
|
||||
|
||||
#define KCS_ZERO_DATA 0
|
||||
|
||||
|
||||
/* IPMI 2.0 - Table 9-1, KCS Interface Status Register Bits */
|
||||
#define KCS_STATUS_STATE(state) (state << 6)
|
||||
#define KCS_STATUS_STATE_MASK GENMASK(7, 6)
|
||||
#define KCS_STATUS_CMD_DAT BIT(3)
|
||||
#define KCS_STATUS_SMS_ATN BIT(2)
|
||||
#define KCS_STATUS_IBF BIT(1)
|
||||
#define KCS_STATUS_OBF BIT(0)
|
||||
|
||||
/* IPMI 2.0 - Table 9-2, KCS Interface State Bits */
|
||||
enum kcs_states {
|
||||
IDLE_STATE = 0,
|
||||
READ_STATE = 1,
|
||||
WRITE_STATE = 2,
|
||||
ERROR_STATE = 3,
|
||||
};
|
||||
|
||||
/* IPMI 2.0 - Table 9-3, KCS Interface Control Codes */
|
||||
#define KCS_CMD_GET_STATUS_ABORT 0x60
|
||||
#define KCS_CMD_WRITE_START 0x61
|
||||
#define KCS_CMD_WRITE_END 0x62
|
||||
#define KCS_CMD_READ_BYTE 0x68
|
||||
|
||||
static inline u8 read_data(struct kcs_bmc *kcs_bmc)
|
||||
{
|
||||
return kcs_bmc->io_inputb(kcs_bmc, kcs_bmc->ioreg.idr);
|
||||
}
|
||||
|
||||
static inline void write_data(struct kcs_bmc *kcs_bmc, u8 data)
|
||||
{
|
||||
kcs_bmc->io_outputb(kcs_bmc, kcs_bmc->ioreg.odr, data);
|
||||
}
|
||||
|
||||
static inline u8 read_status(struct kcs_bmc *kcs_bmc)
|
||||
{
|
||||
return kcs_bmc->io_inputb(kcs_bmc, kcs_bmc->ioreg.str);
|
||||
}
|
||||
|
||||
static inline void write_status(struct kcs_bmc *kcs_bmc, u8 data)
|
||||
{
|
||||
kcs_bmc->io_outputb(kcs_bmc, kcs_bmc->ioreg.str, data);
|
||||
}
|
||||
|
||||
static void update_status_bits(struct kcs_bmc *kcs_bmc, u8 mask, u8 val)
|
||||
{
|
||||
u8 tmp = read_status(kcs_bmc);
|
||||
|
||||
tmp &= ~mask;
|
||||
tmp |= val & mask;
|
||||
|
||||
write_status(kcs_bmc, tmp);
|
||||
}
|
||||
|
||||
static inline void set_state(struct kcs_bmc *kcs_bmc, u8 state)
|
||||
{
|
||||
update_status_bits(kcs_bmc, KCS_STATUS_STATE_MASK,
|
||||
KCS_STATUS_STATE(state));
|
||||
}
|
||||
|
||||
static void kcs_force_abort(struct kcs_bmc *kcs_bmc)
|
||||
{
|
||||
set_state(kcs_bmc, ERROR_STATE);
|
||||
read_data(kcs_bmc);
|
||||
write_data(kcs_bmc, KCS_ZERO_DATA);
|
||||
|
||||
kcs_bmc->phase = KCS_PHASE_ERROR;
|
||||
kcs_bmc->data_in_avail = false;
|
||||
kcs_bmc->data_in_idx = 0;
|
||||
}
|
||||
|
||||
static void kcs_bmc_handle_data(struct kcs_bmc *kcs_bmc)
|
||||
{
|
||||
u8 data;
|
||||
|
||||
switch (kcs_bmc->phase) {
|
||||
case KCS_PHASE_WRITE_START:
|
||||
kcs_bmc->phase = KCS_PHASE_WRITE_DATA;
|
||||
/* fall through */
|
||||
|
||||
case KCS_PHASE_WRITE_DATA:
|
||||
if (kcs_bmc->data_in_idx < KCS_MSG_BUFSIZ) {
|
||||
set_state(kcs_bmc, WRITE_STATE);
|
||||
write_data(kcs_bmc, KCS_ZERO_DATA);
|
||||
kcs_bmc->data_in[kcs_bmc->data_in_idx++] =
|
||||
read_data(kcs_bmc);
|
||||
} else {
|
||||
kcs_force_abort(kcs_bmc);
|
||||
kcs_bmc->error = KCS_LENGTH_ERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
case KCS_PHASE_WRITE_END_CMD:
|
||||
if (kcs_bmc->data_in_idx < KCS_MSG_BUFSIZ) {
|
||||
set_state(kcs_bmc, READ_STATE);
|
||||
kcs_bmc->data_in[kcs_bmc->data_in_idx++] =
|
||||
read_data(kcs_bmc);
|
||||
kcs_bmc->phase = KCS_PHASE_WRITE_DONE;
|
||||
kcs_bmc->data_in_avail = true;
|
||||
wake_up_interruptible(&kcs_bmc->queue);
|
||||
} else {
|
||||
kcs_force_abort(kcs_bmc);
|
||||
kcs_bmc->error = KCS_LENGTH_ERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
case KCS_PHASE_READ:
|
||||
if (kcs_bmc->data_out_idx == kcs_bmc->data_out_len)
|
||||
set_state(kcs_bmc, IDLE_STATE);
|
||||
|
||||
data = read_data(kcs_bmc);
|
||||
if (data != KCS_CMD_READ_BYTE) {
|
||||
set_state(kcs_bmc, ERROR_STATE);
|
||||
write_data(kcs_bmc, KCS_ZERO_DATA);
|
||||
break;
|
||||
}
|
||||
|
||||
if (kcs_bmc->data_out_idx == kcs_bmc->data_out_len) {
|
||||
write_data(kcs_bmc, KCS_ZERO_DATA);
|
||||
kcs_bmc->phase = KCS_PHASE_IDLE;
|
||||
break;
|
||||
}
|
||||
|
||||
write_data(kcs_bmc,
|
||||
kcs_bmc->data_out[kcs_bmc->data_out_idx++]);
|
||||
break;
|
||||
|
||||
case KCS_PHASE_ABORT_ERROR1:
|
||||
set_state(kcs_bmc, READ_STATE);
|
||||
read_data(kcs_bmc);
|
||||
write_data(kcs_bmc, kcs_bmc->error);
|
||||
kcs_bmc->phase = KCS_PHASE_ABORT_ERROR2;
|
||||
break;
|
||||
|
||||
case KCS_PHASE_ABORT_ERROR2:
|
||||
set_state(kcs_bmc, IDLE_STATE);
|
||||
read_data(kcs_bmc);
|
||||
write_data(kcs_bmc, KCS_ZERO_DATA);
|
||||
kcs_bmc->phase = KCS_PHASE_IDLE;
|
||||
break;
|
||||
|
||||
default:
|
||||
kcs_force_abort(kcs_bmc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void kcs_bmc_handle_cmd(struct kcs_bmc *kcs_bmc)
|
||||
{
|
||||
u8 cmd;
|
||||
|
||||
set_state(kcs_bmc, WRITE_STATE);
|
||||
write_data(kcs_bmc, KCS_ZERO_DATA);
|
||||
|
||||
cmd = read_data(kcs_bmc);
|
||||
switch (cmd) {
|
||||
case KCS_CMD_WRITE_START:
|
||||
kcs_bmc->phase = KCS_PHASE_WRITE_START;
|
||||
kcs_bmc->error = KCS_NO_ERROR;
|
||||
kcs_bmc->data_in_avail = false;
|
||||
kcs_bmc->data_in_idx = 0;
|
||||
break;
|
||||
|
||||
case KCS_CMD_WRITE_END:
|
||||
if (kcs_bmc->phase != KCS_PHASE_WRITE_DATA) {
|
||||
kcs_force_abort(kcs_bmc);
|
||||
break;
|
||||
}
|
||||
|
||||
kcs_bmc->phase = KCS_PHASE_WRITE_END_CMD;
|
||||
break;
|
||||
|
||||
case KCS_CMD_GET_STATUS_ABORT:
|
||||
if (kcs_bmc->error == KCS_NO_ERROR)
|
||||
kcs_bmc->error = KCS_ABORTED_BY_COMMAND;
|
||||
|
||||
kcs_bmc->phase = KCS_PHASE_ABORT_ERROR1;
|
||||
kcs_bmc->data_in_avail = false;
|
||||
kcs_bmc->data_in_idx = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
kcs_force_abort(kcs_bmc);
|
||||
kcs_bmc->error = KCS_ILLEGAL_CONTROL_CODE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int kcs_bmc_handle_event(struct kcs_bmc *kcs_bmc)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
u8 status;
|
||||
|
||||
spin_lock_irqsave(&kcs_bmc->lock, flags);
|
||||
|
||||
if (!kcs_bmc->running) {
|
||||
kcs_force_abort(kcs_bmc);
|
||||
ret = -ENODEV;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
status = read_status(kcs_bmc) & (KCS_STATUS_IBF | KCS_STATUS_CMD_DAT);
|
||||
|
||||
switch (status) {
|
||||
case KCS_STATUS_IBF | KCS_STATUS_CMD_DAT:
|
||||
kcs_bmc_handle_cmd(kcs_bmc);
|
||||
break;
|
||||
|
||||
case KCS_STATUS_IBF:
|
||||
kcs_bmc_handle_data(kcs_bmc);
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -ENODATA;
|
||||
break;
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
spin_unlock_irqrestore(&kcs_bmc->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(kcs_bmc_handle_event);
|
||||
|
||||
static inline struct kcs_bmc *to_kcs_bmc(struct file *filp)
|
||||
{
|
||||
return container_of(filp->private_data, struct kcs_bmc, miscdev);
|
||||
}
|
||||
|
||||
static int kcs_bmc_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct kcs_bmc *kcs_bmc = to_kcs_bmc(filp);
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_irq(&kcs_bmc->lock);
|
||||
if (!kcs_bmc->running)
|
||||
kcs_bmc->running = 1;
|
||||
else
|
||||
ret = -EBUSY;
|
||||
spin_unlock_irq(&kcs_bmc->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __poll_t kcs_bmc_poll(struct file *filp, poll_table *wait)
|
||||
{
|
||||
struct kcs_bmc *kcs_bmc = to_kcs_bmc(filp);
|
||||
__poll_t mask = 0;
|
||||
|
||||
poll_wait(filp, &kcs_bmc->queue, wait);
|
||||
|
||||
spin_lock_irq(&kcs_bmc->lock);
|
||||
if (kcs_bmc->data_in_avail)
|
||||
mask |= EPOLLIN;
|
||||
spin_unlock_irq(&kcs_bmc->lock);
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
static ssize_t kcs_bmc_read(struct file *filp, char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct kcs_bmc *kcs_bmc = to_kcs_bmc(filp);
|
||||
bool data_avail;
|
||||
size_t data_len;
|
||||
ssize_t ret;
|
||||
|
||||
if (!(filp->f_flags & O_NONBLOCK))
|
||||
wait_event_interruptible(kcs_bmc->queue,
|
||||
kcs_bmc->data_in_avail);
|
||||
|
||||
mutex_lock(&kcs_bmc->mutex);
|
||||
|
||||
spin_lock_irq(&kcs_bmc->lock);
|
||||
data_avail = kcs_bmc->data_in_avail;
|
||||
if (data_avail) {
|
||||
data_len = kcs_bmc->data_in_idx;
|
||||
memcpy(kcs_bmc->kbuffer, kcs_bmc->data_in, data_len);
|
||||
}
|
||||
spin_unlock_irq(&kcs_bmc->lock);
|
||||
|
||||
if (!data_avail) {
|
||||
ret = -EAGAIN;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (count < data_len) {
|
||||
pr_err("channel=%u with too large data : %zu\n",
|
||||
kcs_bmc->channel, data_len);
|
||||
|
||||
spin_lock_irq(&kcs_bmc->lock);
|
||||
kcs_force_abort(kcs_bmc);
|
||||
spin_unlock_irq(&kcs_bmc->lock);
|
||||
|
||||
ret = -EOVERFLOW;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (copy_to_user(buf, kcs_bmc->kbuffer, data_len)) {
|
||||
ret = -EFAULT;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
ret = data_len;
|
||||
|
||||
spin_lock_irq(&kcs_bmc->lock);
|
||||
if (kcs_bmc->phase == KCS_PHASE_WRITE_DONE) {
|
||||
kcs_bmc->phase = KCS_PHASE_WAIT_READ;
|
||||
kcs_bmc->data_in_avail = false;
|
||||
kcs_bmc->data_in_idx = 0;
|
||||
} else {
|
||||
ret = -EAGAIN;
|
||||
}
|
||||
spin_unlock_irq(&kcs_bmc->lock);
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&kcs_bmc->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t kcs_bmc_write(struct file *filp, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct kcs_bmc *kcs_bmc = to_kcs_bmc(filp);
|
||||
ssize_t ret;
|
||||
|
||||
/* a minimum response size '3' : netfn + cmd + ccode */
|
||||
if (count < 3 || count > KCS_MSG_BUFSIZ)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&kcs_bmc->mutex);
|
||||
|
||||
if (copy_from_user(kcs_bmc->kbuffer, buf, count)) {
|
||||
ret = -EFAULT;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
spin_lock_irq(&kcs_bmc->lock);
|
||||
if (kcs_bmc->phase == KCS_PHASE_WAIT_READ) {
|
||||
kcs_bmc->phase = KCS_PHASE_READ;
|
||||
kcs_bmc->data_out_idx = 1;
|
||||
kcs_bmc->data_out_len = count;
|
||||
memcpy(kcs_bmc->data_out, kcs_bmc->kbuffer, count);
|
||||
write_data(kcs_bmc, kcs_bmc->data_out[0]);
|
||||
ret = count;
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
}
|
||||
spin_unlock_irq(&kcs_bmc->lock);
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&kcs_bmc->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long kcs_bmc_ioctl(struct file *filp, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct kcs_bmc *kcs_bmc = to_kcs_bmc(filp);
|
||||
long ret = 0;
|
||||
|
||||
spin_lock_irq(&kcs_bmc->lock);
|
||||
|
||||
switch (cmd) {
|
||||
case IPMI_BMC_IOCTL_SET_SMS_ATN:
|
||||
update_status_bits(kcs_bmc, KCS_STATUS_SMS_ATN,
|
||||
KCS_STATUS_SMS_ATN);
|
||||
break;
|
||||
|
||||
case IPMI_BMC_IOCTL_CLEAR_SMS_ATN:
|
||||
update_status_bits(kcs_bmc, KCS_STATUS_SMS_ATN,
|
||||
0);
|
||||
break;
|
||||
|
||||
case IPMI_BMC_IOCTL_FORCE_ABORT:
|
||||
kcs_force_abort(kcs_bmc);
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&kcs_bmc->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kcs_bmc_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct kcs_bmc *kcs_bmc = to_kcs_bmc(filp);
|
||||
|
||||
spin_lock_irq(&kcs_bmc->lock);
|
||||
kcs_bmc->running = 0;
|
||||
kcs_force_abort(kcs_bmc);
|
||||
spin_unlock_irq(&kcs_bmc->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations kcs_bmc_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = kcs_bmc_open,
|
||||
.read = kcs_bmc_read,
|
||||
.write = kcs_bmc_write,
|
||||
.release = kcs_bmc_release,
|
||||
.poll = kcs_bmc_poll,
|
||||
.unlocked_ioctl = kcs_bmc_ioctl,
|
||||
};
|
||||
|
||||
struct kcs_bmc *kcs_bmc_alloc(struct device *dev, int sizeof_priv, u32 channel)
|
||||
{
|
||||
struct kcs_bmc *kcs_bmc;
|
||||
|
||||
kcs_bmc = devm_kzalloc(dev, sizeof(*kcs_bmc) + sizeof_priv, GFP_KERNEL);
|
||||
if (!kcs_bmc)
|
||||
return NULL;
|
||||
|
||||
dev_set_name(dev, "ipmi-kcs%u", channel);
|
||||
|
||||
spin_lock_init(&kcs_bmc->lock);
|
||||
kcs_bmc->channel = channel;
|
||||
|
||||
mutex_init(&kcs_bmc->mutex);
|
||||
init_waitqueue_head(&kcs_bmc->queue);
|
||||
|
||||
kcs_bmc->data_in = devm_kmalloc(dev, KCS_MSG_BUFSIZ, GFP_KERNEL);
|
||||
kcs_bmc->data_out = devm_kmalloc(dev, KCS_MSG_BUFSIZ, GFP_KERNEL);
|
||||
kcs_bmc->kbuffer = devm_kmalloc(dev, KCS_MSG_BUFSIZ, GFP_KERNEL);
|
||||
if (!kcs_bmc->data_in || !kcs_bmc->data_out || !kcs_bmc->kbuffer)
|
||||
return NULL;
|
||||
|
||||
kcs_bmc->miscdev.minor = MISC_DYNAMIC_MINOR;
|
||||
kcs_bmc->miscdev.name = dev_name(dev);
|
||||
kcs_bmc->miscdev.fops = &kcs_bmc_fops;
|
||||
|
||||
return kcs_bmc;
|
||||
}
|
||||
EXPORT_SYMBOL(kcs_bmc_alloc);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>");
|
||||
MODULE_DESCRIPTION("KCS BMC to handle the IPMI request from system software");
|
108
drivers/char/ipmi/kcs_bmc.h
Normal file
108
drivers/char/ipmi/kcs_bmc.h
Normal file
@ -0,0 +1,108 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2015-2018, Intel Corporation.
|
||||
*/
|
||||
|
||||
#ifndef __KCS_BMC_H__
|
||||
#define __KCS_BMC_H__
|
||||
|
||||
#include <linux/miscdevice.h>
|
||||
|
||||
/* Different phases of the KCS BMC module.
|
||||
* KCS_PHASE_IDLE:
|
||||
* BMC should not be expecting nor sending any data.
|
||||
* KCS_PHASE_WRITE_START:
|
||||
* BMC is receiving a WRITE_START command from system software.
|
||||
* KCS_PHASE_WRITE_DATA:
|
||||
* BMC is receiving a data byte from system software.
|
||||
* KCS_PHASE_WRITE_END_CMD:
|
||||
* BMC is waiting a last data byte from system software.
|
||||
* KCS_PHASE_WRITE_DONE:
|
||||
* BMC has received the whole request from system software.
|
||||
* KCS_PHASE_WAIT_READ:
|
||||
* BMC is waiting the response from the upper IPMI service.
|
||||
* KCS_PHASE_READ:
|
||||
* BMC is transferring the response to system software.
|
||||
* KCS_PHASE_ABORT_ERROR1:
|
||||
* BMC is waiting error status request from system software.
|
||||
* KCS_PHASE_ABORT_ERROR2:
|
||||
* BMC is waiting for idle status afer error from system software.
|
||||
* KCS_PHASE_ERROR:
|
||||
* BMC has detected a protocol violation at the interface level.
|
||||
*/
|
||||
enum kcs_phases {
|
||||
KCS_PHASE_IDLE,
|
||||
|
||||
KCS_PHASE_WRITE_START,
|
||||
KCS_PHASE_WRITE_DATA,
|
||||
KCS_PHASE_WRITE_END_CMD,
|
||||
KCS_PHASE_WRITE_DONE,
|
||||
|
||||
KCS_PHASE_WAIT_READ,
|
||||
KCS_PHASE_READ,
|
||||
|
||||
KCS_PHASE_ABORT_ERROR1,
|
||||
KCS_PHASE_ABORT_ERROR2,
|
||||
KCS_PHASE_ERROR
|
||||
};
|
||||
|
||||
/* IPMI 2.0 - Table 9-4, KCS Interface Status Codes */
|
||||
enum kcs_errors {
|
||||
KCS_NO_ERROR = 0x00,
|
||||
KCS_ABORTED_BY_COMMAND = 0x01,
|
||||
KCS_ILLEGAL_CONTROL_CODE = 0x02,
|
||||
KCS_LENGTH_ERROR = 0x06,
|
||||
KCS_UNSPECIFIED_ERROR = 0xFF
|
||||
};
|
||||
|
||||
/* IPMI 2.0 - 9.5, KCS Interface Registers
|
||||
* @idr: Input Data Register
|
||||
* @odr: Output Data Register
|
||||
* @str: Status Register
|
||||
*/
|
||||
struct kcs_ioreg {
|
||||
u32 idr;
|
||||
u32 odr;
|
||||
u32 str;
|
||||
};
|
||||
|
||||
struct kcs_bmc {
|
||||
spinlock_t lock;
|
||||
|
||||
u32 channel;
|
||||
int running;
|
||||
|
||||
/* Setup by BMC KCS controller driver */
|
||||
struct kcs_ioreg ioreg;
|
||||
u8 (*io_inputb)(struct kcs_bmc *kcs_bmc, u32 reg);
|
||||
void (*io_outputb)(struct kcs_bmc *kcs_bmc, u32 reg, u8 b);
|
||||
|
||||
enum kcs_phases phase;
|
||||
enum kcs_errors error;
|
||||
|
||||
wait_queue_head_t queue;
|
||||
bool data_in_avail;
|
||||
int data_in_idx;
|
||||
u8 *data_in;
|
||||
|
||||
int data_out_idx;
|
||||
int data_out_len;
|
||||
u8 *data_out;
|
||||
|
||||
struct mutex mutex;
|
||||
u8 *kbuffer;
|
||||
|
||||
struct miscdevice miscdev;
|
||||
|
||||
unsigned long priv[];
|
||||
};
|
||||
|
||||
static inline void *kcs_bmc_priv(struct kcs_bmc *kcs_bmc)
|
||||
{
|
||||
return kcs_bmc->priv;
|
||||
}
|
||||
|
||||
int kcs_bmc_handle_event(struct kcs_bmc *kcs_bmc);
|
||||
struct kcs_bmc *kcs_bmc_alloc(struct device *dev, int sizeof_priv,
|
||||
u32 channel);
|
||||
#endif /* __KCS_BMC_H__ */
|
320
drivers/char/ipmi/kcs_bmc_aspeed.c
Normal file
320
drivers/char/ipmi/kcs_bmc_aspeed.c
Normal file
@ -0,0 +1,320 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2015-2018, Intel Corporation.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "aspeed-kcs-bmc: " fmt
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/timer.h>
|
||||
|
||||
#include "kcs_bmc.h"
|
||||
|
||||
|
||||
#define DEVICE_NAME "ast-kcs-bmc"
|
||||
|
||||
#define KCS_CHANNEL_MAX 4
|
||||
|
||||
/* mapped to lpc-bmc@0 IO space */
|
||||
#define LPC_HICR0 0x000
|
||||
#define LPC_HICR0_LPC3E BIT(7)
|
||||
#define LPC_HICR0_LPC2E BIT(6)
|
||||
#define LPC_HICR0_LPC1E BIT(5)
|
||||
#define LPC_HICR2 0x008
|
||||
#define LPC_HICR2_IBFIF3 BIT(3)
|
||||
#define LPC_HICR2_IBFIF2 BIT(2)
|
||||
#define LPC_HICR2_IBFIF1 BIT(1)
|
||||
#define LPC_HICR4 0x010
|
||||
#define LPC_HICR4_LADR12AS BIT(7)
|
||||
#define LPC_HICR4_KCSENBL BIT(2)
|
||||
#define LPC_LADR3H 0x014
|
||||
#define LPC_LADR3L 0x018
|
||||
#define LPC_LADR12H 0x01C
|
||||
#define LPC_LADR12L 0x020
|
||||
#define LPC_IDR1 0x024
|
||||
#define LPC_IDR2 0x028
|
||||
#define LPC_IDR3 0x02C
|
||||
#define LPC_ODR1 0x030
|
||||
#define LPC_ODR2 0x034
|
||||
#define LPC_ODR3 0x038
|
||||
#define LPC_STR1 0x03C
|
||||
#define LPC_STR2 0x040
|
||||
#define LPC_STR3 0x044
|
||||
|
||||
/* mapped to lpc-host@80 IO space */
|
||||
#define LPC_HICRB 0x080
|
||||
#define LPC_HICRB_IBFIF4 BIT(1)
|
||||
#define LPC_HICRB_LPC4E BIT(0)
|
||||
#define LPC_LADR4 0x090
|
||||
#define LPC_IDR4 0x094
|
||||
#define LPC_ODR4 0x098
|
||||
#define LPC_STR4 0x09C
|
||||
|
||||
struct aspeed_kcs_bmc {
|
||||
struct regmap *map;
|
||||
};
|
||||
|
||||
|
||||
static u8 aspeed_kcs_inb(struct kcs_bmc *kcs_bmc, u32 reg)
|
||||
{
|
||||
struct aspeed_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc);
|
||||
u32 val = 0;
|
||||
int rc;
|
||||
|
||||
rc = regmap_read(priv->map, reg, &val);
|
||||
WARN(rc != 0, "regmap_read() failed: %d\n", rc);
|
||||
|
||||
return rc == 0 ? (u8) val : 0;
|
||||
}
|
||||
|
||||
static void aspeed_kcs_outb(struct kcs_bmc *kcs_bmc, u32 reg, u8 data)
|
||||
{
|
||||
struct aspeed_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc);
|
||||
int rc;
|
||||
|
||||
rc = regmap_write(priv->map, reg, data);
|
||||
WARN(rc != 0, "regmap_write() failed: %d\n", rc);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* AST_usrGuide_KCS.pdf
|
||||
* 2. Background:
|
||||
* we note D for Data, and C for Cmd/Status, default rules are
|
||||
* A. KCS1 / KCS2 ( D / C:X / X+4 )
|
||||
* D / C : CA0h / CA4h
|
||||
* D / C : CA8h / CACh
|
||||
* B. KCS3 ( D / C:XX2h / XX3h )
|
||||
* D / C : CA2h / CA3h
|
||||
* D / C : CB2h / CB3h
|
||||
* C. KCS4
|
||||
* D / C : CA4h / CA5h
|
||||
*/
|
||||
static void aspeed_kcs_set_address(struct kcs_bmc *kcs_bmc, u16 addr)
|
||||
{
|
||||
struct aspeed_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc);
|
||||
|
||||
switch (kcs_bmc->channel) {
|
||||
case 1:
|
||||
regmap_update_bits(priv->map, LPC_HICR4,
|
||||
LPC_HICR4_LADR12AS, 0);
|
||||
regmap_write(priv->map, LPC_LADR12H, addr >> 8);
|
||||
regmap_write(priv->map, LPC_LADR12L, addr & 0xFF);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
regmap_update_bits(priv->map, LPC_HICR4,
|
||||
LPC_HICR4_LADR12AS, LPC_HICR4_LADR12AS);
|
||||
regmap_write(priv->map, LPC_LADR12H, addr >> 8);
|
||||
regmap_write(priv->map, LPC_LADR12L, addr & 0xFF);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
regmap_write(priv->map, LPC_LADR3H, addr >> 8);
|
||||
regmap_write(priv->map, LPC_LADR3L, addr & 0xFF);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
regmap_write(priv->map, LPC_LADR4, ((addr + 1) << 16) |
|
||||
addr);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void aspeed_kcs_enable_channel(struct kcs_bmc *kcs_bmc, bool enable)
|
||||
{
|
||||
struct aspeed_kcs_bmc *priv = kcs_bmc_priv(kcs_bmc);
|
||||
|
||||
switch (kcs_bmc->channel) {
|
||||
case 1:
|
||||
if (enable) {
|
||||
regmap_update_bits(priv->map, LPC_HICR2,
|
||||
LPC_HICR2_IBFIF1, LPC_HICR2_IBFIF1);
|
||||
regmap_update_bits(priv->map, LPC_HICR0,
|
||||
LPC_HICR0_LPC1E, LPC_HICR0_LPC1E);
|
||||
} else {
|
||||
regmap_update_bits(priv->map, LPC_HICR0,
|
||||
LPC_HICR0_LPC1E, 0);
|
||||
regmap_update_bits(priv->map, LPC_HICR2,
|
||||
LPC_HICR2_IBFIF1, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (enable) {
|
||||
regmap_update_bits(priv->map, LPC_HICR2,
|
||||
LPC_HICR2_IBFIF2, LPC_HICR2_IBFIF2);
|
||||
regmap_update_bits(priv->map, LPC_HICR0,
|
||||
LPC_HICR0_LPC2E, LPC_HICR0_LPC2E);
|
||||
} else {
|
||||
regmap_update_bits(priv->map, LPC_HICR0,
|
||||
LPC_HICR0_LPC2E, 0);
|
||||
regmap_update_bits(priv->map, LPC_HICR2,
|
||||
LPC_HICR2_IBFIF2, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if (enable) {
|
||||
regmap_update_bits(priv->map, LPC_HICR2,
|
||||
LPC_HICR2_IBFIF3, LPC_HICR2_IBFIF3);
|
||||
regmap_update_bits(priv->map, LPC_HICR0,
|
||||
LPC_HICR0_LPC3E, LPC_HICR0_LPC3E);
|
||||
regmap_update_bits(priv->map, LPC_HICR4,
|
||||
LPC_HICR4_KCSENBL, LPC_HICR4_KCSENBL);
|
||||
} else {
|
||||
regmap_update_bits(priv->map, LPC_HICR0,
|
||||
LPC_HICR0_LPC3E, 0);
|
||||
regmap_update_bits(priv->map, LPC_HICR4,
|
||||
LPC_HICR4_KCSENBL, 0);
|
||||
regmap_update_bits(priv->map, LPC_HICR2,
|
||||
LPC_HICR2_IBFIF3, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if (enable)
|
||||
regmap_update_bits(priv->map, LPC_HICRB,
|
||||
LPC_HICRB_IBFIF4 | LPC_HICRB_LPC4E,
|
||||
LPC_HICRB_IBFIF4 | LPC_HICRB_LPC4E);
|
||||
else
|
||||
regmap_update_bits(priv->map, LPC_HICRB,
|
||||
LPC_HICRB_IBFIF4 | LPC_HICRB_LPC4E,
|
||||
0);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t aspeed_kcs_irq(int irq, void *arg)
|
||||
{
|
||||
struct kcs_bmc *kcs_bmc = arg;
|
||||
|
||||
if (!kcs_bmc_handle_event(kcs_bmc))
|
||||
return IRQ_HANDLED;
|
||||
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static int aspeed_kcs_config_irq(struct kcs_bmc *kcs_bmc,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
int irq;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
return devm_request_irq(dev, irq, aspeed_kcs_irq, IRQF_SHARED,
|
||||
dev_name(dev), kcs_bmc);
|
||||
}
|
||||
|
||||
static const struct kcs_ioreg ast_kcs_bmc_ioregs[KCS_CHANNEL_MAX] = {
|
||||
{ .idr = LPC_IDR1, .odr = LPC_ODR1, .str = LPC_STR1 },
|
||||
{ .idr = LPC_IDR2, .odr = LPC_ODR2, .str = LPC_STR2 },
|
||||
{ .idr = LPC_IDR3, .odr = LPC_ODR3, .str = LPC_STR3 },
|
||||
{ .idr = LPC_IDR4, .odr = LPC_ODR4, .str = LPC_STR4 },
|
||||
};
|
||||
|
||||
static int aspeed_kcs_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct aspeed_kcs_bmc *priv;
|
||||
struct kcs_bmc *kcs_bmc;
|
||||
u32 chan, addr;
|
||||
int rc;
|
||||
|
||||
rc = of_property_read_u32(dev->of_node, "kcs_chan", &chan);
|
||||
if ((rc != 0) || (chan == 0 || chan > KCS_CHANNEL_MAX)) {
|
||||
dev_err(dev, "no valid 'kcs_chan' configured\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(dev->of_node, "kcs_addr", &addr);
|
||||
if (rc) {
|
||||
dev_err(dev, "no valid 'kcs_addr' configured\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
kcs_bmc = kcs_bmc_alloc(dev, sizeof(*priv), chan);
|
||||
if (!kcs_bmc)
|
||||
return -ENOMEM;
|
||||
|
||||
priv = kcs_bmc_priv(kcs_bmc);
|
||||
priv->map = syscon_node_to_regmap(dev->parent->of_node);
|
||||
if (IS_ERR(priv->map)) {
|
||||
dev_err(dev, "Couldn't get regmap\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
kcs_bmc->ioreg = ast_kcs_bmc_ioregs[chan - 1];
|
||||
kcs_bmc->io_inputb = aspeed_kcs_inb;
|
||||
kcs_bmc->io_outputb = aspeed_kcs_outb;
|
||||
|
||||
dev_set_drvdata(dev, kcs_bmc);
|
||||
|
||||
aspeed_kcs_set_address(kcs_bmc, addr);
|
||||
aspeed_kcs_enable_channel(kcs_bmc, true);
|
||||
rc = aspeed_kcs_config_irq(kcs_bmc, pdev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = misc_register(&kcs_bmc->miscdev);
|
||||
if (rc) {
|
||||
dev_err(dev, "Unable to register device\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
pr_info("channel=%u addr=0x%x idr=0x%x odr=0x%x str=0x%x\n",
|
||||
chan, addr,
|
||||
kcs_bmc->ioreg.idr, kcs_bmc->ioreg.odr, kcs_bmc->ioreg.str);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aspeed_kcs_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct kcs_bmc *kcs_bmc = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
misc_deregister(&kcs_bmc->miscdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ast_kcs_bmc_match[] = {
|
||||
{ .compatible = "aspeed,ast2400-kcs-bmc" },
|
||||
{ .compatible = "aspeed,ast2500-kcs-bmc" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ast_kcs_bmc_match);
|
||||
|
||||
static struct platform_driver ast_kcs_bmc_driver = {
|
||||
.driver = {
|
||||
.name = DEVICE_NAME,
|
||||
.of_match_table = ast_kcs_bmc_match,
|
||||
},
|
||||
.probe = aspeed_kcs_probe,
|
||||
.remove = aspeed_kcs_remove,
|
||||
};
|
||||
module_platform_driver(ast_kcs_bmc_driver);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>");
|
||||
MODULE_DESCRIPTION("Aspeed device interface to the KCS BMC device");
|
@ -1,9 +1,8 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright (C) 2012 CERN (www.cern.ch)
|
||||
* Author: Alessandro Rubini <rubini@gnudd.com>
|
||||
*
|
||||
* Released according to the GNU GPL, version 2 or any later version.
|
||||
*
|
||||
* This work is part of the White Rabbit project, a research effort led
|
||||
* by CERN, the European Institute for Nuclear Research.
|
||||
*/
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* ipmi.h
|
||||
*
|
||||
@ -9,26 +10,6 @@
|
||||
*
|
||||
* Copyright 2002 MontaVista Software Inc.
|
||||
*
|
||||
* 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* 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.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#ifndef __LINUX_IPMI_H
|
||||
#define __LINUX_IPMI_H
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* ipmi_smi.h
|
||||
*
|
||||
@ -9,26 +10,6 @@
|
||||
*
|
||||
* Copyright 2002 MontaVista Software Inc.
|
||||
*
|
||||
* 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* 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.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_IPMI_SMI_H
|
||||
|
@ -10,26 +10,6 @@
|
||||
*
|
||||
* Copyright 2002 MontaVista Software Inc.
|
||||
*
|
||||
* 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* 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.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _UAPI__LINUX_IPMI_H
|
||||
|
16
include/uapi/linux/ipmi_bmc.h
Normal file
16
include/uapi/linux/ipmi_bmc.h
Normal file
@ -0,0 +1,16 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2015-2018, Intel Corporation.
|
||||
*/
|
||||
|
||||
#ifndef _UAPI_LINUX_IPMI_BMC_H
|
||||
#define _UAPI_LINUX_IPMI_BMC_H
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
#define __IPMI_BMC_IOCTL_MAGIC 0xB1
|
||||
#define IPMI_BMC_IOCTL_SET_SMS_ATN _IO(__IPMI_BMC_IOCTL_MAGIC, 0x00)
|
||||
#define IPMI_BMC_IOCTL_CLEAR_SMS_ATN _IO(__IPMI_BMC_IOCTL_MAGIC, 0x01)
|
||||
#define IPMI_BMC_IOCTL_FORCE_ABORT _IO(__IPMI_BMC_IOCTL_MAGIC, 0x02)
|
||||
|
||||
#endif /* _UAPI_LINUX_IPMI_BMC_H */
|
@ -10,26 +10,6 @@
|
||||
*
|
||||
* Copyright 2002 MontaVista Software Inc.
|
||||
*
|
||||
* 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* 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.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_IPMI_MSGDEFS_H
|
||||
|
Loading…
Reference in New Issue
Block a user