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