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) { spin_unlock_irqrestore(&smi->msg_lock, flags); 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 deliver_recv_msg(struct smi_info *smi_info, struct ipmi_smi_msg *msg) { /* Deliver the message to the upper layer. */ if (smi_info->intf) ipmi_smi_msg_received(smi_info->intf, msg); else ipmi_free_smi_msg(msg); }
/* * Allocate a message. If unable to allocate, start the interrupt * disable process and return NULL. If able to allocate but * interrupts are disabled, free the message and return NULL after * starting the interrupt enable process. */ static struct ipmi_smi_msg *alloc_msg_handle_irq(struct smi_info *smi_info) { struct ipmi_smi_msg *msg; msg = ipmi_alloc_smi_msg(); if (!msg) { if (!disable_si_irq(smi_info)) smi_info->si_state = SI_NORMAL; } else if (enable_si_irq(smi_info)) { ipmi_free_smi_msg(msg); msg = NULL; } return msg; }