diff --git a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig index c108441882cc..94719fc6ff9d 100644 --- a/drivers/char/ipmi/Kconfig +++ b/drivers/char/ipmi/Kconfig @@ -18,6 +18,10 @@ menuconfig IPMI_HANDLER If unsure, say N. config IPMI_DMI_DECODE + select IPMI_PLAT_DATA + bool + +config IPMI_PLAT_DATA bool if IPMI_HANDLER @@ -56,6 +60,7 @@ config IPMI_DEVICE_INTERFACE config IPMI_SI tristate 'IPMI System Interface handler' + select IPMI_PLAT_DATA help Provides a driver for System Interfaces (KCS, SMIC, BT). Currently, only KCS and SMIC are supported. If diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile index 7a3baf301a8f..3f06b2062475 100644 --- a/drivers/char/ipmi/Makefile +++ b/drivers/char/ipmi/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o obj-$(CONFIG_IPMI_SI) += ipmi_si.o obj-$(CONFIG_IPMI_DMI_DECODE) += ipmi_dmi.o +obj-$(CONFIG_IPMI_PLAT_DATA) += ipmi_plat_data.o obj-$(CONFIG_IPMI_SSIF) += ipmi_ssif.o obj-$(CONFIG_IPMI_POWERNV) += ipmi_powernv.o obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o diff --git a/drivers/char/ipmi/ipmi_dmi.c b/drivers/char/ipmi/ipmi_dmi.c index 249880457b17..ff0b199be472 100644 --- a/drivers/char/ipmi/ipmi_dmi.c +++ b/drivers/char/ipmi/ipmi_dmi.c @@ -14,6 +14,7 @@ #include #include "ipmi_si_sm.h" #include "ipmi_dmi.h" +#include "ipmi_plat_data.h" #define IPMI_DMI_TYPE_KCS 0x01 #define IPMI_DMI_TYPE_SMIC 0x02 @@ -22,7 +23,7 @@ struct ipmi_dmi_info { enum si_type si_type; - u32 flags; + unsigned int space; /* addr space for si, intf# for ssif */ unsigned long addr; u8 slave_addr; struct ipmi_dmi_info *next; @@ -33,133 +34,60 @@ static struct ipmi_dmi_info *ipmi_dmi_infos; static int ipmi_dmi_nr __initdata; static void __init dmi_add_platform_ipmi(unsigned long base_addr, - u32 flags, + unsigned int space, u8 slave_addr, int irq, int offset, int type) { - struct platform_device *pdev; - struct resource r[4]; - unsigned int num_r = 1, size; - struct property_entry p[5]; - unsigned int pidx = 0; - char *name; - int rv; - enum si_type si_type; + const char *name; struct ipmi_dmi_info *info; + struct ipmi_plat_data p; - memset(p, 0, sizeof(p)); + memset(&p, 0, sizeof(p)); name = "dmi-ipmi-si"; switch (type) { case IPMI_DMI_TYPE_SSIF: name = "dmi-ipmi-ssif"; - offset = 1; - size = 1; - si_type = SI_TYPE_INVALID; + p.type = SI_TYPE_INVALID; break; case IPMI_DMI_TYPE_BT: - size = 3; - si_type = SI_BT; + p.type = SI_BT; break; case IPMI_DMI_TYPE_KCS: - size = 2; - si_type = SI_KCS; + p.type = SI_KCS; break; case IPMI_DMI_TYPE_SMIC: - size = 2; - si_type = SI_SMIC; + p.type = SI_SMIC; break; default: pr_err("Invalid IPMI type: %d\n", type); return; } - if (si_type != SI_TYPE_INVALID) - p[pidx++] = PROPERTY_ENTRY_U8("ipmi-type", si_type); - - p[pidx++] = PROPERTY_ENTRY_U8("slave-addr", slave_addr); - p[pidx++] = PROPERTY_ENTRY_U8("addr-source", SI_SMBIOS); + memset(&p, 0, sizeof(p)); + p.addr = base_addr; + p.space = space; + p.regspacing = offset; + p.irq = irq; + p.slave_addr = slave_addr; + p.addr_source = SI_SMBIOS; info = kmalloc(sizeof(*info), GFP_KERNEL); if (!info) { pr_warn("Could not allocate dmi info\n"); } else { - info->si_type = si_type; - info->flags = flags; + info->si_type = p.type; + info->space = space; info->addr = base_addr; info->slave_addr = slave_addr; info->next = ipmi_dmi_infos; ipmi_dmi_infos = info; } - pdev = platform_device_alloc(name, ipmi_dmi_nr); - if (!pdev) { - pr_err("Error allocation IPMI platform device\n"); - return; - } - - if (type == IPMI_DMI_TYPE_SSIF) { - p[pidx++] = PROPERTY_ENTRY_U16("i2c-addr", base_addr); - goto add_properties; - } - - memset(r, 0, sizeof(r)); - - r[0].start = base_addr; - r[0].end = r[0].start + offset - 1; - r[0].name = "IPMI Address 1"; - r[0].flags = flags; - - if (size > 1) { - r[1].start = r[0].start + offset; - r[1].end = r[1].start + offset - 1; - r[1].name = "IPMI Address 2"; - r[1].flags = flags; - num_r++; - } - - if (size > 2) { - r[2].start = r[1].start + offset; - r[2].end = r[2].start + offset - 1; - r[2].name = "IPMI Address 3"; - r[2].flags = flags; - num_r++; - } - - if (irq) { - r[num_r].start = irq; - r[num_r].end = irq; - r[num_r].name = "IPMI IRQ"; - r[num_r].flags = IORESOURCE_IRQ; - num_r++; - } - - rv = platform_device_add_resources(pdev, r, num_r); - if (rv) { - dev_err(&pdev->dev, "Unable to add resources: %d\n", rv); - goto err; - } - -add_properties: - rv = platform_device_add_properties(pdev, p); - if (rv) { - dev_err(&pdev->dev, "Unable to add properties: %d\n", rv); - goto err; - } - - rv = platform_device_add(pdev); - if (rv) { - dev_err(&pdev->dev, "Unable to add device: %d\n", rv); - goto err; - } - - ipmi_dmi_nr++; - return; - -err: - platform_device_put(pdev); + if (ipmi_platform_add(name, ipmi_dmi_nr, &p)) + ipmi_dmi_nr++; } /* @@ -169,14 +97,14 @@ static void __init dmi_add_platform_ipmi(unsigned long base_addr, * This function allows an ACPI-specified IPMI device to look up the * slave address from the DMI table. */ -int ipmi_dmi_get_slave_addr(enum si_type si_type, u32 flags, +int ipmi_dmi_get_slave_addr(enum si_type si_type, unsigned int space, unsigned long base_addr) { struct ipmi_dmi_info *info = ipmi_dmi_infos; while (info) { if (info->si_type == si_type && - info->flags == flags && + info->space == space && info->addr == base_addr) return info->slave_addr; info = info->next; @@ -197,13 +125,13 @@ EXPORT_SYMBOL(ipmi_dmi_get_slave_addr); static void __init dmi_decode_ipmi(const struct dmi_header *dm) { - const u8 *data = (const u8 *) dm; - u32 flags = IORESOURCE_IO; - unsigned long base_addr; - u8 len = dm->length; - u8 slave_addr; - int irq = 0, offset; - int type; + const u8 *data = (const u8 *) dm; + int space = IPMI_IO_ADDR_SPACE; + unsigned long base_addr; + u8 len = dm->length; + u8 slave_addr; + int irq = 0, offset = 0; + int type; if (len < DMI_IPMI_MIN_LENGTH) return; @@ -218,8 +146,7 @@ static void __init dmi_decode_ipmi(const struct dmi_header *dm) } if (len >= DMI_IPMI_VER2_LENGTH) { if (type == IPMI_DMI_TYPE_SSIF) { - offset = 0; - flags = 0; + space = 0; /* Match I2C interface 0. */ base_addr = data[DMI_IPMI_ADDR] >> 1; if (base_addr == 0) { /* @@ -236,7 +163,7 @@ static void __init dmi_decode_ipmi(const struct dmi_header *dm) base_addr &= DMI_IPMI_IO_MASK; } else { /* Memory */ - flags = IORESOURCE_MEM; + space = IPMI_MEM_ADDR_SPACE; } /* @@ -280,7 +207,7 @@ static void __init dmi_decode_ipmi(const struct dmi_header *dm) offset = 1; } - dmi_add_platform_ipmi(base_addr, flags, slave_addr, irq, + dmi_add_platform_ipmi(base_addr, space, slave_addr, irq, offset, type); } diff --git a/drivers/char/ipmi/ipmi_dmi.h b/drivers/char/ipmi/ipmi_dmi.h index 8d2b094db8e6..2dbec0461d0c 100644 --- a/drivers/char/ipmi/ipmi_dmi.h +++ b/drivers/char/ipmi/ipmi_dmi.h @@ -4,6 +4,6 @@ */ #ifdef CONFIG_IPMI_DMI_DECODE -int ipmi_dmi_get_slave_addr(enum si_type si_type, u32 flags, +int ipmi_dmi_get_slave_addr(enum si_type si_type, unsigned int space, unsigned long base_addr); #endif diff --git a/drivers/char/ipmi/ipmi_plat_data.c b/drivers/char/ipmi/ipmi_plat_data.c new file mode 100644 index 000000000000..8f0ca2a848eb --- /dev/null +++ b/drivers/char/ipmi/ipmi_plat_data.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/* + * Add an IPMI platform device. + */ + +#include +#include "ipmi_plat_data.h" +#include "ipmi_si.h" + +struct platform_device *ipmi_platform_add(const char *name, unsigned int inst, + struct ipmi_plat_data *p) +{ + struct platform_device *pdev; + unsigned int num_r = 1, size, pidx = 0; + struct resource r[4]; + struct property_entry pr[6]; + u32 flags; + int rv; + + memset(pr, 0, sizeof(pr)); + memset(r, 0, sizeof(r)); + + if (p->type == SI_BT) + size = 3; + else if (p->type == SI_TYPE_INVALID) + size = 0; + else + size = 2; + + if (p->regsize == 0) + p->regsize = DEFAULT_REGSIZE; + if (p->regspacing == 0) + p->regspacing = p->regsize; + + pr[pidx++] = PROPERTY_ENTRY_U8("ipmi-type", p->type); + if (p->slave_addr) + pr[pidx++] = PROPERTY_ENTRY_U8("slave-addr", p->slave_addr); + pr[pidx++] = PROPERTY_ENTRY_U8("addr-source", p->addr_source); + if (p->regshift) + pr[pidx++] = PROPERTY_ENTRY_U8("reg-shift", p->regshift); + pr[pidx++] = PROPERTY_ENTRY_U8("reg-size", p->regsize); + /* Last entry must be left NULL to terminate it. */ + + pdev = platform_device_alloc(name, inst); + if (!pdev) { + pr_err("Error allocating IPMI platform device %s.%d\n", + name, inst); + return NULL; + } + + if (size == 0) + /* An invalid or SSIF interface, no resources. */ + goto add_properties; + + /* + * Register spacing is derived from the resources in + * the IPMI platform code. + */ + + if (p->space == IPMI_IO_ADDR_SPACE) + flags = IORESOURCE_IO; + else + flags = IORESOURCE_MEM; + + r[0].start = p->addr; + r[0].end = r[0].start + p->regsize - 1; + r[0].name = "IPMI Address 1"; + r[0].flags = flags; + + if (size > 1) { + r[1].start = r[0].start + p->regspacing; + r[1].end = r[1].start + p->regsize - 1; + r[1].name = "IPMI Address 2"; + r[1].flags = flags; + num_r++; + } + + if (size > 2) { + r[2].start = r[1].start + p->regspacing; + r[2].end = r[2].start + p->regsize - 1; + r[2].name = "IPMI Address 3"; + r[2].flags = flags; + num_r++; + } + + if (p->irq) { + r[num_r].start = p->irq; + r[num_r].end = p->irq; + r[num_r].name = "IPMI IRQ"; + r[num_r].flags = IORESOURCE_IRQ; + num_r++; + } + + rv = platform_device_add_resources(pdev, r, num_r); + if (rv) { + dev_err(&pdev->dev, + "Unable to add hard-code resources: %d\n", rv); + goto err; + } + add_properties: + rv = platform_device_add_properties(pdev, pr); + if (rv) { + dev_err(&pdev->dev, + "Unable to add hard-code properties: %d\n", rv); + goto err; + } + + rv = platform_device_add(pdev); + if (rv) { + dev_err(&pdev->dev, + "Unable to add hard-code device: %d\n", rv); + goto err; + } + return pdev; + +err: + platform_device_put(pdev); + return NULL; +} +EXPORT_SYMBOL(ipmi_platform_add); diff --git a/drivers/char/ipmi/ipmi_plat_data.h b/drivers/char/ipmi/ipmi_plat_data.h new file mode 100644 index 000000000000..567cfcec8ada --- /dev/null +++ b/drivers/char/ipmi/ipmi_plat_data.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +/* + * Generic code to add IPMI platform devices. + */ + +#include + +struct ipmi_plat_data { + unsigned int type; /* si_type for si, SI_INVALID for others */ + unsigned int space; /* addr_space for si, intf# for ssif. */ + unsigned long addr; + unsigned int regspacing; + unsigned int regsize; + unsigned int regshift; + unsigned int irq; + unsigned int slave_addr; + enum ipmi_addr_src addr_source; +}; + +struct platform_device *ipmi_platform_add(const char *name, unsigned int inst, + struct ipmi_plat_data *p); diff --git a/drivers/char/ipmi/ipmi_si.h b/drivers/char/ipmi/ipmi_si.h index 3efc8a71aab4..49b211bf9ad7 100644 --- a/drivers/char/ipmi/ipmi_si.h +++ b/drivers/char/ipmi/ipmi_si.h @@ -7,6 +7,7 @@ */ #include +#include #include "ipmi_si_sm.h" #define DEFAULT_REGSPACING 1 diff --git a/drivers/char/ipmi/ipmi_si_hardcode.c b/drivers/char/ipmi/ipmi_si_hardcode.c index 86ac9b8a3219..cb58298d80f5 100644 --- a/drivers/char/ipmi/ipmi_si_hardcode.c +++ b/drivers/char/ipmi/ipmi_si_hardcode.c @@ -5,6 +5,7 @@ #include #include #include "ipmi_si.h" +#include "ipmi_plat_data.h" /* * There can be 4 IO ports passed in (with or without IRQs), 4 addresses, @@ -78,121 +79,39 @@ static struct platform_device *ipmi_hc_pdevs[SI_MAX_PARMS]; static void __init ipmi_hardcode_init_one(const char *si_type_str, unsigned int i, unsigned long addr, - unsigned int flags) + enum ipmi_addr_space addr_space) { - struct platform_device *pdev; - unsigned int num_r = 1, size; - struct resource r[4]; - struct property_entry p[6]; - enum si_type si_type; - unsigned int regspacing, regsize; - int rv; + struct ipmi_plat_data p; - memset(p, 0, sizeof(p)); - memset(r, 0, sizeof(r)); + memset(&p, 0, sizeof(p)); if (!si_type_str || !*si_type_str || strcmp(si_type_str, "kcs") == 0) { - size = 2; - si_type = SI_KCS; + p.type = SI_KCS; } else if (strcmp(si_type_str, "smic") == 0) { - size = 2; - si_type = SI_SMIC; + p.type = SI_SMIC; } else if (strcmp(si_type_str, "bt") == 0) { - size = 3; - si_type = SI_BT; + p.type = SI_BT; } else if (strcmp(si_type_str, "invalid") == 0) { /* * Allow a firmware-specified interface to be * disabled. */ - size = 1; - si_type = SI_TYPE_INVALID; + p.type = SI_TYPE_INVALID; } else { pr_warn("Interface type specified for interface %d, was invalid: %s\n", i, si_type_str); return; } - regsize = regsizes[i]; - if (regsize == 0) - regsize = DEFAULT_REGSIZE; + p.regsize = regsizes[i]; + p.slave_addr = slave_addrs[i]; + p.addr_source = SI_HARDCODED; + p.regshift = regshifts[i]; + p.regsize = regsizes[i]; + p.addr = addr; + p.space = addr_space; - p[0] = PROPERTY_ENTRY_U8("ipmi-type", si_type); - p[1] = PROPERTY_ENTRY_U8("slave-addr", slave_addrs[i]); - p[2] = PROPERTY_ENTRY_U8("addr-source", SI_HARDCODED); - p[3] = PROPERTY_ENTRY_U8("reg-shift", regshifts[i]); - p[4] = PROPERTY_ENTRY_U8("reg-size", regsize); - /* Last entry must be left NULL to terminate it. */ - - /* - * Register spacing is derived from the resources in - * the IPMI platform code. - */ - regspacing = regspacings[i]; - if (regspacing == 0) - regspacing = regsize; - - r[0].start = addr; - r[0].end = r[0].start + regsize - 1; - r[0].name = "IPMI Address 1"; - r[0].flags = flags; - - if (size > 1) { - r[1].start = r[0].start + regspacing; - r[1].end = r[1].start + regsize - 1; - r[1].name = "IPMI Address 2"; - r[1].flags = flags; - num_r++; - } - - if (size > 2) { - r[2].start = r[1].start + regspacing; - r[2].end = r[2].start + regsize - 1; - r[2].name = "IPMI Address 3"; - r[2].flags = flags; - num_r++; - } - - if (irqs[i]) { - r[num_r].start = irqs[i]; - r[num_r].end = irqs[i]; - r[num_r].name = "IPMI IRQ"; - r[num_r].flags = IORESOURCE_IRQ; - num_r++; - } - - pdev = platform_device_alloc("hardcode-ipmi-si", i); - if (!pdev) { - pr_err("Error allocating IPMI platform device %d\n", i); - return; - } - - rv = platform_device_add_resources(pdev, r, num_r); - if (rv) { - dev_err(&pdev->dev, - "Unable to add hard-code resources: %d\n", rv); - goto err; - } - - rv = platform_device_add_properties(pdev, p); - if (rv) { - dev_err(&pdev->dev, - "Unable to add hard-code properties: %d\n", rv); - goto err; - } - - rv = platform_device_add(pdev); - if (rv) { - dev_err(&pdev->dev, - "Unable to add hard-code device: %d\n", rv); - goto err; - } - - ipmi_hc_pdevs[i] = pdev; - return; - -err: - platform_device_put(pdev); + ipmi_hc_pdevs[i] = ipmi_platform_add("hardcode-ipmi-si", i, &p); } void __init ipmi_hardcode_init(void) @@ -219,10 +138,10 @@ void __init ipmi_hardcode_init(void) for (i = 0; i < SI_MAX_PARMS; i++) { if (i < num_ports && ports[i]) ipmi_hardcode_init_one(si_type[i], i, ports[i], - IORESOURCE_IO); + IPMI_IO_ADDR_SPACE); if (i < num_addrs && addrs[i]) ipmi_hardcode_init_one(si_type[i], i, addrs[i], - IORESOURCE_MEM); + IPMI_MEM_ADDR_SPACE); } } diff --git a/drivers/char/ipmi/ipmi_si_platform.c b/drivers/char/ipmi/ipmi_si_platform.c index f690e9edb08c..f2b5ac0986f2 100644 --- a/drivers/char/ipmi/ipmi_si_platform.c +++ b/drivers/char/ipmi/ipmi_si_platform.c @@ -307,15 +307,10 @@ static int of_ipmi_probe(struct platform_device *dev) static int find_slave_address(struct si_sm_io *io, int slave_addr) { #ifdef CONFIG_IPMI_DMI_DECODE - if (!slave_addr) { - u32 flags = IORESOURCE_IO; - - if (io->addr_space == IPMI_MEM_ADDR_SPACE) - flags = IORESOURCE_MEM; - - slave_addr = ipmi_dmi_get_slave_addr(io->si_type, flags, + if (!slave_addr) + slave_addr = ipmi_dmi_get_slave_addr(io->si_type, + io->addr_space, io->addr_data); - } #endif return slave_addr;