diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 17:40:19 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 17:40:19 +0000 |
commit | 9f0fc191371843c4fc000a226b0a26b6c059aacd (patch) | |
tree | 35f8be3ef04506ac891ad001e8c41e535ae8d01d /drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c | |
parent | Releasing progress-linux version 6.6.15-2~progress7.99u1. (diff) | |
download | linux-9f0fc191371843c4fc000a226b0a26b6c059aacd.tar.xz linux-9f0fc191371843c4fc000a226b0a26b6c059aacd.zip |
Merging upstream version 6.7.7.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c')
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c | 166 |
1 files changed, 126 insertions, 40 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c index 7cd0dfaeee..a08c148b13 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fru_eeprom.c @@ -42,8 +42,9 @@ static bool is_fru_eeprom_supported(struct amdgpu_device *adev, u32 *fru_addr) /* The i2c access is blocked on VF * TODO: Need other way to get the info + * Also, FRU not valid for APU devices. */ - if (amdgpu_sriov_vf(adev)) + if (amdgpu_sriov_vf(adev) || (adev->flags & AMD_IS_APU)) return false; /* The default I2C EEPROM address of the FRU. @@ -57,27 +58,26 @@ static bool is_fru_eeprom_supported(struct amdgpu_device *adev, u32 *fru_addr) * for ease/speed/readability. For now, 2 string comparisons are * reasonable and not too expensive */ - switch (adev->asic_type) { - case CHIP_VEGA20: - /* D161 and D163 are the VG20 server SKUs */ - if (strnstr(atom_ctx->vbios_pn, "D161", - sizeof(atom_ctx->vbios_pn)) || - strnstr(atom_ctx->vbios_pn, "D163", - sizeof(atom_ctx->vbios_pn))) { - if (fru_addr) - *fru_addr = FRU_EEPROM_MADDR_6; - return true; - } else { + switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { + case IP_VERSION(11, 0, 2): + switch (adev->asic_type) { + case CHIP_VEGA20: + /* D161 and D163 are the VG20 server SKUs */ + if (strnstr(atom_ctx->vbios_pn, "D161", + sizeof(atom_ctx->vbios_pn)) || + strnstr(atom_ctx->vbios_pn, "D163", + sizeof(atom_ctx->vbios_pn))) { + if (fru_addr) + *fru_addr = FRU_EEPROM_MADDR_6; + return true; + } else { + return false; + } + case CHIP_ARCTURUS: + default: return false; } - case CHIP_ALDEBARAN: - /* All Aldebaran SKUs have an FRU */ - if (!strnstr(atom_ctx->vbios_pn, "D673", - sizeof(atom_ctx->vbios_pn))) - if (fru_addr) - *fru_addr = FRU_EEPROM_MADDR_6; - return true; - case CHIP_SIENNA_CICHLID: + case IP_VERSION(11, 0, 7): if (strnstr(atom_ctx->vbios_pn, "D603", sizeof(atom_ctx->vbios_pn))) { if (strnstr(atom_ctx->vbios_pn, "D603GLXE", @@ -92,6 +92,17 @@ static bool is_fru_eeprom_supported(struct amdgpu_device *adev, u32 *fru_addr) } else { return false; } + case IP_VERSION(13, 0, 2): + /* All Aldebaran SKUs have an FRU */ + if (!strnstr(atom_ctx->vbios_pn, "D673", + sizeof(atom_ctx->vbios_pn))) + if (fru_addr) + *fru_addr = FRU_EEPROM_MADDR_6; + return true; + case IP_VERSION(13, 0, 6): + if (fru_addr) + *fru_addr = FRU_EEPROM_MADDR_8; + return true; default: return false; } @@ -99,6 +110,7 @@ static bool is_fru_eeprom_supported(struct amdgpu_device *adev, u32 *fru_addr) int amdgpu_fru_get_product_info(struct amdgpu_device *adev) { + struct amdgpu_fru_info *fru_info; unsigned char buf[8], *pia; u32 addr, fru_addr; int size, len; @@ -107,6 +119,19 @@ int amdgpu_fru_get_product_info(struct amdgpu_device *adev) if (!is_fru_eeprom_supported(adev, &fru_addr)) return 0; + if (!adev->fru_info) { + adev->fru_info = kzalloc(sizeof(*adev->fru_info), GFP_KERNEL); + if (!adev->fru_info) + return -ENOMEM; + } + + fru_info = adev->fru_info; + /* For Arcturus-and-later, default value of serial_number is unique_id + * so convert it to a 16-digit HEX string for convenience and + * backwards-compatibility. + */ + sprintf(fru_info->serial, "%llx", adev->unique_id); + /* If algo exists, it means that the i2c_adapter's initialized */ if (!adev->pm.fru_eeprom_i2c_bus || !adev->pm.fru_eeprom_i2c_bus->algo) { DRM_WARN("Cannot access FRU, EEPROM accessor not initialized"); @@ -176,27 +201,33 @@ int amdgpu_fru_get_product_info(struct amdgpu_device *adev) /* Now extract useful information from the PIA. * - * Skip the Manufacturer Name at [3] and go directly to - * the Product Name field. + * Read Manufacturer Name field whose length is [3]. */ - addr = 3 + 1 + (pia[3] & 0x3F); + addr = 3; if (addr + 1 >= len) goto Out; - memcpy(adev->product_name, pia + addr + 1, - min_t(size_t, - sizeof(adev->product_name), + memcpy(fru_info->manufacturer_name, pia + addr + 1, + min_t(size_t, sizeof(fru_info->manufacturer_name), pia[addr] & 0x3F)); - adev->product_name[sizeof(adev->product_name) - 1] = '\0'; + fru_info->manufacturer_name[sizeof(fru_info->manufacturer_name) - 1] = + '\0'; + + /* Read Product Name field. */ + addr += 1 + (pia[addr] & 0x3F); + if (addr + 1 >= len) + goto Out; + memcpy(fru_info->product_name, pia + addr + 1, + min_t(size_t, sizeof(fru_info->product_name), pia[addr] & 0x3F)); + fru_info->product_name[sizeof(fru_info->product_name) - 1] = '\0'; /* Go to the Product Part/Model Number field. */ addr += 1 + (pia[addr] & 0x3F); if (addr + 1 >= len) goto Out; - memcpy(adev->product_number, pia + addr + 1, - min_t(size_t, - sizeof(adev->product_number), + memcpy(fru_info->product_number, pia + addr + 1, + min_t(size_t, sizeof(fru_info->product_number), pia[addr] & 0x3F)); - adev->product_number[sizeof(adev->product_number) - 1] = '\0'; + fru_info->product_number[sizeof(fru_info->product_number) - 1] = '\0'; /* Go to the Product Version field. */ addr += 1 + (pia[addr] & 0x3F); @@ -205,10 +236,21 @@ int amdgpu_fru_get_product_info(struct amdgpu_device *adev) addr += 1 + (pia[addr] & 0x3F); if (addr + 1 >= len) goto Out; - memcpy(adev->serial, pia + addr + 1, min_t(size_t, - sizeof(adev->serial), - pia[addr] & 0x3F)); - adev->serial[sizeof(adev->serial) - 1] = '\0'; + memcpy(fru_info->serial, pia + addr + 1, + min_t(size_t, sizeof(fru_info->serial), pia[addr] & 0x3F)); + fru_info->serial[sizeof(fru_info->serial) - 1] = '\0'; + + /* Asset Tag field */ + addr += 1 + (pia[addr] & 0x3F); + + /* FRU File Id field. This could be 'null'. */ + addr += 1 + (pia[addr] & 0x3F); + if ((addr + 1 >= len) || !(pia[addr] & 0x3F)) + goto Out; + memcpy(fru_info->fru_id, pia + addr + 1, + min_t(size_t, sizeof(fru_info->fru_id), pia[addr] & 0x3F)); + fru_info->fru_id[sizeof(fru_info->fru_id) - 1] = '\0'; + Out: kfree(pia); return 0; @@ -231,7 +273,7 @@ static ssize_t amdgpu_fru_product_name_show(struct device *dev, struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); - return sysfs_emit(buf, "%s\n", adev->product_name); + return sysfs_emit(buf, "%s\n", adev->fru_info->product_name); } static DEVICE_ATTR(product_name, 0444, amdgpu_fru_product_name_show, NULL); @@ -253,7 +295,7 @@ static ssize_t amdgpu_fru_product_number_show(struct device *dev, struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); - return sysfs_emit(buf, "%s\n", adev->product_number); + return sysfs_emit(buf, "%s\n", adev->fru_info->product_number); } static DEVICE_ATTR(product_number, 0444, amdgpu_fru_product_number_show, NULL); @@ -275,21 +317,65 @@ static ssize_t amdgpu_fru_serial_number_show(struct device *dev, struct drm_device *ddev = dev_get_drvdata(dev); struct amdgpu_device *adev = drm_to_adev(ddev); - return sysfs_emit(buf, "%s\n", adev->serial); + return sysfs_emit(buf, "%s\n", adev->fru_info->serial); } static DEVICE_ATTR(serial_number, 0444, amdgpu_fru_serial_number_show, NULL); +/** + * DOC: fru_id + * + * The amdgpu driver provides a sysfs API for reporting FRU File Id + * for the device. + * The file fru_id is used for this and returns the File Id value + * as returned from the FRU. + * NOTE: This is only available for certain server cards + */ + +static ssize_t amdgpu_fru_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + + return sysfs_emit(buf, "%s\n", adev->fru_info->fru_id); +} + +static DEVICE_ATTR(fru_id, 0444, amdgpu_fru_id_show, NULL); + +/** + * DOC: manufacturer + * + * The amdgpu driver provides a sysfs API for reporting manufacturer name from + * FRU information. + * The file manufacturer returns the value as returned from the FRU. + * NOTE: This is only available for certain server cards + */ + +static ssize_t amdgpu_fru_manufacturer_name_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + + return sysfs_emit(buf, "%s\n", adev->fru_info->manufacturer_name); +} + +static DEVICE_ATTR(manufacturer, 0444, amdgpu_fru_manufacturer_name_show, NULL); + static const struct attribute *amdgpu_fru_attributes[] = { &dev_attr_product_name.attr, &dev_attr_product_number.attr, &dev_attr_serial_number.attr, + &dev_attr_fru_id.attr, + &dev_attr_manufacturer.attr, NULL }; int amdgpu_fru_sysfs_init(struct amdgpu_device *adev) { - if (!is_fru_eeprom_supported(adev, NULL)) + if (!is_fru_eeprom_supported(adev, NULL) || !adev->fru_info) return 0; return sysfs_create_files(&adev->dev->kobj, amdgpu_fru_attributes); @@ -297,7 +383,7 @@ int amdgpu_fru_sysfs_init(struct amdgpu_device *adev) void amdgpu_fru_sysfs_fini(struct amdgpu_device *adev) { - if (!is_fru_eeprom_supported(adev, NULL)) + if (!is_fru_eeprom_supported(adev, NULL) || !adev->fru_info) return; sysfs_remove_files(&adev->dev->kobj, amdgpu_fru_attributes); |