Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * ipmi_si_platform.c
0004  *
0005  * Handling for platform devices in IPMI (ACPI, OF, and things
0006  * coming from the platform.
0007  */
0008 
0009 #define pr_fmt(fmt) "ipmi_platform: " fmt
0010 #define dev_fmt pr_fmt
0011 
0012 #include <linux/types.h>
0013 #include <linux/module.h>
0014 #include <linux/of_device.h>
0015 #include <linux/of_platform.h>
0016 #include <linux/of_address.h>
0017 #include <linux/of_irq.h>
0018 #include <linux/acpi.h>
0019 #include "ipmi_si.h"
0020 #include "ipmi_dmi.h"
0021 
0022 static bool platform_registered;
0023 static bool si_tryplatform = true;
0024 #ifdef CONFIG_ACPI
0025 static bool          si_tryacpi = true;
0026 #endif
0027 #ifdef CONFIG_OF
0028 static bool          si_tryopenfirmware = true;
0029 #endif
0030 #ifdef CONFIG_DMI
0031 static bool          si_trydmi = true;
0032 #else
0033 static bool          si_trydmi = false;
0034 #endif
0035 
0036 module_param_named(tryplatform, si_tryplatform, bool, 0);
0037 MODULE_PARM_DESC(tryplatform,
0038          "Setting this to zero will disable the default scan of the interfaces identified via platform interfaces besides ACPI, OpenFirmware, and DMI");
0039 #ifdef CONFIG_ACPI
0040 module_param_named(tryacpi, si_tryacpi, bool, 0);
0041 MODULE_PARM_DESC(tryacpi,
0042          "Setting this to zero will disable the default scan of the interfaces identified via ACPI");
0043 #endif
0044 #ifdef CONFIG_OF
0045 module_param_named(tryopenfirmware, si_tryopenfirmware, bool, 0);
0046 MODULE_PARM_DESC(tryopenfirmware,
0047          "Setting this to zero will disable the default scan of the interfaces identified via OpenFirmware");
0048 #endif
0049 #ifdef CONFIG_DMI
0050 module_param_named(trydmi, si_trydmi, bool, 0);
0051 MODULE_PARM_DESC(trydmi,
0052          "Setting this to zero will disable the default scan of the interfaces identified via DMI");
0053 #endif
0054 
0055 #ifdef CONFIG_ACPI
0056 /* For GPE-type interrupts. */
0057 static u32 ipmi_acpi_gpe(acpi_handle gpe_device,
0058     u32 gpe_number, void *context)
0059 {
0060     struct si_sm_io *io = context;
0061 
0062     ipmi_si_irq_handler(io->irq, io->irq_handler_data);
0063     return ACPI_INTERRUPT_HANDLED;
0064 }
0065 
0066 static void acpi_gpe_irq_cleanup(struct si_sm_io *io)
0067 {
0068     if (!io->irq)
0069         return;
0070 
0071     ipmi_irq_start_cleanup(io);
0072     acpi_remove_gpe_handler(NULL, io->irq, &ipmi_acpi_gpe);
0073 }
0074 
0075 static int acpi_gpe_irq_setup(struct si_sm_io *io)
0076 {
0077     acpi_status status;
0078 
0079     if (!io->irq)
0080         return 0;
0081 
0082     status = acpi_install_gpe_handler(NULL,
0083                       io->irq,
0084                       ACPI_GPE_LEVEL_TRIGGERED,
0085                       &ipmi_acpi_gpe,
0086                       io);
0087     if (ACPI_FAILURE(status)) {
0088         dev_warn(io->dev,
0089              "Unable to claim ACPI GPE %d, running polled\n",
0090              io->irq);
0091         io->irq = 0;
0092         return -EINVAL;
0093     }
0094 
0095     io->irq_cleanup = acpi_gpe_irq_cleanup;
0096     ipmi_irq_finish_setup(io);
0097     dev_info(io->dev, "Using ACPI GPE %d\n", io->irq);
0098     return 0;
0099 }
0100 #endif
0101 
0102 static void ipmi_set_addr_data_and_space(struct resource *r, struct si_sm_io *io)
0103 {
0104     if (resource_type(r) == IORESOURCE_IO)
0105         io->addr_space = IPMI_IO_ADDR_SPACE;
0106     else
0107         io->addr_space = IPMI_MEM_ADDR_SPACE;
0108     io->addr_data = r->start;
0109 }
0110 
0111 static struct resource *
0112 ipmi_get_info_from_resources(struct platform_device *pdev,
0113                  struct si_sm_io *io)
0114 {
0115     struct resource *res, *res_second;
0116 
0117     res = platform_get_mem_or_io(pdev, 0);
0118     if (!res) {
0119         dev_err(&pdev->dev, "no I/O or memory address\n");
0120         return NULL;
0121     }
0122     ipmi_set_addr_data_and_space(res, io);
0123 
0124     io->regspacing = DEFAULT_REGSPACING;
0125     res_second = platform_get_mem_or_io(pdev, 1);
0126     if (res_second && resource_type(res_second) == resource_type(res)) {
0127         if (res_second->start > io->addr_data)
0128             io->regspacing = res_second->start - io->addr_data;
0129     }
0130 
0131     return res;
0132 }
0133 
0134 static int platform_ipmi_probe(struct platform_device *pdev)
0135 {
0136     struct si_sm_io io;
0137     u8 type, slave_addr, addr_source, regsize, regshift;
0138     int rv;
0139 
0140     rv = device_property_read_u8(&pdev->dev, "addr-source", &addr_source);
0141     if (rv)
0142         addr_source = SI_PLATFORM;
0143     if (addr_source >= SI_LAST)
0144         return -EINVAL;
0145 
0146     if (addr_source == SI_SMBIOS) {
0147         if (!si_trydmi)
0148             return -ENODEV;
0149     } else if (addr_source != SI_HARDCODED) {
0150         if (!si_tryplatform)
0151             return -ENODEV;
0152     }
0153 
0154     rv = device_property_read_u8(&pdev->dev, "ipmi-type", &type);
0155     if (rv)
0156         return -ENODEV;
0157 
0158     memset(&io, 0, sizeof(io));
0159     io.addr_source = addr_source;
0160     dev_info(&pdev->dev, "probing via %s\n",
0161          ipmi_addr_src_to_str(addr_source));
0162 
0163     switch (type) {
0164     case SI_KCS:
0165     case SI_SMIC:
0166     case SI_BT:
0167         io.si_type = type;
0168         break;
0169     case SI_TYPE_INVALID: /* User disabled this in hardcode. */
0170         return -ENODEV;
0171     default:
0172         dev_err(&pdev->dev, "ipmi-type property is invalid\n");
0173         return -EINVAL;
0174     }
0175 
0176     io.regsize = DEFAULT_REGSIZE;
0177     rv = device_property_read_u8(&pdev->dev, "reg-size", &regsize);
0178     if (!rv)
0179         io.regsize = regsize;
0180 
0181     io.regshift = 0;
0182     rv = device_property_read_u8(&pdev->dev, "reg-shift", &regshift);
0183     if (!rv)
0184         io.regshift = regshift;
0185 
0186     if (!ipmi_get_info_from_resources(pdev, &io))
0187         return -EINVAL;
0188 
0189     rv = device_property_read_u8(&pdev->dev, "slave-addr", &slave_addr);
0190     if (rv)
0191         io.slave_addr = 0x20;
0192     else
0193         io.slave_addr = slave_addr;
0194 
0195     io.irq = platform_get_irq_optional(pdev, 0);
0196     if (io.irq > 0)
0197         io.irq_setup = ipmi_std_irq_setup;
0198     else
0199         io.irq = 0;
0200 
0201     io.dev = &pdev->dev;
0202 
0203     pr_info("ipmi_si: %s: %s %#lx regsize %d spacing %d irq %d\n",
0204         ipmi_addr_src_to_str(addr_source),
0205         (io.addr_space == IPMI_IO_ADDR_SPACE) ? "io" : "mem",
0206         io.addr_data, io.regsize, io.regspacing, io.irq);
0207 
0208     ipmi_si_add_smi(&io);
0209 
0210     return 0;
0211 }
0212 
0213 #ifdef CONFIG_OF
0214 static const struct of_device_id of_ipmi_match[] = {
0215     { .type = "ipmi", .compatible = "ipmi-kcs",
0216       .data = (void *)(unsigned long) SI_KCS },
0217     { .type = "ipmi", .compatible = "ipmi-smic",
0218       .data = (void *)(unsigned long) SI_SMIC },
0219     { .type = "ipmi", .compatible = "ipmi-bt",
0220       .data = (void *)(unsigned long) SI_BT },
0221     {},
0222 };
0223 MODULE_DEVICE_TABLE(of, of_ipmi_match);
0224 
0225 static int of_ipmi_probe(struct platform_device *pdev)
0226 {
0227     const struct of_device_id *match;
0228     struct si_sm_io io;
0229     struct resource resource;
0230     const __be32 *regsize, *regspacing, *regshift;
0231     struct device_node *np = pdev->dev.of_node;
0232     int ret;
0233     int proplen;
0234 
0235     if (!si_tryopenfirmware)
0236         return -ENODEV;
0237 
0238     dev_info(&pdev->dev, "probing via device tree\n");
0239 
0240     match = of_match_device(of_ipmi_match, &pdev->dev);
0241     if (!match)
0242         return -ENODEV;
0243 
0244     if (!of_device_is_available(np))
0245         return -EINVAL;
0246 
0247     ret = of_address_to_resource(np, 0, &resource);
0248     if (ret) {
0249         dev_warn(&pdev->dev, "invalid address from OF\n");
0250         return ret;
0251     }
0252 
0253     regsize = of_get_property(np, "reg-size", &proplen);
0254     if (regsize && proplen != 4) {
0255         dev_warn(&pdev->dev, "invalid regsize from OF\n");
0256         return -EINVAL;
0257     }
0258 
0259     regspacing = of_get_property(np, "reg-spacing", &proplen);
0260     if (regspacing && proplen != 4) {
0261         dev_warn(&pdev->dev, "invalid regspacing from OF\n");
0262         return -EINVAL;
0263     }
0264 
0265     regshift = of_get_property(np, "reg-shift", &proplen);
0266     if (regshift && proplen != 4) {
0267         dev_warn(&pdev->dev, "invalid regshift from OF\n");
0268         return -EINVAL;
0269     }
0270 
0271     memset(&io, 0, sizeof(io));
0272     io.si_type  = (enum si_type) match->data;
0273     io.addr_source  = SI_DEVICETREE;
0274     io.irq_setup    = ipmi_std_irq_setup;
0275 
0276     ipmi_set_addr_data_and_space(&resource, &io);
0277 
0278     io.regsize  = regsize ? be32_to_cpup(regsize) : DEFAULT_REGSIZE;
0279     io.regspacing   = regspacing ? be32_to_cpup(regspacing) : DEFAULT_REGSPACING;
0280     io.regshift = regshift ? be32_to_cpup(regshift) : 0;
0281 
0282     io.irq      = irq_of_parse_and_map(pdev->dev.of_node, 0);
0283     io.dev      = &pdev->dev;
0284 
0285     dev_dbg(&pdev->dev, "addr 0x%lx regsize %d spacing %d irq %d\n",
0286         io.addr_data, io.regsize, io.regspacing, io.irq);
0287 
0288     return ipmi_si_add_smi(&io);
0289 }
0290 #else
0291 #define of_ipmi_match NULL
0292 static int of_ipmi_probe(struct platform_device *dev)
0293 {
0294     return -ENODEV;
0295 }
0296 #endif
0297 
0298 #ifdef CONFIG_ACPI
0299 static int find_slave_address(struct si_sm_io *io, int slave_addr)
0300 {
0301 #ifdef CONFIG_IPMI_DMI_DECODE
0302     if (!slave_addr)
0303         slave_addr = ipmi_dmi_get_slave_addr(io->si_type,
0304                              io->addr_space,
0305                              io->addr_data);
0306 #endif
0307 
0308     return slave_addr;
0309 }
0310 
0311 static int acpi_ipmi_probe(struct platform_device *pdev)
0312 {
0313     struct device *dev = &pdev->dev;
0314     struct si_sm_io io;
0315     acpi_handle handle;
0316     acpi_status status;
0317     unsigned long long tmp;
0318     struct resource *res;
0319 
0320     if (!si_tryacpi)
0321         return -ENODEV;
0322 
0323     handle = ACPI_HANDLE(dev);
0324     if (!handle)
0325         return -ENODEV;
0326 
0327     memset(&io, 0, sizeof(io));
0328     io.addr_source = SI_ACPI;
0329     dev_info(dev, "probing via ACPI\n");
0330 
0331     io.addr_info.acpi_info.acpi_handle = handle;
0332 
0333     /* _IFT tells us the interface type: KCS, BT, etc */
0334     status = acpi_evaluate_integer(handle, "_IFT", NULL, &tmp);
0335     if (ACPI_FAILURE(status)) {
0336         dev_err(dev, "Could not find ACPI IPMI interface type\n");
0337         return -EINVAL;
0338     }
0339 
0340     switch (tmp) {
0341     case 1:
0342         io.si_type = SI_KCS;
0343         break;
0344     case 2:
0345         io.si_type = SI_SMIC;
0346         break;
0347     case 3:
0348         io.si_type = SI_BT;
0349         break;
0350     case 4: /* SSIF, just ignore */
0351         return -ENODEV;
0352     default:
0353         dev_info(dev, "unknown IPMI type %lld\n", tmp);
0354         return -EINVAL;
0355     }
0356 
0357     io.dev = dev;
0358     io.regsize = DEFAULT_REGSIZE;
0359     io.regshift = 0;
0360 
0361     res = ipmi_get_info_from_resources(pdev, &io);
0362     if (!res)
0363         return -EINVAL;
0364 
0365     /* If _GPE exists, use it; otherwise use standard interrupts */
0366     status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp);
0367     if (ACPI_SUCCESS(status)) {
0368         io.irq = tmp;
0369         io.irq_setup = acpi_gpe_irq_setup;
0370     } else {
0371         int irq = platform_get_irq_optional(pdev, 0);
0372 
0373         if (irq > 0) {
0374             io.irq = irq;
0375             io.irq_setup = ipmi_std_irq_setup;
0376         }
0377     }
0378 
0379     io.slave_addr = find_slave_address(&io, io.slave_addr);
0380 
0381     dev_info(dev, "%pR regsize %d spacing %d irq %d\n",
0382          res, io.regsize, io.regspacing, io.irq);
0383 
0384     request_module("acpi_ipmi");
0385 
0386     return ipmi_si_add_smi(&io);
0387 }
0388 
0389 static const struct acpi_device_id acpi_ipmi_match[] = {
0390     { "IPI0001", 0 },
0391     { },
0392 };
0393 MODULE_DEVICE_TABLE(acpi, acpi_ipmi_match);
0394 #else
0395 static int acpi_ipmi_probe(struct platform_device *dev)
0396 {
0397     return -ENODEV;
0398 }
0399 #endif
0400 
0401 static int ipmi_probe(struct platform_device *pdev)
0402 {
0403     if (pdev->dev.of_node && of_ipmi_probe(pdev) == 0)
0404         return 0;
0405 
0406     if (acpi_ipmi_probe(pdev) == 0)
0407         return 0;
0408 
0409     return platform_ipmi_probe(pdev);
0410 }
0411 
0412 static int ipmi_remove(struct platform_device *pdev)
0413 {
0414     ipmi_si_remove_by_dev(&pdev->dev);
0415 
0416     return 0;
0417 }
0418 
0419 static int pdev_match_name(struct device *dev, const void *data)
0420 {
0421     struct platform_device *pdev = to_platform_device(dev);
0422     const char *name = data;
0423 
0424     return strcmp(pdev->name, name) == 0;
0425 }
0426 
0427 void ipmi_remove_platform_device_by_name(char *name)
0428 {
0429     struct device *dev;
0430 
0431     while ((dev = bus_find_device(&platform_bus_type, NULL, name,
0432                       pdev_match_name))) {
0433         struct platform_device *pdev = to_platform_device(dev);
0434 
0435         platform_device_unregister(pdev);
0436         put_device(dev);
0437     }
0438 }
0439 
0440 static const struct platform_device_id si_plat_ids[] = {
0441     { "dmi-ipmi-si", 0 },
0442     { "hardcode-ipmi-si", 0 },
0443     { "hotmod-ipmi-si", 0 },
0444     { }
0445 };
0446 
0447 struct platform_driver ipmi_platform_driver = {
0448     .driver = {
0449         .name = SI_DEVICE_NAME,
0450         .of_match_table = of_ipmi_match,
0451         .acpi_match_table = ACPI_PTR(acpi_ipmi_match),
0452     },
0453     .probe      = ipmi_probe,
0454     .remove     = ipmi_remove,
0455     .id_table       = si_plat_ids
0456 };
0457 
0458 void ipmi_si_platform_init(void)
0459 {
0460     int rv = platform_driver_register(&ipmi_platform_driver);
0461     if (rv)
0462         pr_err("Unable to register driver: %d\n", rv);
0463     else
0464         platform_registered = true;
0465 }
0466 
0467 void ipmi_si_platform_shutdown(void)
0468 {
0469     if (platform_registered)
0470         platform_driver_unregister(&ipmi_platform_driver);
0471 }