* [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 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 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 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 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 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).