1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) IBM Corporation, 2024 4 */ 5 6 #define pr_fmt(fmt) "htmdump: " fmt 7 8 #include <linux/debugfs.h> 9 #include <linux/module.h> 10 #include <asm/io.h> 11 #include <asm/machdep.h> 12 #include <asm/plpar_wrappers.h> 13 14 static void *htm_buf; 15 static u32 nodeindex; 16 static u32 nodalchipindex; 17 static u32 coreindexonchip; 18 static u32 htmtype; 19 static struct dentry *htmdump_debugfs_dir; 20 21 static ssize_t htmdump_read(struct file *filp, char __user *ubuf, 22 size_t count, loff_t *ppos) 23 { 24 void *htm_buf = filp->private_data; 25 unsigned long page, read_size, available; 26 loff_t offset; 27 long rc; 28 29 page = ALIGN_DOWN(*ppos, PAGE_SIZE); 30 offset = (*ppos) % PAGE_SIZE; 31 32 rc = htm_get_dump_hardware(nodeindex, nodalchipindex, coreindexonchip, 33 htmtype, virt_to_phys(htm_buf), PAGE_SIZE, page); 34 35 switch (rc) { 36 case H_SUCCESS: 37 /* H_PARTIAL for the case where all available data can't be 38 * returned due to buffer size constraint. 39 */ 40 case H_PARTIAL: 41 break; 42 /* H_NOT_AVAILABLE indicates reading from an offset outside the range, 43 * i.e. past end of file. 44 */ 45 case H_NOT_AVAILABLE: 46 return 0; 47 case H_BUSY: 48 case H_LONG_BUSY_ORDER_1_MSEC: 49 case H_LONG_BUSY_ORDER_10_MSEC: 50 case H_LONG_BUSY_ORDER_100_MSEC: 51 case H_LONG_BUSY_ORDER_1_SEC: 52 case H_LONG_BUSY_ORDER_10_SEC: 53 case H_LONG_BUSY_ORDER_100_SEC: 54 return -EBUSY; 55 case H_PARAMETER: 56 case H_P2: 57 case H_P3: 58 case H_P4: 59 case H_P5: 60 case H_P6: 61 return -EINVAL; 62 case H_STATE: 63 return -EIO; 64 case H_AUTHORITY: 65 return -EPERM; 66 } 67 68 available = PAGE_SIZE; 69 read_size = min(count, available); 70 *ppos += read_size; 71 return simple_read_from_buffer(ubuf, count, &offset, htm_buf, available); 72 } 73 74 static const struct file_operations htmdump_fops = { 75 .llseek = NULL, 76 .read = htmdump_read, 77 .open = simple_open, 78 }; 79 80 static int htmdump_init_debugfs(void) 81 { 82 htm_buf = kmalloc(PAGE_SIZE, GFP_KERNEL); 83 if (!htm_buf) { 84 pr_err("Failed to allocate htmdump buf\n"); 85 return -ENOMEM; 86 } 87 88 htmdump_debugfs_dir = debugfs_create_dir("htmdump", 89 arch_debugfs_dir); 90 91 debugfs_create_u32("nodeindex", 0600, 92 htmdump_debugfs_dir, &nodeindex); 93 debugfs_create_u32("nodalchipindex", 0600, 94 htmdump_debugfs_dir, &nodalchipindex); 95 debugfs_create_u32("coreindexonchip", 0600, 96 htmdump_debugfs_dir, &coreindexonchip); 97 debugfs_create_u32("htmtype", 0600, 98 htmdump_debugfs_dir, &htmtype); 99 debugfs_create_file("trace", 0400, htmdump_debugfs_dir, htm_buf, &htmdump_fops); 100 101 return 0; 102 } 103 104 static int __init htmdump_init(void) 105 { 106 if (htmdump_init_debugfs()) 107 return -ENOMEM; 108 109 return 0; 110 } 111 112 static void __exit htmdump_exit(void) 113 { 114 debugfs_remove_recursive(htmdump_debugfs_dir); 115 kfree(htm_buf); 116 } 117 118 module_init(htmdump_init); 119 module_exit(htmdump_exit); 120 MODULE_DESCRIPTION("PHYP Hardware Trace Macro (HTM) data dumper"); 121 MODULE_LICENSE("GPL"); 122