[Skiboot] [PATCH V2 13/15] core/pldm: Register OPAL_RTC_READ/WRITE calls back

Frederic Barrat fbarrat at linux.ibm.com
Thu Apr 27 01:20:14 AEST 2023



On 29/04/2022 11:47, Christophe Lombard wrote:
> OPAL_RTC_READ/WRITE are used to retrieve and write the time. PLDM stack
> provides GetBiosDateTimeReq and SetBiosDateTimeReq commands to exercise.
> 
> Signed-off-by: Christophe Lombard <clombard at linux.vnet.ibm.com>
> ---
>   core/pldm/Makefile.inc         |   2 +-
>   core/pldm/pldm-bios-requests.c | 134 +++++++++++++++++++++++++++++++++
>   core/pldm/pldm-rtc.c           |  76 +++++++++++++++++++
>   core/pldm/pldm.h               |   3 +
>   include/pldm.h                 |   5 ++
>   5 files changed, 219 insertions(+), 1 deletion(-)
>   create mode 100644 core/pldm/pldm-rtc.c
> 
> diff --git a/core/pldm/Makefile.inc b/core/pldm/Makefile.inc
> index 01117680..cf174c86 100644
> --- a/core/pldm/Makefile.inc
> +++ b/core/pldm/Makefile.inc
> @@ -16,7 +16,7 @@ PLDM_OBJS = pldm-common.o pldm-responder.o pldm-requester.o
>   PLDM_OBJS += pldm-base-requests.o pldm-platform-requests.o
>   PLDM_OBJS += pldm-bios-requests.o pldm-fru-requests.o
>   PLDM_OBJS += pldm-file-io-requests.o pldm-lid-files.o
> -PLDM_OBJS += pldm-watchdog.o
> +PLDM_OBJS += pldm-watchdog.o pldm-rtc.o
>   
>   PLDM = $(PLDM_DIR)/built-in.a
>   $(PLDM): $(PLDM_OBJS:%=$(PLDM_DIR)/%)
> diff --git a/core/pldm/pldm-bios-requests.c b/core/pldm/pldm-bios-requests.c
> index 66a46bb8..09a30b2b 100644
> --- a/core/pldm/pldm-bios-requests.c
> +++ b/core/pldm/pldm-bios-requests.c
> @@ -6,9 +6,11 @@
>   #include <opal.h>
>   #include <stdio.h>
>   #include <string.h>
> +#include <time.h>
>   #include <inttypes.h>
>   #include <pldm/libpldm/bios.h>
>   #include <pldm/libpldm/bios_table.h>
> +#include <pldm/libpldm/utils.h>
>   #include "pldm.h"
>   
>   /*
> @@ -84,6 +86,138 @@ static void bios_init_complete(bool success)
>   	bios_ready = true;
>   }
>   
> +struct get_date_time_resp {
> +	uint8_t completion_code;
> +	uint8_t seconds;
> +	uint8_t minutes;
> +	uint8_t hours;
> +	uint8_t day;
> +	uint8_t month;
> +	uint16_t year;
> +};
> +
> +/*
> + * Send/receive a PLDM GetBiosDateTime request message
> + */
> +int pldm_bios_get_date_time_req(struct tm *tm)
> +{
> +	char request_msg[PKT_SIZE(0)]; /* the command doesn't have a message payload */
> +	size_t response_len, payload_len;
> +	void *response_msg;
> +	int rc;
> +
> +	struct get_date_time_resp response;
> +
> +	/* Encode the date time request */
> +	rc = encode_get_date_time_req(
> +				DEFAULT_INSTANCE_ID,
> +				(struct pldm_msg *)request_msg);
> +	if (rc != PLDM_SUCCESS) {
> +		prlog(PR_ERR, "Encode GetBiosDateTimeReq Error, rc: %d\n",
> +			      rc);
> +		return OPAL_PARAMETER;
> +	}
> +
> +	/* Send and get the response message bytes */
> +	rc = pldm_do_request(BMC_EID, request_msg, sizeof(request_msg),
> +			     &response_msg, &response_len);
> +	if (rc) {
> +		prlog(PR_ERR, "Communication Error, req: GetBiosDateTimeReq, rc: %d\n", rc);
> +		return rc;
> +	}
> +
> +	/* Decode the message */
> +	payload_len = response_len - sizeof(struct pldm_msg_hdr);
> +	rc = decode_get_date_time_resp(
> +				response_msg,
> +				payload_len,
> +				&response.completion_code,
> +				&response.seconds,
> +				&response.minutes,
> +				&response.hours,
> +				&response.day,
> +				&response.month,
> +				&response.year);
> +	if (rc != PLDM_SUCCESS || response.completion_code != PLDM_SUCCESS) {
> +		prlog(PR_ERR, "Decode GetBiosDateTimeReq Error, rc: %d, cc: %d\n",
> +			      rc, response.completion_code);
> +		free(response_msg);
> +		return OPAL_PARAMETER;
> +	}
> +
> +	/* The data arrives from BMC in BCD format. Convert it to
> +	 * decimal for processing
> +	 */
> +	tm->tm_sec = bcd2dec8(response.seconds);
> +	tm->tm_min = bcd2dec8(response.minutes);
> +	tm->tm_hour = bcd2dec8(response.hours);
> +	tm->tm_mday = bcd2dec8(response.day);
> +	tm->tm_mon = bcd2dec8(response.month);
> +	tm->tm_year = bcd2dec16(response.year);
> +
> +	if (!is_time_legal(tm->tm_sec, tm->tm_min, tm->tm_hour,
> +			   tm->tm_mday, tm->tm_mon, tm->tm_year)) {
> +		prlog(PR_ERR, "Invalid date time value\n");
> +		free(response_msg);
> +		return OPAL_PARAMETER;
> +	}
> +
> +	free(response_msg);
> +
> +	return OPAL_SUCCESS;
> +}
> +
> +/*
> + * Send/receive a PLDM SetBiosDateTime request message
> + */
> +int pldm_bios_set_date_time_req(struct tm *tm)
> +{
> +	char request_msg[PKT_SIZE(struct pldm_set_date_time_req)];
> +	size_t response_len, payload_len;
> +	uint8_t completion_code;
> +	void *response_msg;
> +	int rc;
> +
> +	/* Encode the date time request */
> +	rc = encode_set_date_time_req(
> +				DEFAULT_INSTANCE_ID,
> +				tm->tm_sec, tm->tm_min, tm->tm_hour,
> +				tm->tm_mday, tm->tm_mon, tm->tm_year,
> +				(struct pldm_msg *)request_msg,
> +				sizeof(struct pldm_set_date_time_req));
> +	if (rc != PLDM_SUCCESS) {
> +		prlog(PR_ERR, "Encode SetBiosDateTimeReq Error, rc: %d\n",
> +			      rc);
> +		return OPAL_PARAMETER;
> +	}
> +
> +	/* Send and get the response message bytes */
> +	rc = pldm_do_request(BMC_EID, request_msg, sizeof(request_msg),
> +			     &response_msg, &response_len);
> +	if (rc) {
> +		prlog(PR_ERR, "Communication Error, req: SetBiosDateTimeReq, rc: %d\n", rc);
> +		return rc;
> +	}
> +
> +	/* Decode the message */
> +	payload_len = response_len - sizeof(struct pldm_msg_hdr);
> +	rc = decode_set_date_time_resp(
> +				response_msg,
> +				payload_len,
> +				&completion_code);
> +	if (rc != PLDM_SUCCESS || (completion_code > PLDM_ERROR)) {
> +		/* FIXME: Time value from OPAL_RTC_WRITE is never correct */
> +		prlog(PR_ERR, "Decode SetBiosDateTimeReq Error, rc: %d, cc: %d\n",
> +			      rc, completion_code);
> +		free(response_msg);
> +		return OPAL_PARAMETER;
> +	}
> +
> +	free(response_msg);
> +
> +	return OPAL_SUCCESS;
> +}
> +
>   /*
>    * parse a string, format:
>    * <ATTR_a>=<lid_id_1>,<ATTR_b>=<lid_id_2>
> diff --git a/core/pldm/pldm-rtc.c b/core/pldm/pldm-rtc.c
> new file mode 100644
> index 00000000..e449b73e
> --- /dev/null
> +++ b/core/pldm/pldm-rtc.c
> @@ -0,0 +1,76 @@
> +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
> +// Copyright 2022 IBM Corp.
> +
> +#define pr_fmt(fmt) "PLDM: " fmt
> +
> +#include <stdlib.h>
> +#include <string.h>
> +#include <time.h>
> +#include <time-utils.h>
> +#include <device.h>
> +#include <opal.h>
> +#include <rtc.h>
> +#include "pldm.h"
> +
> +static int64_t get_and_cache_date_time(struct tm *tm)
> +{
> +	int rc;
> +
> +	rc = pldm_bios_get_date_time_req(tm);
> +	if (!rc)
> +		rtc_cache_update(tm);
> +
> +	return rc;
> +}
> +
> +static int64_t pldm_opal_rtc_read(__be32 *__ymd, __be64 *__hmsm)
> +{
> +	struct tm tm;
> +	uint32_t ymd;
> +	uint64_t hmsm;
> +	int rc;
> +
> +	if (!__ymd || !__hmsm)
> +		return OPAL_PARAMETER;
> +
> +	rc = get_and_cache_date_time(&tm);
> +	if ((rc) && (rc != OPAL_BUSY))
> +		return OPAL_HARDWARE;
> +
> +	if (rc == OPAL_BUSY)
> +		return OPAL_BUSY_EVENT;
> +
> +	rtc_cache_get_datetime(&ymd, &hmsm);
> +	*__ymd = cpu_to_be32(ymd);
> +	*__hmsm = cpu_to_be64(hmsm);
> +
> +	return OPAL_SUCCESS;
> +}
> +
> +static int64_t pldm_opal_rtc_write(uint32_t year_month_day,
> +				   uint64_t hour_minute_second_millisecond)
> +{
> +	struct tm tm;
> +	int rc;
> +
> +	datetime_to_tm(year_month_day, hour_minute_second_millisecond, &tm);
> +
> +	rc = pldm_bios_set_date_time_req(&tm);
> +	if (rc == OPAL_BUSY)
> +		return OPAL_BUSY_EVENT;


if set_date_time_req() fails with something different than OPAL_BUSY, we 
return from this function with OPAL_SUCCESS?

Why are we converting from OPAL_BUSY to OPAL_BUSY_EVENT?

If the OS loops (which will happen on powernv), then we're going to send 
many PLDM requests, while ignoring the response. IPMI doesn't bother and 
ignore the result of the write request.

   Fred


> +
> +	return OPAL_SUCCESS;
> +}
> +
> +void pldm_rtc_init(void)
> +{
> +	struct tm tm;
> +	struct dt_node *np = dt_new(opal_node, "rtc");
> +
> +	dt_add_property_strings(np, "compatible", "ibm,opal-rtc");
> +
> +	opal_register(OPAL_RTC_READ, pldm_opal_rtc_read, 2);
> +	opal_register(OPAL_RTC_WRITE, pldm_opal_rtc_write, 2);
> +
> +	get_and_cache_date_time(&tm);
> +}
> diff --git a/core/pldm/pldm.h b/core/pldm/pldm.h
> index ef884995..81df9f8b 100644
> --- a/core/pldm/pldm.h
> +++ b/core/pldm/pldm.h
> @@ -5,6 +5,7 @@
>   #ifndef __COREPLDM_H__
>   #define __COREPLDM_H__
>   
> +#include <time.h>
>   #include <pldm/libpldm/base.h>
>   #include <pldm/libpldm/utils.h>
>   #include <pldm.h>
> @@ -94,6 +95,8 @@ void pldm_fru_add_record(uint32_t *fru_table_length,
>   int pldm_fru_get_table(void **fru_record_table_bytes,
>   		       uint32_t *fru_record_table_size);
>   
> +int pldm_bios_get_date_time_req(struct tm *tm);
> +int pldm_bios_set_date_time_req(struct tm *tm);
>   int pldm_bios_find_lid_by_attr_name(const char *name, char **lid);
>   int pldm_bios_get_lids_id(char **lid_ids_string);
>   int pldm_bios_init(void);
> diff --git a/include/pldm.h b/include/pldm.h
> index 5acdcbbe..019e811f 100644
> --- a/include/pldm.h
> +++ b/include/pldm.h
> @@ -54,4 +54,9 @@ int pldm_watchdog_init(void);
>   int pldm_platform_send_progress_state_change(
>   		enum pldm_state_set_boot_progress_state_values state);
>   
> +/**
> + * Configure real-time clock
> + */
> +void pldm_rtc_init(void);
> +
>   #endif /* __PLDM_H__ */


More information about the Skiboot mailing list