561 lines · c
1// SPDX-License-Identifier: GPL-2.02 3/*4 * Copyright 2016-2022 HabanaLabs, Ltd.5 * All Rights Reserved.6 */7 8#include "habanalabs.h"9 10#include <linux/pci.h>11#include <linux/types.h>12 13static ssize_t clk_max_freq_mhz_show(struct device *dev, struct device_attribute *attr, char *buf)14{15 struct hl_device *hdev = dev_get_drvdata(dev);16 long value;17 18 if (!hl_device_operational(hdev, NULL))19 return -ENODEV;20 21 value = hl_fw_get_frequency(hdev, hdev->asic_prop.clk_pll_index, false);22 if (value < 0)23 return value;24 25 hdev->asic_prop.max_freq_value = value;26 27 return sprintf(buf, "%lu\n", (value / 1000 / 1000));28}29 30static ssize_t clk_max_freq_mhz_store(struct device *dev, struct device_attribute *attr,31 const char *buf, size_t count)32{33 struct hl_device *hdev = dev_get_drvdata(dev);34 int rc;35 u64 value;36 37 if (!hl_device_operational(hdev, NULL)) {38 count = -ENODEV;39 goto fail;40 }41 42 rc = kstrtoull(buf, 0, &value);43 if (rc) {44 count = -EINVAL;45 goto fail;46 }47 48 hdev->asic_prop.max_freq_value = value * 1000 * 1000;49 50 hl_fw_set_frequency(hdev, hdev->asic_prop.clk_pll_index, hdev->asic_prop.max_freq_value);51 52fail:53 return count;54}55 56static ssize_t clk_cur_freq_mhz_show(struct device *dev, struct device_attribute *attr, char *buf)57{58 struct hl_device *hdev = dev_get_drvdata(dev);59 long value;60 61 if (!hl_device_operational(hdev, NULL))62 return -ENODEV;63 64 value = hl_fw_get_frequency(hdev, hdev->asic_prop.clk_pll_index, true);65 if (value < 0)66 return value;67 68 return sprintf(buf, "%lu\n", (value / 1000 / 1000));69}70 71static DEVICE_ATTR_RW(clk_max_freq_mhz);72static DEVICE_ATTR_RO(clk_cur_freq_mhz);73 74static struct attribute *hl_dev_clk_attrs[] = {75 &dev_attr_clk_max_freq_mhz.attr,76 &dev_attr_clk_cur_freq_mhz.attr,77 NULL,78};79 80static ssize_t vrm_ver_show(struct device *dev, struct device_attribute *attr, char *buf)81{82 struct hl_device *hdev = dev_get_drvdata(dev);83 struct cpucp_info *cpucp_info;84 u32 infineon_second_stage_version;85 u32 infineon_second_stage_first_instance;86 u32 infineon_second_stage_second_instance;87 u32 infineon_second_stage_third_instance;88 u32 mask = 0xff;89 90 cpucp_info = &hdev->asic_prop.cpucp_info;91 92 infineon_second_stage_version = le32_to_cpu(cpucp_info->infineon_second_stage_version);93 infineon_second_stage_first_instance = infineon_second_stage_version & mask;94 infineon_second_stage_second_instance =95 (infineon_second_stage_version >> 8) & mask;96 infineon_second_stage_third_instance =97 (infineon_second_stage_version >> 16) & mask;98 99 if (cpucp_info->infineon_second_stage_version)100 return sprintf(buf, "%#04x %#04x:%#04x:%#04x\n",101 le32_to_cpu(cpucp_info->infineon_version),102 infineon_second_stage_first_instance,103 infineon_second_stage_second_instance,104 infineon_second_stage_third_instance);105 else106 return sprintf(buf, "%#04x\n", le32_to_cpu(cpucp_info->infineon_version));107}108 109static DEVICE_ATTR_RO(vrm_ver);110 111static struct attribute *hl_dev_vrm_attrs[] = {112 &dev_attr_vrm_ver.attr,113 NULL,114};115 116static ssize_t uboot_ver_show(struct device *dev, struct device_attribute *attr,117 char *buf)118{119 struct hl_device *hdev = dev_get_drvdata(dev);120 121 return sprintf(buf, "%s\n", hdev->asic_prop.uboot_ver);122}123 124static ssize_t armcp_kernel_ver_show(struct device *dev,125 struct device_attribute *attr, char *buf)126{127 struct hl_device *hdev = dev_get_drvdata(dev);128 129 return sprintf(buf, "%s", hdev->asic_prop.cpucp_info.kernel_version);130}131 132static ssize_t armcp_ver_show(struct device *dev, struct device_attribute *attr,133 char *buf)134{135 struct hl_device *hdev = dev_get_drvdata(dev);136 137 return sprintf(buf, "%s\n", hdev->asic_prop.cpucp_info.cpucp_version);138}139 140static ssize_t cpld_ver_show(struct device *dev, struct device_attribute *attr,141 char *buf)142{143 struct hl_device *hdev = dev_get_drvdata(dev);144 145 return sprintf(buf, "0x%08x%08x\n",146 le32_to_cpu(hdev->asic_prop.cpucp_info.cpld_timestamp),147 le32_to_cpu(hdev->asic_prop.cpucp_info.cpld_version));148}149 150static ssize_t cpucp_kernel_ver_show(struct device *dev,151 struct device_attribute *attr, char *buf)152{153 struct hl_device *hdev = dev_get_drvdata(dev);154 155 return sprintf(buf, "%s", hdev->asic_prop.cpucp_info.kernel_version);156}157 158static ssize_t cpucp_ver_show(struct device *dev, struct device_attribute *attr,159 char *buf)160{161 struct hl_device *hdev = dev_get_drvdata(dev);162 163 return sprintf(buf, "%s\n", hdev->asic_prop.cpucp_info.cpucp_version);164}165 166static ssize_t fuse_ver_show(struct device *dev, struct device_attribute *attr,167 char *buf)168{169 struct hl_device *hdev = dev_get_drvdata(dev);170 171 return sprintf(buf, "%s\n", hdev->asic_prop.cpucp_info.fuse_version);172}173 174static ssize_t thermal_ver_show(struct device *dev,175 struct device_attribute *attr, char *buf)176{177 struct hl_device *hdev = dev_get_drvdata(dev);178 179 return sprintf(buf, "%s", hdev->asic_prop.cpucp_info.thermal_version);180}181 182static ssize_t fw_os_ver_show(struct device *dev,183 struct device_attribute *attr, char *buf)184{185 struct hl_device *hdev = dev_get_drvdata(dev);186 187 return sprintf(buf, "%s", hdev->asic_prop.cpucp_info.fw_os_version);188}189 190static ssize_t preboot_btl_ver_show(struct device *dev,191 struct device_attribute *attr, char *buf)192{193 struct hl_device *hdev = dev_get_drvdata(dev);194 195 return sprintf(buf, "%s\n", hdev->asic_prop.preboot_ver);196}197 198static ssize_t soft_reset_store(struct device *dev,199 struct device_attribute *attr, const char *buf,200 size_t count)201{202 struct hl_device *hdev = dev_get_drvdata(dev);203 long value;204 int rc;205 206 rc = kstrtoul(buf, 0, &value);207 208 if (rc) {209 count = -EINVAL;210 goto out;211 }212 213 if (!hdev->asic_prop.allow_inference_soft_reset) {214 dev_err(hdev->dev, "Device does not support inference soft-reset\n");215 goto out;216 }217 218 dev_warn(hdev->dev, "Inference Soft-Reset requested through sysfs\n");219 220 hl_device_reset(hdev, 0);221 222out:223 return count;224}225 226static ssize_t hard_reset_store(struct device *dev,227 struct device_attribute *attr,228 const char *buf, size_t count)229{230 struct hl_device *hdev = dev_get_drvdata(dev);231 long value;232 int rc;233 234 rc = kstrtoul(buf, 0, &value);235 236 if (rc) {237 count = -EINVAL;238 goto out;239 }240 241 dev_warn(hdev->dev, "Hard-Reset requested through sysfs\n");242 243 hl_device_reset(hdev, HL_DRV_RESET_HARD);244 245out:246 return count;247}248 249static ssize_t device_type_show(struct device *dev,250 struct device_attribute *attr, char *buf)251{252 struct hl_device *hdev = dev_get_drvdata(dev);253 char *str;254 255 switch (hdev->asic_type) {256 case ASIC_GOYA:257 str = "GOYA";258 break;259 case ASIC_GAUDI:260 str = "GAUDI";261 break;262 case ASIC_GAUDI_SEC:263 str = "GAUDI SEC";264 break;265 case ASIC_GAUDI2:266 str = "GAUDI2";267 break;268 case ASIC_GAUDI2B:269 str = "GAUDI2B";270 break;271 case ASIC_GAUDI2C:272 str = "GAUDI2C";273 break;274 case ASIC_GAUDI2D:275 str = "GAUDI2D";276 break;277 default:278 dev_err(hdev->dev, "Unrecognized ASIC type %d\n",279 hdev->asic_type);280 return -EINVAL;281 }282 283 return sprintf(buf, "%s\n", str);284}285 286static ssize_t pci_addr_show(struct device *dev, struct device_attribute *attr,287 char *buf)288{289 struct hl_device *hdev = dev_get_drvdata(dev);290 291 return sprintf(buf, "%04x:%02x:%02x.%x\n",292 pci_domain_nr(hdev->pdev->bus),293 hdev->pdev->bus->number,294 PCI_SLOT(hdev->pdev->devfn),295 PCI_FUNC(hdev->pdev->devfn));296}297 298static ssize_t status_show(struct device *dev, struct device_attribute *attr,299 char *buf)300{301 struct hl_device *hdev = dev_get_drvdata(dev);302 char str[HL_STR_MAX];303 304 strscpy(str, hdev->status[hl_device_status(hdev)], HL_STR_MAX);305 306 /* use uppercase for backward compatibility */307 str[0] = 'A' + (str[0] - 'a');308 309 return sprintf(buf, "%s\n", str);310}311 312static ssize_t soft_reset_cnt_show(struct device *dev,313 struct device_attribute *attr, char *buf)314{315 struct hl_device *hdev = dev_get_drvdata(dev);316 317 return sprintf(buf, "%d\n", hdev->reset_info.compute_reset_cnt);318}319 320static ssize_t hard_reset_cnt_show(struct device *dev,321 struct device_attribute *attr, char *buf)322{323 struct hl_device *hdev = dev_get_drvdata(dev);324 325 return sprintf(buf, "%d\n", hdev->reset_info.hard_reset_cnt);326}327 328static ssize_t max_power_show(struct device *dev, struct device_attribute *attr,329 char *buf)330{331 struct hl_device *hdev = dev_get_drvdata(dev);332 long val;333 334 if (!hl_device_operational(hdev, NULL))335 return -ENODEV;336 337 val = hl_fw_get_max_power(hdev);338 if (val < 0)339 return val;340 341 return sprintf(buf, "%lu\n", val);342}343 344static ssize_t max_power_store(struct device *dev,345 struct device_attribute *attr, const char *buf, size_t count)346{347 struct hl_device *hdev = dev_get_drvdata(dev);348 unsigned long value;349 int rc;350 351 if (!hl_device_operational(hdev, NULL)) {352 count = -ENODEV;353 goto out;354 }355 356 rc = kstrtoul(buf, 0, &value);357 358 if (rc) {359 count = -EINVAL;360 goto out;361 }362 363 hdev->max_power = value;364 hl_fw_set_max_power(hdev);365 366out:367 return count;368}369 370static ssize_t eeprom_read_handler(struct file *filp, struct kobject *kobj,371 struct bin_attribute *attr, char *buf, loff_t offset,372 size_t max_size)373{374 struct device *dev = kobj_to_dev(kobj);375 struct hl_device *hdev = dev_get_drvdata(dev);376 char *data;377 int rc;378 379 if (!hl_device_operational(hdev, NULL))380 return -ENODEV;381 382 if (!max_size)383 return -EINVAL;384 385 data = kzalloc(max_size, GFP_KERNEL);386 if (!data)387 return -ENOMEM;388 389 rc = hdev->asic_funcs->get_eeprom_data(hdev, data, max_size);390 if (rc)391 goto out;392 393 memcpy(buf, data, max_size);394 395out:396 kfree(data);397 398 return max_size;399}400 401static ssize_t security_enabled_show(struct device *dev,402 struct device_attribute *attr, char *buf)403{404 struct hl_device *hdev = dev_get_drvdata(dev);405 406 return sprintf(buf, "%d\n", hdev->asic_prop.fw_security_enabled);407}408 409static ssize_t module_id_show(struct device *dev,410 struct device_attribute *attr, char *buf)411{412 struct hl_device *hdev = dev_get_drvdata(dev);413 414 return sprintf(buf, "%u\n", le32_to_cpu(hdev->asic_prop.cpucp_info.card_location));415}416 417static ssize_t parent_device_show(struct device *dev, struct device_attribute *attr, char *buf)418{419 struct hl_device *hdev = dev_get_drvdata(dev);420 421 return sprintf(buf, "%s\n", HL_DEV_NAME(hdev));422}423 424static DEVICE_ATTR_RO(armcp_kernel_ver);425static DEVICE_ATTR_RO(armcp_ver);426static DEVICE_ATTR_RO(cpld_ver);427static DEVICE_ATTR_RO(cpucp_kernel_ver);428static DEVICE_ATTR_RO(cpucp_ver);429static DEVICE_ATTR_RO(device_type);430static DEVICE_ATTR_RO(fuse_ver);431static DEVICE_ATTR_WO(hard_reset);432static DEVICE_ATTR_RO(hard_reset_cnt);433static DEVICE_ATTR_RW(max_power);434static DEVICE_ATTR_RO(pci_addr);435static DEVICE_ATTR_RO(preboot_btl_ver);436static DEVICE_ATTR_WO(soft_reset);437static DEVICE_ATTR_RO(soft_reset_cnt);438static DEVICE_ATTR_RO(status);439static DEVICE_ATTR_RO(thermal_ver);440static DEVICE_ATTR_RO(uboot_ver);441static DEVICE_ATTR_RO(fw_os_ver);442static DEVICE_ATTR_RO(security_enabled);443static DEVICE_ATTR_RO(module_id);444static DEVICE_ATTR_RO(parent_device);445 446static struct bin_attribute bin_attr_eeprom = {447 .attr = {.name = "eeprom", .mode = (0444)},448 .size = PAGE_SIZE,449 .read = eeprom_read_handler450};451 452static struct attribute *hl_dev_attrs[] = {453 &dev_attr_armcp_kernel_ver.attr,454 &dev_attr_armcp_ver.attr,455 &dev_attr_cpld_ver.attr,456 &dev_attr_cpucp_kernel_ver.attr,457 &dev_attr_cpucp_ver.attr,458 &dev_attr_device_type.attr,459 &dev_attr_fuse_ver.attr,460 &dev_attr_hard_reset.attr,461 &dev_attr_hard_reset_cnt.attr,462 &dev_attr_max_power.attr,463 &dev_attr_pci_addr.attr,464 &dev_attr_preboot_btl_ver.attr,465 &dev_attr_status.attr,466 &dev_attr_thermal_ver.attr,467 &dev_attr_uboot_ver.attr,468 &dev_attr_fw_os_ver.attr,469 &dev_attr_security_enabled.attr,470 &dev_attr_module_id.attr,471 &dev_attr_parent_device.attr,472 NULL,473};474 475static struct bin_attribute *hl_dev_bin_attrs[] = {476 &bin_attr_eeprom,477 NULL478};479 480static struct attribute_group hl_dev_attr_group = {481 .attrs = hl_dev_attrs,482 .bin_attrs = hl_dev_bin_attrs,483};484 485static struct attribute_group hl_dev_clks_attr_group;486static struct attribute_group hl_dev_vrm_attr_group;487 488static const struct attribute_group *hl_dev_attr_groups[] = {489 &hl_dev_attr_group,490 &hl_dev_clks_attr_group,491 &hl_dev_vrm_attr_group,492 NULL,493};494 495static struct attribute *hl_dev_inference_attrs[] = {496 &dev_attr_soft_reset.attr,497 &dev_attr_soft_reset_cnt.attr,498 NULL,499};500 501static struct attribute_group hl_dev_inference_attr_group = {502 .attrs = hl_dev_inference_attrs,503};504 505static const struct attribute_group *hl_dev_inference_attr_groups[] = {506 &hl_dev_inference_attr_group,507 NULL,508};509 510void hl_sysfs_add_dev_clk_attr(struct hl_device *hdev, struct attribute_group *dev_clk_attr_grp)511{512 dev_clk_attr_grp->attrs = hl_dev_clk_attrs;513}514 515void hl_sysfs_add_dev_vrm_attr(struct hl_device *hdev, struct attribute_group *dev_vrm_attr_grp)516{517 dev_vrm_attr_grp->attrs = hl_dev_vrm_attrs;518}519 520int hl_sysfs_init(struct hl_device *hdev)521{522 int rc;523 524 hdev->max_power = hdev->asic_prop.max_power_default;525 526 hdev->asic_funcs->add_device_attr(hdev, &hl_dev_clks_attr_group, &hl_dev_vrm_attr_group);527 528 rc = device_add_groups(hdev->dev, hl_dev_attr_groups);529 if (rc) {530 dev_err(hdev->dev,531 "Failed to add groups to device, error %d\n", rc);532 return rc;533 }534 535 if (!hdev->asic_prop.allow_inference_soft_reset)536 return 0;537 538 rc = device_add_groups(hdev->dev, hl_dev_inference_attr_groups);539 if (rc) {540 dev_err(hdev->dev,541 "Failed to add groups to device, error %d\n", rc);542 goto remove_groups;543 }544 545 return 0;546 547remove_groups:548 device_remove_groups(hdev->dev, hl_dev_attr_groups);549 return rc;550}551 552void hl_sysfs_fini(struct hl_device *hdev)553{554 device_remove_groups(hdev->dev, hl_dev_attr_groups);555 556 if (!hdev->asic_prop.allow_inference_soft_reset)557 return;558 559 device_remove_groups(hdev->dev, hl_dev_inference_attr_groups);560}561