// SPDX-License-Identifier: GPL-2.0+ /* * Copyright 2020 SolidRun */ #include #include #include #include "tlv_data.h" #define SR_TLV_CODE_RAM_SIZE 0x81 static void store_product_name(struct tlvinfo_tlv *tlv_entry, struct tlv_data *td) { int len; char *dest; if (strlen(td->tlv_product_name[0]) == 0) dest = td->tlv_product_name[0]; else if (strlen(td->tlv_product_name[1]) == 0) dest = td->tlv_product_name[1]; else return; len = min_t(unsigned int, tlv_entry->length, sizeof(td->tlv_product_name[0]) - 1); memcpy(dest, tlv_entry->value, len); } static void parse_tlv_vendor_ext(struct tlvinfo_tlv *tlv_entry, struct tlv_data *td) { u8 *val = tlv_entry->value; u32 pen; /* IANA Private Enterprise Numbers */ if (tlv_entry->length < 5) /* 4 bytes PEN + at least 1 byte type */ return; /* PEN is big endian */ pen = (val[0] << 24) | (val[1] << 16) | (val[2] << 8) | val[3]; /* Not a real PEN */ if (pen != 0xffffffff) return; if (val[4] != SR_TLV_CODE_RAM_SIZE) return; if (tlv_entry->length < 6) return; td->ram_size = val[5]; /* extension with additional data field for number of ddr channels */ if (tlv_entry->length >= 7) { td->ram_channels = val[6]; } } static void parse_tlv_data(u8 *eeprom, struct tlvinfo_header *hdr, struct tlvinfo_tlv *entry, struct tlv_data *td) { unsigned int tlv_offset, tlv_len; tlv_offset = sizeof(struct tlvinfo_header); tlv_len = sizeof(struct tlvinfo_header) + be16_to_cpu(hdr->totallen); while (tlv_offset < tlv_len) { entry = (struct tlvinfo_tlv *)&eeprom[tlv_offset]; switch (entry->type) { case TLV_CODE_PRODUCT_NAME: store_product_name(entry, td); break; case TLV_CODE_VENDOR_EXT: parse_tlv_vendor_ext(entry, td); break; default: break; } tlv_offset += sizeof(struct tlvinfo_tlv) + entry->length; } } void read_tlv_data(struct tlv_data *td) { u8 eeprom_data[TLV_TOTAL_LEN_MAX]; struct tlvinfo_header *tlv_hdr; struct tlvinfo_tlv *tlv_entry; int ret, i; for (i = 0; i < 2; i++) { ret = read_tlvinfo_tlv_eeprom(eeprom_data, &tlv_hdr, &tlv_entry, i); if (ret < 0) continue; parse_tlv_data(eeprom_data, tlv_hdr, tlv_entry, td); } } bool sr_product_is(const struct tlv_data *td, const char *product) { /* Allow prefix sub-string match */ if (strncmp(td->tlv_product_name[0], product, strlen(product)) == 0) return true; if (strncmp(td->tlv_product_name[1], product, strlen(product)) == 0) return true; return false; }