162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright(c) 1999 - 2018 Intel Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/debugfs.h> 562306a36Sopenharmony_ci#include <linux/module.h> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include "ixgbe.h" 862306a36Sopenharmony_ci 962306a36Sopenharmony_cistatic struct dentry *ixgbe_dbg_root; 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cistatic char ixgbe_dbg_reg_ops_buf[256] = ""; 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_cistatic ssize_t ixgbe_dbg_common_ops_read(struct file *filp, char __user *buffer, 1462306a36Sopenharmony_ci size_t count, loff_t *ppos, 1562306a36Sopenharmony_ci char *dbg_buf) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci struct ixgbe_adapter *adapter = filp->private_data; 1862306a36Sopenharmony_ci char *buf; 1962306a36Sopenharmony_ci int len; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci /* don't allow partial reads */ 2262306a36Sopenharmony_ci if (*ppos != 0) 2362306a36Sopenharmony_ci return 0; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci buf = kasprintf(GFP_KERNEL, "%s: %s\n", 2662306a36Sopenharmony_ci adapter->netdev->name, dbg_buf); 2762306a36Sopenharmony_ci if (!buf) 2862306a36Sopenharmony_ci return -ENOMEM; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci if (count < strlen(buf)) { 3162306a36Sopenharmony_ci kfree(buf); 3262306a36Sopenharmony_ci return -ENOSPC; 3362306a36Sopenharmony_ci } 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci len = simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf)); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci kfree(buf); 3862306a36Sopenharmony_ci return len; 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/** 4262306a36Sopenharmony_ci * ixgbe_dbg_reg_ops_read - read for reg_ops datum 4362306a36Sopenharmony_ci * @filp: the opened file 4462306a36Sopenharmony_ci * @buffer: where to write the data for the user to read 4562306a36Sopenharmony_ci * @count: the size of the user's buffer 4662306a36Sopenharmony_ci * @ppos: file position offset 4762306a36Sopenharmony_ci **/ 4862306a36Sopenharmony_cistatic ssize_t ixgbe_dbg_reg_ops_read(struct file *filp, char __user *buffer, 4962306a36Sopenharmony_ci size_t count, loff_t *ppos) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci return ixgbe_dbg_common_ops_read(filp, buffer, count, ppos, 5262306a36Sopenharmony_ci ixgbe_dbg_reg_ops_buf); 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/** 5662306a36Sopenharmony_ci * ixgbe_dbg_reg_ops_write - write into reg_ops datum 5762306a36Sopenharmony_ci * @filp: the opened file 5862306a36Sopenharmony_ci * @buffer: where to find the user's data 5962306a36Sopenharmony_ci * @count: the length of the user's data 6062306a36Sopenharmony_ci * @ppos: file position offset 6162306a36Sopenharmony_ci **/ 6262306a36Sopenharmony_cistatic ssize_t ixgbe_dbg_reg_ops_write(struct file *filp, 6362306a36Sopenharmony_ci const char __user *buffer, 6462306a36Sopenharmony_ci size_t count, loff_t *ppos) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci struct ixgbe_adapter *adapter = filp->private_data; 6762306a36Sopenharmony_ci int len; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci /* don't allow partial writes */ 7062306a36Sopenharmony_ci if (*ppos != 0) 7162306a36Sopenharmony_ci return 0; 7262306a36Sopenharmony_ci if (count >= sizeof(ixgbe_dbg_reg_ops_buf)) 7362306a36Sopenharmony_ci return -ENOSPC; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci len = simple_write_to_buffer(ixgbe_dbg_reg_ops_buf, 7662306a36Sopenharmony_ci sizeof(ixgbe_dbg_reg_ops_buf)-1, 7762306a36Sopenharmony_ci ppos, 7862306a36Sopenharmony_ci buffer, 7962306a36Sopenharmony_ci count); 8062306a36Sopenharmony_ci if (len < 0) 8162306a36Sopenharmony_ci return len; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci ixgbe_dbg_reg_ops_buf[len] = '\0'; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci if (strncmp(ixgbe_dbg_reg_ops_buf, "write", 5) == 0) { 8662306a36Sopenharmony_ci u32 reg, value; 8762306a36Sopenharmony_ci int cnt; 8862306a36Sopenharmony_ci cnt = sscanf(&ixgbe_dbg_reg_ops_buf[5], "%x %x", ®, &value); 8962306a36Sopenharmony_ci if (cnt == 2) { 9062306a36Sopenharmony_ci IXGBE_WRITE_REG(&adapter->hw, reg, value); 9162306a36Sopenharmony_ci value = IXGBE_READ_REG(&adapter->hw, reg); 9262306a36Sopenharmony_ci e_dev_info("write: 0x%08x = 0x%08x\n", reg, value); 9362306a36Sopenharmony_ci } else { 9462306a36Sopenharmony_ci e_dev_info("write <reg> <value>\n"); 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci } else if (strncmp(ixgbe_dbg_reg_ops_buf, "read", 4) == 0) { 9762306a36Sopenharmony_ci u32 reg, value; 9862306a36Sopenharmony_ci int cnt; 9962306a36Sopenharmony_ci cnt = sscanf(&ixgbe_dbg_reg_ops_buf[4], "%x", ®); 10062306a36Sopenharmony_ci if (cnt == 1) { 10162306a36Sopenharmony_ci value = IXGBE_READ_REG(&adapter->hw, reg); 10262306a36Sopenharmony_ci e_dev_info("read 0x%08x = 0x%08x\n", reg, value); 10362306a36Sopenharmony_ci } else { 10462306a36Sopenharmony_ci e_dev_info("read <reg>\n"); 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci } else { 10762306a36Sopenharmony_ci e_dev_info("Unknown command %s\n", ixgbe_dbg_reg_ops_buf); 10862306a36Sopenharmony_ci e_dev_info("Available commands:\n"); 10962306a36Sopenharmony_ci e_dev_info(" read <reg>\n"); 11062306a36Sopenharmony_ci e_dev_info(" write <reg> <value>\n"); 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci return count; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic const struct file_operations ixgbe_dbg_reg_ops_fops = { 11662306a36Sopenharmony_ci .owner = THIS_MODULE, 11762306a36Sopenharmony_ci .open = simple_open, 11862306a36Sopenharmony_ci .read = ixgbe_dbg_reg_ops_read, 11962306a36Sopenharmony_ci .write = ixgbe_dbg_reg_ops_write, 12062306a36Sopenharmony_ci}; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic char ixgbe_dbg_netdev_ops_buf[256] = ""; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci/** 12562306a36Sopenharmony_ci * ixgbe_dbg_netdev_ops_read - read for netdev_ops datum 12662306a36Sopenharmony_ci * @filp: the opened file 12762306a36Sopenharmony_ci * @buffer: where to write the data for the user to read 12862306a36Sopenharmony_ci * @count: the size of the user's buffer 12962306a36Sopenharmony_ci * @ppos: file position offset 13062306a36Sopenharmony_ci **/ 13162306a36Sopenharmony_cistatic ssize_t ixgbe_dbg_netdev_ops_read(struct file *filp, char __user *buffer, 13262306a36Sopenharmony_ci size_t count, loff_t *ppos) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci return ixgbe_dbg_common_ops_read(filp, buffer, count, ppos, 13562306a36Sopenharmony_ci ixgbe_dbg_netdev_ops_buf); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci/** 13962306a36Sopenharmony_ci * ixgbe_dbg_netdev_ops_write - write into netdev_ops datum 14062306a36Sopenharmony_ci * @filp: the opened file 14162306a36Sopenharmony_ci * @buffer: where to find the user's data 14262306a36Sopenharmony_ci * @count: the length of the user's data 14362306a36Sopenharmony_ci * @ppos: file position offset 14462306a36Sopenharmony_ci **/ 14562306a36Sopenharmony_cistatic ssize_t ixgbe_dbg_netdev_ops_write(struct file *filp, 14662306a36Sopenharmony_ci const char __user *buffer, 14762306a36Sopenharmony_ci size_t count, loff_t *ppos) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci struct ixgbe_adapter *adapter = filp->private_data; 15062306a36Sopenharmony_ci int len; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci /* don't allow partial writes */ 15362306a36Sopenharmony_ci if (*ppos != 0) 15462306a36Sopenharmony_ci return 0; 15562306a36Sopenharmony_ci if (count >= sizeof(ixgbe_dbg_netdev_ops_buf)) 15662306a36Sopenharmony_ci return -ENOSPC; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci len = simple_write_to_buffer(ixgbe_dbg_netdev_ops_buf, 15962306a36Sopenharmony_ci sizeof(ixgbe_dbg_netdev_ops_buf)-1, 16062306a36Sopenharmony_ci ppos, 16162306a36Sopenharmony_ci buffer, 16262306a36Sopenharmony_ci count); 16362306a36Sopenharmony_ci if (len < 0) 16462306a36Sopenharmony_ci return len; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci ixgbe_dbg_netdev_ops_buf[len] = '\0'; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (strncmp(ixgbe_dbg_netdev_ops_buf, "tx_timeout", 10) == 0) { 16962306a36Sopenharmony_ci /* TX Queue number below is wrong, but ixgbe does not use it */ 17062306a36Sopenharmony_ci adapter->netdev->netdev_ops->ndo_tx_timeout(adapter->netdev, 17162306a36Sopenharmony_ci UINT_MAX); 17262306a36Sopenharmony_ci e_dev_info("tx_timeout called\n"); 17362306a36Sopenharmony_ci } else { 17462306a36Sopenharmony_ci e_dev_info("Unknown command: %s\n", ixgbe_dbg_netdev_ops_buf); 17562306a36Sopenharmony_ci e_dev_info("Available commands:\n"); 17662306a36Sopenharmony_ci e_dev_info(" tx_timeout\n"); 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci return count; 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic const struct file_operations ixgbe_dbg_netdev_ops_fops = { 18262306a36Sopenharmony_ci .owner = THIS_MODULE, 18362306a36Sopenharmony_ci .open = simple_open, 18462306a36Sopenharmony_ci .read = ixgbe_dbg_netdev_ops_read, 18562306a36Sopenharmony_ci .write = ixgbe_dbg_netdev_ops_write, 18662306a36Sopenharmony_ci}; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci/** 18962306a36Sopenharmony_ci * ixgbe_dbg_adapter_init - setup the debugfs directory for the adapter 19062306a36Sopenharmony_ci * @adapter: the adapter that is starting up 19162306a36Sopenharmony_ci **/ 19262306a36Sopenharmony_civoid ixgbe_dbg_adapter_init(struct ixgbe_adapter *adapter) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci const char *name = pci_name(adapter->pdev); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci adapter->ixgbe_dbg_adapter = debugfs_create_dir(name, ixgbe_dbg_root); 19762306a36Sopenharmony_ci debugfs_create_file("reg_ops", 0600, adapter->ixgbe_dbg_adapter, 19862306a36Sopenharmony_ci adapter, &ixgbe_dbg_reg_ops_fops); 19962306a36Sopenharmony_ci debugfs_create_file("netdev_ops", 0600, adapter->ixgbe_dbg_adapter, 20062306a36Sopenharmony_ci adapter, &ixgbe_dbg_netdev_ops_fops); 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci/** 20462306a36Sopenharmony_ci * ixgbe_dbg_adapter_exit - clear out the adapter's debugfs entries 20562306a36Sopenharmony_ci * @adapter: the adapter that is exiting 20662306a36Sopenharmony_ci **/ 20762306a36Sopenharmony_civoid ixgbe_dbg_adapter_exit(struct ixgbe_adapter *adapter) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci debugfs_remove_recursive(adapter->ixgbe_dbg_adapter); 21062306a36Sopenharmony_ci adapter->ixgbe_dbg_adapter = NULL; 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci/** 21462306a36Sopenharmony_ci * ixgbe_dbg_init - start up debugfs for the driver 21562306a36Sopenharmony_ci **/ 21662306a36Sopenharmony_civoid ixgbe_dbg_init(void) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci ixgbe_dbg_root = debugfs_create_dir(ixgbe_driver_name, NULL); 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci/** 22262306a36Sopenharmony_ci * ixgbe_dbg_exit - clean out the driver's debugfs entries 22362306a36Sopenharmony_ci **/ 22462306a36Sopenharmony_civoid ixgbe_dbg_exit(void) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci debugfs_remove_recursive(ixgbe_dbg_root); 22762306a36Sopenharmony_ci} 228