// SPDX-License-Identifier: GPL-2.0 /* Marvell OcteonTx2 RVU Admin Function driver * * Copyright (C) 2019 Marvell International Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #ifdef CONFIG_DEBUG_FS #include #include #include #include #include "rvu_struct.h" #include "rvu_reg.h" #include "rvu.h" #define DEBUGFS_DIR_NAME "octeontx2" #define rvu_dbg_NULL NULL #define RVU_DEBUG_FOPS(name, read_op, write_op) \ static const struct file_operations rvu_dbg_##name##_fops = { \ .owner = THIS_MODULE, \ .open = simple_open, \ .read = rvu_dbg_##read_op, \ .write = rvu_dbg_##write_op \ } /* Dumps current provisioning status of all RVU block LFs */ static ssize_t rvu_dbg_rsrc_attach_status(struct file *filp, char __user *buffer, size_t count, loff_t *ppos) { int index, off = 0, flag = 0, go_back = 0, off_prev; struct rvu *rvu = filp->private_data; int lf, pf, vf, pcifunc; struct rvu_block block; int bytes_not_copied; int buf_size = 2048; char *buf; /* don't allow partial reads */ if (*ppos != 0) return 0; buf = kzalloc(buf_size, GFP_KERNEL); if (!buf) return -ENOSPC; off += scnprintf(&buf[off], buf_size - 1 - off, "\npcifunc\t\t"); for (index = 0; index < BLK_COUNT; index++) if (strlen(rvu->hw->block[index].name)) off += scnprintf(&buf[off], buf_size - 1 - off, "%*s\t", (index - 1) * 2, rvu->hw->block[index].name); off += scnprintf(&buf[off], buf_size - 1 - off, "\n"); for (pf = 0; pf < rvu->hw->total_pfs; pf++) { for (vf = 0; vf <= rvu->hw->total_vfs; vf++) { pcifunc = pf << 10 | vf; if (!pcifunc) continue; if (vf) { go_back = scnprintf(&buf[off], buf_size - 1 - off, "PF%d:VF%d\t\t", pf, vf - 1); } else { go_back = scnprintf(&buf[off], buf_size - 1 - off, "PF%d\t\t", pf); } off += go_back; for (index = 0; index < BLKTYPE_MAX; index++) { block = rvu->hw->block[index]; if (!strlen(block.name)) continue; off_prev = off; for (lf = 0; lf < block.lf.max; lf++) { if (block.fn_map[lf] != pcifunc) continue; flag = 1; off += scnprintf(&buf[off], buf_size - 1 - off, "%3d,", lf); } if (flag && off_prev != off) off--; else go_back++; off += scnprintf(&buf[off], buf_size - 1 - off, "\t"); } if (!flag) off -= go_back; else flag = 0; off--; off += scnprintf(&buf[off], buf_size - 1 - off, "\n"); } } bytes_not_copied = copy_to_user(buffer, buf, off); kfree(buf); if (bytes_not_copied) return -EFAULT; *ppos = off; return off; } RVU_DEBUG_FOPS(rsrc_status, rsrc_attach_status, NULL); void rvu_dbg_init(struct rvu *rvu) { struct device *dev = &rvu->pdev->dev; struct dentry *pfile; rvu->rvu_dbg.root = debugfs_create_dir(DEBUGFS_DIR_NAME, NULL); if (!rvu->rvu_dbg.root) { dev_err(rvu->dev, "%s failed\n", __func__); return; } pfile = debugfs_create_file("rsrc_alloc", 0444, rvu->rvu_dbg.root, rvu, &rvu_dbg_rsrc_status_fops); if (!pfile) goto create_failed; return; create_failed: dev_err(dev, "Failed to create debugfs dir\n"); debugfs_remove_recursive(rvu->rvu_dbg.root); } void rvu_dbg_exit(struct rvu *rvu) { debugfs_remove_recursive(rvu->rvu_dbg.root); } #endif /* CONFIG_DEBUG_FS */