1/* 2 * Copyright IBM Corp. 2012 3 * 4 * Author(s): 5 * Jan Glauber <jang@linux.vnet.ibm.com> 6 */ 7 8#define KMSG_COMPONENT "zpci" 9#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 10 11#include <linux/kernel.h> 12#include <linux/seq_file.h> 13#include <linux/debugfs.h> 14#include <linux/export.h> 15#include <linux/pci.h> 16#include <asm/debug.h> 17 18#include <asm/pci_dma.h> 19 20static struct dentry *debugfs_root; 21debug_info_t *pci_debug_msg_id; 22EXPORT_SYMBOL_GPL(pci_debug_msg_id); 23debug_info_t *pci_debug_err_id; 24EXPORT_SYMBOL_GPL(pci_debug_err_id); 25 26static char *pci_perf_names[] = { 27 /* hardware counters */ 28 "Load operations", 29 "Store operations", 30 "Store block operations", 31 "Refresh operations", 32 "DMA read bytes", 33 "DMA write bytes", 34}; 35 36static char *pci_sw_names[] = { 37 "Allocated pages", 38 "Mapped pages", 39 "Unmapped pages", 40}; 41 42static void pci_sw_counter_show(struct seq_file *m) 43{ 44 struct zpci_dev *zdev = m->private; 45 atomic64_t *counter = &zdev->allocated_pages; 46 int i; 47 48 for (i = 0; i < ARRAY_SIZE(pci_sw_names); i++, counter++) 49 seq_printf(m, "%26s:\t%llu\n", pci_sw_names[i], 50 atomic64_read(counter)); 51} 52 53static int pci_perf_show(struct seq_file *m, void *v) 54{ 55 struct zpci_dev *zdev = m->private; 56 u64 *stat; 57 int i; 58 59 if (!zdev) 60 return 0; 61 62 mutex_lock(&zdev->lock); 63 if (!zdev->fmb) { 64 mutex_unlock(&zdev->lock); 65 seq_puts(m, "FMB statistics disabled\n"); 66 return 0; 67 } 68 69 /* header */ 70 seq_printf(m, "FMB @ %p\n", zdev->fmb); 71 seq_printf(m, "Update interval: %u ms\n", zdev->fmb_update); 72 seq_printf(m, "Samples: %u\n", zdev->fmb->samples); 73 seq_printf(m, "Last update TOD: %Lx\n", zdev->fmb->last_update); 74 75 /* hardware counters */ 76 stat = (u64 *) &zdev->fmb->ld_ops; 77 for (i = 0; i < 4; i++) 78 seq_printf(m, "%26s:\t%llu\n", 79 pci_perf_names[i], *(stat + i)); 80 if (zdev->fmb->dma_valid) 81 for (i = 4; i < 6; i++) 82 seq_printf(m, "%26s:\t%llu\n", 83 pci_perf_names[i], *(stat + i)); 84 85 pci_sw_counter_show(m); 86 mutex_unlock(&zdev->lock); 87 return 0; 88} 89 90static ssize_t pci_perf_seq_write(struct file *file, const char __user *ubuf, 91 size_t count, loff_t *off) 92{ 93 struct zpci_dev *zdev = ((struct seq_file *) file->private_data)->private; 94 unsigned long val; 95 int rc; 96 97 if (!zdev) 98 return 0; 99 100 rc = kstrtoul_from_user(ubuf, count, 10, &val); 101 if (rc) 102 return rc; 103 104 mutex_lock(&zdev->lock); 105 switch (val) { 106 case 0: 107 rc = zpci_fmb_disable_device(zdev); 108 break; 109 case 1: 110 rc = zpci_fmb_enable_device(zdev); 111 break; 112 } 113 mutex_unlock(&zdev->lock); 114 return rc ? rc : count; 115} 116 117static int pci_perf_seq_open(struct inode *inode, struct file *filp) 118{ 119 return single_open(filp, pci_perf_show, 120 file_inode(filp)->i_private); 121} 122 123static const struct file_operations debugfs_pci_perf_fops = { 124 .open = pci_perf_seq_open, 125 .read = seq_read, 126 .write = pci_perf_seq_write, 127 .llseek = seq_lseek, 128 .release = single_release, 129}; 130 131void zpci_debug_init_device(struct zpci_dev *zdev) 132{ 133 zdev->debugfs_dev = debugfs_create_dir(dev_name(&zdev->pdev->dev), 134 debugfs_root); 135 if (IS_ERR(zdev->debugfs_dev)) 136 zdev->debugfs_dev = NULL; 137 138 zdev->debugfs_perf = debugfs_create_file("statistics", 139 S_IFREG | S_IRUGO | S_IWUSR, 140 zdev->debugfs_dev, zdev, 141 &debugfs_pci_perf_fops); 142 if (IS_ERR(zdev->debugfs_perf)) 143 zdev->debugfs_perf = NULL; 144} 145 146void zpci_debug_exit_device(struct zpci_dev *zdev) 147{ 148 debugfs_remove(zdev->debugfs_perf); 149 debugfs_remove(zdev->debugfs_dev); 150} 151 152int __init zpci_debug_init(void) 153{ 154 /* event trace buffer */ 155 pci_debug_msg_id = debug_register("pci_msg", 8, 1, 8 * sizeof(long)); 156 if (!pci_debug_msg_id) 157 return -EINVAL; 158 debug_register_view(pci_debug_msg_id, &debug_sprintf_view); 159 debug_set_level(pci_debug_msg_id, 3); 160 161 /* error log */ 162 pci_debug_err_id = debug_register("pci_error", 2, 1, 16); 163 if (!pci_debug_err_id) 164 return -EINVAL; 165 debug_register_view(pci_debug_err_id, &debug_hex_ascii_view); 166 debug_set_level(pci_debug_err_id, 6); 167 168 debugfs_root = debugfs_create_dir("pci", NULL); 169 return 0; 170} 171 172void zpci_debug_exit(void) 173{ 174 debug_unregister(pci_debug_msg_id); 175 debug_unregister(pci_debug_err_id); 176 debugfs_remove(debugfs_root); 177} 178