162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright(c) 2021 Intel Corporation. All rights rsvd. */
362306a36Sopenharmony_ci#include <linux/init.h>
462306a36Sopenharmony_ci#include <linux/kernel.h>
562306a36Sopenharmony_ci#include <linux/module.h>
662306a36Sopenharmony_ci#include <linux/pci.h>
762306a36Sopenharmony_ci#include <linux/debugfs.h>
862306a36Sopenharmony_ci#include <linux/io-64-nonatomic-lo-hi.h>
962306a36Sopenharmony_ci#include <uapi/linux/idxd.h>
1062306a36Sopenharmony_ci#include "idxd.h"
1162306a36Sopenharmony_ci#include "registers.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistatic struct dentry *idxd_debugfs_dir;
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistatic void dump_event_entry(struct idxd_device *idxd, struct seq_file *s,
1662306a36Sopenharmony_ci			     u16 index, int *count, bool processed)
1762306a36Sopenharmony_ci{
1862306a36Sopenharmony_ci	struct idxd_evl *evl = idxd->evl;
1962306a36Sopenharmony_ci	struct dsa_evl_entry *entry;
2062306a36Sopenharmony_ci	struct dsa_completion_record *cr;
2162306a36Sopenharmony_ci	u64 *raw;
2262306a36Sopenharmony_ci	int i;
2362306a36Sopenharmony_ci	int evl_strides = evl_ent_size(idxd) / sizeof(u64);
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	entry = (struct dsa_evl_entry *)evl->log + index;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	if (!entry->e.desc_valid)
2862306a36Sopenharmony_ci		return;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	seq_printf(s, "Event Log entry %d (real index %u) processed: %u\n",
3162306a36Sopenharmony_ci		   *count, index, processed);
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	seq_printf(s, "desc valid %u wq idx valid %u\n"
3462306a36Sopenharmony_ci		   "batch %u fault rw %u priv %u error 0x%x\n"
3562306a36Sopenharmony_ci		   "wq idx %u op %#x pasid %u batch idx %u\n"
3662306a36Sopenharmony_ci		   "fault addr %#llx\n",
3762306a36Sopenharmony_ci		   entry->e.desc_valid, entry->e.wq_idx_valid,
3862306a36Sopenharmony_ci		   entry->e.batch, entry->e.fault_rw, entry->e.priv,
3962306a36Sopenharmony_ci		   entry->e.error, entry->e.wq_idx, entry->e.operation,
4062306a36Sopenharmony_ci		   entry->e.pasid, entry->e.batch_idx, entry->e.fault_addr);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	cr = &entry->cr;
4362306a36Sopenharmony_ci	seq_printf(s, "status %#x result %#x fault_info %#x bytes_completed %u\n"
4462306a36Sopenharmony_ci		   "fault addr %#llx inv flags %#x\n\n",
4562306a36Sopenharmony_ci		   cr->status, cr->result, cr->fault_info, cr->bytes_completed,
4662306a36Sopenharmony_ci		   cr->fault_addr, cr->invalid_flags);
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	raw = (u64 *)entry;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	for (i = 0; i < evl_strides; i++)
5162306a36Sopenharmony_ci		seq_printf(s, "entry[%d] = %#llx\n", i, raw[i]);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	seq_puts(s, "\n");
5462306a36Sopenharmony_ci	*count += 1;
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic int debugfs_evl_show(struct seq_file *s, void *d)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	struct idxd_device *idxd = s->private;
6062306a36Sopenharmony_ci	struct idxd_evl *evl = idxd->evl;
6162306a36Sopenharmony_ci	union evl_status_reg evl_status;
6262306a36Sopenharmony_ci	u16 h, t, evl_size, i;
6362306a36Sopenharmony_ci	int count = 0;
6462306a36Sopenharmony_ci	bool processed = true;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	if (!evl || !evl->log)
6762306a36Sopenharmony_ci		return 0;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	spin_lock(&evl->lock);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	evl_status.bits = ioread64(idxd->reg_base + IDXD_EVLSTATUS_OFFSET);
7262306a36Sopenharmony_ci	t = evl_status.tail;
7362306a36Sopenharmony_ci	h = evl_status.head;
7462306a36Sopenharmony_ci	evl_size = evl->size;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	seq_printf(s, "Event Log head %u tail %u interrupt pending %u\n\n",
7762306a36Sopenharmony_ci		   evl_status.head, evl_status.tail, evl_status.int_pending);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	i = t;
8062306a36Sopenharmony_ci	while (1) {
8162306a36Sopenharmony_ci		i = (i + 1) % evl_size;
8262306a36Sopenharmony_ci		if (i == t)
8362306a36Sopenharmony_ci			break;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci		if (processed && i == h)
8662306a36Sopenharmony_ci			processed = false;
8762306a36Sopenharmony_ci		dump_event_entry(idxd, s, i, &count, processed);
8862306a36Sopenharmony_ci	}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	spin_unlock(&evl->lock);
9162306a36Sopenharmony_ci	return 0;
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(debugfs_evl);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ciint idxd_device_init_debugfs(struct idxd_device *idxd)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(idxd_debugfs_dir))
9962306a36Sopenharmony_ci		return 0;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	idxd->dbgfs_dir = debugfs_create_dir(dev_name(idxd_confdev(idxd)), idxd_debugfs_dir);
10262306a36Sopenharmony_ci	if (IS_ERR(idxd->dbgfs_dir))
10362306a36Sopenharmony_ci		return PTR_ERR(idxd->dbgfs_dir);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if (idxd->evl) {
10662306a36Sopenharmony_ci		idxd->dbgfs_evl_file = debugfs_create_file("event_log", 0400,
10762306a36Sopenharmony_ci							   idxd->dbgfs_dir, idxd,
10862306a36Sopenharmony_ci							   &debugfs_evl_fops);
10962306a36Sopenharmony_ci		if (IS_ERR(idxd->dbgfs_evl_file)) {
11062306a36Sopenharmony_ci			debugfs_remove_recursive(idxd->dbgfs_dir);
11162306a36Sopenharmony_ci			idxd->dbgfs_dir = NULL;
11262306a36Sopenharmony_ci			return PTR_ERR(idxd->dbgfs_evl_file);
11362306a36Sopenharmony_ci		}
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	return 0;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_civoid idxd_device_remove_debugfs(struct idxd_device *idxd)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	debugfs_remove_recursive(idxd->dbgfs_dir);
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ciint idxd_init_debugfs(void)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	if (!debugfs_initialized())
12762306a36Sopenharmony_ci		return 0;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	idxd_debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
13062306a36Sopenharmony_ci	if (IS_ERR(idxd_debugfs_dir))
13162306a36Sopenharmony_ci		return  PTR_ERR(idxd_debugfs_dir);
13262306a36Sopenharmony_ci	return 0;
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_civoid idxd_remove_debugfs(void)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	debugfs_remove_recursive(idxd_debugfs_dir);
13862306a36Sopenharmony_ci}
139