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