2 * PowerNV OPAL IPMI driver
4 * Copyright 2014 IBM Corp.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
12 #define pr_fmt(fmt) "ipmi-powernv: " fmt
14 #include <linux/ipmi_smi.h>
15 #include <linux/list.h>
16 #include <linux/module.h>
18 #include <linux/of_irq.h>
19 #include <linux/interrupt.h>
24 struct ipmi_smi_powernv
{
30 * We assume that there can only be one outstanding request, so
31 * keep the pending message in cur_msg. We protect this from concurrent
32 * updates through send & recv calls, (and consequently opal_msg, which
33 * is in-use when cur_msg is set) with msg_lock
36 struct ipmi_smi_msg
*cur_msg
;
37 struct opal_ipmi_msg
*opal_msg
;
40 static int ipmi_powernv_start_processing(void *send_info
, ipmi_smi_t intf
)
42 struct ipmi_smi_powernv
*smi
= send_info
;
48 static void send_error_reply(struct ipmi_smi_powernv
*smi
,
49 struct ipmi_smi_msg
*msg
, u8 completion_code
)
51 msg
->rsp
[0] = msg
->data
[0] | 0x4;
52 msg
->rsp
[1] = msg
->data
[1];
53 msg
->rsp
[2] = completion_code
;
55 ipmi_smi_msg_received(smi
->intf
, msg
);
58 static void ipmi_powernv_send(void *send_info
, struct ipmi_smi_msg
*msg
)
60 struct ipmi_smi_powernv
*smi
= send_info
;
61 struct opal_ipmi_msg
*opal_msg
;
66 /* ensure data_len will fit in the opal_ipmi_msg buffer... */
67 if (msg
->data_size
> IPMI_MAX_MSG_LENGTH
) {
68 comp
= IPMI_REQ_LEN_EXCEEDED_ERR
;
72 /* ... and that we at least have netfn and cmd bytes */
73 if (msg
->data_size
< 2) {
74 comp
= IPMI_REQ_LEN_INVALID_ERR
;
78 spin_lock_irqsave(&smi
->msg_lock
, flags
);
81 comp
= IPMI_NODE_BUSY_ERR
;
85 /* format our data for the OPAL API */
86 opal_msg
= smi
->opal_msg
;
87 opal_msg
->version
= OPAL_IPMI_MSG_FORMAT_VERSION_1
;
88 opal_msg
->netfn
= msg
->data
[0];
89 opal_msg
->cmd
= msg
->data
[1];
90 if (msg
->data_size
> 2)
91 memcpy(opal_msg
->data
, msg
->data
+ 2, msg
->data_size
- 2);
93 /* data_size already includes the netfn and cmd bytes */
94 size
= sizeof(*opal_msg
) + msg
->data_size
- 2;
96 pr_devel("%s: opal_ipmi_send(0x%llx, %p, %ld)\n", __func__
,
97 smi
->interface_id
, opal_msg
, size
);
98 rc
= opal_ipmi_send(smi
->interface_id
, opal_msg
, size
);
99 pr_devel("%s: -> %d\n", __func__
, rc
);
103 spin_unlock_irqrestore(&smi
->msg_lock
, flags
);
107 comp
= IPMI_ERR_UNSPECIFIED
;
109 spin_unlock_irqrestore(&smi
->msg_lock
, flags
);
111 send_error_reply(smi
, msg
, comp
);
114 static int ipmi_powernv_recv(struct ipmi_smi_powernv
*smi
)
116 struct opal_ipmi_msg
*opal_msg
;
117 struct ipmi_smi_msg
*msg
;
122 pr_devel("%s: opal_ipmi_recv(%llx, msg, sz)\n", __func__
,
125 spin_lock_irqsave(&smi
->msg_lock
, flags
);
128 spin_unlock_irqrestore(&smi
->msg_lock
, flags
);
129 pr_warn("no current message?\n");
134 opal_msg
= smi
->opal_msg
;
136 size
= cpu_to_be64(sizeof(*opal_msg
) + IPMI_MAX_MSG_LENGTH
);
138 rc
= opal_ipmi_recv(smi
->interface_id
,
141 size
= be64_to_cpu(size
);
142 pr_devel("%s: -> %d (size %lld)\n", __func__
,
143 rc
, rc
== 0 ? size
: 0);
145 /* If came via the poll, and response was not yet ready */
146 if (rc
== OPAL_EMPTY
) {
147 spin_unlock_irqrestore(&smi
->msg_lock
, flags
);
152 spin_unlock_irqrestore(&smi
->msg_lock
, flags
);
153 send_error_reply(smi
, msg
, IPMI_ERR_UNSPECIFIED
);
157 if (size
< sizeof(*opal_msg
)) {
158 spin_unlock_irqrestore(&smi
->msg_lock
, flags
);
159 pr_warn("unexpected IPMI message size %lld\n", size
);
163 if (opal_msg
->version
!= OPAL_IPMI_MSG_FORMAT_VERSION_1
) {
164 spin_unlock_irqrestore(&smi
->msg_lock
, flags
);
165 pr_warn("unexpected IPMI message format (version %d)\n",
170 msg
->rsp
[0] = opal_msg
->netfn
;
171 msg
->rsp
[1] = opal_msg
->cmd
;
172 if (size
> sizeof(*opal_msg
))
173 memcpy(&msg
->rsp
[2], opal_msg
->data
, size
- sizeof(*opal_msg
));
174 msg
->rsp_size
= 2 + size
- sizeof(*opal_msg
);
177 spin_unlock_irqrestore(&smi
->msg_lock
, flags
);
178 ipmi_smi_msg_received(smi
->intf
, msg
);
182 static void ipmi_powernv_request_events(void *send_info
)
186 static void ipmi_powernv_set_run_to_completion(void *send_info
,
187 bool run_to_completion
)
191 static void ipmi_powernv_poll(void *send_info
)
193 struct ipmi_smi_powernv
*smi
= send_info
;
195 ipmi_powernv_recv(smi
);
198 static const struct ipmi_smi_handlers ipmi_powernv_smi_handlers
= {
199 .owner
= THIS_MODULE
,
200 .start_processing
= ipmi_powernv_start_processing
,
201 .sender
= ipmi_powernv_send
,
202 .request_events
= ipmi_powernv_request_events
,
203 .set_run_to_completion
= ipmi_powernv_set_run_to_completion
,
204 .poll
= ipmi_powernv_poll
,
207 static irqreturn_t
ipmi_opal_event(int irq
, void *data
)
209 struct ipmi_smi_powernv
*smi
= data
;
211 ipmi_powernv_recv(smi
);
215 static int ipmi_powernv_probe(struct platform_device
*pdev
)
217 struct ipmi_smi_powernv
*ipmi
;
222 if (!pdev
|| !pdev
->dev
.of_node
)
227 ipmi
= devm_kzalloc(dev
, sizeof(*ipmi
), GFP_KERNEL
);
231 spin_lock_init(&ipmi
->msg_lock
);
233 rc
= of_property_read_u32(dev
->of_node
, "ibm,ipmi-interface-id",
236 dev_warn(dev
, "No interface ID property\n");
239 ipmi
->interface_id
= prop
;
241 rc
= of_property_read_u32(dev
->of_node
, "interrupts", &prop
);
243 dev_warn(dev
, "No interrupts property\n");
247 ipmi
->irq
= irq_of_parse_and_map(dev
->of_node
, 0);
249 dev_info(dev
, "Unable to map irq from device tree\n");
250 ipmi
->irq
= opal_event_request(prop
);
253 rc
= request_irq(ipmi
->irq
, ipmi_opal_event
, IRQ_TYPE_LEVEL_HIGH
,
256 dev_warn(dev
, "Unable to request irq\n");
260 ipmi
->opal_msg
= devm_kmalloc(dev
,
261 sizeof(*ipmi
->opal_msg
) + IPMI_MAX_MSG_LENGTH
,
263 if (!ipmi
->opal_msg
) {
268 rc
= ipmi_register_smi(&ipmi_powernv_smi_handlers
, ipmi
, dev
, 0);
270 dev_warn(dev
, "IPMI SMI registration failed (%d)\n", rc
);
274 dev_set_drvdata(dev
, ipmi
);
278 devm_kfree(dev
, ipmi
->opal_msg
);
280 free_irq(ipmi
->irq
, ipmi
);
282 irq_dispose_mapping(ipmi
->irq
);
284 devm_kfree(dev
, ipmi
);
288 static int ipmi_powernv_remove(struct platform_device
*pdev
)
290 struct ipmi_smi_powernv
*smi
= dev_get_drvdata(&pdev
->dev
);
292 ipmi_unregister_smi(smi
->intf
);
293 free_irq(smi
->irq
, smi
);
294 irq_dispose_mapping(smi
->irq
);
299 static const struct of_device_id ipmi_powernv_match
[] = {
300 { .compatible
= "ibm,opal-ipmi" },
305 static struct platform_driver powernv_ipmi_driver
= {
307 .name
= "ipmi-powernv",
308 .of_match_table
= ipmi_powernv_match
,
310 .probe
= ipmi_powernv_probe
,
311 .remove
= ipmi_powernv_remove
,
315 module_platform_driver(powernv_ipmi_driver
);
317 MODULE_DEVICE_TABLE(of
, ipmi_powernv_match
);
318 MODULE_DESCRIPTION("powernv IPMI driver");
319 MODULE_AUTHOR("Jeremy Kerr <jk@ozlabs.org>");
320 MODULE_LICENSE("GPL");