/* * FPGA Manager DebugFS * * Copyright (C) 2016 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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. * * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ #include #include #include #include #if IS_ENABLED(CONFIG_FPGA_MGR_DEBUG_FS) static struct dentry *fpga_mgr_debugfs_root; struct fpga_mgr_debugfs { struct dentry *debugfs_dir; struct fpga_image_info *info; }; static ssize_t fpga_mgr_firmware_write_file(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct fpga_manager *mgr = file->private_data; struct fpga_mgr_debugfs *debugfs = mgr->debugfs; char *buf; int ret; ret = fpga_mgr_lock(mgr); if (ret) { dev_err(&mgr->dev, "FPGA manager is busy\n"); return -EBUSY; } buf = devm_kzalloc(&mgr->dev, count, GFP_KERNEL); if (!buf) { fpga_mgr_unlock(mgr); return -ENOMEM; } if (copy_from_user(buf, user_buf, count)) { fpga_mgr_unlock(mgr); devm_kfree(&mgr->dev, buf); return -EFAULT; } buf[count] = 0; if (buf[count - 1] == '\n') buf[count - 1] = 0; /* Release previous firmware name (if any). Save current one. */ if (debugfs->info->firmware_name) devm_kfree(&mgr->dev, debugfs->info->firmware_name); debugfs->info->firmware_name = buf; ret = fpga_mgr_load(mgr, debugfs->info); if (ret) dev_err(&mgr->dev, "fpga_mgr_load returned with value %d\n", ret); fpga_mgr_unlock(mgr); return count; } static ssize_t fpga_mgr_firmware_read_file(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct fpga_manager *mgr = file->private_data; struct fpga_mgr_debugfs *debugfs = mgr->debugfs; char *buf; int ret; if (!debugfs->info->firmware_name) return 0; buf = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!buf) return -ENOMEM; ret = snprintf(buf, PAGE_SIZE, "%s\n", debugfs->info->firmware_name); if (ret < 0) { kfree(buf); return ret; } ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); kfree(buf); return ret; } static const struct file_operations fpga_mgr_firmware_fops = { .open = simple_open, .read = fpga_mgr_firmware_read_file, .write = fpga_mgr_firmware_write_file, .llseek = default_llseek, }; static ssize_t fpga_mgr_image_write_file(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct fpga_manager *mgr = file->private_data; struct fpga_mgr_debugfs *debugfs = mgr->debugfs; char *buf; int ret; dev_info(&mgr->dev, "writing %zu bytes to %s\n", count, mgr->name); ret = fpga_mgr_lock(mgr); if (ret) { dev_err(&mgr->dev, "FPGA manager is busy\n"); return -EBUSY; } buf = kzalloc(count, GFP_KERNEL); if (!buf) { fpga_mgr_unlock(mgr); return -ENOMEM; } if (copy_from_user(buf, user_buf, count)) { fpga_mgr_unlock(mgr); kfree(buf); return -EFAULT; } /* If firmware interface was previously used, forget it. */ if (debugfs->info->firmware_name) devm_kfree(&mgr->dev, debugfs->info->firmware_name); debugfs->info->firmware_name = NULL; debugfs->info->buf = buf; debugfs->info->count = count; ret = fpga_mgr_load(mgr, debugfs->info); if (ret) dev_err(&mgr->dev, "fpga_mgr_buf_load returned with value %d\n", ret); fpga_mgr_unlock(mgr); debugfs->info->buf = NULL; debugfs->info->count = 0; kfree(buf); return count; } static const struct file_operations fpga_mgr_image_fops = { .open = simple_open, .write = fpga_mgr_image_write_file, .llseek = default_llseek, }; void fpga_mgr_debugfs_add(struct fpga_manager *mgr) { struct fpga_mgr_debugfs *debugfs; struct fpga_image_info *info; if (!fpga_mgr_debugfs_root) return; debugfs = kzalloc(sizeof(*debugfs), GFP_KERNEL); if (!debugfs) return; info = fpga_image_info_alloc(&mgr->dev); if (!info) { kfree(debugfs); return; } debugfs->info = info; debugfs->debugfs_dir = debugfs_create_dir(dev_name(&mgr->dev), fpga_mgr_debugfs_root); debugfs_create_file("firmware_name", 0600, debugfs->debugfs_dir, mgr, &fpga_mgr_firmware_fops); debugfs_create_file("image", 0200, debugfs->debugfs_dir, mgr, &fpga_mgr_image_fops); debugfs_create_u32("flags", 0600, debugfs->debugfs_dir, &info->flags); debugfs_create_u32("config_complete_timeout_us", 0600, debugfs->debugfs_dir, &info->config_complete_timeout_us); mgr->debugfs = debugfs; } void fpga_mgr_debugfs_remove(struct fpga_manager *mgr) { struct fpga_mgr_debugfs *debugfs = mgr->debugfs; if (!fpga_mgr_debugfs_root) return; debugfs_remove_recursive(debugfs->debugfs_dir); /* this function also frees debugfs->info->firmware_name */ fpga_image_info_free(debugfs->info); kfree(debugfs); } void fpga_mgr_debugfs_init(void) { fpga_mgr_debugfs_root = debugfs_create_dir("fpga_manager", NULL); if (!fpga_mgr_debugfs_root) pr_warn("fpga_mgr: Failed to create debugfs root\n"); } void fpga_mgr_debugfs_uninit(void) { debugfs_remove_recursive(fpga_mgr_debugfs_root); } #endif /* CONFIG_FPGA_MGR_DEBUG_FS */