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