|
21 | 21 | #include <asm/io.h>
|
22 | 22 | #include <asm/imc-pmu.h>
|
23 | 23 | #include <asm/cputhreads.h>
|
| 24 | +#include <asm/debugfs.h> |
| 25 | + |
| 26 | +static struct dentry *imc_debugfs_parent; |
| 27 | + |
| 28 | +/* Helpers to export imc command and mode via debugfs */ |
| 29 | +static int imc_mem_get(void *data, u64 *val) |
| 30 | +{ |
| 31 | + *val = cpu_to_be64(*(u64 *)data); |
| 32 | + return 0; |
| 33 | +} |
| 34 | + |
| 35 | +static int imc_mem_set(void *data, u64 val) |
| 36 | +{ |
| 37 | + *(u64 *)data = cpu_to_be64(val); |
| 38 | + return 0; |
| 39 | +} |
| 40 | +DEFINE_DEBUGFS_ATTRIBUTE(fops_imc_x64, imc_mem_get, imc_mem_set, "0x%016llx\n"); |
| 41 | + |
| 42 | +static struct dentry *imc_debugfs_create_x64(const char *name, umode_t mode, |
| 43 | + struct dentry *parent, u64 *value) |
| 44 | +{ |
| 45 | + return debugfs_create_file_unsafe(name, mode, parent, |
| 46 | + value, &fops_imc_x64); |
| 47 | +} |
| 48 | + |
| 49 | +/* |
| 50 | + * export_imc_mode_and_cmd: Create a debugfs interface |
| 51 | + * for imc_cmd and imc_mode |
| 52 | + * for each node in the system. |
| 53 | + * imc_mode and imc_cmd can be changed by echo into |
| 54 | + * this interface. |
| 55 | + */ |
| 56 | +static void export_imc_mode_and_cmd(struct device_node *node, |
| 57 | + struct imc_pmu *pmu_ptr) |
| 58 | +{ |
| 59 | + static u64 loc, *imc_mode_addr, *imc_cmd_addr; |
| 60 | + int chip = 0, nid; |
| 61 | + char mode[16], cmd[16]; |
| 62 | + u32 cb_offset; |
| 63 | + |
| 64 | + imc_debugfs_parent = debugfs_create_dir("imc", powerpc_debugfs_root); |
| 65 | + |
| 66 | + /* |
| 67 | + * Return here, either because 'imc' directory already exists, |
| 68 | + * Or failed to create a new one. |
| 69 | + */ |
| 70 | + if (!imc_debugfs_parent) |
| 71 | + return; |
| 72 | + |
| 73 | + if (of_property_read_u32(node, "cb_offset", &cb_offset)) |
| 74 | + cb_offset = IMC_CNTL_BLK_OFFSET; |
| 75 | + |
| 76 | + for_each_node(nid) { |
| 77 | + loc = (u64)(pmu_ptr->mem_info[chip].vbase) + cb_offset; |
| 78 | + imc_mode_addr = (u64 *)(loc + IMC_CNTL_BLK_MODE_OFFSET); |
| 79 | + sprintf(mode, "imc_mode_%d", nid); |
| 80 | + if (!imc_debugfs_create_x64(mode, 0600, imc_debugfs_parent, |
| 81 | + imc_mode_addr)) |
| 82 | + goto err; |
| 83 | + |
| 84 | + imc_cmd_addr = (u64 *)(loc + IMC_CNTL_BLK_CMD_OFFSET); |
| 85 | + sprintf(cmd, "imc_cmd_%d", nid); |
| 86 | + if (!imc_debugfs_create_x64(cmd, 0600, imc_debugfs_parent, |
| 87 | + imc_cmd_addr)) |
| 88 | + goto err; |
| 89 | + chip++; |
| 90 | + } |
| 91 | + return; |
| 92 | + |
| 93 | +err: |
| 94 | + debugfs_remove_recursive(imc_debugfs_parent); |
| 95 | +} |
24 | 96 |
|
25 | 97 | /*
|
26 | 98 | * imc_get_mem_addr_nest: Function to get nest counter memory region
|
@@ -65,6 +137,7 @@ static int imc_get_mem_addr_nest(struct device_node *node,
|
65 | 137 | }
|
66 | 138 |
|
67 | 139 | pmu_ptr->imc_counter_mmaped = true;
|
| 140 | + export_imc_mode_and_cmd(node, pmu_ptr); |
68 | 141 | kfree(base_addr_arr);
|
69 | 142 | kfree(chipid_arr);
|
70 | 143 | return 0;
|
@@ -213,6 +286,10 @@ static int opal_imc_counters_probe(struct platform_device *pdev)
|
213 | 286 | }
|
214 | 287 | }
|
215 | 288 |
|
| 289 | + /* If none of the nest units are registered, remove debugfs interface */ |
| 290 | + if (pmu_count == 0) |
| 291 | + debugfs_remove_recursive(imc_debugfs_parent); |
| 292 | + |
216 | 293 | return 0;
|
217 | 294 | }
|
218 | 295 |
|
|
0 commit comments