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#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}
 441