1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * ipmi_si_platform.c 4 * 5 * Handling for platform devices in IPMI (ACPI, OF, and things 6 * coming from the platform. 7 */ 8 9 #define pr_fmt(fmt) "ipmi_platform: " fmt 10 #define dev_fmt pr_fmt 11 12 #include <linux/types.h> 13 #include <linux/module.h> 14 #include <linux/of_device.h> 15 #include <linux/of_platform.h> 16 #include <linux/of_address.h> 17 #include <linux/of_irq.h> 18 #include <linux/acpi.h> 19 #include "ipmi_si.h" 20 #include "ipmi_dmi.h" 21 22 static bool platform_registered; 23 static bool si_tryplatform = true; 24 #ifdef CONFIG_ACPI 25 static bool si_tryacpi = true; 26 #endif 27 #ifdef CONFIG_OF 28 static bool si_tryopenfirmware = true; 29 #endif 30 #ifdef CONFIG_DMI 31 static bool si_trydmi = true; 32 #else 33 static bool si_trydmi = false; 34 #endif 35 36 module_param_named(tryplatform, si_tryplatform, bool, 0); 37 MODULE_PARM_DESC(tryplatform, 38 "Setting this to zero will disable the default scan of the interfaces identified via platform interfaces besides ACPI, OpenFirmware, and DMI"); 39 #ifdef CONFIG_ACPI 40 module_param_named(tryacpi, si_tryacpi, bool, 0); 41 MODULE_PARM_DESC(tryacpi, 42 "Setting this to zero will disable the default scan of the interfaces identified via ACPI"); 43 #endif 44 #ifdef CONFIG_OF 45 module_param_named(tryopenfirmware, si_tryopenfirmware, bool, 0); 46 MODULE_PARM_DESC(tryopenfirmware, 47 "Setting this to zero will disable the default scan of the interfaces identified via OpenFirmware"); 48 #endif 49 #ifdef CONFIG_DMI 50 module_param_named(trydmi, si_trydmi, bool, 0); 51 MODULE_PARM_DESC(trydmi, 52 "Setting this to zero will disable the default scan of the interfaces identified via DMI"); 53 #endif 54 55 #ifdef CONFIG_ACPI 56 /* For GPE-type interrupts. */ 57 static u32 ipmi_acpi_gpe(acpi_handle gpe_device, 58 u32 gpe_number, void *context) 59 { 60 struct si_sm_io *io = context; 61 62 ipmi_si_irq_handler(io->irq, io->irq_handler_data); 63 return ACPI_INTERRUPT_HANDLED; 64 } 65 66 static void acpi_gpe_irq_cleanup(struct si_sm_io *io) 67 { 68 if (!io->irq) 69 return; 70 71 ipmi_irq_start_cleanup(io); 72 acpi_remove_gpe_handler(NULL, io->irq, &ipmi_acpi_gpe); 73 } 74 75 static int acpi_gpe_irq_setup(struct si_sm_io *io) 76 { 77 acpi_status status; 78 79 if (!io->irq) 80 return 0; 81 82 status = acpi_install_gpe_handler(NULL, 83 io->irq, 84 ACPI_GPE_LEVEL_TRIGGERED, 85 &ipmi_acpi_gpe, 86 io); 87 if (ACPI_FAILURE(status)) { 88 dev_warn(io->dev, 89 "Unable to claim ACPI GPE %d, running polled\n", 90 io->irq); 91 io->irq = 0; 92 return -EINVAL; 93 } 94 95 io->irq_cleanup = acpi_gpe_irq_cleanup; 96 ipmi_irq_finish_setup(io); 97 dev_info(io->dev, "Using ACPI GPE %d\n", io->irq); 98 return 0; 99 } 100 #endif 101 102 static void ipmi_set_addr_data_and_space(struct resource *r, struct si_sm_io *io) 103 { 104 if (resource_type(r) == IORESOURCE_IO) 105 io->addr_space = IPMI_IO_ADDR_SPACE; 106 else 107 io->addr_space = IPMI_MEM_ADDR_SPACE; 108 io->addr_data = r->start; 109 } 110 111 static struct resource * 112 ipmi_get_info_from_resources(struct platform_device *pdev, 113 struct si_sm_io *io) 114 { 115 struct resource *res, *res_second; 116 117 res = platform_get_mem_or_io(pdev, 0); 118 if (!res) { 119 dev_err(&pdev->dev, "no I/O or memory address\n"); 120 return NULL; 121 } 122 ipmi_set_addr_data_and_space(res, io); 123 124 io->regspacing = DEFAULT_REGSPACING; 125 res_second = platform_get_mem_or_io(pdev, 1); 126 if (res_second && resource_type(res_second) == resource_type(res)) { 127 if (res_second->start > io->addr_data) 128 io->regspacing = res_second->start - io->addr_data; 129 } 130 131 return res; 132 } 133 134 static int platform_ipmi_probe(struct platform_device *pdev) 135 { 136 struct si_sm_io io; 137 u8 type, slave_addr, addr_source, regsize, regshift; 138 int rv; 139 140 rv = device_property_read_u8(&pdev->dev, "addr-source", &addr_source); 141 if (rv) 142 addr_source = SI_PLATFORM; 143 if (addr_source >= SI_LAST) 144 return -EINVAL; 145 146 if (addr_source == SI_SMBIOS) { 147 if (!si_trydmi) 148 return -ENODEV; 149 } else if (addr_source != SI_HARDCODED) { 150 if (!si_tryplatform) 151 return -ENODEV; 152 } 153 154 rv = device_property_read_u8(&pdev->dev, "ipmi-type", &type); 155 if (rv) 156 return -ENODEV; 157 158 memset(&io, 0, sizeof(io)); 159 io.addr_source = addr_source; 160 dev_info(&pdev->dev, "probing via %s\n", 161 ipmi_addr_src_to_str(addr_source)); 162 163 switch (type) { 164 case SI_KCS: 165 case SI_SMIC: 166 case SI_BT: 167 io.si_type = type; 168 break; 169 case SI_TYPE_INVALID: /* User disabled this in hardcode. */ 170 return -ENODEV; 171 default: 172 dev_err(&pdev->dev, "ipmi-type property is invalid\n"); 173 return -EINVAL; 174 } 175 176 io.regsize = DEFAULT_REGSIZE; 177 rv = device_property_read_u8(&pdev->dev, "reg-size", ®size); 178 if (!rv) 179 io.regsize = regsize; 180 181 io.regshift = 0; 182 rv = device_property_read_u8(&pdev->dev, "reg-shift", ®shift); 183 if (!rv) 184 io.regshift = regshift; 185 186 if (!ipmi_get_info_from_resources(pdev, &io)) 187 return -EINVAL; 188 189 rv = device_property_read_u8(&pdev->dev, "slave-addr", &slave_addr); 190 if (rv) 191 io.slave_addr = 0x20; 192 else 193 io.slave_addr = slave_addr; 194 195 io.irq = platform_get_irq_optional(pdev, 0); 196 if (io.irq > 0) 197 io.irq_setup = ipmi_std_irq_setup; 198 else 199 io.irq = 0; 200 201 io.dev = &pdev->dev; 202 203 pr_info("ipmi_si: %s: %s %#lx regsize %d spacing %d irq %d\n", 204 ipmi_addr_src_to_str(addr_source), 205 (io.addr_space == IPMI_IO_ADDR_SPACE) ? "io" : "mem", 206 io.addr_data, io.regsize, io.regspacing, io.irq); 207 208 ipmi_si_add_smi(&io); 209 210 return 0; 211 } 212 213 #ifdef CONFIG_OF 214 static const struct of_device_id of_ipmi_match[] = { 215 { .type = "ipmi", .compatible = "ipmi-kcs", 216 .data = (void *)(unsigned long) SI_KCS }, 217 { .type = "ipmi", .compatible = "ipmi-smic", 218 .data = (void *)(unsigned long) SI_SMIC }, 219 { .type = "ipmi", .compatible = "ipmi-bt", 220 .data = (void *)(unsigned long) SI_BT }, 221 {}, 222 }; 223 MODULE_DEVICE_TABLE(of, of_ipmi_match); 224 225 static int of_ipmi_probe(struct platform_device *pdev) 226 { 227 const struct of_device_id *match; 228 struct si_sm_io io; 229 struct resource resource; 230 const __be32 *regsize, *regspacing, *regshift; 231 struct device_node *np = pdev->dev.of_node; 232 int ret; 233 int proplen; 234 235 if (!si_tryopenfirmware) 236 return -ENODEV; 237 238 dev_info(&pdev->dev, "probing via device tree\n"); 239 240 match = of_match_device(of_ipmi_match, &pdev->dev); 241 if (!match) 242 return -ENODEV; 243 244 if (!of_device_is_available(np)) 245 return -EINVAL; 246 247 ret = of_address_to_resource(np, 0, &resource); 248 if (ret) { 249 dev_warn(&pdev->dev, "invalid address from OF\n"); 250 return ret; 251 } 252 253 regsize = of_get_property(np, "reg-size", &proplen); 254 if (regsize && proplen != 4) { 255 dev_warn(&pdev->dev, "invalid regsize from OF\n"); 256 return -EINVAL; 257 } 258 259 regspacing = of_get_property(np, "reg-spacing", &proplen); 260 if (regspacing && proplen != 4) { 261 dev_warn(&pdev->dev, "invalid regspacing from OF\n"); 262 return -EINVAL; 263 } 264 265 regshift = of_get_property(np, "reg-shift", &proplen); 266 if (regshift && proplen != 4) { 267 dev_warn(&pdev->dev, "invalid regshift from OF\n"); 268 return -EINVAL; 269 } 270 271 memset(&io, 0, sizeof(io)); 272 io.si_type = (enum si_type) match->data; 273 io.addr_source = SI_DEVICETREE; 274 io.irq_setup = ipmi_std_irq_setup; 275 276 ipmi_set_addr_data_and_space(&resource, &io); 277 278 io.regsize = regsize ? be32_to_cpup(regsize) : DEFAULT_REGSIZE; 279 io.regspacing = regspacing ? be32_to_cpup(regspacing) : DEFAULT_REGSPACING; 280 io.regshift = regshift ? be32_to_cpup(regshift) : 0; 281 282 io.irq = irq_of_parse_and_map(pdev->dev.of_node, 0); 283 io.dev = &pdev->dev; 284 285 dev_dbg(&pdev->dev, "addr 0x%lx regsize %d spacing %d irq %d\n", 286 io.addr_data, io.regsize, io.regspacing, io.irq); 287 288 return ipmi_si_add_smi(&io); 289 } 290 #else 291 #define of_ipmi_match NULL 292 static int of_ipmi_probe(struct platform_device *dev) 293 { 294 return -ENODEV; 295 } 296 #endif 297 298 #ifdef CONFIG_ACPI 299 static int find_slave_address(struct si_sm_io *io, int slave_addr) 300 { 301 #ifdef CONFIG_IPMI_DMI_DECODE 302 if (!slave_addr) 303 slave_addr = ipmi_dmi_get_slave_addr(io->si_type, 304 io->addr_space, 305 io->addr_data); 306 #endif 307 308 return slave_addr; 309 } 310 311 static int acpi_ipmi_probe(struct platform_device *pdev) 312 { 313 struct device *dev = &pdev->dev; 314 struct si_sm_io io; 315 acpi_handle handle; 316 acpi_status status; 317 unsigned long long tmp; 318 struct resource *res; 319 320 if (!si_tryacpi) 321 return -ENODEV; 322 323 handle = ACPI_HANDLE(dev); 324 if (!handle) 325 return -ENODEV; 326 327 memset(&io, 0, sizeof(io)); 328 io.addr_source = SI_ACPI; 329 dev_info(dev, "probing via ACPI\n"); 330 331 io.addr_info.acpi_info.acpi_handle = handle; 332 333 /* _IFT tells us the interface type: KCS, BT, etc */ 334 status = acpi_evaluate_integer(handle, "_IFT", NULL, &tmp); 335 if (ACPI_FAILURE(status)) { 336 dev_err(dev, "Could not find ACPI IPMI interface type\n"); 337 return -EINVAL; 338 } 339 340 switch (tmp) { 341 case 1: 342 io.si_type = SI_KCS; 343 break; 344 case 2: 345 io.si_type = SI_SMIC; 346 break; 347 case 3: 348 io.si_type = SI_BT; 349 break; 350 case 4: /* SSIF, just ignore */ 351 return -ENODEV; 352 default: 353 dev_info(dev, "unknown IPMI type %lld\n", tmp); 354 return -EINVAL; 355 } 356 357 io.dev = dev; 358 io.regsize = DEFAULT_REGSIZE; 359 io.regshift = 0; 360 361 res = ipmi_get_info_from_resources(pdev, &io); 362 if (!res) 363 return -EINVAL; 364 365 /* If _GPE exists, use it; otherwise use standard interrupts */ 366 status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp); 367 if (ACPI_SUCCESS(status)) { 368 io.irq = tmp; 369 io.irq_setup = acpi_gpe_irq_setup; 370 } else { 371 int irq = platform_get_irq_optional(pdev, 0); 372 373 if (irq > 0) { 374 io.irq = irq; 375 io.irq_setup = ipmi_std_irq_setup; 376 } 377 } 378 379 io.slave_addr = find_slave_address(&io, io.slave_addr); 380 381 dev_info(dev, "%pR regsize %d spacing %d irq %d\n", 382 res, io.regsize, io.regspacing, io.irq); 383 384 request_module("acpi_ipmi"); 385 386 return ipmi_si_add_smi(&io); 387 } 388 389 static const struct acpi_device_id acpi_ipmi_match[] = { 390 { "IPI0001", 0 }, 391 { }, 392 }; 393 MODULE_DEVICE_TABLE(acpi, acpi_ipmi_match); 394 #else 395 static int acpi_ipmi_probe(struct platform_device *dev) 396 { 397 return -ENODEV; 398 } 399 #endif 400 401 static int ipmi_probe(struct platform_device *pdev) 402 { 403 if (pdev->dev.of_node && of_ipmi_probe(pdev) == 0) 404 return 0; 405 406 if (acpi_ipmi_probe(pdev) == 0) 407 return 0; 408 409 return platform_ipmi_probe(pdev); 410 } 411 412 static int ipmi_remove(struct platform_device *pdev) 413 { 414 return ipmi_si_remove_by_dev(&pdev->dev); 415 } 416 417 static int pdev_match_name(struct device *dev, const void *data) 418 { 419 struct platform_device *pdev = to_platform_device(dev); 420 const char *name = data; 421 422 return strcmp(pdev->name, name) == 0; 423 } 424 425 void ipmi_remove_platform_device_by_name(char *name) 426 { 427 struct device *dev; 428 429 while ((dev = bus_find_device(&platform_bus_type, NULL, name, 430 pdev_match_name))) { 431 struct platform_device *pdev = to_platform_device(dev); 432 433 platform_device_unregister(pdev); 434 put_device(dev); 435 } 436 } 437 438 static const struct platform_device_id si_plat_ids[] = { 439 { "dmi-ipmi-si", 0 }, 440 { "hardcode-ipmi-si", 0 }, 441 { "hotmod-ipmi-si", 0 }, 442 { } 443 }; 444 445 struct platform_driver ipmi_platform_driver = { 446 .driver = { 447 .name = SI_DEVICE_NAME, 448 .of_match_table = of_ipmi_match, 449 .acpi_match_table = ACPI_PTR(acpi_ipmi_match), 450 }, 451 .probe = ipmi_probe, 452 .remove = ipmi_remove, 453 .id_table = si_plat_ids 454 }; 455 456 void ipmi_si_platform_init(void) 457 { 458 int rv = platform_driver_register(&ipmi_platform_driver); 459 if (rv) 460 pr_err("Unable to register driver: %d\n", rv); 461 else 462 platform_registered = true; 463 } 464 465 void ipmi_si_platform_shutdown(void) 466 { 467 if (platform_registered) 468 platform_driver_unregister(&ipmi_platform_driver); 469 } 470