1/*
2 * Intel MIC Platform Software Stack (MPSS)
3 *
4 * Copyright(c) 2013 Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version 2, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * The full GNU General Public License is included in this distribution in
16 * the file called "COPYING".
17 *
18 * Intel MIC Host driver.
19 *
20 */
21#include <linux/debugfs.h>
22#include <linux/pci.h>
23#include <linux/seq_file.h>
24
25#include <linux/mic_common.h>
26#include "../common/mic_dev.h"
27#include "mic_device.h"
28#include "mic_smpt.h"
29#include "mic_virtio.h"
30
31/* Debugfs parent dir */
32static struct dentry *mic_dbg;
33
34/**
35 * mic_log_buf_show - Display MIC kernel log buffer.
36 *
37 * log_buf addr/len is read from System.map by user space
38 * and populated in sysfs entries.
39 */
40static int mic_log_buf_show(struct seq_file *s, void *unused)
41{
42	void __iomem *log_buf_va;
43	int __iomem *log_buf_len_va;
44	struct mic_device *mdev = s->private;
45	void *kva;
46	int size;
47	unsigned long aper_offset;
48
49	if (!mdev || !mdev->log_buf_addr || !mdev->log_buf_len)
50		goto done;
51	/*
52	 * Card kernel will never be relocated and any kernel text/data mapping
53	 * can be translated to phys address by subtracting __START_KERNEL_map.
54	 */
55	aper_offset = (unsigned long)mdev->log_buf_len - __START_KERNEL_map;
56	log_buf_len_va = mdev->aper.va + aper_offset;
57	aper_offset = (unsigned long)mdev->log_buf_addr - __START_KERNEL_map;
58	log_buf_va = mdev->aper.va + aper_offset;
59	size = ioread32(log_buf_len_va);
60
61	kva = kmalloc(size, GFP_KERNEL);
62	if (!kva)
63		goto done;
64	mutex_lock(&mdev->mic_mutex);
65	memcpy_fromio(kva, log_buf_va, size);
66	switch (mdev->state) {
67	case MIC_ONLINE:
68		/* Fall through */
69	case MIC_SHUTTING_DOWN:
70		seq_write(s, kva, size);
71		break;
72	default:
73		break;
74	}
75	mutex_unlock(&mdev->mic_mutex);
76	kfree(kva);
77done:
78	return 0;
79}
80
81static int mic_log_buf_open(struct inode *inode, struct file *file)
82{
83	return single_open(file, mic_log_buf_show, inode->i_private);
84}
85
86static int mic_log_buf_release(struct inode *inode, struct file *file)
87{
88	return single_release(inode, file);
89}
90
91static const struct file_operations log_buf_ops = {
92	.owner   = THIS_MODULE,
93	.open    = mic_log_buf_open,
94	.read    = seq_read,
95	.llseek  = seq_lseek,
96	.release = mic_log_buf_release
97};
98
99static int mic_smpt_show(struct seq_file *s, void *pos)
100{
101	int i;
102	struct mic_device *mdev = s->private;
103	unsigned long flags;
104
105	seq_printf(s, "MIC %-2d |%-10s| %-14s %-10s\n",
106		   mdev->id, "SMPT entry", "SW DMA addr", "RefCount");
107	seq_puts(s, "====================================================\n");
108
109	if (mdev->smpt) {
110		struct mic_smpt_info *smpt_info = mdev->smpt;
111		spin_lock_irqsave(&smpt_info->smpt_lock, flags);
112		for (i = 0; i < smpt_info->info.num_reg; i++) {
113			seq_printf(s, "%9s|%-10d| %-#14llx %-10lld\n",
114				   " ",  i, smpt_info->entry[i].dma_addr,
115				   smpt_info->entry[i].ref_count);
116		}
117		spin_unlock_irqrestore(&smpt_info->smpt_lock, flags);
118	}
119	seq_puts(s, "====================================================\n");
120	return 0;
121}
122
123static int mic_smpt_debug_open(struct inode *inode, struct file *file)
124{
125	return single_open(file, mic_smpt_show, inode->i_private);
126}
127
128static int mic_smpt_debug_release(struct inode *inode, struct file *file)
129{
130	return single_release(inode, file);
131}
132
133static const struct file_operations smpt_file_ops = {
134	.owner   = THIS_MODULE,
135	.open    = mic_smpt_debug_open,
136	.read    = seq_read,
137	.llseek  = seq_lseek,
138	.release = mic_smpt_debug_release
139};
140
141static int mic_soft_reset_show(struct seq_file *s, void *pos)
142{
143	struct mic_device *mdev = s->private;
144
145	mic_stop(mdev, true);
146	return 0;
147}
148
149static int mic_soft_reset_debug_open(struct inode *inode, struct file *file)
150{
151	return single_open(file, mic_soft_reset_show, inode->i_private);
152}
153
154static int mic_soft_reset_debug_release(struct inode *inode, struct file *file)
155{
156	return single_release(inode, file);
157}
158
159static const struct file_operations soft_reset_ops = {
160	.owner   = THIS_MODULE,
161	.open    = mic_soft_reset_debug_open,
162	.read    = seq_read,
163	.llseek  = seq_lseek,
164	.release = mic_soft_reset_debug_release
165};
166
167static int mic_post_code_show(struct seq_file *s, void *pos)
168{
169	struct mic_device *mdev = s->private;
170	u32 reg = mdev->ops->get_postcode(mdev);
171
172	seq_printf(s, "%c%c", reg & 0xff, (reg >> 8) & 0xff);
173	return 0;
174}
175
176static int mic_post_code_debug_open(struct inode *inode, struct file *file)
177{
178	return single_open(file, mic_post_code_show, inode->i_private);
179}
180
181static int mic_post_code_debug_release(struct inode *inode, struct file *file)
182{
183	return single_release(inode, file);
184}
185
186static const struct file_operations post_code_ops = {
187	.owner   = THIS_MODULE,
188	.open    = mic_post_code_debug_open,
189	.read    = seq_read,
190	.llseek  = seq_lseek,
191	.release = mic_post_code_debug_release
192};
193
194static int mic_dp_show(struct seq_file *s, void *pos)
195{
196	struct mic_device *mdev = s->private;
197	struct mic_device_desc *d;
198	struct mic_device_ctrl *dc;
199	struct mic_vqconfig *vqconfig;
200	__u32 *features;
201	__u8 *config;
202	struct mic_bootparam *bootparam = mdev->dp;
203	int i, j;
204
205	seq_printf(s, "Bootparam: magic 0x%x\n",
206		   bootparam->magic);
207	seq_printf(s, "Bootparam: h2c_shutdown_db %d\n",
208		   bootparam->h2c_shutdown_db);
209	seq_printf(s, "Bootparam: h2c_config_db %d\n",
210		   bootparam->h2c_config_db);
211	seq_printf(s, "Bootparam: c2h_shutdown_db %d\n",
212		   bootparam->c2h_shutdown_db);
213	seq_printf(s, "Bootparam: shutdown_status %d\n",
214		   bootparam->shutdown_status);
215	seq_printf(s, "Bootparam: shutdown_card %d\n",
216		   bootparam->shutdown_card);
217
218	for (i = sizeof(*bootparam); i < MIC_DP_SIZE;
219	     i += mic_total_desc_size(d)) {
220		d = mdev->dp + i;
221		dc = (void *)d + mic_aligned_desc_size(d);
222
223		/* end of list */
224		if (d->type == 0)
225			break;
226
227		if (d->type == -1)
228			continue;
229
230		seq_printf(s, "Type %d ", d->type);
231		seq_printf(s, "Num VQ %d ", d->num_vq);
232		seq_printf(s, "Feature Len %d\n", d->feature_len);
233		seq_printf(s, "Config Len %d ", d->config_len);
234		seq_printf(s, "Shutdown Status %d\n", d->status);
235
236		for (j = 0; j < d->num_vq; j++) {
237			vqconfig = mic_vq_config(d) + j;
238			seq_printf(s, "vqconfig[%d]: ", j);
239			seq_printf(s, "address 0x%llx ", vqconfig->address);
240			seq_printf(s, "num %d ", vqconfig->num);
241			seq_printf(s, "used address 0x%llx\n",
242				   vqconfig->used_address);
243		}
244
245		features = (__u32 *)mic_vq_features(d);
246		seq_printf(s, "Features: Host 0x%x ", features[0]);
247		seq_printf(s, "Guest 0x%x\n", features[1]);
248
249		config = mic_vq_configspace(d);
250		for (j = 0; j < d->config_len; j++)
251			seq_printf(s, "config[%d]=%d\n", j, config[j]);
252
253		seq_puts(s, "Device control:\n");
254		seq_printf(s, "Config Change %d ", dc->config_change);
255		seq_printf(s, "Vdev reset %d\n", dc->vdev_reset);
256		seq_printf(s, "Guest Ack %d ", dc->guest_ack);
257		seq_printf(s, "Host ack %d\n", dc->host_ack);
258		seq_printf(s, "Used address updated %d ",
259			   dc->used_address_updated);
260		seq_printf(s, "Vdev 0x%llx\n", dc->vdev);
261		seq_printf(s, "c2h doorbell %d ", dc->c2h_vdev_db);
262		seq_printf(s, "h2c doorbell %d\n", dc->h2c_vdev_db);
263	}
264
265	return 0;
266}
267
268static int mic_dp_debug_open(struct inode *inode, struct file *file)
269{
270	return single_open(file, mic_dp_show, inode->i_private);
271}
272
273static int mic_dp_debug_release(struct inode *inode, struct file *file)
274{
275	return single_release(inode, file);
276}
277
278static const struct file_operations dp_ops = {
279	.owner   = THIS_MODULE,
280	.open    = mic_dp_debug_open,
281	.read    = seq_read,
282	.llseek  = seq_lseek,
283	.release = mic_dp_debug_release
284};
285
286static int mic_vdev_info_show(struct seq_file *s, void *unused)
287{
288	struct mic_device *mdev = s->private;
289	struct list_head *pos, *tmp;
290	struct mic_vdev *mvdev;
291	int i, j;
292
293	mutex_lock(&mdev->mic_mutex);
294	list_for_each_safe(pos, tmp, &mdev->vdev_list) {
295		mvdev = list_entry(pos, struct mic_vdev, list);
296		seq_printf(s, "VDEV type %d state %s in %ld out %ld\n",
297			   mvdev->virtio_id,
298			   mic_vdevup(mvdev) ? "UP" : "DOWN",
299			   mvdev->in_bytes,
300			   mvdev->out_bytes);
301		for (i = 0; i < MIC_MAX_VRINGS; i++) {
302			struct vring_desc *desc;
303			struct vring_avail *avail;
304			struct vring_used *used;
305			struct mic_vringh *mvr = &mvdev->mvr[i];
306			struct vringh *vrh = &mvr->vrh;
307			int num = vrh->vring.num;
308			if (!num)
309				continue;
310			desc = vrh->vring.desc;
311			seq_printf(s, "vring i %d avail_idx %d",
312				   i, mvr->vring.info->avail_idx & (num - 1));
313			seq_printf(s, " vring i %d avail_idx %d\n",
314				   i, mvr->vring.info->avail_idx);
315			seq_printf(s, "vrh i %d weak_barriers %d",
316				   i, vrh->weak_barriers);
317			seq_printf(s, " last_avail_idx %d last_used_idx %d",
318				   vrh->last_avail_idx, vrh->last_used_idx);
319			seq_printf(s, " completed %d\n", vrh->completed);
320			for (j = 0; j < num; j++) {
321				seq_printf(s, "desc[%d] addr 0x%llx len %d",
322					   j, desc->addr, desc->len);
323				seq_printf(s, " flags 0x%x next %d\n",
324					   desc->flags, desc->next);
325				desc++;
326			}
327			avail = vrh->vring.avail;
328			seq_printf(s, "avail flags 0x%x idx %d\n",
329				   vringh16_to_cpu(vrh, avail->flags),
330				   vringh16_to_cpu(vrh, avail->idx) & (num - 1));
331			seq_printf(s, "avail flags 0x%x idx %d\n",
332				   vringh16_to_cpu(vrh, avail->flags),
333				   vringh16_to_cpu(vrh, avail->idx));
334			for (j = 0; j < num; j++)
335				seq_printf(s, "avail ring[%d] %d\n",
336					   j, avail->ring[j]);
337			used = vrh->vring.used;
338			seq_printf(s, "used flags 0x%x idx %d\n",
339				   vringh16_to_cpu(vrh, used->flags),
340				   vringh16_to_cpu(vrh, used->idx) & (num - 1));
341			seq_printf(s, "used flags 0x%x idx %d\n",
342				   vringh16_to_cpu(vrh, used->flags),
343				   vringh16_to_cpu(vrh, used->idx));
344			for (j = 0; j < num; j++)
345				seq_printf(s, "used ring[%d] id %d len %d\n",
346					   j, vringh32_to_cpu(vrh,
347							      used->ring[j].id),
348					   vringh32_to_cpu(vrh,
349							   used->ring[j].len));
350		}
351	}
352	mutex_unlock(&mdev->mic_mutex);
353
354	return 0;
355}
356
357static int mic_vdev_info_debug_open(struct inode *inode, struct file *file)
358{
359	return single_open(file, mic_vdev_info_show, inode->i_private);
360}
361
362static int mic_vdev_info_debug_release(struct inode *inode, struct file *file)
363{
364	return single_release(inode, file);
365}
366
367static const struct file_operations vdev_info_ops = {
368	.owner   = THIS_MODULE,
369	.open    = mic_vdev_info_debug_open,
370	.read    = seq_read,
371	.llseek  = seq_lseek,
372	.release = mic_vdev_info_debug_release
373};
374
375static int mic_msi_irq_info_show(struct seq_file *s, void *pos)
376{
377	struct mic_device *mdev  = s->private;
378	int reg;
379	int i, j;
380	u16 entry;
381	u16 vector;
382	struct pci_dev *pdev = container_of(mdev->sdev->parent,
383		struct pci_dev, dev);
384
385	if (pci_dev_msi_enabled(pdev)) {
386		for (i = 0; i < mdev->irq_info.num_vectors; i++) {
387			if (pdev->msix_enabled) {
388				entry = mdev->irq_info.msix_entries[i].entry;
389				vector = mdev->irq_info.msix_entries[i].vector;
390			} else {
391				entry = 0;
392				vector = pdev->irq;
393			}
394
395			reg = mdev->intr_ops->read_msi_to_src_map(mdev, entry);
396
397			seq_printf(s, "%s %-10d %s %-10d MXAR[%d]: %08X\n",
398				   "IRQ:", vector, "Entry:", entry, i, reg);
399
400			seq_printf(s, "%-10s", "offset:");
401			for (j = (MIC_NUM_OFFSETS - 1); j >= 0; j--)
402				seq_printf(s, "%4d ", j);
403			seq_puts(s, "\n");
404
405
406			seq_printf(s, "%-10s", "count:");
407			for (j = (MIC_NUM_OFFSETS - 1); j >= 0; j--)
408				seq_printf(s, "%4d ",
409					   (mdev->irq_info.mic_msi_map[i] &
410					   BIT(j)) ? 1 : 0);
411			seq_puts(s, "\n\n");
412		}
413	} else {
414		seq_puts(s, "MSI/MSIx interrupts not enabled\n");
415	}
416
417	return 0;
418}
419
420static int mic_msi_irq_info_debug_open(struct inode *inode, struct file *file)
421{
422	return single_open(file, mic_msi_irq_info_show, inode->i_private);
423}
424
425static int
426mic_msi_irq_info_debug_release(struct inode *inode, struct file *file)
427{
428	return single_release(inode, file);
429}
430
431static const struct file_operations msi_irq_info_ops = {
432	.owner   = THIS_MODULE,
433	.open    = mic_msi_irq_info_debug_open,
434	.read    = seq_read,
435	.llseek  = seq_lseek,
436	.release = mic_msi_irq_info_debug_release
437};
438
439/**
440 * mic_create_debug_dir - Initialize MIC debugfs entries.
441 */
442void mic_create_debug_dir(struct mic_device *mdev)
443{
444	if (!mic_dbg)
445		return;
446
447	mdev->dbg_dir = debugfs_create_dir(dev_name(mdev->sdev), mic_dbg);
448	if (!mdev->dbg_dir)
449		return;
450
451	debugfs_create_file("log_buf", 0444, mdev->dbg_dir, mdev, &log_buf_ops);
452
453	debugfs_create_file("smpt", 0444, mdev->dbg_dir, mdev, &smpt_file_ops);
454
455	debugfs_create_file("soft_reset", 0444, mdev->dbg_dir, mdev,
456			    &soft_reset_ops);
457
458	debugfs_create_file("post_code", 0444, mdev->dbg_dir, mdev,
459			    &post_code_ops);
460
461	debugfs_create_file("dp", 0444, mdev->dbg_dir, mdev, &dp_ops);
462
463	debugfs_create_file("vdev_info", 0444, mdev->dbg_dir, mdev,
464			    &vdev_info_ops);
465
466	debugfs_create_file("msi_irq_info", 0444, mdev->dbg_dir, mdev,
467			    &msi_irq_info_ops);
468}
469
470/**
471 * mic_delete_debug_dir - Uninitialize MIC debugfs entries.
472 */
473void mic_delete_debug_dir(struct mic_device *mdev)
474{
475	if (!mdev->dbg_dir)
476		return;
477
478	debugfs_remove_recursive(mdev->dbg_dir);
479}
480
481/**
482 * mic_init_debugfs - Initialize global debugfs entry.
483 */
484void __init mic_init_debugfs(void)
485{
486	mic_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL);
487	if (!mic_dbg)
488		pr_err("can't create debugfs dir\n");
489}
490
491/**
492 * mic_exit_debugfs - Uninitialize global debugfs entry
493 */
494void mic_exit_debugfs(void)
495{
496	debugfs_remove(mic_dbg);
497}
498