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

Christophe Lombard clombard at linux.ibm.com
Wed May 17 00:12:40 AEST 2023



Le 26/04/2023 à 17:20, Frederic Barrat a écrit :
>
>
> 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?
>

A bad copy/past. Thanks

> 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