From patchwork Thu May 25 07:05:51 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeremy Kerr X-Patchwork-Id: 766856 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3wYL133wRpz9s9Y for ; Thu, 25 May 2017 17:07:03 +1000 (AEST) Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 3wYL132vmrzDqgh for ; Thu, 25 May 2017 17:07:03 +1000 (AEST) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Received: from ozlabs.org (ozlabs.org [IPv6:2401:3900:2:1::2]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 3wYL0d35sfzDqhH for ; Thu, 25 May 2017 17:06:41 +1000 (AEST) Received: by ozlabs.org (Postfix, from userid 1023) id 3wYL0d1ld8z9s3T; Thu, 25 May 2017 17:06:41 +1000 (AEST) From: Jeremy Kerr To: skiboot@lists.ozlabs.org Date: Thu, 25 May 2017 17:05:51 +1000 Message-Id: <1495695955-30718-9-git-send-email-jk@ozlabs.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1495695955-30718-1-git-send-email-jk@ozlabs.org> References: <1495695955-30718-1-git-send-email-jk@ozlabs.org> Subject: [Skiboot] [PATCH RFC 08/12] opal-prd: Add support for variable-sized messages X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Dan Crowell MIME-Version: 1.0 Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" With the introductuion of the opaque firmware channel, we want to support variable-sized messages. Rather than expecting to read an entire 'struct opal_prd_msg' in one read() call, we can split this over mutiple reads, potentially expanding our message buffer. Signed-off-by: Jeremy Kerr --- external/opal-prd/opal-prd.c | 67 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 12 deletions(-) diff --git a/external/opal-prd/opal-prd.c b/external/opal-prd/opal-prd.c index c7cdc61..ebd6c0f 100644 --- a/external/opal-prd/opal-prd.c +++ b/external/opal-prd/opal-prd.c @@ -80,6 +80,8 @@ struct opal_prd_ctx { char *hbrt_file_name; bool use_syslog; bool expert_mode; + struct opal_prd_msg *msg; + size_t msg_alloc_len; void (*vlog)(int, const char *, va_list); }; @@ -1225,41 +1227,76 @@ static int handle_msg_occ_reset(struct opal_prd_ctx *ctx, static int handle_prd_msg(struct opal_prd_ctx *ctx) { - struct opal_prd_msg msg; + struct opal_prd_msg *msg; int size; int rc; - rc = read(ctx->fd, &msg, sizeof(msg)); + msg = ctx->msg; + + rc = read(ctx->fd, msg, ctx->msg_alloc_len); if (rc < 0 && errno == EAGAIN) return -1; - if (rc != sizeof(msg)) { - pr_log(LOG_WARNING, "FW: Error reading events from OPAL: %m"); + /* we need at least enough for the message header... */ + if (rc < 0) { + pr_log(LOG_WARNING, "FW: error reading from firmware: %m"); + return -1; + } + + if (rc < sizeof(msg->hdr)) { + pr_log(LOG_WARNING, "FW: short message read from firmware"); return -1; } - size = htobe16(msg.hdr.size); - if (size < sizeof(msg)) { + /* ... and for the reported message size to be sane */ + size = htobe16(msg->hdr.size); + if (size < sizeof(msg->hdr)) { pr_log(LOG_ERR, "FW: Mismatched message size " "between opal-prd and firmware " "(%d from FW, %zd expected)", - size, sizeof(msg)); + size, sizeof(msg->hdr)); return -1; } - switch (msg.hdr.type) { + /* expand our message buffer if necessary... */ + if (size > ctx->msg_alloc_len) { + ctx->msg = msg = realloc(ctx->msg, size); + ctx->msg_alloc_len = size; + } + + /* ... and complete the read */ + if (size > rc) { + size_t pos; + + for (pos = rc; pos < size;) { + rc = read(ctx->fd, msg + pos, size - pos); + + if (rc < 0 && errno == EAGAIN) + continue; + + if (rc <= 0) { + pr_log(LOG_WARNING, + "FW: error reading from firmware: %m"); + return -1; + } + + pos += rc; + } + } + + switch (msg->hdr.type) { case OPAL_PRD_MSG_TYPE_ATTN: - rc = handle_msg_attn(ctx, &msg); + rc = handle_msg_attn(ctx, msg); break; case OPAL_PRD_MSG_TYPE_OCC_RESET: - rc = handle_msg_occ_reset(ctx, &msg); + rc = handle_msg_occ_reset(ctx, msg); break; case OPAL_PRD_MSG_TYPE_OCC_ERROR: - rc = handle_msg_occ_error(ctx, &msg); + rc = handle_msg_occ_error(ctx, msg); break; default: pr_log(LOG_WARNING, "Invalid incoming message type 0x%x", - msg.hdr.type); + msg->hdr.type); return -1; } @@ -1621,6 +1658,10 @@ static int run_prd_daemon(struct opal_prd_ctx *ctx) ctx->fd = -1; ctx->socket = -1; + /* set up our message buffer */ + ctx->msg_alloc_len = sizeof(*ctx->msg); + ctx->msg = malloc(ctx->msg_alloc_len); + i2c_init(); #ifdef DEBUG_I2C @@ -1708,6 +1749,8 @@ out_close: close(ctx->fd); if (ctx->socket != -1) close(ctx->socket); + if (ctx->msg) + free(ctx->msg); return rc; }