Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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