* [PATCH 1/2] powerpc/powernv: Add OPAL IPMI interface
2014-11-06 3:38 [PATCH 0/2] Add IPMI support for powernv powerpc machines Jeremy Kerr
@ 2014-11-06 3:38 ` Jeremy Kerr
2014-11-06 3:38 ` [PATCH 2/2] drivers/char/ipmi: Add powernv IPMI driver Jeremy Kerr
2014-11-06 14:15 ` [PATCH 0/2] Add IPMI support for powernv powerpc machines Corey Minyard
2 siblings, 0 replies; 16+ messages in thread
From: Jeremy Kerr @ 2014-11-06 3:38 UTC (permalink / raw)
To: openipmi-developer, Corey Minyard, linuxppc-dev
Recent OPAL firmare adds a couple of functions to send and receive IPMI
messages:
https://github.com/open-power/skiboot/commit/b2a374da
This change updates the token list and wrappers to suit, and adds the
platform devices for any IPMI interfaces.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
---
arch/powerpc/include/asm/opal.h | 17 +++++++++++++++++
arch/powerpc/platforms/powernv/opal-wrappers.S | 2 ++
arch/powerpc/platforms/powernv/opal.c | 14 ++++++++++++++
3 files changed, 33 insertions(+)
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 9124b0e..5d073e5 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -154,6 +154,8 @@ struct opal_sg_list {
#define OPAL_HANDLE_HMI 98
#define OPAL_REGISTER_DUMP_REGION 101
#define OPAL_UNREGISTER_DUMP_REGION 102
+#define OPAL_IPMI_SEND 107
+#define OPAL_IPMI_RECV 108
#ifndef __ASSEMBLY__
@@ -452,6 +454,17 @@ struct opal_msg {
__be64 params[8];
};
+enum {
+ OPAL_IPMI_MSG_FORMAT_VERSION_1 = 1,
+};
+
+struct opal_ipmi_msg {
+ uint8_t version;
+ uint8_t netfn;
+ uint8_t cmd;
+ uint8_t data[];
+};
+
struct opal_machine_check_event {
enum OpalMCE_Version version:8; /* 0x00 */
uint8_t in_use; /* 0x01 */
@@ -963,6 +976,10 @@ int64_t opal_handle_hmi(void);
int64_t opal_register_dump_region(uint32_t id, uint64_t start, uint64_t end);
int64_t opal_unregister_dump_region(uint32_t id);
int64_t opal_pci_set_phb_cxl_mode(uint64_t phb_id, uint64_t mode, uint64_t pe_number);
+int64_t opal_ipmi_send(uint64_t interface, struct opal_ipmi_msg *msg,
+ uint64_t msg_len);
+int64_t opal_ipmi_recv(uint64_t interface, struct opal_ipmi_msg *msg,
+ uint64_t *msg_len);
/* Internal functions */
extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index e9e2450..f463068 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -250,3 +250,5 @@ OPAL_CALL(opal_handle_hmi, OPAL_HANDLE_HMI);
OPAL_CALL(opal_register_dump_region, OPAL_REGISTER_DUMP_REGION);
OPAL_CALL(opal_unregister_dump_region, OPAL_UNREGISTER_DUMP_REGION);
OPAL_CALL(opal_pci_set_phb_cxl_mode, OPAL_PCI_SET_PHB_CXL_MODE);
+OPAL_CALL(opal_ipmi_send, OPAL_IPMI_SEND);
+OPAL_CALL(opal_ipmi_recv, OPAL_IPMI_RECV);
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index b642b05..c2f873e 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -623,6 +623,16 @@ static void __init opal_dump_region_init(void)
pr_warn("DUMP: Failed to register kernel log buffer. "
"rc = %d\n", rc);
}
+
+static void opal_ipmi_init(struct device_node *opal_node)
+{
+ struct device_node *np;
+
+ for_each_child_of_node(opal_node, np)
+ if (of_device_is_compatible(np, "ibm,opal-ipmi"))
+ of_platform_device_create(np, NULL, NULL);
+}
+
static int __init opal_init(void)
{
struct device_node *np, *consoles;
@@ -686,6 +696,8 @@ static int __init opal_init(void)
opal_msglog_init();
}
+ opal_ipmi_init(opal_node);
+
return 0;
}
machine_subsys_initcall(powernv, opal_init);
@@ -721,6 +733,8 @@ void opal_shutdown(void)
/* Export this so that test modules can use it */
EXPORT_SYMBOL_GPL(opal_invalid_call);
+EXPORT_SYMBOL_GPL(opal_ipmi_send);
+EXPORT_SYMBOL_GPL(opal_ipmi_recv);
/* Convert a region of vmalloc memory to an opal sg list */
struct opal_sg_list *opal_vmalloc_to_sg_list(void *vmalloc_addr,
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 0/2] Add IPMI support for powernv powerpc machines
@ 2014-11-06 3:38 Jeremy Kerr
2014-11-06 3:38 ` [PATCH 1/2] powerpc/powernv: Add OPAL IPMI interface Jeremy Kerr
` (2 more replies)
0 siblings, 3 replies; 16+ messages in thread
From: Jeremy Kerr @ 2014-11-06 3:38 UTC (permalink / raw)
To: openipmi-developer, Corey Minyard, linuxppc-dev
This series adds IPMI driver and arch glue for OPAL-firmware-based
powernv machines. The first change exposes the firmware's IPMI API, and
the second adds an actual driver.
IPMI folks: the IPMI driver could do with a little review, as it's not a
conventional BT/KCS/SMI SI, in that the low-level send/recv interface
will handle the entire message at once.
Corey & Michael: if this is acceptable, it may be mergable as two
separate patches - one for the IPMI subsystem, one for the powernv
platform. However, we'd need to preserve their order: patch 2/2 depends
on 1/2, which provides the structure & function definitions. This'll
break the build if only 2/2 is in the tree, and CONFIG_IPMI_POWERNV is
set.
Alternatively, they could be merged by one maintainer, pending an ack
from the other.
Comments / queries / etc welcome.
Cheers,
Jeremy
---
Jeremy Kerr (2):
powerpc/powernv: Add OPAL IPMI interface
drivers/char/ipmi: Add powernv IPMI driver
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 2/2] drivers/char/ipmi: Add powernv IPMI driver
2014-11-06 3:38 [PATCH 0/2] Add IPMI support for powernv powerpc machines Jeremy Kerr
2014-11-06 3:38 ` [PATCH 1/2] powerpc/powernv: Add OPAL IPMI interface Jeremy Kerr
@ 2014-11-06 3:38 ` Jeremy Kerr
2014-11-06 14:15 ` [PATCH 0/2] Add IPMI support for powernv powerpc machines Corey Minyard
2 siblings, 0 replies; 16+ messages in thread
From: Jeremy Kerr @ 2014-11-06 3:38 UTC (permalink / raw)
To: openipmi-developer, Corey Minyard, linuxppc-dev
This change adds an initial IPMI driver for powerpc OPAL firmware. The
interface is exposed entirely through firmware: we have two functions to
send and receive IPMI messages, and an interrupt notification from the
firmware to signify that a message is available.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
---
drivers/char/ipmi/Kconfig | 6
drivers/char/ipmi/Makefile | 1
drivers/char/ipmi/ipmi_powernv.c | 298 +++++++++++++++++++++++++++++++
3 files changed, 305 insertions(+)
diff --git a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig
index db1c9b7..a6a8cb3 100644
--- a/drivers/char/ipmi/Kconfig
+++ b/drivers/char/ipmi/Kconfig
@@ -62,6 +62,12 @@ config IPMI_SI_PROBE_DEFAULTS
only be available on older systems if the "ipmi_si_intf.trydefaults=1"
boot argument is passed.
+config IPMI_POWERNV
+ depends on PPC_POWERNV
+ tristate 'POWERNV (OPAL firmware) IPMI interface'
+ help
+ Provides a driver for OPAL firmware-based IPMI interfaces.
+
config IPMI_WATCHDOG
tristate 'IPMI Watchdog Timer'
help
diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile
index 16a9364..6620404 100644
--- a/drivers/char/ipmi/Makefile
+++ b/drivers/char/ipmi/Makefile
@@ -7,5 +7,6 @@ ipmi_si-y := ipmi_si_intf.o ipmi_kcs_sm.o ipmi_smic_sm.o ipmi_bt_sm.o
obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o
obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o
obj-$(CONFIG_IPMI_SI) += ipmi_si.o
+obj-$(CONFIG_IPMI_POWERNV) += ipmi_powernv.o
obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o
obj-$(CONFIG_IPMI_POWEROFF) += ipmi_poweroff.o
diff --git a/drivers/char/ipmi/ipmi_powernv.c b/drivers/char/ipmi/ipmi_powernv.c
new file mode 100644
index 0000000..79bbed9
--- /dev/null
+++ b/drivers/char/ipmi/ipmi_powernv.c
@@ -0,0 +1,298 @@
+
+#define pr_fmt(fmt) "ipmi-powernv: " fmt
+
+#include <linux/ipmi_smi.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#include <asm/opal.h>
+
+
+struct ipmi_smi_powernv {
+ u64 interface_id;
+ struct ipmi_device_id ipmi_id;
+ ipmi_smi_t intf;
+ u64 event;
+ struct notifier_block event_nb;
+
+ /**
+ * We assume that there can only be one outstanding request, so
+ * keep the pending message in cur_msg. We protect this from concurrent
+ * updates through send & recv calls, (and consequently opal_msg, which
+ * is in-use when cur_msg is set) with msg_lock
+ */
+ spinlock_t msg_lock;
+ struct ipmi_smi_msg *cur_msg;
+ struct opal_ipmi_msg *opal_msg;
+};
+
+static int ipmi_powernv_start_processing(void *send_info, ipmi_smi_t intf)
+{
+ struct ipmi_smi_powernv *smi = send_info;
+ smi->intf = intf;
+ return 0;
+}
+
+static void send_error_reply(struct ipmi_smi_powernv *smi,
+ struct ipmi_smi_msg *msg, u8 completion_code)
+{
+ msg->rsp[0] = msg->data[0] | 0x4;
+ msg->rsp[1] = msg->data[1];
+ msg->rsp[2] = completion_code;
+ msg->rsp_size = 3;
+ ipmi_smi_msg_received(smi->intf, msg);
+}
+
+static void ipmi_powernv_send(void *send_info, struct ipmi_smi_msg *msg,
+ int priority)
+{
+ struct ipmi_smi_powernv *smi = send_info;
+ struct opal_ipmi_msg *opal_msg;
+ unsigned long flags;
+ int comp, rc;
+ size_t size;
+
+ /* ensure data_len will fit in the opal_ipmi_msg buffer... */
+ if (msg->data_size > IPMI_MAX_MSG_LENGTH) {
+ comp = IPMI_REQ_LEN_EXCEEDED_ERR;
+ goto err;
+ }
+
+ /* ... and that we at least have netfn and cmd bytes */
+ if (msg->data_size < 2) {
+ comp = IPMI_REQ_LEN_INVALID_ERR;
+ goto err;
+ }
+
+ spin_lock_irqsave(&smi->msg_lock, flags);
+
+ if (smi->cur_msg) {
+ comp = IPMI_NODE_BUSY_ERR;
+ goto err_unlock;
+ }
+
+ /* format our data for the OPAL API */
+ opal_msg = smi->opal_msg;
+ opal_msg->version = OPAL_IPMI_MSG_FORMAT_VERSION_1;
+ opal_msg->netfn = msg->data[0];
+ opal_msg->cmd = msg->data[1];
+ if (msg->data_size > 2)
+ memcpy(opal_msg->data, msg->data + 2, msg->data_size - 2);
+
+ /* data_size already includes the netfn and cmd bytes */
+ size = sizeof(*opal_msg) + msg->data_size - 2;
+
+ pr_devel("%s: opal_ipmi_send(0x%llx, %p, %ld)\n", __func__,
+ smi->interface_id, opal_msg, size);
+ rc = opal_ipmi_send(smi->interface_id, opal_msg, size);
+ pr_devel("%s: -> %d\n", __func__, rc);
+
+ if (!rc) {
+ smi->cur_msg = msg;
+ spin_unlock_irqrestore(&smi->msg_lock, flags);
+ return;
+ }
+
+ comp = IPMI_ERR_UNSPECIFIED;
+err_unlock:
+ spin_unlock_irqrestore(&smi->msg_lock, flags);
+err:
+ send_error_reply(smi, msg, comp);
+}
+
+static int ipmi_powernv_recv(struct ipmi_smi_powernv *smi)
+{
+ struct opal_ipmi_msg *opal_msg;
+ struct ipmi_smi_msg *msg;
+ unsigned long flags;
+ uint64_t size;
+ int rc;
+
+ pr_devel("%s: opal_ipmi_recv(%llx, msg, sz)\n", __func__,
+ smi->interface_id);
+
+ spin_lock_irqsave(&smi->msg_lock, flags);
+
+ if (!smi->cur_msg) {
+ pr_warn("no current message?\n");
+ return 0;
+ }
+
+ msg = smi->cur_msg;
+ opal_msg = smi->opal_msg;
+
+ size = cpu_to_be64(sizeof(*opal_msg) + IPMI_MAX_MSG_LENGTH);
+
+ rc = opal_ipmi_recv(smi->interface_id,
+ opal_msg,
+ &size);
+ size = be64_to_cpu(size);
+ pr_devel("%s: -> %d (size %lld)\n", __func__,
+ rc, rc == 0 ? size : 0);
+ if (rc) {
+ spin_unlock_irqrestore(&smi->msg_lock, flags);
+ ipmi_free_smi_msg(msg);
+ return 0;
+ }
+
+ if (size < sizeof(*opal_msg)) {
+ spin_unlock_irqrestore(&smi->msg_lock, flags);
+ pr_warn("unexpected IPMI message size %lld\n", size);
+ return 0;
+ }
+
+ if (opal_msg->version != OPAL_IPMI_MSG_FORMAT_VERSION_1) {
+ spin_unlock_irqrestore(&smi->msg_lock, flags);
+ pr_warn("unexpected IPMI message format (version %d)\n",
+ opal_msg->version);
+ return 0;
+ }
+
+ msg->rsp[0] = opal_msg->netfn;
+ msg->rsp[1] = opal_msg->cmd;
+ if (size > sizeof(*opal_msg))
+ memcpy(&msg->rsp[2], opal_msg->data, size - sizeof(*opal_msg));
+ msg->rsp_size = 2 + size - sizeof(*opal_msg);
+
+ smi->cur_msg = NULL;
+ spin_unlock_irqrestore(&smi->msg_lock, flags);
+ ipmi_smi_msg_received(smi->intf, msg);
+ return 0;
+}
+
+static void ipmi_powernv_request_events(void *send_info)
+{
+}
+
+static void ipmi_powernv_set_run_to_completion(void *send_info,
+ bool run_to_completion)
+{
+}
+
+static void ipmi_powernv_poll(void *send_info)
+{
+ struct ipmi_smi_powernv *smi = send_info;
+ ipmi_powernv_recv(smi);
+}
+
+static struct ipmi_smi_handlers ipmi_powernv_smi_handlers = {
+ .owner = THIS_MODULE,
+ .start_processing = ipmi_powernv_start_processing,
+ .sender = ipmi_powernv_send,
+ .request_events = ipmi_powernv_request_events,
+ .set_run_to_completion = ipmi_powernv_set_run_to_completion,
+ .poll = ipmi_powernv_poll,
+};
+
+static int ipmi_opal_event(struct notifier_block *nb,
+ unsigned long events, void *change)
+{
+ struct ipmi_smi_powernv *smi = container_of(nb,
+ struct ipmi_smi_powernv, event_nb);
+
+ if (events & smi->event)
+ ipmi_powernv_recv(smi);
+ return 0;
+}
+
+static int ipmi_powernv_probe(struct platform_device *pdev)
+{
+ struct ipmi_smi_powernv *ipmi;
+ struct device *dev;
+ u32 prop;
+ int rc;
+
+ if (!pdev || !pdev->dev.of_node)
+ return -ENODEV;
+
+ dev = &pdev->dev;
+
+ ipmi = devm_kzalloc(dev, sizeof(*ipmi), GFP_KERNEL);
+ if (!ipmi)
+ return -ENOMEM;
+
+ spin_lock_init(&ipmi->msg_lock);
+
+ rc = of_property_read_u32(dev->of_node, "ibm,ipmi-interface-id",
+ &prop);
+ if (rc) {
+ dev_warn(dev, "No interface ID property\n");
+ goto err_free;
+ }
+ ipmi->interface_id = prop;
+
+ rc = of_property_read_u32(dev->of_node, "interrupts", &prop);
+ if (rc) {
+ dev_warn(dev, "No interrupts property\n");
+ goto err_free;
+ }
+
+ ipmi->event = 1ull << prop;
+ ipmi->event_nb.notifier_call = ipmi_opal_event;
+
+ rc = opal_notifier_register(&ipmi->event_nb);
+ if (rc) {
+ dev_warn(dev, "OPAL notifier registration failed (%d)\n", rc);
+ goto err_free;
+ }
+
+ ipmi->opal_msg = devm_kmalloc(dev,
+ sizeof(*ipmi->opal_msg) + IPMI_MAX_MSG_LENGTH,
+ GFP_KERNEL);
+ if (!ipmi->opal_msg) {
+ rc = -ENOMEM;
+ goto err_unregister;
+ }
+
+ /* todo: query actual ipmi_device_id */
+ rc = ipmi_register_smi(&ipmi_powernv_smi_handlers, ipmi,
+ &ipmi->ipmi_id, dev, "powernv", 0);
+ if (rc) {
+ dev_warn(dev, "IPMI SMI registration failed (%d)\n", rc);
+ goto err_free_msg;
+ }
+
+ dev_set_drvdata(dev, ipmi);
+ return 0;
+
+err_free_msg:
+ devm_kfree(dev, ipmi->opal_msg);
+err_unregister:
+ opal_notifier_unregister(&ipmi->event_nb);
+err_free:
+ devm_kfree(dev, ipmi);
+ return rc;
+}
+
+static int ipmi_powernv_remove(struct platform_device *pdev)
+{
+ struct ipmi_smi_powernv *smi = dev_get_drvdata(&pdev->dev);
+ ipmi_unregister_smi(smi->intf);
+ opal_notifier_unregister(&smi->event_nb);
+ return 0;
+}
+
+static const struct of_device_id ipmi_powernv_match[] = {
+ { .compatible = "ibm,opal-ipmi" },
+ { },
+};
+
+
+static struct platform_driver powernv_ipmi_driver = {
+ .driver = {
+ .name = "ipmi-powernv",
+ .owner = THIS_MODULE,
+ .of_match_table = ipmi_powernv_match,
+ },
+ .probe = ipmi_powernv_probe,
+ .remove = ipmi_powernv_remove,
+};
+
+
+module_platform_driver(powernv_ipmi_driver);
+
+MODULE_DEVICE_TABLE(of, ipmi_powernv_match);
+MODULE_DESCRIPTION("powernv IPMI driver");
+MODULE_AUTHOR("Jeremy Kerr <jk@ozlabs.org>");
+MODULE_LICENSE("GPL");
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH 0/2] Add IPMI support for powernv powerpc machines
2014-11-06 3:38 [PATCH 0/2] Add IPMI support for powernv powerpc machines Jeremy Kerr
2014-11-06 3:38 ` [PATCH 1/2] powerpc/powernv: Add OPAL IPMI interface Jeremy Kerr
2014-11-06 3:38 ` [PATCH 2/2] drivers/char/ipmi: Add powernv IPMI driver Jeremy Kerr
@ 2014-11-06 14:15 ` Corey Minyard
2014-11-10 3:26 ` Jeremy Kerr
2014-11-12 6:10 ` Michael Ellerman
2 siblings, 2 replies; 16+ messages in thread
From: Corey Minyard @ 2014-11-06 14:15 UTC (permalink / raw)
To: Jeremy Kerr, openipmi-developer, linuxppc-dev
On 11/05/2014 09:38 PM, Jeremy Kerr wrote:
> This series adds IPMI driver and arch glue for OPAL-firmware-based
> powernv machines. The first change exposes the firmware's IPMI API, and
> the second adds an actual driver.
>
> IPMI folks: the IPMI driver could do with a little review, as it's not a
> conventional BT/KCS/SMI SI, in that the low-level send/recv interface
> will handle the entire message at once.
Handling the entire message at once should be fine, as that's what this
driver level is designed to do for the message handler. That part all
looks correct. The code itself looks good, but I have a couple of
high-level comments.
The driver at this level can receive more than one message to handle at
a time, so it needs some sort of queue. This is to allow multiple users
and to allow the message handler to send its own commands while other
commands are going on. You might argue that the queuing should be done
in ipmi_msghandler, and you would probably be right. I'll look at doing
that. If that is the case, then your NULL check for current message
should probably be a BUG_ON().
Do you need to handle any BMC flags? Particularly incoming events?
> Corey & Michael: if this is acceptable, it may be mergable as two
> separate patches - one for the IPMI subsystem, one for the powernv
> platform. However, we'd need to preserve their order: patch 2/2 depends
> on 1/2, which provides the structure & function definitions. This'll
> break the build if only 2/2 is in the tree, and CONFIG_IPMI_POWERNV is
> set.
>
> Alternatively, they could be merged by one maintainer, pending an ack
> from the other.
I'm fine either way.
Thanks,
-corey
> Comments / queries / etc welcome.
>
> Cheers,
>
>
> Jeremy
>
> ---
> Jeremy Kerr (2):
> powerpc/powernv: Add OPAL IPMI interface
> drivers/char/ipmi: Add powernv IPMI driver
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 0/2] Add IPMI support for powernv powerpc machines
2014-11-06 14:15 ` [PATCH 0/2] Add IPMI support for powernv powerpc machines Corey Minyard
@ 2014-11-10 3:26 ` Jeremy Kerr
2014-11-10 5:41 ` Benjamin Herrenschmidt
2014-11-11 21:07 ` Corey Minyard
2014-11-12 6:10 ` Michael Ellerman
1 sibling, 2 replies; 16+ messages in thread
From: Jeremy Kerr @ 2014-11-10 3:26 UTC (permalink / raw)
To: minyard, openipmi-developer, linuxppc-dev
Hi Corey,
Thanks for the review.
>> IPMI folks: the IPMI driver could do with a little review, as it's
>> not a conventional BT/KCS/SMI SI, in that the low-level send/recv
>> interface will handle the entire message at once.
>
> Handling the entire message at once should be fine, as that's what
> this driver level is designed to do for the message handler. That
> part all looks correct. The code itself looks good, but I have a
> couple of high-level comments.
>
> The driver at this level can receive more than one message to handle
> at a time, so it needs some sort of queue. This is to allow multiple
> users and to allow the message handler to send its own commands while
> other commands are going on. You might argue that the queuing should
> be done in ipmi_msghandler, and you would probably be right.
Ah, that's what I'd been assuming was being done - I missed the
xmit_list in the si_intf code. It'd be great if this could be in the
generic msghandler code, otherwise I'd just be duplicating the si_intf
logic.
> I'll look at doing that. If that is the case, then your NULL check
> for current message should probably be a BUG_ON().
OK, I'll update this when the msghandler bit is implemented.
> Do you need to handle any BMC flags? Particularly incoming events?
Not at this stage - we may in future though.
Cheers,
Jeremy
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 0/2] Add IPMI support for powernv powerpc machines
2014-11-10 3:26 ` Jeremy Kerr
@ 2014-11-10 5:41 ` Benjamin Herrenschmidt
2014-11-10 6:01 ` Alistair Popple
2014-11-10 6:41 ` Jeremy Kerr
2014-11-11 21:07 ` Corey Minyard
1 sibling, 2 replies; 16+ messages in thread
From: Benjamin Herrenschmidt @ 2014-11-10 5:41 UTC (permalink / raw)
To: Jeremy Kerr; +Cc: openipmi-developer, linuxppc-dev, minyard
On Mon, 2014-11-10 at 11:26 +0800, Jeremy Kerr wrote:
> Hi Corey,
>
> Thanks for the review.
>
> >> IPMI folks: the IPMI driver could do with a little review, as it's
> >> not a conventional BT/KCS/SMI SI, in that the low-level send/recv
> >> interface will handle the entire message at once.
> >
> > Handling the entire message at once should be fine, as that's what
> > this driver level is designed to do for the message handler. That
> > part all looks correct. The code itself looks good, but I have a
> > couple of high-level comments.
> >
> > The driver at this level can receive more than one message to handle
> > at a time, so it needs some sort of queue. This is to allow multiple
> > users and to allow the message handler to send its own commands while
> > other commands are going on. You might argue that the queuing should
> > be done in ipmi_msghandler, and you would probably be right.
>
> Ah, that's what I'd been assuming was being done - I missed the
> xmit_list in the si_intf code. It'd be great if this could be in the
> generic msghandler code, otherwise I'd just be duplicating the si_intf
> logic.
Our OPAL interface can only do one at a time ? Because our underlying FW
driver already has a queue ..
> > I'll look at doing that. If that is the case, then your NULL check
> > for current message should probably be a BUG_ON().
>
> OK, I'll update this when the msghandler bit is implemented.
>
> > Do you need to handle any BMC flags? Particularly incoming events?
>
> Not at this stage - we may in future though.
>
> Cheers,
>
>
> Jeremy
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 0/2] Add IPMI support for powernv powerpc machines
2014-11-10 5:41 ` Benjamin Herrenschmidt
@ 2014-11-10 6:01 ` Alistair Popple
2014-11-10 6:57 ` Benjamin Herrenschmidt
2014-11-10 6:41 ` Jeremy Kerr
1 sibling, 1 reply; 16+ messages in thread
From: Alistair Popple @ 2014-11-10 6:01 UTC (permalink / raw)
To: linuxppc-dev; +Cc: openipmi-developer, Jeremy Kerr, minyard
Ben,
>
> Our OPAL interface can only do one at a time ? Because our underlying FW
> driver already has a queue ..
The OPAL interface supports sending more than one message at a time using the
underlying FW queue as you suggest. However in theory the interface doesn't
make any response order guarantees, but in practice they should be ordered as
our BMC doesn't send out-of-order responses.
Regards,
Alistair
> > > I'll look at doing that. If that is the case, then your NULL check
> > > for current message should probably be a BUG_ON().
> >
> > OK, I'll update this when the msghandler bit is implemented.
> >
> > > Do you need to handle any BMC flags? Particularly incoming events?
> >
> > Not at this stage - we may in future though.
> >
> > Cheers,
> >
> >
> > Jeremy
> > _______________________________________________
> > Linuxppc-dev mailing list
> > Linuxppc-dev@lists.ozlabs.org
> > https://lists.ozlabs.org/listinfo/linuxppc-dev
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 0/2] Add IPMI support for powernv powerpc machines
2014-11-10 5:41 ` Benjamin Herrenschmidt
2014-11-10 6:01 ` Alistair Popple
@ 2014-11-10 6:41 ` Jeremy Kerr
1 sibling, 0 replies; 16+ messages in thread
From: Jeremy Kerr @ 2014-11-10 6:41 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: openipmi-developer, linuxppc-dev, minyard
Hi Ben,
> Our OPAL interface can only do one at a time ? Because our underlying
> FW driver already has a queue ..
The Linux driver needs to match responses to their requests, so the
driver needs to keep a reference to the requests that we've sent. The
current implementation is very simple: we just keep one pointer, and
require that there's only one outstanding request.
To have multiple outstanding requests, our options here are that we either:
1) duplicate the si_intf's queuing code in the powernv driver; or
2) move the queuing code from the si_intf component to the generic
IPMI msghander, and use that (so all drivers can assume a single
outstanding request)
Corey has suggested the latter, which will only require a minimal change
to the powerpv IPMI driver.
Cheers,
Jeremy
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 0/2] Add IPMI support for powernv powerpc machines
2014-11-10 6:01 ` Alistair Popple
@ 2014-11-10 6:57 ` Benjamin Herrenschmidt
0 siblings, 0 replies; 16+ messages in thread
From: Benjamin Herrenschmidt @ 2014-11-10 6:57 UTC (permalink / raw)
To: Alistair Popple; +Cc: openipmi-developer, linuxppc-dev, Jeremy Kerr, minyard
On Mon, 2014-11-10 at 17:01 +1100, Alistair Popple wrote:
> Ben,
>
> >
> > Our OPAL interface can only do one at a time ? Because our underlying FW
> > driver already has a queue ..
>
> The OPAL interface supports sending more than one message at a time using the
> underlying FW queue as you suggest. However in theory the interface doesn't
> make any response order guarantees, but in practice they should be ordered as
> our BMC doesn't send out-of-order responses.
Can't we put some ID in the response message ? OPAL messages have
room...
Cheers,
Ben.
> Regards,
>
> Alistair
>
> > > > I'll look at doing that. If that is the case, then your NULL check
> > > > for current message should probably be a BUG_ON().
> > >
> > > OK, I'll update this when the msghandler bit is implemented.
> > >
> > > > Do you need to handle any BMC flags? Particularly incoming events?
> > >
> > > Not at this stage - we may in future though.
> > >
> > > Cheers,
> > >
> > >
> > > Jeremy
> > > _______________________________________________
> > > Linuxppc-dev mailing list
> > > Linuxppc-dev@lists.ozlabs.org
> > > https://lists.ozlabs.org/listinfo/linuxppc-dev
> >
> > _______________________________________________
> > Linuxppc-dev mailing list
> > Linuxppc-dev@lists.ozlabs.org
> > https://lists.ozlabs.org/listinfo/linuxppc-dev
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 0/2] Add IPMI support for powernv powerpc machines
2014-11-10 3:26 ` Jeremy Kerr
2014-11-10 5:41 ` Benjamin Herrenschmidt
@ 2014-11-11 21:07 ` Corey Minyard
1 sibling, 0 replies; 16+ messages in thread
From: Corey Minyard @ 2014-11-11 21:07 UTC (permalink / raw)
To: Jeremy Kerr, openipmi-developer, linuxppc-dev
On 11/09/2014 09:26 PM, Jeremy Kerr wrote:
> Hi Corey,
>
> Thanks for the review.
>
>>> IPMI folks: the IPMI driver could do with a little review, as it's
>>> not a conventional BT/KCS/SMI SI, in that the low-level send/recv
>>> interface will handle the entire message at once.
>> Handling the entire message at once should be fine, as that's what
>> this driver level is designed to do for the message handler. That
>> part all looks correct. The code itself looks good, but I have a
>> couple of high-level comments.
>>
>> The driver at this level can receive more than one message to handle
>> at a time, so it needs some sort of queue. This is to allow multiple
>> users and to allow the message handler to send its own commands while
>> other commands are going on. You might argue that the queuing should
>> be done in ipmi_msghandler, and you would probably be right.
> Ah, that's what I'd been assuming was being done - I missed the
> xmit_list in the si_intf code. It'd be great if this could be in the
> generic msghandler code, otherwise I'd just be duplicating the si_intf
> logic.
>
>> I'll look at doing that. If that is the case, then your NULL check
>> for current message should probably be a BUG_ON().
> OK, I'll update this when the msghandler bit is implemented.
I've finally finished that, you can get it at:
git://git.code.sf.net/p/openipmi/linux-ipmi
using the for-next branch. This is what goes into linux-next.
>> Do you need to handle any BMC flags? Particularly incoming events?
> Not at this stage - we may in future though.
Ok. That will complicate things a bit when they are added, but not very
much.
Thanks,
-corey
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 0/2] Add IPMI support for powernv powerpc machines
2014-11-06 14:15 ` [PATCH 0/2] Add IPMI support for powernv powerpc machines Corey Minyard
2014-11-10 3:26 ` Jeremy Kerr
@ 2014-11-12 6:10 ` Michael Ellerman
2014-11-12 7:37 ` Jeremy Kerr
2014-11-12 7:41 ` [PATCH v2] drivers/char/ipmi: Add powernv IPMI driver Jeremy Kerr
1 sibling, 2 replies; 16+ messages in thread
From: Michael Ellerman @ 2014-11-12 6:10 UTC (permalink / raw)
To: minyard; +Cc: openipmi-developer, linuxppc-dev, Jeremy Kerr
On Thu, 2014-11-06 at 08:15 -0600, Corey Minyard wrote:
> On 11/05/2014 09:38 PM, Jeremy Kerr wrote:
> > Corey & Michael: if this is acceptable, it may be mergable as two
> > separate patches - one for the IPMI subsystem, one for the powernv
> > platform. However, we'd need to preserve their order: patch 2/2 depends
> > on 1/2, which provides the structure & function definitions. This'll
> > break the build if only 2/2 is in the tree, and CONFIG_IPMI_POWERNV is
> > set.
> >
> > Alternatively, they could be merged by one maintainer, pending an ack
> > from the other.
>
> I'm fine either way.
How about the third option? :)
I've put patch 1 in a topic branch:
https://git.kernel.org/cgit/linux/kernel/git/mpe/linux.git/log/?h=topic/opal-ipmi
And will merge that into my next, probably by tomorrow.
If you merge the topic branch and then apply patch 2/2, then it should all go
in without any hiccups.
cheers
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 0/2] Add IPMI support for powernv powerpc machines
2014-11-12 6:10 ` Michael Ellerman
@ 2014-11-12 7:37 ` Jeremy Kerr
2014-11-12 7:41 ` [PATCH v2] drivers/char/ipmi: Add powernv IPMI driver Jeremy Kerr
1 sibling, 0 replies; 16+ messages in thread
From: Jeremy Kerr @ 2014-11-12 7:37 UTC (permalink / raw)
To: Michael Ellerman, minyard; +Cc: openipmi-developer, linuxppc-dev
Hi Corey,
>>> Alternatively, they could be merged by one maintainer, pending an ack
>>> from the other.
>>
>> I'm fine either way.
>
> How about the third option? :)
>
> I've put patch 1 in a topic branch:
>
> https://git.kernel.org/cgit/linux/kernel/git/mpe/linux.git/log/?h=topic/opal-ipmi
>
> And will merge that into my next, probably by tomorrow.
>
> If you merge the topic branch and then apply patch 2/2, then it should all go
> in without any hiccups.
OK, and I have an updated IPMI driver patch (ie, 2/2) that will apply on
top of the new ipmi/for-next tree (best done after that merge). Patch
coming shortly...
Cheers,
Jeremy
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v2] drivers/char/ipmi: Add powernv IPMI driver
2014-11-12 6:10 ` Michael Ellerman
2014-11-12 7:37 ` Jeremy Kerr
@ 2014-11-12 7:41 ` Jeremy Kerr
2014-11-14 1:42 ` Corey Minyard
1 sibling, 1 reply; 16+ messages in thread
From: Jeremy Kerr @ 2014-11-12 7:41 UTC (permalink / raw)
To: linuxppc-dev, Corey Minyard, openipmi-developer; +Cc: Michael Ellerman
This change adds an initial IPMI driver for powerpc OPAL firmware. The
interface is exposed entirely through firmware: we have two functions to
send and receive IPMI messages, and an interrupt notification from the
firmware to signify that a message is available.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
---
v2: Update for ipmi/for-next tree, add copyright header
---
drivers/char/ipmi/Kconfig | 6
drivers/char/ipmi/Makefile | 1
drivers/char/ipmi/ipmi_powernv.c | 307 +++++++++++++++++++++++++++++++
3 files changed, 314 insertions(+)
diff --git a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig
index c1fccf4..65fb008 100644
--- a/drivers/char/ipmi/Kconfig
+++ b/drivers/char/ipmi/Kconfig
@@ -72,6 +72,12 @@ config IPMI_SSIF
have a driver that must be accessed over an I2C bus instead of a
standard interface. This module requires I2C support.
+config IPMI_POWERNV
+ depends on PPC_POWERNV
+ tristate 'POWERNV (OPAL firmware) IPMI interface'
+ help
+ Provides a driver for OPAL firmware-based IPMI interfaces.
+
config IPMI_WATCHDOG
tristate 'IPMI Watchdog Timer'
help
diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile
index 115c08d..f3ffde1 100644
--- a/drivers/char/ipmi/Makefile
+++ b/drivers/char/ipmi/Makefile
@@ -8,5 +8,6 @@ obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o
obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o
obj-$(CONFIG_IPMI_SI) += ipmi_si.o
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
diff --git a/drivers/char/ipmi/ipmi_powernv.c b/drivers/char/ipmi/ipmi_powernv.c
new file mode 100644
index 0000000..50134ec
--- /dev/null
+++ b/drivers/char/ipmi/ipmi_powernv.c
@@ -0,0 +1,307 @@
+/*
+ * 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
+
+#include <linux/ipmi_smi.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#include <asm/opal.h>
+
+
+struct ipmi_smi_powernv {
+ u64 interface_id;
+ struct ipmi_device_id ipmi_id;
+ ipmi_smi_t intf;
+ u64 event;
+ struct notifier_block event_nb;
+
+ /**
+ * We assume that there can only be one outstanding request, so
+ * keep the pending message in cur_msg. We protect this from concurrent
+ * updates through send & recv calls, (and consequently opal_msg, which
+ * is in-use when cur_msg is set) with msg_lock
+ */
+ spinlock_t msg_lock;
+ struct ipmi_smi_msg *cur_msg;
+ struct opal_ipmi_msg *opal_msg;
+};
+
+static int ipmi_powernv_start_processing(void *send_info, ipmi_smi_t intf)
+{
+ struct ipmi_smi_powernv *smi = send_info;
+ smi->intf = intf;
+ return 0;
+}
+
+static void send_error_reply(struct ipmi_smi_powernv *smi,
+ struct ipmi_smi_msg *msg, u8 completion_code)
+{
+ msg->rsp[0] = msg->data[0] | 0x4;
+ msg->rsp[1] = msg->data[1];
+ msg->rsp[2] = completion_code;
+ msg->rsp_size = 3;
+ ipmi_smi_msg_received(smi->intf, msg);
+}
+
+static void ipmi_powernv_send(void *send_info, struct ipmi_smi_msg *msg)
+{
+ struct ipmi_smi_powernv *smi = send_info;
+ struct opal_ipmi_msg *opal_msg;
+ unsigned long flags;
+ int comp, rc;
+ size_t size;
+
+ /* ensure data_len will fit in the opal_ipmi_msg buffer... */
+ if (msg->data_size > IPMI_MAX_MSG_LENGTH) {
+ comp = IPMI_REQ_LEN_EXCEEDED_ERR;
+ goto err;
+ }
+
+ /* ... and that we at least have netfn and cmd bytes */
+ if (msg->data_size < 2) {
+ comp = IPMI_REQ_LEN_INVALID_ERR;
+ goto err;
+ }
+
+ spin_lock_irqsave(&smi->msg_lock, flags);
+
+ if (smi->cur_msg) {
+ comp = IPMI_NODE_BUSY_ERR;
+ goto err_unlock;
+ }
+
+ /* format our data for the OPAL API */
+ opal_msg = smi->opal_msg;
+ opal_msg->version = OPAL_IPMI_MSG_FORMAT_VERSION_1;
+ opal_msg->netfn = msg->data[0];
+ opal_msg->cmd = msg->data[1];
+ if (msg->data_size > 2)
+ memcpy(opal_msg->data, msg->data + 2, msg->data_size - 2);
+
+ /* data_size already includes the netfn and cmd bytes */
+ size = sizeof(*opal_msg) + msg->data_size - 2;
+
+ pr_devel("%s: opal_ipmi_send(0x%llx, %p, %ld)\n", __func__,
+ smi->interface_id, opal_msg, size);
+ rc = opal_ipmi_send(smi->interface_id, opal_msg, size);
+ pr_devel("%s: -> %d\n", __func__, rc);
+
+ if (!rc) {
+ smi->cur_msg = msg;
+ spin_unlock_irqrestore(&smi->msg_lock, flags);
+ return;
+ }
+
+ comp = IPMI_ERR_UNSPECIFIED;
+err_unlock:
+ spin_unlock_irqrestore(&smi->msg_lock, flags);
+err:
+ send_error_reply(smi, msg, comp);
+}
+
+static int ipmi_powernv_recv(struct ipmi_smi_powernv *smi)
+{
+ struct opal_ipmi_msg *opal_msg;
+ struct ipmi_smi_msg *msg;
+ unsigned long flags;
+ uint64_t size;
+ int rc;
+
+ pr_devel("%s: opal_ipmi_recv(%llx, msg, sz)\n", __func__,
+ smi->interface_id);
+
+ spin_lock_irqsave(&smi->msg_lock, flags);
+
+ if (!smi->cur_msg) {
+ pr_warn("no current message?\n");
+ return 0;
+ }
+
+ msg = smi->cur_msg;
+ opal_msg = smi->opal_msg;
+
+ size = cpu_to_be64(sizeof(*opal_msg) + IPMI_MAX_MSG_LENGTH);
+
+ rc = opal_ipmi_recv(smi->interface_id,
+ opal_msg,
+ &size);
+ size = be64_to_cpu(size);
+ pr_devel("%s: -> %d (size %lld)\n", __func__,
+ rc, rc == 0 ? size : 0);
+ if (rc) {
+ spin_unlock_irqrestore(&smi->msg_lock, flags);
+ ipmi_free_smi_msg(msg);
+ return 0;
+ }
+
+ if (size < sizeof(*opal_msg)) {
+ spin_unlock_irqrestore(&smi->msg_lock, flags);
+ pr_warn("unexpected IPMI message size %lld\n", size);
+ return 0;
+ }
+
+ if (opal_msg->version != OPAL_IPMI_MSG_FORMAT_VERSION_1) {
+ spin_unlock_irqrestore(&smi->msg_lock, flags);
+ pr_warn("unexpected IPMI message format (version %d)\n",
+ opal_msg->version);
+ return 0;
+ }
+
+ msg->rsp[0] = opal_msg->netfn;
+ msg->rsp[1] = opal_msg->cmd;
+ if (size > sizeof(*opal_msg))
+ memcpy(&msg->rsp[2], opal_msg->data, size - sizeof(*opal_msg));
+ msg->rsp_size = 2 + size - sizeof(*opal_msg);
+
+ smi->cur_msg = NULL;
+ spin_unlock_irqrestore(&smi->msg_lock, flags);
+ ipmi_smi_msg_received(smi->intf, msg);
+ return 0;
+}
+
+static void ipmi_powernv_request_events(void *send_info)
+{
+}
+
+static void ipmi_powernv_set_run_to_completion(void *send_info,
+ bool run_to_completion)
+{
+}
+
+static void ipmi_powernv_poll(void *send_info)
+{
+ struct ipmi_smi_powernv *smi = send_info;
+ ipmi_powernv_recv(smi);
+}
+
+static struct ipmi_smi_handlers ipmi_powernv_smi_handlers = {
+ .owner = THIS_MODULE,
+ .start_processing = ipmi_powernv_start_processing,
+ .sender = ipmi_powernv_send,
+ .request_events = ipmi_powernv_request_events,
+ .set_run_to_completion = ipmi_powernv_set_run_to_completion,
+ .poll = ipmi_powernv_poll,
+};
+
+static int ipmi_opal_event(struct notifier_block *nb,
+ unsigned long events, void *change)
+{
+ struct ipmi_smi_powernv *smi = container_of(nb,
+ struct ipmi_smi_powernv, event_nb);
+
+ if (events & smi->event)
+ ipmi_powernv_recv(smi);
+ return 0;
+}
+
+static int ipmi_powernv_probe(struct platform_device *pdev)
+{
+ struct ipmi_smi_powernv *ipmi;
+ struct device *dev;
+ u32 prop;
+ int rc;
+
+ if (!pdev || !pdev->dev.of_node)
+ return -ENODEV;
+
+ dev = &pdev->dev;
+
+ ipmi = devm_kzalloc(dev, sizeof(*ipmi), GFP_KERNEL);
+ if (!ipmi)
+ return -ENOMEM;
+
+ spin_lock_init(&ipmi->msg_lock);
+
+ rc = of_property_read_u32(dev->of_node, "ibm,ipmi-interface-id",
+ &prop);
+ if (rc) {
+ dev_warn(dev, "No interface ID property\n");
+ goto err_free;
+ }
+ ipmi->interface_id = prop;
+
+ rc = of_property_read_u32(dev->of_node, "interrupts", &prop);
+ if (rc) {
+ dev_warn(dev, "No interrupts property\n");
+ goto err_free;
+ }
+
+ ipmi->event = 1ull << prop;
+ ipmi->event_nb.notifier_call = ipmi_opal_event;
+
+ rc = opal_notifier_register(&ipmi->event_nb);
+ if (rc) {
+ dev_warn(dev, "OPAL notifier registration failed (%d)\n", rc);
+ goto err_free;
+ }
+
+ ipmi->opal_msg = devm_kmalloc(dev,
+ sizeof(*ipmi->opal_msg) + IPMI_MAX_MSG_LENGTH,
+ GFP_KERNEL);
+ if (!ipmi->opal_msg) {
+ rc = -ENOMEM;
+ goto err_unregister;
+ }
+
+ /* todo: query actual ipmi_device_id */
+ rc = ipmi_register_smi(&ipmi_powernv_smi_handlers, ipmi,
+ &ipmi->ipmi_id, dev, 0);
+ if (rc) {
+ dev_warn(dev, "IPMI SMI registration failed (%d)\n", rc);
+ goto err_free_msg;
+ }
+
+ dev_set_drvdata(dev, ipmi);
+ return 0;
+
+err_free_msg:
+ devm_kfree(dev, ipmi->opal_msg);
+err_unregister:
+ opal_notifier_unregister(&ipmi->event_nb);
+err_free:
+ devm_kfree(dev, ipmi);
+ return rc;
+}
+
+static int ipmi_powernv_remove(struct platform_device *pdev)
+{
+ struct ipmi_smi_powernv *smi = dev_get_drvdata(&pdev->dev);
+ ipmi_unregister_smi(smi->intf);
+ opal_notifier_unregister(&smi->event_nb);
+ return 0;
+}
+
+static const struct of_device_id ipmi_powernv_match[] = {
+ { .compatible = "ibm,opal-ipmi" },
+ { },
+};
+
+
+static struct platform_driver powernv_ipmi_driver = {
+ .driver = {
+ .name = "ipmi-powernv",
+ .owner = THIS_MODULE,
+ .of_match_table = ipmi_powernv_match,
+ },
+ .probe = ipmi_powernv_probe,
+ .remove = ipmi_powernv_remove,
+};
+
+
+module_platform_driver(powernv_ipmi_driver);
+
+MODULE_DEVICE_TABLE(of, ipmi_powernv_match);
+MODULE_DESCRIPTION("powernv IPMI driver");
+MODULE_AUTHOR("Jeremy Kerr <jk@ozlabs.org>");
+MODULE_LICENSE("GPL");
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH v2] drivers/char/ipmi: Add powernv IPMI driver
2014-11-12 7:41 ` [PATCH v2] drivers/char/ipmi: Add powernv IPMI driver Jeremy Kerr
@ 2014-11-14 1:42 ` Corey Minyard
2014-11-14 2:00 ` Jeremy Kerr
2014-11-14 2:04 ` Michael Ellerman
0 siblings, 2 replies; 16+ messages in thread
From: Corey Minyard @ 2014-11-14 1:42 UTC (permalink / raw)
To: Jeremy Kerr, linuxppc-dev, openipmi-developer; +Cc: Michael Ellerman
This looks good. Can this go into the IPMI tree now, or does it need
work done in the PowerPC tree first?
Thanks,
-corey
On 11/12/2014 01:41 AM, Jeremy Kerr wrote:
> This change adds an initial IPMI driver for powerpc OPAL firmware. The
> interface is exposed entirely through firmware: we have two functions to
> send and receive IPMI messages, and an interrupt notification from the
> firmware to signify that a message is available.
>
> Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
>
> ---
> v2: Update for ipmi/for-next tree, add copyright header
>
> ---
> drivers/char/ipmi/Kconfig | 6
> drivers/char/ipmi/Makefile | 1
> drivers/char/ipmi/ipmi_powernv.c | 307 +++++++++++++++++++++++++++++++
> 3 files changed, 314 insertions(+)
>
> diff --git a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig
> index c1fccf4..65fb008 100644
> --- a/drivers/char/ipmi/Kconfig
> +++ b/drivers/char/ipmi/Kconfig
> @@ -72,6 +72,12 @@ config IPMI_SSIF
> have a driver that must be accessed over an I2C bus instead of a
> standard interface. This module requires I2C support.
>
> +config IPMI_POWERNV
> + depends on PPC_POWERNV
> + tristate 'POWERNV (OPAL firmware) IPMI interface'
> + help
> + Provides a driver for OPAL firmware-based IPMI interfaces.
> +
> config IPMI_WATCHDOG
> tristate 'IPMI Watchdog Timer'
> help
> diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile
> index 115c08d..f3ffde1 100644
> --- a/drivers/char/ipmi/Makefile
> +++ b/drivers/char/ipmi/Makefile
> @@ -8,5 +8,6 @@ obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o
> obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o
> obj-$(CONFIG_IPMI_SI) += ipmi_si.o
> 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
> diff --git a/drivers/char/ipmi/ipmi_powernv.c b/drivers/char/ipmi/ipmi_powernv.c
> new file mode 100644
> index 0000000..50134ec
> --- /dev/null
> +++ b/drivers/char/ipmi/ipmi_powernv.c
> @@ -0,0 +1,307 @@
> +/*
> + * 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
> +
> +#include <linux/ipmi_smi.h>
> +#include <linux/list.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +
> +#include <asm/opal.h>
> +
> +
> +struct ipmi_smi_powernv {
> + u64 interface_id;
> + struct ipmi_device_id ipmi_id;
> + ipmi_smi_t intf;
> + u64 event;
> + struct notifier_block event_nb;
> +
> + /**
> + * We assume that there can only be one outstanding request, so
> + * keep the pending message in cur_msg. We protect this from concurrent
> + * updates through send & recv calls, (and consequently opal_msg, which
> + * is in-use when cur_msg is set) with msg_lock
> + */
> + spinlock_t msg_lock;
> + struct ipmi_smi_msg *cur_msg;
> + struct opal_ipmi_msg *opal_msg;
> +};
> +
> +static int ipmi_powernv_start_processing(void *send_info, ipmi_smi_t intf)
> +{
> + struct ipmi_smi_powernv *smi = send_info;
> + smi->intf = intf;
> + return 0;
> +}
> +
> +static void send_error_reply(struct ipmi_smi_powernv *smi,
> + struct ipmi_smi_msg *msg, u8 completion_code)
> +{
> + msg->rsp[0] = msg->data[0] | 0x4;
> + msg->rsp[1] = msg->data[1];
> + msg->rsp[2] = completion_code;
> + msg->rsp_size = 3;
> + ipmi_smi_msg_received(smi->intf, msg);
> +}
> +
> +static void ipmi_powernv_send(void *send_info, struct ipmi_smi_msg *msg)
> +{
> + struct ipmi_smi_powernv *smi = send_info;
> + struct opal_ipmi_msg *opal_msg;
> + unsigned long flags;
> + int comp, rc;
> + size_t size;
> +
> + /* ensure data_len will fit in the opal_ipmi_msg buffer... */
> + if (msg->data_size > IPMI_MAX_MSG_LENGTH) {
> + comp = IPMI_REQ_LEN_EXCEEDED_ERR;
> + goto err;
> + }
> +
> + /* ... and that we at least have netfn and cmd bytes */
> + if (msg->data_size < 2) {
> + comp = IPMI_REQ_LEN_INVALID_ERR;
> + goto err;
> + }
> +
> + spin_lock_irqsave(&smi->msg_lock, flags);
> +
> + if (smi->cur_msg) {
> + comp = IPMI_NODE_BUSY_ERR;
> + goto err_unlock;
> + }
> +
> + /* format our data for the OPAL API */
> + opal_msg = smi->opal_msg;
> + opal_msg->version = OPAL_IPMI_MSG_FORMAT_VERSION_1;
> + opal_msg->netfn = msg->data[0];
> + opal_msg->cmd = msg->data[1];
> + if (msg->data_size > 2)
> + memcpy(opal_msg->data, msg->data + 2, msg->data_size - 2);
> +
> + /* data_size already includes the netfn and cmd bytes */
> + size = sizeof(*opal_msg) + msg->data_size - 2;
> +
> + pr_devel("%s: opal_ipmi_send(0x%llx, %p, %ld)\n", __func__,
> + smi->interface_id, opal_msg, size);
> + rc = opal_ipmi_send(smi->interface_id, opal_msg, size);
> + pr_devel("%s: -> %d\n", __func__, rc);
> +
> + if (!rc) {
> + smi->cur_msg = msg;
> + spin_unlock_irqrestore(&smi->msg_lock, flags);
> + return;
> + }
> +
> + comp = IPMI_ERR_UNSPECIFIED;
> +err_unlock:
> + spin_unlock_irqrestore(&smi->msg_lock, flags);
> +err:
> + send_error_reply(smi, msg, comp);
> +}
> +
> +static int ipmi_powernv_recv(struct ipmi_smi_powernv *smi)
> +{
> + struct opal_ipmi_msg *opal_msg;
> + struct ipmi_smi_msg *msg;
> + unsigned long flags;
> + uint64_t size;
> + int rc;
> +
> + pr_devel("%s: opal_ipmi_recv(%llx, msg, sz)\n", __func__,
> + smi->interface_id);
> +
> + spin_lock_irqsave(&smi->msg_lock, flags);
> +
> + if (!smi->cur_msg) {
> + pr_warn("no current message?\n");
> + return 0;
> + }
> +
> + msg = smi->cur_msg;
> + opal_msg = smi->opal_msg;
> +
> + size = cpu_to_be64(sizeof(*opal_msg) + IPMI_MAX_MSG_LENGTH);
> +
> + rc = opal_ipmi_recv(smi->interface_id,
> + opal_msg,
> + &size);
> + size = be64_to_cpu(size);
> + pr_devel("%s: -> %d (size %lld)\n", __func__,
> + rc, rc == 0 ? size : 0);
> + if (rc) {
> + spin_unlock_irqrestore(&smi->msg_lock, flags);
> + ipmi_free_smi_msg(msg);
> + return 0;
> + }
> +
> + if (size < sizeof(*opal_msg)) {
> + spin_unlock_irqrestore(&smi->msg_lock, flags);
> + pr_warn("unexpected IPMI message size %lld\n", size);
> + return 0;
> + }
> +
> + if (opal_msg->version != OPAL_IPMI_MSG_FORMAT_VERSION_1) {
> + spin_unlock_irqrestore(&smi->msg_lock, flags);
> + pr_warn("unexpected IPMI message format (version %d)\n",
> + opal_msg->version);
> + return 0;
> + }
> +
> + msg->rsp[0] = opal_msg->netfn;
> + msg->rsp[1] = opal_msg->cmd;
> + if (size > sizeof(*opal_msg))
> + memcpy(&msg->rsp[2], opal_msg->data, size - sizeof(*opal_msg));
> + msg->rsp_size = 2 + size - sizeof(*opal_msg);
> +
> + smi->cur_msg = NULL;
> + spin_unlock_irqrestore(&smi->msg_lock, flags);
> + ipmi_smi_msg_received(smi->intf, msg);
> + return 0;
> +}
> +
> +static void ipmi_powernv_request_events(void *send_info)
> +{
> +}
> +
> +static void ipmi_powernv_set_run_to_completion(void *send_info,
> + bool run_to_completion)
> +{
> +}
> +
> +static void ipmi_powernv_poll(void *send_info)
> +{
> + struct ipmi_smi_powernv *smi = send_info;
> + ipmi_powernv_recv(smi);
> +}
> +
> +static struct ipmi_smi_handlers ipmi_powernv_smi_handlers = {
> + .owner = THIS_MODULE,
> + .start_processing = ipmi_powernv_start_processing,
> + .sender = ipmi_powernv_send,
> + .request_events = ipmi_powernv_request_events,
> + .set_run_to_completion = ipmi_powernv_set_run_to_completion,
> + .poll = ipmi_powernv_poll,
> +};
> +
> +static int ipmi_opal_event(struct notifier_block *nb,
> + unsigned long events, void *change)
> +{
> + struct ipmi_smi_powernv *smi = container_of(nb,
> + struct ipmi_smi_powernv, event_nb);
> +
> + if (events & smi->event)
> + ipmi_powernv_recv(smi);
> + return 0;
> +}
> +
> +static int ipmi_powernv_probe(struct platform_device *pdev)
> +{
> + struct ipmi_smi_powernv *ipmi;
> + struct device *dev;
> + u32 prop;
> + int rc;
> +
> + if (!pdev || !pdev->dev.of_node)
> + return -ENODEV;
> +
> + dev = &pdev->dev;
> +
> + ipmi = devm_kzalloc(dev, sizeof(*ipmi), GFP_KERNEL);
> + if (!ipmi)
> + return -ENOMEM;
> +
> + spin_lock_init(&ipmi->msg_lock);
> +
> + rc = of_property_read_u32(dev->of_node, "ibm,ipmi-interface-id",
> + &prop);
> + if (rc) {
> + dev_warn(dev, "No interface ID property\n");
> + goto err_free;
> + }
> + ipmi->interface_id = prop;
> +
> + rc = of_property_read_u32(dev->of_node, "interrupts", &prop);
> + if (rc) {
> + dev_warn(dev, "No interrupts property\n");
> + goto err_free;
> + }
> +
> + ipmi->event = 1ull << prop;
> + ipmi->event_nb.notifier_call = ipmi_opal_event;
> +
> + rc = opal_notifier_register(&ipmi->event_nb);
> + if (rc) {
> + dev_warn(dev, "OPAL notifier registration failed (%d)\n", rc);
> + goto err_free;
> + }
> +
> + ipmi->opal_msg = devm_kmalloc(dev,
> + sizeof(*ipmi->opal_msg) + IPMI_MAX_MSG_LENGTH,
> + GFP_KERNEL);
> + if (!ipmi->opal_msg) {
> + rc = -ENOMEM;
> + goto err_unregister;
> + }
> +
> + /* todo: query actual ipmi_device_id */
> + rc = ipmi_register_smi(&ipmi_powernv_smi_handlers, ipmi,
> + &ipmi->ipmi_id, dev, 0);
> + if (rc) {
> + dev_warn(dev, "IPMI SMI registration failed (%d)\n", rc);
> + goto err_free_msg;
> + }
> +
> + dev_set_drvdata(dev, ipmi);
> + return 0;
> +
> +err_free_msg:
> + devm_kfree(dev, ipmi->opal_msg);
> +err_unregister:
> + opal_notifier_unregister(&ipmi->event_nb);
> +err_free:
> + devm_kfree(dev, ipmi);
> + return rc;
> +}
> +
> +static int ipmi_powernv_remove(struct platform_device *pdev)
> +{
> + struct ipmi_smi_powernv *smi = dev_get_drvdata(&pdev->dev);
> + ipmi_unregister_smi(smi->intf);
> + opal_notifier_unregister(&smi->event_nb);
> + return 0;
> +}
> +
> +static const struct of_device_id ipmi_powernv_match[] = {
> + { .compatible = "ibm,opal-ipmi" },
> + { },
> +};
> +
> +
> +static struct platform_driver powernv_ipmi_driver = {
> + .driver = {
> + .name = "ipmi-powernv",
> + .owner = THIS_MODULE,
> + .of_match_table = ipmi_powernv_match,
> + },
> + .probe = ipmi_powernv_probe,
> + .remove = ipmi_powernv_remove,
> +};
> +
> +
> +module_platform_driver(powernv_ipmi_driver);
> +
> +MODULE_DEVICE_TABLE(of, ipmi_powernv_match);
> +MODULE_DESCRIPTION("powernv IPMI driver");
> +MODULE_AUTHOR("Jeremy Kerr <jk@ozlabs.org>");
> +MODULE_LICENSE("GPL");
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2] drivers/char/ipmi: Add powernv IPMI driver
2014-11-14 1:42 ` Corey Minyard
@ 2014-11-14 2:00 ` Jeremy Kerr
2014-11-14 2:04 ` Michael Ellerman
1 sibling, 0 replies; 16+ messages in thread
From: Jeremy Kerr @ 2014-11-14 2:00 UTC (permalink / raw)
To: minyard, linuxppc-dev, openipmi-developer; +Cc: Michael Ellerman
Hi Corey,
> This looks good. Can this go into the IPMI tree now, or does it need
> work done in the PowerPC tree first?
The 1/2 patch is already in the powerpc tree - but to ensure that we hit
Linus' tree in the right order, Michael has suggested that you merge his
topic branch (which only has that one change):
https://git.kernel.org/cgit/linux/kernel/git/mpe/linux.git/log/?h=topic/opal-ipmi
- then apply the patch. This way, whichever tree Linus pulls first will
have the changes in the correct order.
Cheers,
Jeremy
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2] drivers/char/ipmi: Add powernv IPMI driver
2014-11-14 1:42 ` Corey Minyard
2014-11-14 2:00 ` Jeremy Kerr
@ 2014-11-14 2:04 ` Michael Ellerman
1 sibling, 0 replies; 16+ messages in thread
From: Michael Ellerman @ 2014-11-14 2:04 UTC (permalink / raw)
To: minyard; +Cc: openipmi-developer, linuxppc-dev, Jeremy Kerr
On Thu, 2014-11-13 at 19:42 -0600, Corey Minyard wrote:
> This looks good. Can this go into the IPMI tree now, or does it need
> work done in the PowerPC tree first?
You need to merge this first:
https://git.kernel.org/cgit/linux/kernel/git/mpe/linux.git/log/?h=topic/opal-ipmi
ie.
$ git fetch git://git.kernel.org/pub/scm/linux/kernel/git/mpe/linux.git topic/opal-ipmi
$ git merge FETCH_HEAD
cheers
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2014-11-14 2:04 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-11-06 3:38 [PATCH 0/2] Add IPMI support for powernv powerpc machines Jeremy Kerr
2014-11-06 3:38 ` [PATCH 1/2] powerpc/powernv: Add OPAL IPMI interface Jeremy Kerr
2014-11-06 3:38 ` [PATCH 2/2] drivers/char/ipmi: Add powernv IPMI driver Jeremy Kerr
2014-11-06 14:15 ` [PATCH 0/2] Add IPMI support for powernv powerpc machines Corey Minyard
2014-11-10 3:26 ` Jeremy Kerr
2014-11-10 5:41 ` Benjamin Herrenschmidt
2014-11-10 6:01 ` Alistair Popple
2014-11-10 6:57 ` Benjamin Herrenschmidt
2014-11-10 6:41 ` Jeremy Kerr
2014-11-11 21:07 ` Corey Minyard
2014-11-12 6:10 ` Michael Ellerman
2014-11-12 7:37 ` Jeremy Kerr
2014-11-12 7:41 ` [PATCH v2] drivers/char/ipmi: Add powernv IPMI driver Jeremy Kerr
2014-11-14 1:42 ` Corey Minyard
2014-11-14 2:00 ` Jeremy Kerr
2014-11-14 2:04 ` Michael Ellerman
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).