18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright(c) 1999 - 2018 Intel Corporation. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 58c2ecf20Sopenharmony_ci#include <linux/module.h> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include "ixgbe.h" 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_cistatic struct dentry *ixgbe_dbg_root; 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_cistatic char ixgbe_dbg_reg_ops_buf[256] = ""; 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_cistatic ssize_t ixgbe_dbg_common_ops_read(struct file *filp, char __user *buffer, 148c2ecf20Sopenharmony_ci size_t count, loff_t *ppos, 158c2ecf20Sopenharmony_ci char *dbg_buf) 168c2ecf20Sopenharmony_ci{ 178c2ecf20Sopenharmony_ci struct ixgbe_adapter *adapter = filp->private_data; 188c2ecf20Sopenharmony_ci char *buf; 198c2ecf20Sopenharmony_ci int len; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci /* don't allow partial reads */ 228c2ecf20Sopenharmony_ci if (*ppos != 0) 238c2ecf20Sopenharmony_ci return 0; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci buf = kasprintf(GFP_KERNEL, "%s: %s\n", 268c2ecf20Sopenharmony_ci adapter->netdev->name, dbg_buf); 278c2ecf20Sopenharmony_ci if (!buf) 288c2ecf20Sopenharmony_ci return -ENOMEM; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci if (count < strlen(buf)) { 318c2ecf20Sopenharmony_ci kfree(buf); 328c2ecf20Sopenharmony_ci return -ENOSPC; 338c2ecf20Sopenharmony_ci } 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci len = simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf)); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci kfree(buf); 388c2ecf20Sopenharmony_ci return len; 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/** 428c2ecf20Sopenharmony_ci * ixgbe_dbg_reg_ops_read - read for reg_ops datum 438c2ecf20Sopenharmony_ci * @filp: the opened file 448c2ecf20Sopenharmony_ci * @buffer: where to write the data for the user to read 458c2ecf20Sopenharmony_ci * @count: the size of the user's buffer 468c2ecf20Sopenharmony_ci * @ppos: file position offset 478c2ecf20Sopenharmony_ci **/ 488c2ecf20Sopenharmony_cistatic ssize_t ixgbe_dbg_reg_ops_read(struct file *filp, char __user *buffer, 498c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci return ixgbe_dbg_common_ops_read(filp, buffer, count, ppos, 528c2ecf20Sopenharmony_ci ixgbe_dbg_reg_ops_buf); 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/** 568c2ecf20Sopenharmony_ci * ixgbe_dbg_reg_ops_write - write into reg_ops datum 578c2ecf20Sopenharmony_ci * @filp: the opened file 588c2ecf20Sopenharmony_ci * @buffer: where to find the user's data 598c2ecf20Sopenharmony_ci * @count: the length of the user's data 608c2ecf20Sopenharmony_ci * @ppos: file position offset 618c2ecf20Sopenharmony_ci **/ 628c2ecf20Sopenharmony_cistatic ssize_t ixgbe_dbg_reg_ops_write(struct file *filp, 638c2ecf20Sopenharmony_ci const char __user *buffer, 648c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci struct ixgbe_adapter *adapter = filp->private_data; 678c2ecf20Sopenharmony_ci int len; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci /* don't allow partial writes */ 708c2ecf20Sopenharmony_ci if (*ppos != 0) 718c2ecf20Sopenharmony_ci return 0; 728c2ecf20Sopenharmony_ci if (count >= sizeof(ixgbe_dbg_reg_ops_buf)) 738c2ecf20Sopenharmony_ci return -ENOSPC; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci len = simple_write_to_buffer(ixgbe_dbg_reg_ops_buf, 768c2ecf20Sopenharmony_ci sizeof(ixgbe_dbg_reg_ops_buf)-1, 778c2ecf20Sopenharmony_ci ppos, 788c2ecf20Sopenharmony_ci buffer, 798c2ecf20Sopenharmony_ci count); 808c2ecf20Sopenharmony_ci if (len < 0) 818c2ecf20Sopenharmony_ci return len; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci ixgbe_dbg_reg_ops_buf[len] = '\0'; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (strncmp(ixgbe_dbg_reg_ops_buf, "write", 5) == 0) { 868c2ecf20Sopenharmony_ci u32 reg, value; 878c2ecf20Sopenharmony_ci int cnt; 888c2ecf20Sopenharmony_ci cnt = sscanf(&ixgbe_dbg_reg_ops_buf[5], "%x %x", ®, &value); 898c2ecf20Sopenharmony_ci if (cnt == 2) { 908c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(&adapter->hw, reg, value); 918c2ecf20Sopenharmony_ci value = IXGBE_READ_REG(&adapter->hw, reg); 928c2ecf20Sopenharmony_ci e_dev_info("write: 0x%08x = 0x%08x\n", reg, value); 938c2ecf20Sopenharmony_ci } else { 948c2ecf20Sopenharmony_ci e_dev_info("write <reg> <value>\n"); 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci } else if (strncmp(ixgbe_dbg_reg_ops_buf, "read", 4) == 0) { 978c2ecf20Sopenharmony_ci u32 reg, value; 988c2ecf20Sopenharmony_ci int cnt; 998c2ecf20Sopenharmony_ci cnt = sscanf(&ixgbe_dbg_reg_ops_buf[4], "%x", ®); 1008c2ecf20Sopenharmony_ci if (cnt == 1) { 1018c2ecf20Sopenharmony_ci value = IXGBE_READ_REG(&adapter->hw, reg); 1028c2ecf20Sopenharmony_ci e_dev_info("read 0x%08x = 0x%08x\n", reg, value); 1038c2ecf20Sopenharmony_ci } else { 1048c2ecf20Sopenharmony_ci e_dev_info("read <reg>\n"); 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci } else { 1078c2ecf20Sopenharmony_ci e_dev_info("Unknown command %s\n", ixgbe_dbg_reg_ops_buf); 1088c2ecf20Sopenharmony_ci e_dev_info("Available commands:\n"); 1098c2ecf20Sopenharmony_ci e_dev_info(" read <reg>\n"); 1108c2ecf20Sopenharmony_ci e_dev_info(" write <reg> <value>\n"); 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci return count; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic const struct file_operations ixgbe_dbg_reg_ops_fops = { 1168c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1178c2ecf20Sopenharmony_ci .open = simple_open, 1188c2ecf20Sopenharmony_ci .read = ixgbe_dbg_reg_ops_read, 1198c2ecf20Sopenharmony_ci .write = ixgbe_dbg_reg_ops_write, 1208c2ecf20Sopenharmony_ci}; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic char ixgbe_dbg_netdev_ops_buf[256] = ""; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/** 1258c2ecf20Sopenharmony_ci * ixgbe_dbg_netdev_ops_read - read for netdev_ops datum 1268c2ecf20Sopenharmony_ci * @filp: the opened file 1278c2ecf20Sopenharmony_ci * @buffer: where to write the data for the user to read 1288c2ecf20Sopenharmony_ci * @count: the size of the user's buffer 1298c2ecf20Sopenharmony_ci * @ppos: file position offset 1308c2ecf20Sopenharmony_ci **/ 1318c2ecf20Sopenharmony_cistatic ssize_t ixgbe_dbg_netdev_ops_read(struct file *filp, char __user *buffer, 1328c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci return ixgbe_dbg_common_ops_read(filp, buffer, count, ppos, 1358c2ecf20Sopenharmony_ci ixgbe_dbg_netdev_ops_buf); 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci/** 1398c2ecf20Sopenharmony_ci * ixgbe_dbg_netdev_ops_write - write into netdev_ops datum 1408c2ecf20Sopenharmony_ci * @filp: the opened file 1418c2ecf20Sopenharmony_ci * @buffer: where to find the user's data 1428c2ecf20Sopenharmony_ci * @count: the length of the user's data 1438c2ecf20Sopenharmony_ci * @ppos: file position offset 1448c2ecf20Sopenharmony_ci **/ 1458c2ecf20Sopenharmony_cistatic ssize_t ixgbe_dbg_netdev_ops_write(struct file *filp, 1468c2ecf20Sopenharmony_ci const char __user *buffer, 1478c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct ixgbe_adapter *adapter = filp->private_data; 1508c2ecf20Sopenharmony_ci int len; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* don't allow partial writes */ 1538c2ecf20Sopenharmony_ci if (*ppos != 0) 1548c2ecf20Sopenharmony_ci return 0; 1558c2ecf20Sopenharmony_ci if (count >= sizeof(ixgbe_dbg_netdev_ops_buf)) 1568c2ecf20Sopenharmony_ci return -ENOSPC; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci len = simple_write_to_buffer(ixgbe_dbg_netdev_ops_buf, 1598c2ecf20Sopenharmony_ci sizeof(ixgbe_dbg_netdev_ops_buf)-1, 1608c2ecf20Sopenharmony_ci ppos, 1618c2ecf20Sopenharmony_ci buffer, 1628c2ecf20Sopenharmony_ci count); 1638c2ecf20Sopenharmony_ci if (len < 0) 1648c2ecf20Sopenharmony_ci return len; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci ixgbe_dbg_netdev_ops_buf[len] = '\0'; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci if (strncmp(ixgbe_dbg_netdev_ops_buf, "tx_timeout", 10) == 0) { 1698c2ecf20Sopenharmony_ci /* TX Queue number below is wrong, but ixgbe does not use it */ 1708c2ecf20Sopenharmony_ci adapter->netdev->netdev_ops->ndo_tx_timeout(adapter->netdev, 1718c2ecf20Sopenharmony_ci UINT_MAX); 1728c2ecf20Sopenharmony_ci e_dev_info("tx_timeout called\n"); 1738c2ecf20Sopenharmony_ci } else { 1748c2ecf20Sopenharmony_ci e_dev_info("Unknown command: %s\n", ixgbe_dbg_netdev_ops_buf); 1758c2ecf20Sopenharmony_ci e_dev_info("Available commands:\n"); 1768c2ecf20Sopenharmony_ci e_dev_info(" tx_timeout\n"); 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci return count; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic const struct file_operations ixgbe_dbg_netdev_ops_fops = { 1828c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1838c2ecf20Sopenharmony_ci .open = simple_open, 1848c2ecf20Sopenharmony_ci .read = ixgbe_dbg_netdev_ops_read, 1858c2ecf20Sopenharmony_ci .write = ixgbe_dbg_netdev_ops_write, 1868c2ecf20Sopenharmony_ci}; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci/** 1898c2ecf20Sopenharmony_ci * ixgbe_dbg_adapter_init - setup the debugfs directory for the adapter 1908c2ecf20Sopenharmony_ci * @adapter: the adapter that is starting up 1918c2ecf20Sopenharmony_ci **/ 1928c2ecf20Sopenharmony_civoid ixgbe_dbg_adapter_init(struct ixgbe_adapter *adapter) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci const char *name = pci_name(adapter->pdev); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci adapter->ixgbe_dbg_adapter = debugfs_create_dir(name, ixgbe_dbg_root); 1978c2ecf20Sopenharmony_ci debugfs_create_file("reg_ops", 0600, adapter->ixgbe_dbg_adapter, 1988c2ecf20Sopenharmony_ci adapter, &ixgbe_dbg_reg_ops_fops); 1998c2ecf20Sopenharmony_ci debugfs_create_file("netdev_ops", 0600, adapter->ixgbe_dbg_adapter, 2008c2ecf20Sopenharmony_ci adapter, &ixgbe_dbg_netdev_ops_fops); 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci/** 2048c2ecf20Sopenharmony_ci * ixgbe_dbg_adapter_exit - clear out the adapter's debugfs entries 2058c2ecf20Sopenharmony_ci * @adapter: the adapter that is exiting 2068c2ecf20Sopenharmony_ci **/ 2078c2ecf20Sopenharmony_civoid ixgbe_dbg_adapter_exit(struct ixgbe_adapter *adapter) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci debugfs_remove_recursive(adapter->ixgbe_dbg_adapter); 2108c2ecf20Sopenharmony_ci adapter->ixgbe_dbg_adapter = NULL; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci/** 2148c2ecf20Sopenharmony_ci * ixgbe_dbg_init - start up debugfs for the driver 2158c2ecf20Sopenharmony_ci **/ 2168c2ecf20Sopenharmony_civoid ixgbe_dbg_init(void) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci ixgbe_dbg_root = debugfs_create_dir(ixgbe_driver_name, NULL); 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci/** 2228c2ecf20Sopenharmony_ci * ixgbe_dbg_exit - clean out the driver's debugfs entries 2238c2ecf20Sopenharmony_ci **/ 2248c2ecf20Sopenharmony_civoid ixgbe_dbg_exit(void) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci debugfs_remove_recursive(ixgbe_dbg_root); 2278c2ecf20Sopenharmony_ci} 228