From abhishek at linux.ibm.com Mon Oct 3 16:16:52 2022 From: abhishek at linux.ibm.com (Abhishek SIngh Tomar) Date: Mon, 3 Oct 2022 10:46:52 +0530 Subject: [Skiboot] [PATCH V3 09/15] core/pldm: Decode the GetPDR request In-Reply-To: <20220913102724.65563-10-clombard@linux.vnet.ibm.com> References: <20220913102724.65563-1-clombard@linux.vnet.ibm.com> <20220913102724.65563-10-clombard@linux.vnet.ibm.com> Message-ID: On Tue, Sep 13, 2022 at 12:27:18PM +0200, Christophe Lombard wrote: > The GetPDR command is used to retrieve individual PDRs from a PDR > repository. The record is identified by the PDR recordHandle value > that is passed in the request. > > Signed-off-by: Christophe Lombard Reviewed-by: Abhishek Singh Tomar > --- > core/pldm/pldm-responder.c | 127 +++++++++++++++++++++++++++++++++++++ > 1 file changed, 127 insertions(+) > > diff --git a/core/pldm/pldm-responder.c b/core/pldm/pldm-responder.c > index bbfd167d..8fbd57c3 100644 > --- a/core/pldm/pldm-responder.c > +++ b/core/pldm/pldm-responder.c > @@ -788,6 +788,132 @@ static struct pldm_cmd pldm_platform_set_state_effecter_states = { > .handler = platform_set_state_effecter_states_handler, > }; > > +struct get_pdr_req { > + uint32_t record_handle; > + uint32_t data_transfer_handle; > + uint8_t transfer_op_flag; > + uint16_t request_count; > + uint16_t record_change_number; > +}; > + > +/* > + * GetPDR (0x51) > + * The GetPDR command is used to retrieve individual PDRs from a PDR > + * Repository. The record is identified by the PDR recordHandle value > + * that is passed in the request. > + */ > +static int platform_get_pdr_handle(const struct pldm_rx_data *req) > +{ > + size_t payload_len, response_length; > + uint32_t next_record_handle; > + struct get_pdr_req pdr_req; > + uint8_t *pdr_data = NULL; > + uint32_t pdr_data_size = 0; > + char *response_msg; > + int rc; > + > + payload_len = req->msg_len - sizeof(struct pldm_msg_hdr); > + rc = decode_get_pdr_req(req->msg, > + payload_len, > + &pdr_req.record_handle, > + &pdr_req.data_transfer_handle, > + &pdr_req.transfer_op_flag, > + &pdr_req.request_count, > + &pdr_req.record_change_number); > + if (rc) { > + prlog(PR_ERR, "Failed to decode GetPDR request, rc = %d\n", rc); > + cc_resp(req, req->hdrinf.pldm_type, > + req->hdrinf.command, PLDM_ERROR); > + return OPAL_INTERNAL_ERROR; > + } > + > + if (pdr_req.data_transfer_handle != 0) { > + /* We don't support multipart transfers */ > + prlog(PR_ERR, "Got invalid data transfer handle 0x%x in GetPDR request\n", > + pdr_req.data_transfer_handle); > + cc_resp(req, req->hdrinf.pldm_type, > + req->hdrinf.command, > + PLDM_PLATFORM_INVALID_DATA_TRANSFER_HANDLE); > + return OPAL_PARAMETER; > + } > + > + if (pdr_req.transfer_op_flag != PLDM_GET_FIRSTPART) { > + prlog(PR_ERR, "Got invalid transfer op flag 0x%x in GetPDR request\n", > + pdr_req.transfer_op_flag); > + cc_resp(req, req->hdrinf.pldm_type, > + req->hdrinf.command, > + PLDM_PLATFORM_INVALID_TRANSFER_OPERATION_FLAG); > + return OPAL_PARAMETER; > + } > + > + if (pdr_req.record_change_number != 0) { > + prlog(PR_ERR, "Got invalid record change number 0x%x in GetPDR request\n", > + pdr_req.record_change_number); > + cc_resp(req, req->hdrinf.pldm_type, > + req->hdrinf.command, > + PLDM_PLATFORM_INVALID_RECORD_CHANGE_NUMBER); > + return OPAL_PARAMETER; > + } > + > + /* find PDR record by record handle */ > + prlog(PR_INFO, "BMC requesting PDR handle %d\n", pdr_req.record_handle); > + > + rc = pldm_platform_pdr_find_record(pdr_req.record_handle, > + &pdr_data, > + &pdr_data_size, > + &next_record_handle); > + if (rc) { > + prlog(PR_ERR, "Got invalid record handle 0x%x in GetPDR request\n", > + pdr_req.record_handle); > + cc_resp(req, req->hdrinf.pldm_type, > + req->hdrinf.command, > + PLDM_PLATFORM_INVALID_RECORD_HANDLE); > + return OPAL_PARAMETER; > + } > + > + response_length = sizeof(struct pldm_msg_hdr) + > + sizeof(struct pldm_get_pdr_resp) + > + pdr_data_size; > + response_msg = zalloc(response_length); > + memset(response_msg, 0, response_length); > + > + /* create a PLDM response message for GetPDR */ > + rc = encode_get_pdr_resp(req->hdrinf.instance, > + PLDM_SUCCESS, > + next_record_handle, > + 0, /* No remaining data */ > + PLDM_START_AND_END, > + pdr_data_size, > + pdr_data, > + 0, /* CRC not used for START_AND_END */ > + (struct pldm_msg *)response_msg); > + if (rc != PLDM_SUCCESS) { > + prlog(PR_ERR, "Encode GetPDR Error, rc: %d\n", rc); > + cc_resp(req, req->hdrinf.pldm_type, > + req->hdrinf.command, PLDM_ERROR); > + free(response_msg); > + return OPAL_PARAMETER; > + } > + > + /* send PLDM message over MCTP */ > + rc = pldm_mctp_message_tx(req->source_eid, response_msg, response_length - 1); > + if (rc) { > + prlog(PR_ERR, "Failed to send GetPDR response, rc = %d\n", rc); > + free(response_msg); > + return OPAL_HARDWARE; > + } > + > + free(response_msg); > + > + return OPAL_SUCCESS; > +} > + > +static struct pldm_cmd pldm_platform_get_pdr = { > + .name = "PLDM_GET_PDR", > + .pldm_cmd_id = PLDM_GET_PDR, > + .handler = platform_get_pdr_handle, > +}; > + > int pldm_responder_handle_request(struct pldm_rx_data *rx) > { > const struct pldm_type *type; > @@ -834,6 +960,7 @@ int pldm_responder_init(void) > add_cmd(&pldm_platform_type, &pldm_platform_event_message); > add_cmd(&pldm_platform_type, &pldm_platform_get_state_sensor_readings); > add_cmd(&pldm_platform_type, &pldm_platform_set_state_effecter_states); > + add_cmd(&pldm_platform_type, &pldm_platform_get_pdr); > > return OPAL_SUCCESS; > } > -- > 2.37.3 > > _______________________________________________ > Skiboot mailing list > Skiboot at lists.ozlabs.org > https://lists.ozlabs.org/listinfo/skiboot From abhishek at linux.ibm.com Mon Oct 3 16:19:46 2022 From: abhishek at linux.ibm.com (Abhishek SIngh Tomar) Date: Mon, 3 Oct 2022 10:49:46 +0530 Subject: [Skiboot] [PATCH V3 10/15] core/pldm: Decode the GetFRURecordTableMetadata request In-Reply-To: <20220913102724.65563-11-clombard@linux.vnet.ibm.com> References: <20220913102724.65563-1-clombard@linux.vnet.ibm.com> <20220913102724.65563-11-clombard@linux.vnet.ibm.com> Message-ID: On Tue, Sep 13, 2022 at 12:27:19PM +0200, Christophe Lombard wrote: > The GetFRURecordTableMetadata command is used to get the FRU Record > Table metadata information that includes the FRU Record major version, > the FRU Record minor version, the size of the largest FRU Record data, > total length of the FRU Record Table, total number of FRU Record Data > structures, and the integrity checksum on the FRU Record Table data. > > Add an "IBM, skiboot" FRU Record product requested by the BMC. > > Signed-off-by: Christophe Lombard Reviewed-by : Abhishek Singh Tomar > --- > core/pldm/pldm-fru-requests.c | 53 ++++++++++++++++++++++ > core/pldm/pldm-responder.c | 85 +++++++++++++++++++++++++++++++++++ > core/pldm/pldm.h | 3 ++ > 3 files changed, 141 insertions(+) > > diff --git a/core/pldm/pldm-fru-requests.c b/core/pldm/pldm-fru-requests.c > index b07a7b1a..80a13ef1 100644 > --- a/core/pldm/pldm-fru-requests.c > +++ b/core/pldm/pldm-fru-requests.c > @@ -14,6 +14,9 @@ > static void *fru_record_table; > static size_t fru_record_length; > > +static void *local_fru_record_table; > +static size_t local_fru_table_length; > + > static bool fru_ready; > static char *bmc_version = NULL; > > @@ -175,6 +178,56 @@ int pldm_fru_dt_add_bmc_version(void) > return OPAL_SUCCESS; > } > > +#define RECORD_SET_ID 100 > + > +void pldm_fru_add_record(uint32_t *table_length, > + uint16_t *total_record_set_identifiers, > + uint16_t *total_table_records) > +{ > + struct pldm_fru_record_data_format *record; > + struct pldm_fru_record_tlv *fru_tlv; > + size_t fru_table_size, record_size; > + char fru_product[] = "IBM, skiboot"; > + > + if (local_fru_record_table) { > + *table_length = local_fru_table_length; > + *total_record_set_identifiers = 1; > + *total_table_records = 1; > + return; > + } > + > + /* allocate fru table */ > + fru_table_size = sizeof(struct pldm_fru_record_data_format) + > + sizeof(struct pldm_fru_record_tlv) + > + strlen(fru_product); > + local_fru_record_table = zalloc(fru_table_size); > + > + /* fill fru record data */ > + record = (struct pldm_fru_record_data_format *)local_fru_record_table; > + record->record_set_id = htole16(RECORD_SET_ID); > + record->record_type = PLDM_FRU_RECORD_TYPE_GENERAL; > + record->num_fru_fields = 1; > + record->encoding_type = PLDM_FRU_ENCODING_ASCII; > + > + /* to start, set the size as the start of the TLV structs */ > + record_size = offsetof(struct pldm_fru_record_data_format, tlvs); > + > + /* TLVs data */ > + fru_tlv = (struct pldm_fru_record_tlv *)(local_fru_record_table + record_size); > + fru_tlv->type = PLDM_FRU_FIELD_TYPE_OTHER; > + fru_tlv->length = strlen(fru_product); > + memcpy(fru_tlv->value, fru_product, fru_tlv->length); > + > + /* increment record_size by total size of this TLV */ > + record_size += (offsetof(struct pldm_fru_record_tlv, value) + fru_tlv->length); > + > + *table_length = record_size; > + *total_record_set_identifiers = 1; > + *total_table_records = 1; > + > + local_fru_table_length = *table_length; > +} > + > int pldm_fru_init(void) > { > int rc; > diff --git a/core/pldm/pldm-responder.c b/core/pldm/pldm-responder.c > index 8fbd57c3..cd2cbc1c 100644 > --- a/core/pldm/pldm-responder.c > +++ b/core/pldm/pldm-responder.c > @@ -11,6 +11,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -914,6 +915,86 @@ static struct pldm_cmd pldm_platform_get_pdr = { > .handler = platform_get_pdr_handle, > }; > > +/* > + * PLDM Fru commands support > + */ > +static struct pldm_type pldm_fru_type = { > + .name = "fru", > + .pldm_type_id = PLDM_FRU, > +}; > + > +/* currently we support version 1.0 of fru table */ > +#define SUPPORTED_FRU_VERSION_MAJOR 1 > +#define SUPPORTED_FRU_VERSION_MINOR 0 > + > +/* Used by the metadata request handler for the value of > + * FRUTableMaximumSize > + * 0 means SetFRURecordTable command is not supported (see DSP 0257 > + * v1.0.0 Table 9) > + */ > +#define FRU_TABLE_MAX_SIZE_UNSUPPORTED 0 > + > +/* > + * GetFRURecordTableMetadata (0X01) > + * The GetFRURecordTableMetadata command is used to get the FRU Record > + * Table metadata information that includes the FRU Record major > + * version, the FRU Record minor version, the size of the largest FRU > + * Record data, total length of the FRU Record Table, total number of > + * FRU Record Data structures, and the integrity checksum on the FRU > + * Record Table data. > + */ > +static int fru_get_record_table_metadata_handler(const struct pldm_rx_data *req) > +{ > + char response_msg[PKT_SIZE(struct pldm_get_fru_record_table_metadata_resp)]; > + uint16_t total_record_set_identifiers, total_table_records; > + uint32_t fru_table_length; > + int rc; > + > + /* > + * GetFRURecordTableMetadata requests > + * don't have any payload, so no need to decode them > + */ > + > + /* add specific fru record */ > + pldm_fru_add_record(&fru_table_length, > + &total_record_set_identifiers, > + &total_table_records); > + > + /* create a PLDM response message for GetFRURecordTableMetadata */ > + rc = encode_get_fru_record_table_metadata_resp( > + req->hdrinf.instance, > + PLDM_SUCCESS, > + SUPPORTED_FRU_VERSION_MAJOR, > + SUPPORTED_FRU_VERSION_MINOR, > + FRU_TABLE_MAX_SIZE_UNSUPPORTED, > + fru_table_length, > + total_record_set_identifiers, > + total_table_records, > + 0, // checksum, not calculated > + (struct pldm_msg *)response_msg); > + if (rc != PLDM_SUCCESS) { > + prlog(PR_ERR, "Encode GetFRURecordTableMetadata Error, rc: %d\n", rc); > + cc_resp(req, req->hdrinf.pldm_type, > + req->hdrinf.command, PLDM_ERROR); > + return OPAL_PARAMETER; > + } > + > + /* send PLDM message over MCTP */ > + rc = pldm_mctp_message_tx(req->source_eid, response_msg, sizeof(response_msg)); > + if (rc) { > + prlog(PR_ERR, "Failed to send GetFRURecordTableMetadata response, rc = %d\n", rc); > + return OPAL_HARDWARE; > + } > + > + return OPAL_SUCCESS; > +} > + > +static struct pldm_cmd pldm_fru_get_record_table_metadata = { > + .name = "PLDM_GET_FRU_RECORD_TABLE_METADATA", > + .pldm_cmd_id = PLDM_GET_FRU_RECORD_TABLE_METADATA, > + .handler = fru_get_record_table_metadata_handler, > +}; > + > int pldm_responder_handle_request(struct pldm_rx_data *rx) > { > const struct pldm_type *type; > @@ -962,5 +1043,9 @@ int pldm_responder_init(void) > add_cmd(&pldm_platform_type, &pldm_platform_set_state_effecter_states); > add_cmd(&pldm_platform_type, &pldm_platform_get_pdr); > > + /* Register fru commands we'll respond to - DSP0257 */ > + add_type(&pldm_fru_type); > + add_cmd(&pldm_fru_type, &pldm_fru_get_record_table_metadata); > + > return OPAL_SUCCESS; > } > diff --git a/core/pldm/pldm.h b/core/pldm/pldm.h > index af8c8925..fea06b0b 100644 > --- a/core/pldm/pldm.h > +++ b/core/pldm/pldm.h > @@ -75,6 +75,9 @@ int pldm_file_io_write_file(uint32_t file_handle, const void *buf, > int pldm_file_io_init(void); > > int pldm_fru_get_bmc_version(void *bv); > +void pldm_fru_add_record(uint32_t *fru_table_length, > + uint16_t *total_record_set_identifiers, > + uint16_t *total_table_records); > int pldm_fru_init(void); > > int pldm_bios_find_lid_by_attr_name(const char *name, char **lid); > -- > 2.37.3 > > _______________________________________________ > Skiboot mailing list > Skiboot at lists.ozlabs.org > https://lists.ozlabs.org/listinfo/skiboot From abhishek at linux.ibm.com Mon Oct 3 16:25:44 2022 From: abhishek at linux.ibm.com (Abhishek SIngh Tomar) Date: Mon, 3 Oct 2022 10:55:44 +0530 Subject: [Skiboot] [PATCH V3 11/15] core/pldm: Decode the GetFruRecordTable request In-Reply-To: <20220913102724.65563-12-clombard@linux.vnet.ibm.com> References: <20220913102724.65563-1-clombard@linux.vnet.ibm.com> <20220913102724.65563-12-clombard@linux.vnet.ibm.com> Message-ID: On Tue, Sep 13, 2022 at 12:27:20PM +0200, Christophe Lombard wrote: > The GetFRURecordTable command is used to get the FRU Record Table data. > This command is defined to allow the FRU Record Table data to be > transferred using a sequence of one or more command/response messages. > > Signed-off-by: Christophe Lombard Reviewed-by: Abhishek Singh Tomar > --- > core/pldm/pldm-fru-requests.c | 12 ++++++ > core/pldm/pldm-responder.c | 78 +++++++++++++++++++++++++++++++++++ > core/pldm/pldm.h | 2 + > 3 files changed, 92 insertions(+) > > diff --git a/core/pldm/pldm-fru-requests.c b/core/pldm/pldm-fru-requests.c > index 80a13ef1..c90f08b3 100644 > --- a/core/pldm/pldm-fru-requests.c > +++ b/core/pldm/pldm-fru-requests.c > @@ -228,6 +228,18 @@ void pldm_fru_add_record(uint32_t *table_length, > local_fru_table_length = *table_length; > } > > +int pldm_fru_get_local_table(void **fru_record_table_bytes, > + uint32_t *fru_record_table_size) > +{ > + if (!local_fru_record_table) > + return OPAL_PARAMETER; > + > + *fru_record_table_bytes = local_fru_record_table; > + *fru_record_table_size = local_fru_table_length; > + > + return OPAL_SUCCESS; > +} > + > int pldm_fru_init(void) > { > int rc; > diff --git a/core/pldm/pldm-responder.c b/core/pldm/pldm-responder.c > index cd2cbc1c..2c5b3677 100644 > --- a/core/pldm/pldm-responder.c > +++ b/core/pldm/pldm-responder.c > @@ -995,6 +995,83 @@ static struct pldm_cmd pldm_fru_get_record_table_metadata = { > .handler = fru_get_record_table_metadata_handler, > }; > > +/* > + * GetFRURecordTable (0X02) > + * The GetFRURecordTable command is used to get the FRU Record Table > + * data. This command is defined to allow the FRU Record Table data to > + * be transferred using a sequence of one or more command/response > + * messages. > + */ > +static int fru_get_record_table_handler(const struct pldm_rx_data *req) > +{ > + struct pldm_get_fru_record_table_resp *resp; > + void *fru_record_table_bytes; > + uint32_t fru_record_table_size; > + size_t response_length; > + struct pldm_msg *msg; > + char *response_msg; > + int rc; > + > + /* The getFruRecordTable requests do have request data, but it's > + * only related to multi-part transfers which we don't support > + * and which the BMC will not send us. > + */ > + > + /* get local fru record table */ > + rc = pldm_fru_get_local_table(&fru_record_table_bytes, &fru_record_table_size); > + if (rc) { > + prlog(PR_ERR, "Failed to get Fru Record Table\n"); > + cc_resp(req, req->hdrinf.pldm_type, > + req->hdrinf.command, PLDM_ERROR); > + return OPAL_PARAMETER; > + } > + > + /* create a PLDM response message for GetFRURecordTable */ > + response_length = sizeof(struct pldm_msg_hdr) + > + sizeof(struct pldm_get_fru_record_table_resp) + > + fru_record_table_size; > + response_msg = zalloc(response_length); > + memset(response_msg, 0, response_length); > + > + rc = encode_get_fru_record_table_resp( > + req->hdrinf.instance, > + PLDM_SUCCESS, > + 0, // No next transfer handle > + PLDM_START_AND_END, > + (struct pldm_msg *)response_msg); > + if (rc != PLDM_SUCCESS) { > + prlog(PR_ERR, "Encode GetFruRecordTable Error, rc: %d\n", rc); > + cc_resp(req, req->hdrinf.pldm_type, > + req->hdrinf.command, PLDM_ERROR); > + free(response_msg); > + return OPAL_PARAMETER; > + } > + > + msg = (struct pldm_msg *)response_msg; > + resp = (struct pldm_get_fru_record_table_resp *)(msg->payload); > + memcpy(resp->fru_record_table_data, > + fru_record_table_bytes, > + fru_record_table_size); > + > + /* send PLDM message over MCTP */ > + rc = pldm_mctp_message_tx(req->source_eid, response_msg, response_length - 1); > + if (rc) { > + prlog(PR_ERR, "Failed to send GetFruRecordTable response, rc = %d\n", rc); > + free(response_msg); > + return OPAL_HARDWARE; > + } > + > + free(response_msg); > + > + return OPAL_SUCCESS; > +} > + > +static struct pldm_cmd pldm_fru_get_record_table = { > + .name = "PLDM_GET_FRU_RECORD_TABLE", > + .pldm_cmd_id = PLDM_GET_FRU_RECORD_TABLE, > + .handler = fru_get_record_table_handler, > +}; > + > int pldm_responder_handle_request(struct pldm_rx_data *rx) > { > const struct pldm_type *type; > @@ -1046,6 +1123,7 @@ int pldm_responder_init(void) > /* Register fru commands we'll respond to - DSP0257 */ > add_type(&pldm_fru_type); > add_cmd(&pldm_fru_type, &pldm_fru_get_record_table_metadata); > + add_cmd(&pldm_fru_type, &pldm_fru_get_record_table); > > return OPAL_SUCCESS; > } > diff --git a/core/pldm/pldm.h b/core/pldm/pldm.h > index fea06b0b..dd6f2352 100644 > --- a/core/pldm/pldm.h > +++ b/core/pldm/pldm.h > @@ -78,6 +78,8 @@ int pldm_fru_get_bmc_version(void *bv); > void pldm_fru_add_record(uint32_t *fru_table_length, > uint16_t *total_record_set_identifiers, > uint16_t *total_table_records); > +int pldm_fru_get_local_table(void **fru_record_table_bytes, > + uint32_t *fru_record_table_size); > int pldm_fru_init(void); > > int pldm_bios_find_lid_by_attr_name(const char *name, char **lid); > -- > 2.37.3 > > _______________________________________________ > Skiboot mailing list > Skiboot at lists.ozlabs.org > https://lists.ozlabs.org/listinfo/skiboot From abhishek at linux.ibm.com Mon Oct 3 16:28:09 2022 From: abhishek at linux.ibm.com (Abhishek SIngh Tomar) Date: Mon, 3 Oct 2022 10:58:09 +0530 Subject: [Skiboot] [PATCH V3 13/15] core/pldm: Register OPAL_RTC_READ/WRITE calls back In-Reply-To: <20220913102724.65563-14-clombard@linux.vnet.ibm.com> References: <20220913102724.65563-1-clombard@linux.vnet.ibm.com> <20220913102724.65563-14-clombard@linux.vnet.ibm.com> Message-ID: On Tue, Sep 13, 2022 at 12:27:22PM +0200, 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 Reviedwe-by: Abhishek Singh Tomar > --- > core/pldm/Makefile.inc | 2 +- > core/pldm/pldm-rtc.c | 244 +++++++++++++++++++++++++++++++++++++++++ > include/pldm.h | 5 + > 3 files changed, 250 insertions(+), 1 deletion(-) > create mode 100644 core/pldm/pldm-rtc.c > > diff --git a/core/pldm/Makefile.inc b/core/pldm/Makefile.inc > index 5d10d572..00d6c458 100644 > --- a/core/pldm/Makefile.inc > +++ b/core/pldm/Makefile.inc > @@ -16,7 +16,7 @@ PLDM_OBJS = pldm-mctp.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-rtc.c b/core/pldm/pldm-rtc.c > new file mode 100644 > index 00000000..b6702a0b > --- /dev/null > +++ b/core/pldm/pldm-rtc.c > @@ -0,0 +1,244 @@ > +// 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 > +#include > +#include > +#include "pldm.h" > + > +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; > +}; > + > +static enum {idle, waiting, updated, error} time_status; > + > +static void cache_get_datetime(struct tm *tm) > +{ > + if (tm == NULL) > + time_status = error; > + else { > + rtc_cache_update(tm); > + time_status = updated; > + } > +} > + > +static void get_date_time_req_complete(struct pldm_rx_data *rx, > + void *data __unused) > +{ > + struct get_date_time_resp response; > + size_t payload_len; > + struct tm tm; > + int rc; > + > + if (rx == NULL) { > + prlog(PR_ERR, "%s: Response not received\n", __func__); > + cache_get_datetime(NULL); > + return; > + } > + > + /* Decode the message */ > + payload_len = rx->msg_len - sizeof(struct pldm_msg_hdr); > + rc = decode_get_date_time_resp( > + rx->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); > + cache_get_datetime(NULL); > + return; > + } > + > + /* 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, "%s: Invalid date time value\n", __func__); > + cache_get_datetime(NULL); > + return; > + } > + > + cache_get_datetime(&tm); > +} > + > +/* > + * Send a PLDM GetBiosDateTime request message > + */ > +static int get_date_time_req(void) > +{ > + char request_msg[PKT_SIZE(0)]; /* the command doesn't have a message payload */ > + int rc; > + > + /* 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; > + } > + > + /* Queue and get the response message bytes */ > + rc = pldm_requester_queue(request_msg, sizeof(request_msg), > + get_date_time_req_complete, NULL); > + if (rc) { > + prlog(PR_ERR, "Communication Error, req: GetBiosDateTimeReq, rc: %d\n", rc); > + return rc; > + } > + > + return OPAL_SUCCESS; > +} > + > +static int64_t pldm_opal_rtc_read(__be32 *__ymd, __be64 *__hmsm) > +{ > + uint32_t ymd; > + uint64_t hmsm; > + int rc = OPAL_SUCCESS; > + > + if (!__ymd || !__hmsm) > + return OPAL_PARAMETER; > + > + switch (time_status) { > + case idle: > + rc = get_date_time_req(); > + if (rc) > + return OPAL_HARDWARE; > + time_status = waiting; > + rc = OPAL_BUSY_EVENT; > + break; > + > + case waiting: > + rc = OPAL_BUSY_EVENT; > + break; > + > + case updated: > + rtc_cache_get_datetime(&ymd, &hmsm); > + *__ymd = cpu_to_be32(ymd); > + *__hmsm = cpu_to_be64(hmsm); > + time_status = idle; > + rc = OPAL_SUCCESS; > + break; > + > + case error: > + time_status = idle; > + rc = OPAL_HARDWARE; > + break; > + } > + > + return rc; > +} > + > +/* > + * Receive the PLDM SetBiosDateTime response > + */ > +static void set_date_time_req_complete(struct pldm_rx_data *rx, > + void *data __unused) > +{ > + uint8_t completion_code; > + size_t payload_len; > + int rc; > + > + if (rx == NULL) { > + prlog(PR_ERR, "%s: Response not received\n", __func__); > + return; > + } > + > + /* Decode the message */ > + payload_len = rx->msg_len - sizeof(struct pldm_msg_hdr); > + > + rc = decode_set_date_time_resp(rx->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); > + } > +} > + > +/* > + * Send a PLDM SetBiosDateTime request message > + */ > +static int set_date_time_req(struct tm *tm) > +{ > + char request_msg[PKT_SIZE(struct pldm_set_date_time_req)]; > + 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; > + } > + > + /* Queue and get the response message bytes */ > + rc = pldm_requester_queue(request_msg, sizeof(request_msg), > + set_date_time_req_complete, NULL); > + if (rc) { > + prlog(PR_ERR, "Communication Error, req: SetBiosDateTimeReq, rc: %d\n", rc); > + return rc; > + } > + > + 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 = set_date_time_req(&tm); > + if (rc == OPAL_BUSY) > + return OPAL_BUSY_EVENT; > + > + return OPAL_SUCCESS; > +} > + > +void pldm_rtc_init(void) > +{ > + 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); > + > + /* Initialise the rtc cache */ > + get_date_time_req(); > +} > diff --git a/include/pldm.h b/include/pldm.h > index 2100c12c..db24040d 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__ */ > -- > 2.37.3 > > _______________________________________________ > Skiboot mailing list > Skiboot at lists.ozlabs.org > https://lists.ozlabs.org/listinfo/skiboot From abhishek at linux.ibm.com Mon Oct 3 16:29:15 2022 From: abhishek at linux.ibm.com (Abhishek SIngh Tomar) Date: Mon, 3 Oct 2022 10:59:15 +0530 Subject: [Skiboot] [PATCH V3 14/15] core/pldm: Register OPAL_IPMI_SEND/RECV calls back In-Reply-To: <20220913102724.65563-15-clombard@linux.vnet.ibm.com> References: <20220913102724.65563-1-clombard@linux.vnet.ibm.com> <20220913102724.65563-15-clombard@linux.vnet.ibm.com> Message-ID: On Tue, Sep 13, 2022 at 12:27:23PM +0200, Christophe Lombard wrote: > OPAL_IPMI_SEND/RECV are used to retrieve and write IPMI requests. > This support is needed for Linux driver. > Only IPMI_GET_DEVICE_ID_CMD and IPMI_GET_DEVICE_GUID_CMD commands are > supported. > > Signed-off-by: Christophe Lombard Reviewed-by: Abhishek Singh Tomar > --- > core/pldm/Makefile.inc | 2 +- > core/pldm/pldm-opal.c | 291 +++++++++++++++++++++++++++++++++++++++++ > include/pldm.h | 5 + > 3 files changed, 297 insertions(+), 1 deletion(-) > create mode 100644 core/pldm/pldm-opal.c > > diff --git a/core/pldm/Makefile.inc b/core/pldm/Makefile.inc > index 00d6c458..14dd833e 100644 > --- a/core/pldm/Makefile.inc > +++ b/core/pldm/Makefile.inc > @@ -16,7 +16,7 @@ PLDM_OBJS = pldm-mctp.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-rtc.o > +PLDM_OBJS += pldm-watchdog.o pldm-rtc.o pldm-opal.o > > PLDM = $(PLDM_DIR)/built-in.a > $(PLDM): $(PLDM_OBJS:%=$(PLDM_DIR)/%) > diff --git a/core/pldm/pldm-opal.c b/core/pldm/pldm-opal.c > new file mode 100644 > index 00000000..3169d9d0 > --- /dev/null > +++ b/core/pldm/pldm-opal.c > @@ -0,0 +1,291 @@ > +// 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 > +#include > +#include "pldm.h" > + > +/* > + * Response data from IPMI Get device ID command (As defined in > + * Section 20.1 Get Device ID Command - IPMI standard spec). > + */ > +struct ipmi_dev_id { > + uint8_t dev_id; > + uint8_t dev_revision; > + uint8_t fw_rev1; > + uint8_t fw_rev2; > + uint8_t ipmi_ver; > + uint8_t add_dev_support; > + uint8_t manufactur_id[3]; > + uint8_t product_id[2]; > + uint8_t aux_fw_rev[4]; > +}; > + > +static struct lock msgq_lock = LOCK_UNLOCKED; > +static struct list_head msgq = LIST_HEAD_INIT(msgq); > +uint64_t opal_event_ipmi_recv; > + > +static void opal_send_complete(struct ipmi_msg *msg) > +{ > + lock(&msgq_lock); > + list_add_tail(&msgq, &msg->link); > + opal_update_pending_evt(opal_event_ipmi_recv, > + opal_event_ipmi_recv); > + unlock(&msgq_lock); > +} > + > +#define GUID_SIZE 16 > + > +static int opal_get_tid_req(struct opal_ipmi_msg *opal_ipmi_msg, > + uint64_t msg_len __unused) > +{ > + struct ipmi_msg *opal_ipmi_response = NULL; > + uint8_t guid[GUID_SIZE]; > + int bmc_tid; > + > + opal_ipmi_response = zalloc(sizeof(struct ipmi_msg) + GUID_SIZE); > + opal_ipmi_response->netfn = IPMI_NETFN_RETURN_CODE(opal_ipmi_msg->netfn); > + opal_ipmi_response->cmd = opal_ipmi_msg->cmd; > + > + memset(&guid, 0, GUID_SIZE); > + > + /* First byte of guid contains bmc tid */ > + bmc_tid = pldm_base_get_bmc_tid(); > + if (bmc_tid == -1) { > + opal_ipmi_response->resp_size = 0; > + opal_ipmi_response->cc = IPMI_ERR_UNSPECIFIED; > + goto out; > + } > + > + guid[0] = (uint8_t)bmc_tid; > + memcpy(opal_ipmi_response->data, guid, GUID_SIZE); > + > + opal_ipmi_response->resp_size = GUID_SIZE; > + opal_ipmi_response->cc = IPMI_CC_NO_ERROR; > + > +out: > + opal_send_complete(opal_ipmi_response); > + return OPAL_SUCCESS; > +} > + > +static int parse_bmc_version(uint8_t *bmc_version, > + struct ipmi_dev_id *devid) > +{ > + uint8_t *ptr; > + uint8_t temp; > + > + prlog(PR_TRACE, "%s - bmc version: %s len=%d\n", __func__, > + bmc_version, (int)strlen(bmc_version)); > + > + /* > + * parse bmc version string to find fw_rev1 and fw_rev2 > + * Firmware Name is in format : > + * fw1030.00-2.8-1030.2233.20220819a (NL1030_007) > + * so fw_rev1 = 10 > + * fw_rev2 = 20 > + * aux_fw_rev = "007" > + */ > + ptr = strstr(bmc_version, "NL"); > + if (ptr == NULL || strlen(ptr) < 8) > + return OPAL_PARAMETER; > + > + ptr += 2; > + /* > + * Convert first two byte to > + * fw_rev1 and net 2byte to fw_rev2 > + */ > + temp = ptr[2]; > + ptr[2] = '\0'; > + devid->fw_rev1 = (uint8_t)atoi(ptr); > + ptr += 2; > + ptr[0] = temp; > + > + temp = ptr[2]; > + ptr[2] = '\0'; > + devid->fw_rev2 = (uint8_t)atoi(ptr); > + ptr += 2; > + ptr[0] = temp; > + > + /* Aux version is truncated to 4 char only */ > + if (*ptr == '_') > + strncpy(devid->aux_fw_rev, ptr + 1, 3); > + > + prlog(PR_TRACE, "BMC Version major->%d minor->%d aux->%.4s\n", > + devid->fw_rev1, devid->fw_rev2, devid->aux_fw_rev); > + > + return OPAL_SUCCESS; > +} > + > +static int opal_get_bmc_info(struct opal_ipmi_msg *opal_ipmi_msg, > + uint64_t msg_len __unused) > +{ > + struct ipmi_msg *opal_ipmi_response = NULL; > + char bmc_version[100]; > + struct ipmi_dev_id devid; > + int rc; > + > + opal_ipmi_response = zalloc(sizeof(struct ipmi_msg) + > + sizeof(struct ipmi_dev_id)); > + opal_ipmi_response->resp_size = sizeof(struct ipmi_dev_id); > + opal_ipmi_response->netfn = IPMI_NETFN_RETURN_CODE(opal_ipmi_msg->netfn); > + opal_ipmi_response->cmd = opal_ipmi_msg->cmd; > + opal_ipmi_response->cc = IPMI_CC_NO_ERROR; > + > + memset(&devid, 0, sizeof(devid)); > + devid.ipmi_ver = OPAL_IPMI_MSG_FORMAT_VERSION_1; > + > + /* retrieve bmc version */ > + rc = pldm_fru_get_bmc_version(bmc_version); > + if (rc) { > + opal_ipmi_response->resp_size = 0; > + opal_ipmi_response->cc = IPMI_ERR_UNSPECIFIED; > + goto out; > + } > + > + /* parse the bmc version */ > + rc = parse_bmc_version(bmc_version, &devid); > + if (rc) { > + prlog(PR_ERR, "%s: Failed to parse BMC version, bmc version: %s\n", > + __func__, bmc_version); > + opal_ipmi_response->resp_size = 0; > + opal_ipmi_response->cc = IPMI_ERR_UNSPECIFIED; > + goto out; > + } > + > + memcpy(opal_ipmi_response->data, &devid, sizeof(devid)); > + > +out: > + opal_send_complete(opal_ipmi_response); > + return OPAL_SUCCESS; > +} > + > +static int64_t opal_ipmi_send(uint64_t interface __unused, > + struct opal_ipmi_msg *opal_ipmi_msg, > + uint64_t msg_len) > +{ > + int16_t ipmi_code; > + > + if (opal_ipmi_msg->version != OPAL_IPMI_MSG_FORMAT_VERSION_1) { > + prerror("OPAL IPMI: Incorrect version\n"); > + return OPAL_UNSUPPORTED; > + } > + > + msg_len -= sizeof(struct opal_ipmi_msg); > + if (msg_len > IPMI_MAX_REQ_SIZE) { > + prerror("OPAL IPMI: Invalid request length\n"); > + return OPAL_PARAMETER; > + } > + > + ipmi_code = IPMI_CODE(opal_ipmi_msg->netfn >> 2, opal_ipmi_msg->cmd); > + if ((ipmi_code == IPMI_CHASSIS_GET_SYS_BOOT_OPT_CMD) || > + (opal_ipmi_msg->cmd == IPMI_CODE(opal_ipmi_msg->netfn >> 2, 0x1a)) || > + (opal_ipmi_msg->cmd == IPMI_CODE(opal_ipmi_msg->netfn >> 2, 0x42))) { > + prerror("OPAL IPMI: Command not supported\n"); > + return OPAL_UNSUPPORTED; > + } > + > + prlog(PR_TRACE, "%s - cmd: 0x%02x netfn: 0x%02x len: 0x%02llx\n", > + __func__, opal_ipmi_msg->cmd, opal_ipmi_msg->netfn >> 2, > + msg_len); > + > + switch (opal_ipmi_msg->cmd) { > + case IPMI_GET_DEVICE_ID_CMD: > + return opal_get_bmc_info(opal_ipmi_msg, msg_len); > + > + case IPMI_GET_DEVICE_GUID_CMD: > + return opal_get_tid_req(opal_ipmi_msg, msg_len); > + } > + > + return OPAL_UNSUPPORTED; > +} > + > +static int64_t opal_ipmi_recv(uint64_t interface, > + struct opal_ipmi_msg *opal_ipmi_msg, > + __be64 *msg_len) > +{ > + struct ipmi_msg *msg; > + int64_t rc; > + > + lock(&msgq_lock); > + msg = list_top(&msgq, struct ipmi_msg, link); > + > + if (!msg) { > + rc = OPAL_EMPTY; > + goto out_unlock; > + } > + > + if (opal_ipmi_msg->version != OPAL_IPMI_MSG_FORMAT_VERSION_1) { > + prerror("OPAL IPMI: Incorrect version\n"); > + rc = OPAL_UNSUPPORTED; > + goto out_del_msg; > + } > + > + if (interface != IPMI_DEFAULT_INTERFACE) { > + prerror("IPMI: Invalid interface 0x%llx in %s\n", interface, __func__); > + rc = OPAL_PARAMETER; > + goto out_del_msg; > + } > + > + if (be64_to_cpu(*msg_len) - sizeof(struct opal_ipmi_msg) < msg->resp_size + 1) { > + rc = OPAL_RESOURCE; > + goto out_del_msg; > + } > + > + list_del(&msg->link); > + if (list_empty(&msgq)) > + opal_update_pending_evt(opal_event_ipmi_recv, 0); > + unlock(&msgq_lock); > + > + opal_ipmi_msg->cmd = msg->cmd; > + opal_ipmi_msg->netfn = msg->netfn; > + opal_ipmi_msg->data[0] = msg->cc; > + memcpy(&opal_ipmi_msg->data[1], msg->data, msg->resp_size); > + > + prlog(PR_TRACE, "%s - cmd: 0x%02x netfn: 0x%02x resp_size: 0x%02x\n", > + __func__, msg->cmd, msg->netfn >> 2, msg->resp_size); > + > + /* Add one as the completion code is returned in the message data */ > + *msg_len = cpu_to_be64(msg->resp_size + sizeof(struct opal_ipmi_msg) + 1); > + free(msg); > + > + return OPAL_SUCCESS; > + > +out_del_msg: > + list_del(&msg->link); > + if (list_empty(&msgq)) > + opal_update_pending_evt(opal_event_ipmi_recv, 0); > + free(msg); > + > +out_unlock: > + unlock(&msgq_lock); > + return rc; > +} > + > +void pldm_opal_init(void) > +{ > + struct dt_node *opal_ipmi, *opal_event = NULL; > + > + opal_ipmi = dt_new(opal_node, "ipmi"); > + dt_add_property_strings(opal_ipmi, "compatible", "ibm,opal-ipmi"); > + dt_add_property_cells(opal_ipmi, "ibm,ipmi-interface-id", > + IPMI_DEFAULT_INTERFACE); > + opal_event_ipmi_recv = opal_dynamic_event_alloc(); > + dt_add_property_cells(opal_ipmi, "interrupts", > + ilog2(opal_event_ipmi_recv)); > + > + opal_event = dt_find_by_name(opal_node, "event"); > + if (opal_event) > + dt_add_property_cells(opal_ipmi, "interrupt-parent", > + opal_event->phandle); > + > + opal_register(OPAL_IPMI_SEND, opal_ipmi_send, 3); > + opal_register(OPAL_IPMI_RECV, opal_ipmi_recv, 3); > +} > diff --git a/include/pldm.h b/include/pldm.h > index db24040d..cb9cee08 100644 > --- a/include/pldm.h > +++ b/include/pldm.h > @@ -59,4 +59,9 @@ int pldm_platform_send_progress_state_change( > */ > void pldm_rtc_init(void); > > +/** > + * Register ipmi host interface access callbacks > + */ > +void pldm_opal_init(void); > + > #endif /* __PLDM_H__ */ > -- > 2.37.3 > > _______________________________________________ > Skiboot mailing list > Skiboot at lists.ozlabs.org > https://lists.ozlabs.org/listinfo/skiboot From abhishek at linux.ibm.com Mon Oct 3 16:35:55 2022 From: abhishek at linux.ibm.com (Abhishek SIngh Tomar) Date: Mon, 3 Oct 2022 11:05:55 +0530 Subject: [Skiboot] [PATCH V3 15/15] platforms/astbmc: Enable PLDM support In-Reply-To: <20220913102724.65563-16-clombard@linux.vnet.ibm.com> References: <20220913102724.65563-1-clombard@linux.vnet.ibm.com> <20220913102724.65563-16-clombard@linux.vnet.ibm.com> Message-ID: On Tue, Sep 13, 2022 at 12:27:24PM +0200, Christophe Lombard wrote: > Last BMC firmware is available with a complete PLDM support on Rainier > system. > This patch allows initially to: > - Initialize the MCTP core. > - Enable the mctp binding over LPC bus interface and new wrappers to send > and receive PLDM messages over the mctp library. > - Retrieve all needed PLDM data. > - "Virtualize" the content of a BMC flash based on lid files. > > Then, others mandatory support (watchdog, opal rtc, opal ipmi) are enabled. > > Signed-off-by: Christophe Lombard Reviewed-by : Abhisheek Singh Tomar > --- > core/init.c | 29 ++++++++++++++++++++++++++--- > core/pldm/pldm-mctp.c | 11 +++++++++++ > include/pldm.h | 2 ++ > platforms/astbmc/astbmc.h | 4 ++++ > platforms/astbmc/common.c | 35 +++++++++++++++++++++++++++++++++++ > platforms/astbmc/pnor.c | 25 +++++++++++++++++++++++++ > platforms/qemu/qemu.c | 6 ++++++ > 7 files changed, 109 insertions(+), 3 deletions(-) > > diff --git a/core/init.c b/core/init.c > index 005ecf31..e32e87a8 100644 > --- a/core/init.c > +++ b/core/init.c > @@ -34,6 +34,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -562,8 +563,15 @@ void __noreturn load_and_boot_kernel(bool is_reboot) > > trustedboot_exit_boot_services(); > > +#ifdef CONFIG_PLDM > + if (pldm_present()) > + pldm_platform_send_progress_state_change( > + PLDM_STATE_SET_BOOT_PROG_STATE_STARTING_OP_SYS); > + else > + ipmi_set_fw_progress_sensor(IPMI_FW_OS_BOOT); > +#else > ipmi_set_fw_progress_sensor(IPMI_FW_OS_BOOT); > - > +#endif > > if (!is_reboot) { > /* We wait for the nvram read to complete here so we can > @@ -1410,10 +1418,25 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt) > /* Setup ibm,firmware-versions if able */ > if (platform.bmc) { > flash_dt_add_fw_version(); > - ipmi_dt_add_bmc_info(); > +#ifdef CONFIG_PLDM > + if (pldm_present()) > + pldm_fru_dt_add_bmc_version(); > + else > + ipmi_dt_add_bmc_info(); > +#else > + ipmi_dt_add_bmc_info(); > +#endif > } > > - ipmi_set_fw_progress_sensor(IPMI_FW_PCI_INIT); > +#ifdef CONFIG_PLDM > + if (pldm_present()) > + pldm_platform_send_progress_state_change( > + PLDM_STATE_SET_BOOT_PROG_STATE_PCI_RESORUCE_CONFIG); > + else > + ipmi_set_fw_progress_sensor(IPMI_FW_PCI_INIT); > +#else > + ipmi_set_fw_progress_sensor(IPMI_FW_PCI_INIT); > +#endif > > /* > * These last few things must be done as late as possible > diff --git a/core/pldm/pldm-mctp.c b/core/pldm/pldm-mctp.c > index 1d1d1b37..972a23e5 100644 > --- a/core/pldm/pldm-mctp.c > +++ b/core/pldm/pldm-mctp.c > @@ -10,6 +10,13 @@ > #include > #include "pldm.h" > > +bool pldm_enabled; > + > +bool pldm_present(void) > +{ > + return pldm_enabled; > +} > + > /* > * Print content of PLDM message in hex mode. > * 15 bytes per line. > @@ -139,6 +146,8 @@ int pldm_mctp_init(uint8_t mode) > goto out; > } > > + pldm_enabled = true; > + > /* Get PDRs data */ > rc = pldm_platform_init(); > if (rc) { > @@ -172,6 +181,8 @@ out: > > void pldm_mctp_exit(void) > { > + pldm_enabled = false; > + > pldm_platform_exit(); > > ast_mctp_exit(); > diff --git a/include/pldm.h b/include/pldm.h > index cb9cee08..8aa14a4f 100644 > --- a/include/pldm.h > +++ b/include/pldm.h > @@ -8,6 +8,8 @@ > #include > #include > > +bool pldm_present(void); > + > /** > * PLDM over MCTP initialization > */ > diff --git a/platforms/astbmc/astbmc.h b/platforms/astbmc/astbmc.h > index 00f22123..5d0509b8 100644 > --- a/platforms/astbmc/astbmc.h > +++ b/platforms/astbmc/astbmc.h > @@ -96,6 +96,10 @@ extern const struct bmc_platform bmc_plat_ast2600_openbmc; > extern void astbmc_early_init(void); > extern int64_t astbmc_ipmi_reboot(void); > extern int64_t astbmc_ipmi_power_down(uint64_t request); > +#ifdef CONFIG_PLDM > +extern int astbmc_pldm_init(uint8_t mode); > +extern int pnor_pldm_init(void); > +#endif > extern void astbmc_init(void); > extern void astbmc_ext_irq_serirq_cpld(unsigned int chip_id); > extern int pnor_init(void); > diff --git a/platforms/astbmc/common.c b/platforms/astbmc/common.c > index 83ef70ad..e360a7bd 100644 > --- a/platforms/astbmc/common.c > +++ b/platforms/astbmc/common.c > @@ -9,6 +9,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -104,6 +105,36 @@ static int astbmc_fru_init(void) > return 0; > } > > +#ifdef CONFIG_PLDM > +int astbmc_pldm_init(uint8_t mode) > +{ > + int rc = OPAL_SUCCESS; > + > + /* PLDM over MCTP */ > + rc = pldm_mctp_init(mode); > + if (!rc) { > + /* Initialize PNOR/NVRAM */ > + rc = pnor_pldm_init(); > + > + if (!rc) { > + pldm_watchdog_init(); > + pldm_rtc_init(); > + pldm_opal_init(); > + } > + } > + > + /* Initialize elog */ > + elog_init(); > + > + /* Setup UART console for use by Linux via OPAL API */ > + set_opal_console(&uart_opal_con); > + > + if (rc) > + prlog(PR_WARNING, "Failed to configure PLDM\n"); > + > + return rc; > +} > +#endif > > void astbmc_init(void) > { > @@ -501,6 +532,10 @@ void astbmc_early_init(void) > > void astbmc_exit(void) > { > +#ifdef CONFIG_PLDM > + if (pldm_present()) > + return; > +#endif > ipmi_wdt_final_reset(); > } > > diff --git a/platforms/astbmc/pnor.c b/platforms/astbmc/pnor.c > index 64f2249d..853da467 100644 > --- a/platforms/astbmc/pnor.c > +++ b/platforms/astbmc/pnor.c > @@ -5,6 +5,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -32,6 +33,30 @@ static enum ast_flash_style ast_flash_get_fallback_style(void) > return raw_mem; > } > > +#ifdef CONFIG_PLDM > +int pnor_pldm_init(void) > +{ > + struct blocklevel_device *bl = NULL; > + int rc = 0; > + > + rc = pldm_lid_files_init(&bl); > + if (rc) { > + prerror("PLAT: Failed to init PNOR driver\n"); > + goto fail; > + } > + > + rc = flash_register(bl); > + if (!rc) > + return 0; > + > +fail: > + if (bl) > + pldm_lid_files_exit(bl); > + > + return rc; > +} > +#endif > + > int pnor_init(void) > { > struct spi_flash_ctrl *pnor_ctrl = NULL; > diff --git a/platforms/qemu/qemu.c b/platforms/qemu/qemu.c > index 96153e85..81c5e5e1 100644 > --- a/platforms/qemu/qemu.c > +++ b/platforms/qemu/qemu.c > @@ -4,6 +4,7 @@ > #include > #include > #include > +#include > #include > > #include > @@ -80,7 +81,12 @@ static void qemu_init(void) > if (!bt_device_present) { > set_opal_console(&uart_opal_con); > } else { > +#ifdef CONFIG_PLDM > + /* need to be checked according platform: P10, P11 ... */ > + astbmc_pldm_init(MCTP_BINDING_ASTLPC_MODE); > +#else > astbmc_init(); > +#endif > } > } > > -- > 2.37.3 > > _______________________________________________ > Skiboot mailing list > Skiboot at lists.ozlabs.org > https://lists.ozlabs.org/listinfo/skiboot From abhishek at linux.ibm.com Mon Oct 3 16:37:41 2022 From: abhishek at linux.ibm.com (Abhishek SIngh Tomar) Date: Mon, 3 Oct 2022 11:07:41 +0530 Subject: [Skiboot] [PATCH V3 15/15] platforms/astbmc: Enable PLDM support In-Reply-To: References: <20220913102724.65563-1-clombard@linux.vnet.ibm.com> <20220913102724.65563-16-clombard@linux.vnet.ibm.com> Message-ID: On Mon, Oct 03, 2022 at 11:05:55AM +0530, Abhishek SIngh Tomar wrote: > On Tue, Sep 13, 2022 at 12:27:24PM +0200, Christophe Lombard wrote: > > Last BMC firmware is available with a complete PLDM support on Rainier > > system. > > This patch allows initially to: > > - Initialize the MCTP core. > > - Enable the mctp binding over LPC bus interface and new wrappers to send > > and receive PLDM messages over the mctp library. > > - Retrieve all needed PLDM data. > > - "Virtualize" the content of a BMC flash based on lid files. > > > > Then, others mandatory support (watchdog, opal rtc, opal ipmi) are enabled. > > > > Signed-off-by: Christophe Lombard > Reviewed-by : Abhisheek Singh Tomar > > --- > > core/init.c | 29 ++++++++++++++++++++++++++--- > > core/pldm/pldm-mctp.c | 11 +++++++++++ > > include/pldm.h | 2 ++ > > platforms/astbmc/astbmc.h | 4 ++++ > > platforms/astbmc/common.c | 35 +++++++++++++++++++++++++++++++++++ > > platforms/astbmc/pnor.c | 25 +++++++++++++++++++++++++ > > platforms/qemu/qemu.c | 6 ++++++ > > 7 files changed, 109 insertions(+), 3 deletions(-) > > > > diff --git a/core/init.c b/core/init.c > > index 005ecf31..e32e87a8 100644 > > --- a/core/init.c > > +++ b/core/init.c > > @@ -34,6 +34,7 @@ > > #include > > #include > > #include > > +#include > > #include > > #include > > #include > > @@ -562,8 +563,15 @@ void __noreturn load_and_boot_kernel(bool is_reboot) > > > > trustedboot_exit_boot_services(); > > > > +#ifdef CONFIG_PLDM > > + if (pldm_present()) > > + pldm_platform_send_progress_state_change( > > + PLDM_STATE_SET_BOOT_PROG_STATE_STARTING_OP_SYS); > > + else > > + ipmi_set_fw_progress_sensor(IPMI_FW_OS_BOOT); > > +#else > > ipmi_set_fw_progress_sensor(IPMI_FW_OS_BOOT); > > - > > +#endif > > > > if (!is_reboot) { > > /* We wait for the nvram read to complete here so we can > > @@ -1410,10 +1418,25 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt) > > /* Setup ibm,firmware-versions if able */ > > if (platform.bmc) { > > flash_dt_add_fw_version(); > > - ipmi_dt_add_bmc_info(); > > +#ifdef CONFIG_PLDM > > + if (pldm_present()) > > + pldm_fru_dt_add_bmc_version(); > > + else > > + ipmi_dt_add_bmc_info(); > > +#else > > + ipmi_dt_add_bmc_info(); > > +#endif > > } > > > > - ipmi_set_fw_progress_sensor(IPMI_FW_PCI_INIT); > > +#ifdef CONFIG_PLDM > > + if (pldm_present()) > > + pldm_platform_send_progress_state_change( > > + PLDM_STATE_SET_BOOT_PROG_STATE_PCI_RESORUCE_CONFIG); > > + else > > + ipmi_set_fw_progress_sensor(IPMI_FW_PCI_INIT); > > +#else > > + ipmi_set_fw_progress_sensor(IPMI_FW_PCI_INIT); > > +#endif > > > > /* > > * These last few things must be done as late as possible > > diff --git a/core/pldm/pldm-mctp.c b/core/pldm/pldm-mctp.c > > index 1d1d1b37..972a23e5 100644 > > --- a/core/pldm/pldm-mctp.c > > +++ b/core/pldm/pldm-mctp.c > > @@ -10,6 +10,13 @@ > > #include > > #include "pldm.h" > > > > +bool pldm_enabled; > > + > > +bool pldm_present(void) > > +{ > > + return pldm_enabled; > > +} > > + > > /* > > * Print content of PLDM message in hex mode. > > * 15 bytes per line. > > @@ -139,6 +146,8 @@ int pldm_mctp_init(uint8_t mode) > > goto out; > > } > > > > + pldm_enabled = true; > > + > > /* Get PDRs data */ > > rc = pldm_platform_init(); > > if (rc) { > > @@ -172,6 +181,8 @@ out: > > > > void pldm_mctp_exit(void) > > { > > + pldm_enabled = false; > > + > > pldm_platform_exit(); > > > > ast_mctp_exit(); > > diff --git a/include/pldm.h b/include/pldm.h > > index cb9cee08..8aa14a4f 100644 > > --- a/include/pldm.h > > +++ b/include/pldm.h > > @@ -8,6 +8,8 @@ > > #include > > #include > > > > +bool pldm_present(void); > > + > > /** > > * PLDM over MCTP initialization > > */ > > diff --git a/platforms/astbmc/astbmc.h b/platforms/astbmc/astbmc.h > > index 00f22123..5d0509b8 100644 > > --- a/platforms/astbmc/astbmc.h > > +++ b/platforms/astbmc/astbmc.h > > @@ -96,6 +96,10 @@ extern const struct bmc_platform bmc_plat_ast2600_openbmc; > > extern void astbmc_early_init(void); > > extern int64_t astbmc_ipmi_reboot(void); > > extern int64_t astbmc_ipmi_power_down(uint64_t request); > > +#ifdef CONFIG_PLDM > > +extern int astbmc_pldm_init(uint8_t mode); > > +extern int pnor_pldm_init(void); > > +#endif > > extern void astbmc_init(void); > > extern void astbmc_ext_irq_serirq_cpld(unsigned int chip_id); > > extern int pnor_init(void); > > diff --git a/platforms/astbmc/common.c b/platforms/astbmc/common.c > > index 83ef70ad..e360a7bd 100644 > > --- a/platforms/astbmc/common.c > > +++ b/platforms/astbmc/common.c > > @@ -9,6 +9,7 @@ > > #include > > #include > > #include > > +#include > > #include > > #include > > #include > > @@ -104,6 +105,36 @@ static int astbmc_fru_init(void) > > return 0; > > } > > > > +#ifdef CONFIG_PLDM > > +int astbmc_pldm_init(uint8_t mode) > > +{ > > + int rc = OPAL_SUCCESS; > > + > > + /* PLDM over MCTP */ > > + rc = pldm_mctp_init(mode); > > + if (!rc) { > > + /* Initialize PNOR/NVRAM */ > > + rc = pnor_pldm_init(); > > + > > + if (!rc) { > > + pldm_watchdog_init(); > > + pldm_rtc_init(); > > + pldm_opal_init(); > > + } > > + } > > + > > + /* Initialize elog */ > > + elog_init(); > > + > > + /* Setup UART console for use by Linux via OPAL API */ > > + set_opal_console(&uart_opal_con); > > + > > + if (rc) > > + prlog(PR_WARNING, "Failed to configure PLDM\n"); > > + > > + return rc; > > +} > > +#endif > > > > void astbmc_init(void) > > { > > @@ -501,6 +532,10 @@ void astbmc_early_init(void) > > > > void astbmc_exit(void) > > { > > +#ifdef CONFIG_PLDM > > + if (pldm_present()) > > + return; > > +#endif > > ipmi_wdt_final_reset(); > > } > > > > diff --git a/platforms/astbmc/pnor.c b/platforms/astbmc/pnor.c > > index 64f2249d..853da467 100644 > > --- a/platforms/astbmc/pnor.c > > +++ b/platforms/astbmc/pnor.c > > @@ -5,6 +5,7 @@ > > #include > > #include > > #include > > +#include > > #include > > #include > > #include > > @@ -32,6 +33,30 @@ static enum ast_flash_style ast_flash_get_fallback_style(void) > > return raw_mem; > > } > > > > +#ifdef CONFIG_PLDM > > +int pnor_pldm_init(void) > > +{ > > + struct blocklevel_device *bl = NULL; > > + int rc = 0; > > + > > + rc = pldm_lid_files_init(&bl); > > + if (rc) { > > + prerror("PLAT: Failed to init PNOR driver\n"); > > + goto fail; > > + } > > + > > + rc = flash_register(bl); > > + if (!rc) > > + return 0; > > + > > +fail: > > + if (bl) > > + pldm_lid_files_exit(bl); > > + > > + return rc; > > +} > > +#endif > > + > > int pnor_init(void) > > { > > struct spi_flash_ctrl *pnor_ctrl = NULL; > > diff --git a/platforms/qemu/qemu.c b/platforms/qemu/qemu.c > > index 96153e85..81c5e5e1 100644 > > --- a/platforms/qemu/qemu.c > > +++ b/platforms/qemu/qemu.c > > @@ -4,6 +4,7 @@ > > #include > > #include > > #include > > +#include > > #include > > > > #include > > @@ -80,7 +81,12 @@ static void qemu_init(void) > > if (!bt_device_present) { > > set_opal_console(&uart_opal_con); > > } else { > > +#ifdef CONFIG_PLDM > > + /* need to be checked according platform: P10, P11 ... */ > > + astbmc_pldm_init(MCTP_BINDING_ASTLPC_MODE); > > +#else > > astbmc_init(); > > +#endif > > } > > } > > > > -- > > 2.37.3 > > > > _______________________________________________ > > Skiboot mailing list > > Skiboot at lists.ozlabs.org > > https://lists.ozlabs.org/listinfo/skiboot > _______________________________________________ > Skiboot mailing list > Skiboot at lists.ozlabs.org > https://lists.ozlabs.org/listinfo/skiboot From clombard at linux.vnet.ibm.com Thu Oct 27 20:25:44 2022 From: clombard at linux.vnet.ibm.com (Christophe Lombard) Date: Thu, 27 Oct 2022 11:25:44 +0200 Subject: [Skiboot] [PATCH V6 20/21] core/pldm: Add file io write request In-Reply-To: References: <20220913102705.65506-1-clombard@linux.vnet.ibm.com> <20220913102705.65506-21-clombard@linux.vnet.ibm.com> Message-ID: Le 30/09/2022 ? 08:27, Abhishek SIngh Tomar a ?crit?: > Hello Christophe > I am having some questions in this patch >> + >> + if ((offset) && (offset > size)) >> + return OPAL_PARAMETER; > Why is offset need to be lesser than size of buffer to write? Good catch ! The test is not correct. The good solution is: ??? if ((offset) && ((size + offset) > file_length)) ?? ???? return OPAL_PARAMETER; >> + >> + request_length = sizeof(struct pldm_msg_hdr) + >> + sizeof(struct pldm_write_file_req) + >> + size; > Why request payload is equal to size (size of buffer)? > The Maximum request payload needed when size > MAX_TRANSFER_SIZE_BYTES > is MAX_TRANSFER_SIZE_BYTES > request_length is the size of the complete PLDM request you send to the BMC. We need to add the size of the common header + the specific header + the size of lid file requested. >> + >> + for (i = 0; i < num_transfers; i++) { >> + file_req.offset = offset + (i * MAX_TRANSFER_SIZE_BYTES); >> + >> + /* Encode the file request */ >> + rc = encode_write_file_req( >> + DEFAULT_INSTANCE_ID, >> + file_req.file_handle, >> + file_req.offset, >> + file_req.length, >> + (struct pldm_msg *)request_msg); >> + if (rc != PLDM_SUCCESS) { >> + prlog(PR_ERR, "Encode WriteFileReq Error, rc: %d\n", rc); >> + free(request_msg); >> + return OPAL_PARAMETER; >> + } >> + >> + /* Send and get the response message bytes */ >> + rc = pldm_requester_queue_and_wait( >> + request_msg, request_length - 1, >> + &response_msg, &response_len); >> + if (rc) { >> + prlog(PR_ERR, "Communication Error, req: WriteFileReq, rc: %d\n", rc); >> + free(request_msg); >> + return rc; >> + } >> + >> + /* Decode the message */ >> + payload_len = response_len - sizeof(struct pldm_msg_hdr); >> + rc = decode_write_file_resp( >> + response_msg, >> + payload_len, >> + &completion_code, >> + &resp_length); >> + if (rc != PLDM_SUCCESS || completion_code != PLDM_SUCCESS) { >> + prlog(PR_ERR, "Decode WriteFileResp Error, rc: %d, cc: %d\n", >> + rc, completion_code); >> + free(request_msg); >> + free(response_msg); >> + return OPAL_PARAMETER; >> + } >> + >> + if (resp_length == 0) { >> + free(response_msg); >> + break; >> + } >> + >> + total_write += resp_length; >> + current_ptr += resp_length; >> + free(response_msg); >> + > In this loop, if size > MAX_TRANSFER_SIZE_BYTES, after sending > MAX_TRANSFER_SIZE_BYTES once how is payload pointer increasing? > I think we should copy current_ptr to request_msg payload You are right. Good point. >> + if (total_write == size) >> + break; >> + else if (resp_length != file_req.length) { >> + /* end of file */ >> + break; >> + } else if (MAX_TRANSFER_SIZE_BYTES > (size - total_write)) >> + file_req.length = size - total_write; >> + } >> + > Reviewed-by: Abhishek Singh Tomar From clombard at linux.vnet.ibm.com Thu Oct 27 20:38:16 2022 From: clombard at linux.vnet.ibm.com (Christophe Lombard) Date: Thu, 27 Oct 2022 11:38:16 +0200 Subject: [Skiboot] [PATCH V6 21/21] core/pldm: Get file handle and file length In-Reply-To: References: <20220913102705.65506-1-clombard@linux.vnet.ibm.com> <20220913102705.65506-22-clombard@linux.vnet.ibm.com> Message-ID: Le 30/09/2022 ? 14:12, Abhishek SIngh Tomar a ?crit?: >> + * Retrieve the file handle and file length from the file attribute >> + * table. >> + */ >> +static int find_file_handle_by_lid_id(const char *lid_id, > ... >> + file_entry = (struct pldm_file_attr_table_entry *)startptr; >> + >> + *file_handle = le32_to_cpu(file_entry->file_handle); >> + startptr += sizeof(uint32_t); >> + >> + file_name_length = le16_to_cpu(file_entry->file_name_length); >> + startptr += sizeof(file_name_length); >> + >> + if (!strncmp(startptr, lid_id, strlen(lid_id))) { >> + startptr += file_name_length; >> + *file_length = le32_to_cpu(*(uint32_t *)startptr); >> + break; >> + } > In above code we compare string using strncmp with n=strlen(lid_id) > This issue maybe rare or impossible to generate but > 1. if in some case lid_id is substring of strtptr > 2. if strtptr is smaller but comparision concatinate some bytes > from file_length which make two string equal > As there is no comparision between strlen(lid_id) and file_name_length > Adding comparision between two values can be good practice correct. We should compare the "lid_id" length and file_name_length Thanks. > Thanks > Reviewed-by: Abhishek Singh Tomar >