1 // SPDX-License-Identifier: GPL-2.0+
3 * PowerNV OPAL IPMI driver
5 * Copyright 2014 IBM Corp.
8 #define pr_fmt(fmt) "ipmi-powernv: " fmt
10 #include <linux/ipmi_smi.h>
11 #include <linux/list.h>
12 #include <linux/module.h>
14 #include <linux/of_irq.h>
15 #include <linux/interrupt.h>
20 struct ipmi_smi_powernv
{
22 struct ipmi_smi
*intf
;
26 * We assume that there can only be one outstanding request, so
27 * keep the pending message in cur_msg. We protect this from concurrent
28 * updates through send & recv calls, (and consequently opal_msg, which
29 * is in-use when cur_msg is set) with msg_lock
32 struct ipmi_smi_msg
*cur_msg
;
33 struct opal_ipmi_msg
*opal_msg
;
36 static int ipmi_powernv_start_processing(void *send_info
, struct ipmi_smi
*intf
)
38 struct ipmi_smi_powernv
*smi
= send_info
;
44 static void send_error_reply(struct ipmi_smi_powernv
*smi
,
45 struct ipmi_smi_msg
*msg
, u8 completion_code
)
47 msg
->rsp
[0] = msg
->data
[0] | 0x4;
48 msg
->rsp
[1] = msg
->data
[1];
49 msg
->rsp
[2] = completion_code
;
51 ipmi_smi_msg_received(smi
->intf
, msg
);
54 static void ipmi_powernv_send(void *send_info
, struct ipmi_smi_msg
*msg
)
56 struct ipmi_smi_powernv
*smi
= send_info
;
57 struct opal_ipmi_msg
*opal_msg
;
62 /* ensure data_len will fit in the opal_ipmi_msg buffer... */
63 if (msg
->data_size
> IPMI_MAX_MSG_LENGTH
) {
64 comp
= IPMI_REQ_LEN_EXCEEDED_ERR
;
68 /* ... and that we at least have netfn and cmd bytes */
69 if (msg
->data_size
< 2) {
70 comp
= IPMI_REQ_LEN_INVALID_ERR
;
74 spin_lock_irqsave(&smi
->msg_lock
, flags
);
77 comp
= IPMI_NODE_BUSY_ERR
;
81 /* format our data for the OPAL API */
82 opal_msg
= smi
->opal_msg
;
83 opal_msg
->version
= OPAL_IPMI_MSG_FORMAT_VERSION_1
;
84 opal_msg
->netfn
= msg
->data
[0];
85 opal_msg
->cmd
= msg
->data
[1];
86 if (msg
->data_size
> 2)
87 memcpy(opal_msg
->data
, msg
->data
+ 2, msg
->data_size
- 2);
89 /* data_size already includes the netfn and cmd bytes */
90 size
= sizeof(*opal_msg
) + msg
->data_size
- 2;
92 pr_devel("%s: opal_ipmi_send(0x%llx, %p, %ld)\n", __func__
,
93 smi
->interface_id
, opal_msg
, size
);
94 rc
= opal_ipmi_send(smi
->interface_id
, opal_msg
, size
);
95 pr_devel("%s: -> %d\n", __func__
, rc
);
99 spin_unlock_irqrestore(&smi
->msg_lock
, flags
);
103 comp
= IPMI_ERR_UNSPECIFIED
;
105 spin_unlock_irqrestore(&smi
->msg_lock
, flags
);
107 send_error_reply(smi
, msg
, comp
);
110 static int ipmi_powernv_recv(struct ipmi_smi_powernv
*smi
)
112 struct opal_ipmi_msg
*opal_msg
;
113 struct ipmi_smi_msg
*msg
;
118 pr_devel("%s: opal_ipmi_recv(%llx, msg, sz)\n", __func__
,
121 spin_lock_irqsave(&smi
->msg_lock
, flags
);
124 spin_unlock_irqrestore(&smi
->msg_lock
, flags
);
125 pr_warn("no current message?\n");
130 opal_msg
= smi
->opal_msg
;
132 size
= cpu_to_be64(sizeof(*opal_msg
) + IPMI_MAX_MSG_LENGTH
);
134 rc
= opal_ipmi_recv(smi
->interface_id
,
137 size
= be64_to_cpu(size
);
138 pr_devel("%s: -> %d (size %lld)\n", __func__
,
139 rc
, rc
== 0 ? size
: 0);
141 /* If came via the poll, and response was not yet ready */
142 if (rc
== OPAL_EMPTY
) {
143 spin_unlock_irqrestore(&smi
->msg_lock
, flags
);
148 spin_unlock_irqrestore(&smi
->msg_lock
, flags
);
149 send_error_reply(smi
, msg
, IPMI_ERR_UNSPECIFIED
);
153 if (size
< sizeof(*opal_msg
)) {
154 spin_unlock_irqrestore(&smi
->msg_lock
, flags
);
155 pr_warn("unexpected IPMI message size %lld\n", size
);
159 if (opal_msg
->version
!= OPAL_IPMI_MSG_FORMAT_VERSION_1
) {
160 spin_unlock_irqrestore(&smi
->msg_lock
, flags
);
161 pr_warn("unexpected IPMI message format (version %d)\n",
166 msg
->rsp
[0] = opal_msg
->netfn
;
167 msg
->rsp
[1] = opal_msg
->cmd
;
168 if (size
> sizeof(*opal_msg
))
169 memcpy(&msg
->rsp
[2], opal_msg
->data
, size
- sizeof(*opal_msg
));
170 msg
->rsp_size
= 2 + size
- sizeof(*opal_msg
);
173 spin_unlock_irqrestore(&smi
->msg_lock
, flags
);
174 ipmi_smi_msg_received(smi
->intf
, msg
);
178 static void ipmi_powernv_request_events(void *send_info
)
182 static void ipmi_powernv_set_run_to_completion(void *send_info
,
183 bool run_to_completion
)
187 static void ipmi_powernv_poll(void *send_info
)
189 struct ipmi_smi_powernv
*smi
= send_info
;
191 ipmi_powernv_recv(smi
);
194 static const struct ipmi_smi_handlers ipmi_powernv_smi_handlers
= {
195 .owner
= THIS_MODULE
,
196 .start_processing
= ipmi_powernv_start_processing
,
197 .sender
= ipmi_powernv_send
,
198 .request_events
= ipmi_powernv_request_events
,
199 .set_run_to_completion
= ipmi_powernv_set_run_to_completion
,
200 .poll
= ipmi_powernv_poll
,
203 static irqreturn_t
ipmi_opal_event(int irq
, void *data
)
205 struct ipmi_smi_powernv
*smi
= data
;
207 ipmi_powernv_recv(smi
);
211 static int ipmi_powernv_probe(struct platform_device
*pdev
)
213 struct ipmi_smi_powernv
*ipmi
;
218 if (!pdev
|| !pdev
->dev
.of_node
)
223 ipmi
= devm_kzalloc(dev
, sizeof(*ipmi
), GFP_KERNEL
);
227 spin_lock_init(&ipmi
->msg_lock
);
229 rc
= of_property_read_u32(dev
->of_node
, "ibm,ipmi-interface-id",
232 dev_warn(dev
, "No interface ID property\n");
235 ipmi
->interface_id
= prop
;
237 rc
= of_property_read_u32(dev
->of_node
, "interrupts", &prop
);
239 dev_warn(dev
, "No interrupts property\n");
243 ipmi
->irq
= irq_of_parse_and_map(dev
->of_node
, 0);
245 dev_info(dev
, "Unable to map irq from device tree\n");
246 ipmi
->irq
= opal_event_request(prop
);
249 rc
= request_irq(ipmi
->irq
, ipmi_opal_event
, IRQ_TYPE_LEVEL_HIGH
,
252 dev_warn(dev
, "Unable to request irq\n");
256 ipmi
->opal_msg
= devm_kmalloc(dev
,
257 sizeof(*ipmi
->opal_msg
) + IPMI_MAX_MSG_LENGTH
,
259 if (!ipmi
->opal_msg
) {
264 rc
= ipmi_register_smi(&ipmi_powernv_smi_handlers
, ipmi
, dev
, 0);
266 dev_warn(dev
, "IPMI SMI registration failed (%d)\n", rc
);
270 dev_set_drvdata(dev
, ipmi
);
274 devm_kfree(dev
, ipmi
->opal_msg
);
276 free_irq(ipmi
->irq
, ipmi
);
278 irq_dispose_mapping(ipmi
->irq
);
280 devm_kfree(dev
, ipmi
);
284 static int ipmi_powernv_remove(struct platform_device
*pdev
)
286 struct ipmi_smi_powernv
*smi
= dev_get_drvdata(&pdev
->dev
);
288 ipmi_unregister_smi(smi
->intf
);
289 free_irq(smi
->irq
, smi
);
290 irq_dispose_mapping(smi
->irq
);
295 static const struct of_device_id ipmi_powernv_match
[] = {
296 { .compatible
= "ibm,opal-ipmi" },
301 static struct platform_driver powernv_ipmi_driver
= {
303 .name
= "ipmi-powernv",
304 .of_match_table
= ipmi_powernv_match
,
306 .probe
= ipmi_powernv_probe
,
307 .remove
= ipmi_powernv_remove
,
311 module_platform_driver(powernv_ipmi_driver
);
313 MODULE_DEVICE_TABLE(of
, ipmi_powernv_match
);
314 MODULE_DESCRIPTION("powernv IPMI driver");
315 MODULE_AUTHOR("Jeremy Kerr <jk@ozlabs.org>");
316 MODULE_LICENSE("GPL");