| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * Support for atomisp driver sysfs interface |
| * |
| * Copyright (c) 2014 Intel Corporation. All Rights Reserved. |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License version |
| * 2 as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * |
| */ |
| |
| #include <linux/device.h> |
| #include <linux/err.h> |
| #include <linux/kernel.h> |
| |
| #include "atomisp_compat.h" |
| #include "atomisp_internal.h" |
| #include "atomisp_ioctl.h" |
| #include "atomisp_drvfs.h" |
| #include "hmm/hmm.h" |
| #include "ia_css_debug.h" |
| |
| /* |
| * _iunit_debug: |
| * dbglvl: iunit css driver trace level |
| * dbgopt: iunit debug option: |
| * bit 0: binary list |
| * bit 1: running binary |
| * bit 2: memory statistic |
| */ |
| struct _iunit_debug { |
| struct device_driver *drv; |
| struct atomisp_device *isp; |
| unsigned int dbglvl; |
| unsigned int dbgfun; |
| unsigned int dbgopt; |
| }; |
| |
| #define OPTION_BIN_LIST BIT(0) |
| #define OPTION_BIN_RUN BIT(1) |
| #define OPTION_VALID (OPTION_BIN_LIST \ |
| | OPTION_BIN_RUN) |
| |
| static struct _iunit_debug iunit_debug = { |
| .dbglvl = 0, |
| .dbgopt = OPTION_BIN_LIST, |
| }; |
| |
| static inline int iunit_dump_dbgopt(struct atomisp_device *isp, |
| unsigned int opt) |
| { |
| int ret = 0; |
| |
| if (opt & OPTION_VALID) { |
| if (opt & OPTION_BIN_LIST) { |
| ret = atomisp_css_dump_blob_infor(isp); |
| if (ret) { |
| dev_err(isp->dev, "%s dump blob infor err[ret:%d]\n", |
| __func__, ret); |
| goto opt_err; |
| } |
| } |
| |
| if (opt & OPTION_BIN_RUN) { |
| if (atomisp_streaming_count(isp)) { |
| atomisp_css_dump_sp_raw_copy_linecount(true); |
| atomisp_css_debug_dump_isp_binary(); |
| } else { |
| ret = -EPERM; |
| dev_err(isp->dev, "%s dump running bin err[ret:%d]\n", |
| __func__, ret); |
| goto opt_err; |
| } |
| } |
| } else { |
| ret = -EINVAL; |
| dev_err(isp->dev, "%s dump nothing[ret=%d]\n", __func__, ret); |
| } |
| |
| opt_err: |
| return ret; |
| } |
| |
| static ssize_t iunit_dbglvl_show(struct device_driver *drv, char *buf) |
| { |
| iunit_debug.dbglvl = dbg_level; |
| return sysfs_emit(buf, "dtrace level:%u\n", iunit_debug.dbglvl); |
| } |
| |
| static ssize_t iunit_dbglvl_store(struct device_driver *drv, const char *buf, |
| size_t size) |
| { |
| if (kstrtouint(buf, 10, &iunit_debug.dbglvl) |
| || iunit_debug.dbglvl < 1 |
| || iunit_debug.dbglvl > 9) { |
| return -ERANGE; |
| } |
| ia_css_debug_set_dtrace_level(iunit_debug.dbglvl); |
| |
| return size; |
| } |
| |
| static ssize_t iunit_dbgfun_show(struct device_driver *drv, char *buf) |
| { |
| iunit_debug.dbgfun = atomisp_get_css_dbgfunc(); |
| return sysfs_emit(buf, "dbgfun opt:%u\n", iunit_debug.dbgfun); |
| } |
| |
| static ssize_t iunit_dbgfun_store(struct device_driver *drv, const char *buf, |
| size_t size) |
| { |
| unsigned int opt; |
| int ret; |
| |
| ret = kstrtouint(buf, 10, &opt); |
| if (ret) |
| return ret; |
| |
| ret = atomisp_set_css_dbgfunc(iunit_debug.isp, opt); |
| if (ret) |
| return ret; |
| |
| iunit_debug.dbgfun = opt; |
| |
| return size; |
| } |
| |
| static ssize_t iunit_dbgopt_show(struct device_driver *drv, char *buf) |
| { |
| return sysfs_emit(buf, "option:0x%x\n", iunit_debug.dbgopt); |
| } |
| |
| static ssize_t iunit_dbgopt_store(struct device_driver *drv, const char *buf, |
| size_t size) |
| { |
| unsigned int opt; |
| int ret; |
| |
| ret = kstrtouint(buf, 10, &opt); |
| if (ret) |
| return ret; |
| |
| iunit_debug.dbgopt = opt; |
| ret = iunit_dump_dbgopt(iunit_debug.isp, iunit_debug.dbgopt); |
| if (ret) |
| return ret; |
| |
| return size; |
| } |
| |
| static const struct driver_attribute iunit_drvfs_attrs[] = { |
| __ATTR(dbglvl, 0644, iunit_dbglvl_show, iunit_dbglvl_store), |
| __ATTR(dbgfun, 0644, iunit_dbgfun_show, iunit_dbgfun_store), |
| __ATTR(dbgopt, 0644, iunit_dbgopt_show, iunit_dbgopt_store), |
| }; |
| |
| static int iunit_drvfs_create_files(struct device_driver *drv) |
| { |
| int i, ret = 0; |
| |
| for (i = 0; i < ARRAY_SIZE(iunit_drvfs_attrs); i++) |
| ret |= driver_create_file(drv, &iunit_drvfs_attrs[i]); |
| |
| return ret; |
| } |
| |
| static void iunit_drvfs_remove_files(struct device_driver *drv) |
| { |
| int i; |
| |
| for (i = 0; i < ARRAY_SIZE(iunit_drvfs_attrs); i++) |
| driver_remove_file(drv, &iunit_drvfs_attrs[i]); |
| } |
| |
| int atomisp_drvfs_init(struct atomisp_device *isp) |
| { |
| struct device_driver *drv = isp->dev->driver; |
| int ret; |
| |
| iunit_debug.isp = isp; |
| iunit_debug.drv = drv; |
| |
| ret = iunit_drvfs_create_files(iunit_debug.drv); |
| if (ret) { |
| dev_err(isp->dev, "drvfs_create_files error: %d\n", ret); |
| iunit_drvfs_remove_files(iunit_debug.drv); |
| } |
| |
| return ret; |
| } |
| |
| void atomisp_drvfs_exit(void) |
| { |
| iunit_drvfs_remove_files(iunit_debug.drv); |
| } |