Thomas Gleixner | f4344b1 | 2019-05-23 11:14:49 +0200 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 2 | /* |
| 3 | * OPAL IMC interface detection driver |
| 4 | * Supported on POWERNV platform |
| 5 | * |
| 6 | * Copyright (C) 2017 Madhavan Srinivasan, IBM Corporation. |
| 7 | * (C) 2017 Anju T Sudhakar, IBM Corporation. |
| 8 | * (C) 2017 Hemant K Shaw, IBM Corporation. |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 9 | */ |
| 10 | #include <linux/kernel.h> |
| 11 | #include <linux/platform_device.h> |
| 12 | #include <linux/of.h> |
| 13 | #include <linux/of_address.h> |
| 14 | #include <linux/of_platform.h> |
| 15 | #include <linux/crash_dump.h> |
Aneesh Kumar K.V | dbf77fed | 2021-08-12 18:58:31 +0530 | [diff] [blame] | 16 | #include <linux/debugfs.h> |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 17 | #include <asm/opal.h> |
| 18 | #include <asm/io.h> |
| 19 | #include <asm/imc-pmu.h> |
| 20 | #include <asm/cputhreads.h> |
Anju T Sudhakar | 684d984 | 2017-12-13 11:39:54 +0530 | [diff] [blame] | 21 | |
| 22 | static struct dentry *imc_debugfs_parent; |
| 23 | |
| 24 | /* Helpers to export imc command and mode via debugfs */ |
| 25 | static int imc_mem_get(void *data, u64 *val) |
| 26 | { |
| 27 | *val = cpu_to_be64(*(u64 *)data); |
| 28 | return 0; |
| 29 | } |
| 30 | |
| 31 | static int imc_mem_set(void *data, u64 val) |
| 32 | { |
| 33 | *(u64 *)data = cpu_to_be64(val); |
| 34 | return 0; |
| 35 | } |
| 36 | DEFINE_DEBUGFS_ATTRIBUTE(fops_imc_x64, imc_mem_get, imc_mem_set, "0x%016llx\n"); |
| 37 | |
Greg Kroah-Hartman | f344f0a | 2020-02-09 11:59:01 +0100 | [diff] [blame] | 38 | static void imc_debugfs_create_x64(const char *name, umode_t mode, |
| 39 | struct dentry *parent, u64 *value) |
Anju T Sudhakar | 684d984 | 2017-12-13 11:39:54 +0530 | [diff] [blame] | 40 | { |
Greg Kroah-Hartman | f344f0a | 2020-02-09 11:59:01 +0100 | [diff] [blame] | 41 | debugfs_create_file_unsafe(name, mode, parent, value, &fops_imc_x64); |
Anju T Sudhakar | 684d984 | 2017-12-13 11:39:54 +0530 | [diff] [blame] | 42 | } |
| 43 | |
| 44 | /* |
| 45 | * export_imc_mode_and_cmd: Create a debugfs interface |
| 46 | * for imc_cmd and imc_mode |
| 47 | * for each node in the system. |
| 48 | * imc_mode and imc_cmd can be changed by echo into |
| 49 | * this interface. |
| 50 | */ |
| 51 | static void export_imc_mode_and_cmd(struct device_node *node, |
| 52 | struct imc_pmu *pmu_ptr) |
| 53 | { |
| 54 | static u64 loc, *imc_mode_addr, *imc_cmd_addr; |
Anju T Sudhakar | 684d984 | 2017-12-13 11:39:54 +0530 | [diff] [blame] | 55 | char mode[16], cmd[16]; |
| 56 | u32 cb_offset; |
Madhavan Srinivasan | 41ba17f | 2019-08-27 15:46:35 +0530 | [diff] [blame] | 57 | struct imc_mem_info *ptr = pmu_ptr->mem_info; |
Anju T Sudhakar | 684d984 | 2017-12-13 11:39:54 +0530 | [diff] [blame] | 58 | |
Aneesh Kumar K.V | dbf77fed | 2021-08-12 18:58:31 +0530 | [diff] [blame] | 59 | imc_debugfs_parent = debugfs_create_dir("imc", arch_debugfs_dir); |
Anju T Sudhakar | 684d984 | 2017-12-13 11:39:54 +0530 | [diff] [blame] | 60 | |
Anju T Sudhakar | 684d984 | 2017-12-13 11:39:54 +0530 | [diff] [blame] | 61 | if (of_property_read_u32(node, "cb_offset", &cb_offset)) |
| 62 | cb_offset = IMC_CNTL_BLK_OFFSET; |
| 63 | |
Madhavan Srinivasan | 41ba17f | 2019-08-27 15:46:35 +0530 | [diff] [blame] | 64 | while (ptr->vbase != NULL) { |
| 65 | loc = (u64)(ptr->vbase) + cb_offset; |
Anju T Sudhakar | 684d984 | 2017-12-13 11:39:54 +0530 | [diff] [blame] | 66 | imc_mode_addr = (u64 *)(loc + IMC_CNTL_BLK_MODE_OFFSET); |
Madhavan Srinivasan | 41ba17f | 2019-08-27 15:46:35 +0530 | [diff] [blame] | 67 | sprintf(mode, "imc_mode_%d", (u32)(ptr->id)); |
Greg Kroah-Hartman | f344f0a | 2020-02-09 11:59:01 +0100 | [diff] [blame] | 68 | imc_debugfs_create_x64(mode, 0600, imc_debugfs_parent, |
| 69 | imc_mode_addr); |
Anju T Sudhakar | 684d984 | 2017-12-13 11:39:54 +0530 | [diff] [blame] | 70 | |
| 71 | imc_cmd_addr = (u64 *)(loc + IMC_CNTL_BLK_CMD_OFFSET); |
Madhavan Srinivasan | 41ba17f | 2019-08-27 15:46:35 +0530 | [diff] [blame] | 72 | sprintf(cmd, "imc_cmd_%d", (u32)(ptr->id)); |
Greg Kroah-Hartman | f344f0a | 2020-02-09 11:59:01 +0100 | [diff] [blame] | 73 | imc_debugfs_create_x64(cmd, 0600, imc_debugfs_parent, |
| 74 | imc_cmd_addr); |
Madhavan Srinivasan | 41ba17f | 2019-08-27 15:46:35 +0530 | [diff] [blame] | 75 | ptr++; |
Anju T Sudhakar | 684d984 | 2017-12-13 11:39:54 +0530 | [diff] [blame] | 76 | } |
Anju T Sudhakar | 684d984 | 2017-12-13 11:39:54 +0530 | [diff] [blame] | 77 | } |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 78 | |
| 79 | /* |
| 80 | * imc_get_mem_addr_nest: Function to get nest counter memory region |
| 81 | * for each chip |
| 82 | */ |
| 83 | static int imc_get_mem_addr_nest(struct device_node *node, |
| 84 | struct imc_pmu *pmu_ptr, |
| 85 | u32 offset) |
| 86 | { |
| 87 | int nr_chips = 0, i; |
| 88 | u64 *base_addr_arr, baddr; |
| 89 | u32 *chipid_arr; |
| 90 | |
| 91 | nr_chips = of_property_count_u32_elems(node, "chip-id"); |
| 92 | if (nr_chips <= 0) |
| 93 | return -ENODEV; |
| 94 | |
Markus Elfring | a0828cf | 2017-01-19 17:15:30 +0100 | [diff] [blame] | 95 | base_addr_arr = kcalloc(nr_chips, sizeof(*base_addr_arr), GFP_KERNEL); |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 96 | if (!base_addr_arr) |
| 97 | return -ENOMEM; |
| 98 | |
Markus Elfring | a0828cf | 2017-01-19 17:15:30 +0100 | [diff] [blame] | 99 | chipid_arr = kcalloc(nr_chips, sizeof(*chipid_arr), GFP_KERNEL); |
Anju T Sudhakar | cb094fa | 2018-05-22 14:42:34 +0530 | [diff] [blame] | 100 | if (!chipid_arr) { |
| 101 | kfree(base_addr_arr); |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 102 | return -ENOMEM; |
Anju T Sudhakar | cb094fa | 2018-05-22 14:42:34 +0530 | [diff] [blame] | 103 | } |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 104 | |
| 105 | if (of_property_read_u32_array(node, "chip-id", chipid_arr, nr_chips)) |
| 106 | goto error; |
| 107 | |
| 108 | if (of_property_read_u64_array(node, "base-addr", base_addr_arr, |
| 109 | nr_chips)) |
| 110 | goto error; |
| 111 | |
Anju T Sudhakar | 860b7d2 | 2018-12-18 11:50:41 +0530 | [diff] [blame] | 112 | pmu_ptr->mem_info = kcalloc(nr_chips + 1, sizeof(*pmu_ptr->mem_info), |
Markus Elfring | a0828cf | 2017-01-19 17:15:30 +0100 | [diff] [blame] | 113 | GFP_KERNEL); |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 114 | if (!pmu_ptr->mem_info) |
| 115 | goto error; |
| 116 | |
| 117 | for (i = 0; i < nr_chips; i++) { |
| 118 | pmu_ptr->mem_info[i].id = chipid_arr[i]; |
| 119 | baddr = base_addr_arr[i] + offset; |
| 120 | pmu_ptr->mem_info[i].vbase = phys_to_virt(baddr); |
| 121 | } |
| 122 | |
| 123 | pmu_ptr->imc_counter_mmaped = true; |
| 124 | kfree(base_addr_arr); |
| 125 | kfree(chipid_arr); |
| 126 | return 0; |
| 127 | |
| 128 | error: |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 129 | kfree(base_addr_arr); |
| 130 | kfree(chipid_arr); |
| 131 | return -1; |
| 132 | } |
| 133 | |
| 134 | /* |
| 135 | * imc_pmu_create : Takes the parent device which is the pmu unit, pmu_index |
| 136 | * and domain as the inputs. |
| 137 | * Allocates memory for the struct imc_pmu, sets up its domain, size and offsets |
| 138 | */ |
Anju T Sudhakar | 48e626a | 2019-11-27 12:50:35 +0530 | [diff] [blame] | 139 | static struct imc_pmu *imc_pmu_create(struct device_node *parent, int pmu_index, int domain) |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 140 | { |
| 141 | int ret = 0; |
| 142 | struct imc_pmu *pmu_ptr; |
| 143 | u32 offset; |
| 144 | |
Anju T Sudhakar | b59bd35 | 2019-05-20 14:27:53 +0530 | [diff] [blame] | 145 | /* Return for unknown domain */ |
| 146 | if (domain < 0) |
Anju T Sudhakar | 48e626a | 2019-11-27 12:50:35 +0530 | [diff] [blame] | 147 | return NULL; |
Anju T Sudhakar | b59bd35 | 2019-05-20 14:27:53 +0530 | [diff] [blame] | 148 | |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 149 | /* memory for pmu */ |
Markus Elfring | a0828cf | 2017-01-19 17:15:30 +0100 | [diff] [blame] | 150 | pmu_ptr = kzalloc(sizeof(*pmu_ptr), GFP_KERNEL); |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 151 | if (!pmu_ptr) |
Anju T Sudhakar | 48e626a | 2019-11-27 12:50:35 +0530 | [diff] [blame] | 152 | return NULL; |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 153 | |
| 154 | /* Set the domain */ |
| 155 | pmu_ptr->domain = domain; |
| 156 | |
| 157 | ret = of_property_read_u32(parent, "size", &pmu_ptr->counter_mem_size); |
Anju T Sudhakar | 48e626a | 2019-11-27 12:50:35 +0530 | [diff] [blame] | 158 | if (ret) |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 159 | goto free_pmu; |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 160 | |
| 161 | if (!of_property_read_u32(parent, "offset", &offset)) { |
Anju T Sudhakar | 48e626a | 2019-11-27 12:50:35 +0530 | [diff] [blame] | 162 | if (imc_get_mem_addr_nest(parent, pmu_ptr, offset)) |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 163 | goto free_pmu; |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 164 | } |
| 165 | |
Anju T Sudhakar | 885dcd7 | 2017-07-19 03:06:34 +0530 | [diff] [blame] | 166 | /* Function to register IMC pmu */ |
| 167 | ret = init_imc_pmu(parent, pmu_ptr, pmu_index); |
Anju T Sudhakar | cb094fa | 2018-05-22 14:42:34 +0530 | [diff] [blame] | 168 | if (ret) { |
Anju T Sudhakar | 885dcd7 | 2017-07-19 03:06:34 +0530 | [diff] [blame] | 169 | pr_err("IMC PMU %s Register failed\n", pmu_ptr->pmu.name); |
Anju T Sudhakar | cb094fa | 2018-05-22 14:42:34 +0530 | [diff] [blame] | 170 | kfree(pmu_ptr->pmu.name); |
| 171 | if (pmu_ptr->domain == IMC_DOMAIN_NEST) |
| 172 | kfree(pmu_ptr->mem_info); |
| 173 | kfree(pmu_ptr); |
Anju T Sudhakar | 48e626a | 2019-11-27 12:50:35 +0530 | [diff] [blame] | 174 | return NULL; |
Anju T Sudhakar | cb094fa | 2018-05-22 14:42:34 +0530 | [diff] [blame] | 175 | } |
Anju T Sudhakar | 885dcd7 | 2017-07-19 03:06:34 +0530 | [diff] [blame] | 176 | |
Anju T Sudhakar | 48e626a | 2019-11-27 12:50:35 +0530 | [diff] [blame] | 177 | return pmu_ptr; |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 178 | |
| 179 | free_pmu: |
| 180 | kfree(pmu_ptr); |
Anju T Sudhakar | 48e626a | 2019-11-27 12:50:35 +0530 | [diff] [blame] | 181 | return NULL; |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 182 | } |
| 183 | |
| 184 | static void disable_nest_pmu_counters(void) |
| 185 | { |
| 186 | int nid, cpu; |
LABBE Corentin | 6538ac3 | 2017-08-16 14:34:44 +0200 | [diff] [blame] | 187 | const struct cpumask *l_cpumask; |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 188 | |
Sebastian Andrzej Siewior | 5ae3640 | 2021-08-03 16:15:46 +0200 | [diff] [blame] | 189 | cpus_read_lock(); |
Nicholas Piggin | e7bde88 | 2018-02-13 17:45:11 +1000 | [diff] [blame] | 190 | for_each_node_with_cpus(nid) { |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 191 | l_cpumask = cpumask_of_node(nid); |
Nicholas Piggin | e7bde88 | 2018-02-13 17:45:11 +1000 | [diff] [blame] | 192 | cpu = cpumask_first_and(l_cpumask, cpu_online_mask); |
| 193 | if (cpu >= nr_cpu_ids) |
| 194 | continue; |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 195 | opal_imc_counters_stop(OPAL_IMC_COUNTERS_NEST, |
| 196 | get_hard_smp_processor_id(cpu)); |
| 197 | } |
Sebastian Andrzej Siewior | 5ae3640 | 2021-08-03 16:15:46 +0200 | [diff] [blame] | 198 | cpus_read_unlock(); |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 199 | } |
| 200 | |
| 201 | static void disable_core_pmu_counters(void) |
| 202 | { |
| 203 | cpumask_t cores_map; |
| 204 | int cpu, rc; |
| 205 | |
Sebastian Andrzej Siewior | 5ae3640 | 2021-08-03 16:15:46 +0200 | [diff] [blame] | 206 | cpus_read_lock(); |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 207 | /* Disable the IMC Core functions */ |
| 208 | cores_map = cpu_online_cores_map(); |
| 209 | for_each_cpu(cpu, &cores_map) { |
| 210 | rc = opal_imc_counters_stop(OPAL_IMC_COUNTERS_CORE, |
| 211 | get_hard_smp_processor_id(cpu)); |
| 212 | if (rc) |
| 213 | pr_err("%s: Failed to stop Core (cpu = %d)\n", |
| 214 | __FUNCTION__, cpu); |
| 215 | } |
Sebastian Andrzej Siewior | 5ae3640 | 2021-08-03 16:15:46 +0200 | [diff] [blame] | 216 | cpus_read_unlock(); |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 217 | } |
| 218 | |
Madhavan Srinivasan | 73ce9aec | 2017-11-22 10:45:39 +0530 | [diff] [blame] | 219 | int get_max_nest_dev(void) |
| 220 | { |
| 221 | struct device_node *node; |
| 222 | u32 pmu_units = 0, type; |
| 223 | |
| 224 | for_each_compatible_node(node, NULL, IMC_DTB_UNIT_COMPAT) { |
| 225 | if (of_property_read_u32(node, "type", &type)) |
| 226 | continue; |
| 227 | |
| 228 | if (type == IMC_TYPE_CHIP) |
| 229 | pmu_units++; |
| 230 | } |
| 231 | |
| 232 | return pmu_units; |
| 233 | } |
| 234 | |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 235 | static int opal_imc_counters_probe(struct platform_device *pdev) |
| 236 | { |
| 237 | struct device_node *imc_dev = pdev->dev.of_node; |
Anju T Sudhakar | 48e626a | 2019-11-27 12:50:35 +0530 | [diff] [blame] | 238 | struct imc_pmu *pmu; |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 239 | int pmu_count = 0, domain; |
Anju T Sudhakar | 25af86b | 2018-05-22 14:42:37 +0530 | [diff] [blame] | 240 | bool core_imc_reg = false, thread_imc_reg = false; |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 241 | u32 type; |
| 242 | |
| 243 | /* |
| 244 | * Check whether this is kdump kernel. If yes, force the engines to |
| 245 | * stop and return. |
| 246 | */ |
| 247 | if (is_kdump_kernel()) { |
| 248 | disable_nest_pmu_counters(); |
| 249 | disable_core_pmu_counters(); |
| 250 | return -ENODEV; |
| 251 | } |
| 252 | |
| 253 | for_each_compatible_node(imc_dev, NULL, IMC_DTB_UNIT_COMPAT) { |
Anju T Sudhakar | 48e626a | 2019-11-27 12:50:35 +0530 | [diff] [blame] | 254 | pmu = NULL; |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 255 | if (of_property_read_u32(imc_dev, "type", &type)) { |
| 256 | pr_warn("IMC Device without type property\n"); |
| 257 | continue; |
| 258 | } |
| 259 | |
| 260 | switch (type) { |
| 261 | case IMC_TYPE_CHIP: |
| 262 | domain = IMC_DOMAIN_NEST; |
| 263 | break; |
| 264 | case IMC_TYPE_CORE: |
| 265 | domain =IMC_DOMAIN_CORE; |
| 266 | break; |
| 267 | case IMC_TYPE_THREAD: |
| 268 | domain = IMC_DOMAIN_THREAD; |
| 269 | break; |
Anju T Sudhakar | 72c69dc | 2019-04-16 15:18:30 +0530 | [diff] [blame] | 270 | case IMC_TYPE_TRACE: |
Anju T Sudhakar | 4bdd394 | 2020-03-13 11:22:38 +0530 | [diff] [blame] | 271 | domain = IMC_DOMAIN_TRACE; |
Anju T Sudhakar | 72c69dc | 2019-04-16 15:18:30 +0530 | [diff] [blame] | 272 | break; |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 273 | default: |
| 274 | pr_warn("IMC Unknown Device type \n"); |
| 275 | domain = -1; |
| 276 | break; |
| 277 | } |
| 278 | |
Anju T Sudhakar | 48e626a | 2019-11-27 12:50:35 +0530 | [diff] [blame] | 279 | pmu = imc_pmu_create(imc_dev, pmu_count, domain); |
| 280 | if (pmu != NULL) { |
| 281 | if (domain == IMC_DOMAIN_NEST) { |
| 282 | if (!imc_debugfs_parent) |
| 283 | export_imc_mode_and_cmd(imc_dev, pmu); |
Madhavan Srinivasan | de34787f | 2017-11-22 10:45:38 +0530 | [diff] [blame] | 284 | pmu_count++; |
Anju T Sudhakar | 48e626a | 2019-11-27 12:50:35 +0530 | [diff] [blame] | 285 | } |
Anju T Sudhakar | 25af86b | 2018-05-22 14:42:37 +0530 | [diff] [blame] | 286 | if (domain == IMC_DOMAIN_CORE) |
| 287 | core_imc_reg = true; |
| 288 | if (domain == IMC_DOMAIN_THREAD) |
| 289 | thread_imc_reg = true; |
Madhavan Srinivasan | de34787f | 2017-11-22 10:45:38 +0530 | [diff] [blame] | 290 | } |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 291 | } |
| 292 | |
Anju T Sudhakar | 25af86b | 2018-05-22 14:42:37 +0530 | [diff] [blame] | 293 | /* If core imc is not registered, unregister thread-imc */ |
| 294 | if (!core_imc_reg && thread_imc_reg) |
| 295 | unregister_thread_imc(); |
| 296 | |
Madhavan Srinivasan | 8f95faa | 2017-07-19 03:06:33 +0530 | [diff] [blame] | 297 | return 0; |
| 298 | } |
| 299 | |
| 300 | static void opal_imc_counters_shutdown(struct platform_device *pdev) |
| 301 | { |
| 302 | /* |
| 303 | * Function only stops the engines which is bare minimum. |
| 304 | * TODO: Need to handle proper memory cleanup and pmu |
| 305 | * unregister. |
| 306 | */ |
| 307 | disable_nest_pmu_counters(); |
| 308 | disable_core_pmu_counters(); |
| 309 | } |
| 310 | |
| 311 | static const struct of_device_id opal_imc_match[] = { |
| 312 | { .compatible = IMC_DTB_COMPAT }, |
| 313 | {}, |
| 314 | }; |
| 315 | |
| 316 | static struct platform_driver opal_imc_driver = { |
| 317 | .driver = { |
| 318 | .name = "opal-imc-counters", |
| 319 | .of_match_table = opal_imc_match, |
| 320 | }, |
| 321 | .probe = opal_imc_counters_probe, |
| 322 | .shutdown = opal_imc_counters_shutdown, |
| 323 | }; |
| 324 | |
| 325 | builtin_platform_driver(opal_imc_driver); |