From patchwork Tue Sep 13 10:26:53 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christophe Lombard X-Patchwork-Id: 1677220 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org (client-ip=2404:9400:2:0:216:3eff:fee1:b9f1; helo=lists.ozlabs.org; envelope-from=skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=da+SCGmf; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2404:9400:2:0:216:3eff:fee1:b9f1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4MRfmz30tmz1ynm for ; Tue, 13 Sep 2022 20:28:03 +1000 (AEST) Received: from boromir.ozlabs.org (localhost [IPv6:::1]) by lists.ozlabs.org (Postfix) with ESMTP id 4MRfmz2846z308w for ; Tue, 13 Sep 2022 20:28:03 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=da+SCGmf; dkim-atps=neutral X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=linux.vnet.ibm.com (client-ip=148.163.158.5; helo=mx0b-001b2d01.pphosted.com; envelope-from=clombard@linux.vnet.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=da+SCGmf; dkim-atps=neutral Received: from mx0b-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4MRfm432rqz308b for ; Tue, 13 Sep 2022 20:27:16 +1000 (AEST) Received: from pps.filterd (m0098421.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.17.1.5/8.17.1.5) with ESMTP id 28D9jBpq002956 for ; Tue, 13 Sep 2022 10:27:14 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=pp1; bh=eKf7SoDCFuETtzZwKdNI3uglO7jfYtG4WWCbrnU7MXw=; b=da+SCGmfwab0T4t/hUByIKc3BV7gPW1u+d2S0R76cGHFpvyEQtgnnJBvZJ91BT9o8xNz bReKn4HWcMZ1cfSmL6tD8cvjH4HoLe3hpy0m/JMcFqd9MR5tRV4BiVvhgk4FFuyPbSgX KqZ3p8xM1UJfdIWUzxIbK+aBEqDjxxFsj2oI7lVTCjcocJ8CT+Kwhj/rEopqET15IX5b I7I/KWRrwBicnAdlVFKsLQtTzqaRCrXLb6viyvRev3DPpFZDvwtqJfvQZpHztDKpw7D5 15QkAavoUazX3SHlUqUeLMpsY8Qpa/mG1bqDTe7KBPi1SPuHx7VGG1H8t+AYoQgTN7/i XA== Received: from ppma06ams.nl.ibm.com (66.31.33a9.ip4.static.sl-reverse.com [169.51.49.102]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3jjmjay1cy-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 13 Sep 2022 10:27:13 +0000 Received: from pps.filterd (ppma06ams.nl.ibm.com [127.0.0.1]) by ppma06ams.nl.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 28DAKrBe006140 for ; Tue, 13 Sep 2022 10:27:11 GMT Received: from b06cxnps4074.portsmouth.uk.ibm.com (d06relay11.portsmouth.uk.ibm.com [9.149.109.196]) by ppma06ams.nl.ibm.com with ESMTP id 3jghujbnpu-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 13 Sep 2022 10:27:10 +0000 Received: from d06av23.portsmouth.uk.ibm.com (d06av23.portsmouth.uk.ibm.com [9.149.105.59]) by b06cxnps4074.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 28DAR8IH11076070 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Tue, 13 Sep 2022 10:27:08 GMT Received: from d06av23.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 8B7DDA404D for ; Tue, 13 Sep 2022 10:27:08 +0000 (GMT) Received: from d06av23.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 611B6A4040 for ; Tue, 13 Sep 2022 10:27:08 +0000 (GMT) Received: from li-ac0ca24c-3330-11b2-a85c-93224c50ad7a.ibm.com.com (unknown [9.171.35.136]) by d06av23.portsmouth.uk.ibm.com (Postfix) with ESMTP for ; Tue, 13 Sep 2022 10:27:08 +0000 (GMT) From: Christophe Lombard To: skiboot@lists.ozlabs.org Date: Tue, 13 Sep 2022 12:26:53 +0200 Message-Id: <20220913102705.65506-10-clombard@linux.vnet.ibm.com> X-Mailer: git-send-email 2.37.3 In-Reply-To: <20220913102705.65506-1-clombard@linux.vnet.ibm.com> References: <20220913102705.65506-1-clombard@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: IjlS-A2ZdXUpuKJdxkWWfAOHFVNgkmRM X-Proofpoint-ORIG-GUID: IjlS-A2ZdXUpuKJdxkWWfAOHFVNgkmRM X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.895,Hydra:6.0.528,FMLib:17.11.122.1 definitions=2022-09-13_03,2022-09-13_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 impostorscore=0 malwarescore=0 adultscore=0 mlxlogscore=999 lowpriorityscore=0 bulkscore=0 priorityscore=1501 clxscore=1015 mlxscore=0 phishscore=0 suspectscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2207270000 definitions=main-2209130045 Subject: [Skiboot] [PATCH V6 09/21] core/pldm: Implement PLDM requester X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" Implement a way for sending PLDM requests for specific PLDM commands. Send a PLDM request message. Wait for corresponding response message, which once received, is returned to the caller. If there's data available, return success only if data is a PLDM response message that matches instance, pldm_type and command code. Signed-off-by: Christophe Lombard Reviewed-by: Abhishek Singh Tomar --- core/pldm/Makefile.inc | 2 +- core/pldm/pldm-mctp.c | 9 +- core/pldm/pldm-requester.c | 331 +++++++++++++++++++++++++++++++++++++ core/pldm/pldm.h | 9 + 4 files changed, 349 insertions(+), 2 deletions(-) create mode 100644 core/pldm/pldm-requester.c diff --git a/core/pldm/Makefile.inc b/core/pldm/Makefile.inc index dbca102a..a9b3b7e6 100644 --- a/core/pldm/Makefile.inc +++ b/core/pldm/Makefile.inc @@ -7,7 +7,7 @@ SUBDIRS += $(PLDM_DIR) CPPFLAGS += -I$(SRC)/pldm/libpldm/ CPPFLAGS += -I$(SRC)/pldm/ibm/libpldm/ -PLDM_OBJS = pldm-mctp.o pldm-responder.o +PLDM_OBJS = pldm-mctp.o pldm-responder.o pldm-requester.o PLDM = $(PLDM_DIR)/built-in.a $(PLDM): $(PLDM_OBJS:%=$(PLDM_DIR)/%) diff --git a/core/pldm/pldm-mctp.c b/core/pldm/pldm-mctp.c index 51dbad0a..c7d7bb3b 100644 --- a/core/pldm/pldm-mctp.c +++ b/core/pldm/pldm-mctp.c @@ -76,6 +76,8 @@ static int handle_message_rx(uint8_t eid, const uint8_t *buf, int len) } switch (rx.hdrinf.msg_type) { + case PLDM_RESPONSE: + return pldm_requester_handle_response(&rx); case PLDM_REQUEST: return pldm_responder_handle_request(&rx); break; @@ -120,8 +122,13 @@ int pldm_mctp_init(uint8_t mode) /* Register mandatory commands we'll respond to */ rc = pldm_responder_init(); - if (rc) + if (rc) { prlog(PR_ERR, "Failed to register mandatory commands\n"); + goto out; + } + + /* Requester implementation */ + pldm_requester_init(); out: prlog(PR_NOTICE, "%s - done, rc: %d\n", __func__, rc); diff --git a/core/pldm/pldm-requester.c b/core/pldm/pldm-requester.c new file mode 100644 index 00000000..412d495a --- /dev/null +++ b/core/pldm/pldm-requester.c @@ -0,0 +1,331 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +// Copyright 2022 IBM Corp. + +#define pr_fmt(fmt) "PLDM: " fmt + +#include +#include +#include +#include +#include +#include +#include "pldm.h" + +struct pldm_request { + struct list_node link; + + /* originating request params */ + int dest; + int instance; + int cmd_code; + int type; + + /* messages requested */ + void *request_msg; + int request_len; + + /* timeout handling */ + struct timer timeout; + uint64_t timeout_ms; + uint64_t start_time; + + /* completion callback */ + void (*complete)(struct pldm_rx_data *rx, void *data); + void *complete_data; +}; + +struct pldm_response { + void **response_msg; + size_t *response_len; + bool done; + int rc; +}; + +/* pldm requests queue */ +static LIST_HEAD(list_pldm_requests); +struct lock list_lock; +struct timer requests_timer; + +static struct pldm_request *active_request; + +static bool matches_request(const struct pldm_rx_data *rx, + const struct pldm_request *req) +{ + if (req->instance != rx->hdrinf.instance) + return false; + if (req->type != rx->hdrinf.pldm_type) + return false; + if (req->cmd_code != rx->hdrinf.command) + return false; + + return true; +} + +static void send_and_wait_complete(struct pldm_rx_data *rx, void *data) +{ + struct pldm_response *resp = (struct pldm_response *)data; + int len; + + if (rx != NULL) { + len = rx->msg_len; + *resp->response_len = len; + *resp->response_msg = zalloc(len); + memcpy(*resp->response_msg, rx->msg, len); + + resp->rc = OPAL_SUCCESS; + } else { + *resp->response_len = 0; + *resp->response_msg = NULL; + resp->rc = OPAL_TIMEOUT; + } + + resp->done = true; +} + +static void handle_response(struct pldm_rx_data *rx) +{ + uint64_t now; + + if (active_request == NULL) { + prlog(PR_ERR, "%s: No active request\n", __func__); + return; + } + + /* unactivate the timer */ + if (rx != NULL) + cancel_timer(&active_request->timeout); + + if (active_request->complete) + active_request->complete(rx, active_request->complete_data); + + now = mftb(); + prlog(PR_TRACE, "%s: Finished after %ldms, t:%d c:%d i:%d \n", + __func__, + tb_to_msecs(now - active_request->start_time), + active_request->type, + active_request->cmd_code, + active_request->instance); + + free(active_request->request_msg); + free(active_request); + active_request = NULL; +} + +/* + * Timeout :( + */ +static void expiry(struct timer *t __unused, void *data, uint64_t now __unused) +{ + struct pldm_request *req = (struct pldm_request *)data; + + if (active_request == NULL) { + prlog(PR_ERR, "request timedout! (active request NULL)\n"); + return; + } + + prlog(PR_ERR, "request timedout! (active request: t:%d c:%d i:%d)\n", + active_request->type, + active_request->cmd_code, + active_request->instance); + + prlog(PR_TRACE, "%s: Original request t:%d c:%d i:%d -----\n", + __func__, req->type, req->cmd_code, req->instance); + + /* no data received. Finish the procedure */ + handle_response(NULL); +} + +/* + * Handle PLDM message received from the PLDM terminus over MCTP + */ +int pldm_requester_handle_response(struct pldm_rx_data *rx) +{ + /* check the message received */ + if (active_request == NULL) { + prlog(PR_ERR, "%s: No active request. " + "Response received t:%d c:%d i:%d\n", + __func__, + rx->hdrinf.pldm_type, + rx->hdrinf.command, + rx->hdrinf.instance); + return OPAL_WRONG_STATE; + } + + if (!matches_request(rx, active_request)) { + prlog(PR_ERR, "%s: Unexpected response! t:%d c:%d i:%d want %d,%d,%d\n", + __func__, + rx->hdrinf.pldm_type, + rx->hdrinf.command, + rx->hdrinf.instance, + active_request->type, + active_request->cmd_code, + active_request->instance + ); + return OPAL_WRONG_STATE; + } + + /* The expected message seems correct */ + handle_response(rx); + + return OPAL_SUCCESS; +} + +/* + * Send the PLDM request + */ +static void requests_poller(struct timer *t __unused, + void *data __unused, + uint64_t now __unused) +{ + int rc = OPAL_SUCCESS; + + lock(&list_lock); + + /* no new request to handle */ + if (list_empty(&list_pldm_requests)) + goto out; + + /* wait for the end of the processing of the current request */ + if (active_request) + goto out; + + /* remove the first entry in a list */ + active_request = list_pop(&list_pldm_requests, + struct pldm_request, + link); + + /* Start timer to control a timeout from the PLDM terminus */ + init_timer(&active_request->timeout, expiry, active_request); + schedule_timer(&active_request->timeout, + msecs_to_tb(active_request->timeout_ms)); + active_request->start_time = mftb(); + + /* Send PLDM message over MCTP */ + prlog(PR_TRACE, "%s: Sending request to BMC t:%d c:%d i:%d -----\n", + __func__, + active_request->type, + active_request->cmd_code, + active_request->instance); + + rc = pldm_mctp_message_tx(active_request->dest, + active_request->request_msg, + active_request->request_len); + if (rc) + prlog(PR_ERR, "%s: Error %d while sending request\n", + __func__, rc); + +out: + unlock(&list_lock); + schedule_timer(&requests_timer, msecs_to_tb(5)); +} + +/* + * Add PLDM request in the queue + */ +static int queue_request(void *request_msg, int request_len, + uint64_t timeout_ms, + void (*complete)(struct pldm_rx_data *rx, void *data), + void *complete_data) +{ + struct pldm_header_info hdrinf; + struct pldm_request *pending; + + if (unpack_pldm_header(request_msg, &hdrinf)) { + prlog(PR_ERR, "%s: error parsing pldm header\n", + __func__); + return OPAL_PARAMETER; + } + + pending = zalloc(sizeof(struct pldm_request)); + + pending->dest = BMC_EID; + pending->instance = hdrinf.instance; + pending->type = hdrinf.pldm_type; + pending->cmd_code = hdrinf.command; + pending->timeout_ms = timeout_ms; + pending->request_msg = zalloc(request_len); + memcpy(pending->request_msg, request_msg, request_len); + + pending->request_len = request_len; + pending->complete = complete; + pending->complete_data = complete_data; + + /* add an entry at the end of a linked list */ + lock(&list_lock); + prlog(PR_TRACE, "%s: Add request t:%d c:%d i:%d -----\n", + __func__, + pending->type, + pending->cmd_code, + pending->instance); + list_add_tail(&list_pldm_requests, &pending->link); + unlock(&list_lock); + + return OPAL_SUCCESS; +} + +#define TIMEOUT_MS 8000 + +/* + * Queue a PLDM request and don't wait. + * When a response is received, call the associated callback. + */ +int pldm_requester_queue(void *request_msg, size_t request_len, + void (*complete)(struct pldm_rx_data *rx, void *data), + void *complete_data) +{ + int rc = OPAL_SUCCESS; + + rc = ast_mctp_ready(); + if (rc) { + prlog(PR_ERR, "%s: BMC is not listening (rc: %d)\n", + __func__, rc); + return rc; + } + + /* Queue PLDM request */ + rc = queue_request(request_msg, request_len, + TIMEOUT_MS, complete, + complete_data); + if (rc) { + prlog(PR_ERR, "%s: Error %d while queuing request\n", + __func__, rc); + return rc; + } + + return rc; +} + +/* + * Queue a PLDM request and spin until we get a response. + */ +int pldm_requester_queue_and_wait(void *request_msg, size_t request_len, + void **response_msg, size_t *response_len) +{ + struct pldm_response resp; + int rc; + + memset(&resp, 0, sizeof(resp)); + resp.response_msg = response_msg; + resp.response_len = response_len; + + rc = pldm_requester_queue(request_msg, request_len, + send_and_wait_complete, &resp); + if (rc) + return rc; + + /* wait for a response from the BMC */ + do { + time_wait_ms(5); + } while (!resp.done); + + return resp.rc; +} + +void pldm_requester_init(void) +{ + /* lock used to queue and unqueue pldm requests */ + init_lock(&list_lock); + + init_timer(&requests_timer, requests_poller, NULL); + schedule_timer(&requests_timer, msecs_to_tb(5)); +} diff --git a/core/pldm/pldm.h b/core/pldm/pldm.h index 7df413da..fa7a80de 100644 --- a/core/pldm/pldm.h +++ b/core/pldm/pldm.h @@ -42,4 +42,13 @@ int pldm_mctp_message_tx(uint8_t dest_id, uint8_t *buf, int len); int pldm_responder_handle_request(struct pldm_rx_data *rx); int pldm_responder_init(void); +/* Requester support */ +int pldm_requester_handle_response(struct pldm_rx_data *rx); +int pldm_requester_queue(void *request_msg, size_t request_len, + void (*complete)(struct pldm_rx_data *rx, void *data), + void *complete_data); +int pldm_requester_queue_and_wait(void *request_msg, size_t request_len, + void **response_msg, size_t *response_len); +void pldm_requester_init(void); + #endif /* __COREPLDM_H__ */