From patchwork Fri Jan 29 22:43:14 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Corey Minyard X-Patchwork-Id: 60842 Delivered-To: patch@linaro.org Received: by 10.112.130.2 with SMTP id oa2csp1415841lbb; Fri, 29 Jan 2016 15:43:45 -0800 (PST) X-Received: by 10.67.1.102 with SMTP id bf6mr17782367pad.103.1454111025710; Fri, 29 Jan 2016 15:43:45 -0800 (PST) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id p80si27107362pfi.237.2016.01.29.15.43.45; Fri, 29 Jan 2016 15:43:45 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755086AbcA2Xnm (ORCPT + 30 others); Fri, 29 Jan 2016 18:43:42 -0500 Received: from vms173023pub.verizon.net ([206.46.173.23]:62969 "EHLO vms173023pub.verizon.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752852AbcA2Xnl (ORCPT ); Fri, 29 Jan 2016 18:43:41 -0500 X-Greylist: delayed 3608 seconds by postgrey-1.27 at vger.kernel.org; Fri, 29 Jan 2016 18:43:40 EST Received: from serve.minyard.net ([173.57.176.17]) by vms173023.mailsrvcs.net (Oracle Communications Messaging Server 7.0.5.32.0 64bit (built Jul 16 2014)) with ESMTPA id <0O1Q00K3BKGD1R00@vms173023.mailsrvcs.net> for linux-kernel@vger.kernel.org; Fri, 29 Jan 2016 16:43:30 -0600 (CST) X-CMAE-Score: 0 X-CMAE-Analysis: v=2.1 cv=WcjxEBVX c=1 sm=1 tr=0 a=bXmWQgKa9n63w7XTPFb8JQ==:117 a=xqWC_Br6kY4A:10 a=7aQ_Q-yQQ-AA:10 a=fk1lIlRQAAAA:8 a=VwQbUJbxAAAA:8 a=QyXUC8HyAAAA:8 a=N54-gffFAAAA:8 a=9HpZsGgYdKqS3LovaNwA:9 a=WEOZ9XmPThK7gSaE:21 a=pKRxG0BOnK63YA1U:21 Received: from t430.minyard.net (unknown [IPv6:2001:470:b8f6:1b:4c7b:9846:cb54:c61]) by serve.minyard.net (Postfix) with ESMTPA id 3BF593263; Fri, 29 Jan 2016 16:43:25 -0600 (CST) Received: by t430.minyard.net (Postfix, from userid 1000) id 982B7300740; Fri, 29 Jan 2016 16:43:23 -0600 (CST) From: minyard@acm.org To: openipmi-developer@lists.sourceforge.net, linux-kernel@vger.kernel.org Cc: Jean Delvare , Andy Lutomirski , Corey Minyard Subject: [PATCH 4/4] dmi/ipmi: Add IPMI DMI devices as platform devices Date: Fri, 29 Jan 2016 16:43:14 -0600 Message-id: <1454107394-8914-5-git-send-email-minyard@acm.org> X-Mailer: git-send-email 2.5.0 In-reply-to: <1454107394-8914-1-git-send-email-minyard@acm.org> References: <1454107394-8914-1-git-send-email-minyard@acm.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Corey Minyard Have DMI create a platform device for every IPMI device it finds. This requires some modification of the IPMI driver to find the IPMI devices as platform devices. Signed-off-by: Corey Minyard Cc: Jean Delvare Cc: Andy Lutomirski --- drivers/char/ipmi/ipmi_si_intf.c | 42 +++++++++---------- drivers/char/ipmi/ipmi_ssif.c | 87 ++++++++++++++++++++++++++++++++-------- drivers/firmware/dmi_scan.c | 55 ++++++++++++++++++++++++- 3 files changed, 142 insertions(+), 42 deletions(-) -- 2.5.0 diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 22292e1..4984c86 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2272,23 +2272,19 @@ static void spmi_find_bmc(void) #endif #ifdef CONFIG_DMI -static void try_init_dmi(struct dmi_device *dmi_dev) +static int dmi_ipmi_probe(struct platform_device *pdev) { + struct dmi_device *dmi_dev = to_dmi_device(pdev->dev.fwnode); struct dmi_dev_ipmi *ipmi_data = to_dmi_dev_ipmi(dmi_dev); struct smi_info *info; - if (!ipmi_data) - return; - - if (!ipmi_data->good_data) { - pr_err(PFX "DMI data for this device was invalid.\n"); - return; - } + if (!si_trydmi || !ipmi_data) + return -ENODEV; info = smi_info_alloc(); if (!info) { pr_err(PFX "Could not allocate SI data\n"); - return; + return -ENOMEM; } info->addr_source = SI_SMBIOS; @@ -2306,7 +2302,7 @@ static void try_init_dmi(struct dmi_device *dmi_dev) break; default: kfree(info); - return; + return -EINVAL; } if (ipmi_data->is_io_space) { @@ -2330,6 +2326,8 @@ static void try_init_dmi(struct dmi_device *dmi_dev) if (info->irq) info->irq_setup = std_irq_setup; + info->dev = &pdev->dev; + pr_info("ipmi_si: SMBIOS: %s %#lx regsize %d spacing %d irq %d\n", (info->io.addr_type == IPMI_IO_ADDR_SPACE) ? "io" : "mem", info->io.addr_data, info->io.regsize, info->io.regspacing, @@ -2337,14 +2335,13 @@ static void try_init_dmi(struct dmi_device *dmi_dev) if (add_smi(info)) kfree(info); -} -static void dmi_find_bmc(void) + return 0; +} +#else +static int dmi_ipmi_probe(struct platform_device *pdev) { - struct dmi_device *dev = NULL; - - while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) - try_init_dmi(dev); + return -ENODEV; } #endif /* CONFIG_DMI */ @@ -2729,7 +2726,10 @@ static int ipmi_probe(struct platform_device *dev) if (of_ipmi_probe(dev) == 0) return 0; - return acpi_ipmi_probe(dev); + if (acpi_ipmi_probe(dev) == 0) + return 0; + + return dmi_ipmi_probe(dev); } static int ipmi_remove(struct platform_device *dev) @@ -3446,7 +3446,7 @@ static int add_smi(struct smi_info *new_smi) si_to_str[new_smi->si_type]); mutex_lock(&smi_infos_lock); if (!is_new_interface(new_smi)) { - printk(KERN_CONT " duplicate interface\n"); + printk(KERN_CONT ": duplicate interface\n"); rv = -EBUSY; goto out_err; } @@ -3737,11 +3737,6 @@ static int init_ipmi_si(void) } #endif -#ifdef CONFIG_DMI - if (si_trydmi) - dmi_find_bmc(); -#endif - #ifdef CONFIG_ACPI if (si_tryacpi) spmi_find_bmc(); @@ -3902,6 +3897,7 @@ static void cleanup_ipmi_si(void) } module_exit(cleanup_ipmi_si); +MODULE_ALIAS("platform:dmi-ipmi-si"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Corey Minyard "); MODULE_DESCRIPTION("Interface to the IPMI driver for the KCS, SMIC, and BT" diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index 7be0109..4579e59 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -181,6 +181,8 @@ struct ssif_addr_info { int slave_addr; enum ipmi_addr_src addr_src; union ipmi_smi_info_union addr_info; + struct device *dev; + struct i2c_client *client; struct mutex clients_mutex; struct list_head clients; @@ -1444,6 +1446,7 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) ssif_info->addr_source = addr_info->addr_src; ssif_info->ssif_debug = addr_info->debug; ssif_info->addr_info = addr_info->addr_info; + addr_info->client = client; slave_addr = addr_info->slave_addr; } } @@ -1680,8 +1683,19 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) } out: - if (rv) + if (rv) { + /* + * Note that if addr_info->client is assigned, we + * leave it. The i2c client hangs around even if we + * return a failure here, and the failure here is not + * propagated back to the i2c code. This seems to be + * design intent, strange as it may be. But if we + * don't leave it, ssif_platform_remove will not remove + * the client like it should. + */ + dev_err(&client->dev, "Unable to start IPMI SSIF: %d\n", rv); kfree(ssif_info); + } kfree(resp); return rv; @@ -1706,7 +1720,8 @@ static int ssif_adapter_handler(struct device *adev, void *opaque) static int new_ssif_client(int addr, char *adapter_name, int debug, int slave_addr, - enum ipmi_addr_src addr_src) + enum ipmi_addr_src addr_src, + struct device *dev) { struct ssif_addr_info *addr_info; int rv = 0; @@ -1736,9 +1751,14 @@ static int new_ssif_client(int addr, char *adapter_name, sizeof(addr_info->binfo.type)); addr_info->binfo.addr = addr; addr_info->binfo.platform_data = addr_info; + if (dev) + addr_info->binfo.fwnode = dev->fwnode; addr_info->debug = debug; addr_info->slave_addr = slave_addr; addr_info->addr_src = addr_src; + addr_info->dev = dev; + + dev_set_drvdata(dev, addr_info); list_add_tail(&addr_info->link, &ssif_infos); @@ -1877,7 +1897,7 @@ static int try_init_spmi(struct SPMITable *spmi) myaddr = spmi->addr.address >> 1; - return new_ssif_client(myaddr, NULL, 0, 0, SI_SPMI); + return new_ssif_client(myaddr, NULL, 0, 0, SI_SPMI, NULL); } static void spmi_find_bmc(void) @@ -1906,11 +1926,12 @@ static void spmi_find_bmc(void) { } #endif #ifdef CONFIG_DMI -static int decode_dmi(struct dmi_device *dmi_dev) +static int dmi_ipmi_probe(struct platform_device *pdev) { + struct dmi_device *dmi_dev = to_dmi_device(pdev->dev.fwnode); struct dmi_dev_ipmi *ipmi_data = to_dmi_dev_ipmi(dmi_dev); - if (!ipmi_data) + if (!ssif_trydmi || !ipmi_data) return -ENODEV; if (!ipmi_data->good_data) { @@ -1922,18 +1943,13 @@ static int decode_dmi(struct dmi_device *dmi_dev) return -ENODEV; return new_ssif_client(ipmi_data->base_addr, NULL, 0, - ipmi_data->slave_addr, SI_SMBIOS); + ipmi_data->slave_addr, SI_SMBIOS, &pdev->dev); } - -static void dmi_iterator(void) +#else +static int dmi_ipmi_probe(struct platform_device *pdev) { - struct dmi_device *dev = NULL; - - while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) - decode_dmi(dev); + return -ENODEV; } -#else -static void dmi_iterator(void) { } #endif static const struct i2c_device_id ssif_id[] = { @@ -1954,6 +1970,36 @@ static struct i2c_driver ssif_i2c_driver = { .detect = ssif_detect }; +static int ssif_platform_probe(struct platform_device *dev) +{ + return dmi_ipmi_probe(dev); +} + +static int ssif_platform_remove(struct platform_device *dev) +{ + struct ssif_addr_info *addr_info = dev_get_drvdata(&dev->dev); + + if (!addr_info) + return 0; + + mutex_lock(&ssif_infos_mutex); + if (addr_info->client) + i2c_unregister_device(addr_info->client); + + list_del(&addr_info->link); + kfree(addr_info); + mutex_unlock(&ssif_infos_mutex); + return 0; +} + +static struct platform_driver ipmi_driver = { + .driver = { + .name = DEVICE_NAME, + }, + .probe = ssif_platform_probe, + .remove = ssif_platform_remove, +}; + static int init_ipmi_ssif(void) { int i; @@ -1968,7 +2014,7 @@ static int init_ipmi_ssif(void) for (i = 0; i < num_addrs; i++) { rv = new_ssif_client(addr[i], adapter_name[i], dbg[i], slave_addrs[i], - SI_HARDCODED); + SI_HARDCODED, NULL); if (rv) pr_err(PFX "Couldn't add hardcoded device at addr 0x%x\n", @@ -1978,8 +2024,7 @@ static int init_ipmi_ssif(void) if (ssif_tryacpi) ssif_i2c_driver.driver.acpi_match_table = ACPI_PTR(ssif_acpi_match); - if (ssif_trydmi) - dmi_iterator(); + if (ssif_tryacpi) spmi_find_bmc(); @@ -1989,6 +2034,11 @@ static int init_ipmi_ssif(void) if (!rv) initialized = true; + /* Wait until here so ACPI devices will start first. */ + rv = platform_driver_register(&ipmi_driver); + if (rv) + pr_err(PFX "Unable to register driver: %d\n", rv); + return rv; } module_init(init_ipmi_ssif); @@ -2000,12 +2050,15 @@ static void cleanup_ipmi_ssif(void) initialized = false; + platform_driver_unregister(&ipmi_driver); + i2c_del_driver(&ssif_i2c_driver); free_ssif_clients(); } module_exit(cleanup_ipmi_ssif); +MODULE_ALIAS("platform:dmi-ipmi-ssif"); MODULE_AUTHOR("Todd C Davis , Corey Minyard "); MODULE_DESCRIPTION("IPMI driver for management controllers on a SMBus"); MODULE_LICENSE("GPL"); diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 6e4859d..7fda3ce 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -793,6 +794,52 @@ static ssize_t raw_table_read(struct file *file, struct kobject *kobj, return count; } +static void __init dmi_add_platform_ipmi(struct dmi_device *dev, int *nr) +{ + struct platform_device *pdev; + struct dmi_dev_ipmi *ipmi_dev = to_dmi_dev_ipmi(dev); + int rv; + + if (!ipmi_dev->good_data) { + pr_err("dmi: Invalid IPMI data, not creating platform device"); + return; + } + + if (ipmi_dev->type == IPMI_DMI_TYPE_SSIF) + pdev = platform_device_alloc("dmi-ipmi-ssif", *nr); + else + pdev = platform_device_alloc("dmi-ipmi-si", *nr); + if (!pdev) { + pr_err("dmi: Error allocation IPMI platform device"); + return; + } + if (ipmi_dev->type == IPMI_DMI_TYPE_SSIF) + pdev->driver_override = "ipmi_ssif"; + else + pdev->driver_override = "ipmi_si"; + + pdev->dev.fwnode = &dev->fwnode; + rv = platform_device_add(pdev); + if (rv) { + dev_err(&pdev->dev, "dmi: Unable to add device: %d\n", rv); + platform_device_del(pdev); + return; + } + + (*nr)++; +} + +static void __init dmi_add_platform_devices(void) +{ + struct dmi_device *dev; + int nr_ipmi = 0; + + list_for_each_entry(dev, &dmi_devices, list) { + if (dev->type == DMI_DEV_TYPE_IPMI) + dmi_add_platform_ipmi(dev, &nr_ipmi); + } +} + static BIN_ATTR(smbios_entry_point, S_IRUSR, raw_table_read, NULL, 0); static BIN_ATTR(DMI, S_IRUSR, raw_table_read, NULL, 0); @@ -833,9 +880,13 @@ static int __init dmi_init(void) bin_attr_DMI.size = dmi_len; bin_attr_DMI.private = dmi_table; ret = sysfs_create_bin_file(tables_kobj, &bin_attr_DMI); - if (!ret) - return 0; + if (ret) + goto out_remove_bin_file; + + dmi_add_platform_devices(); + return 0; + out_remove_bin_file: sysfs_remove_bin_file(tables_kobj, &bin_attr_smbios_entry_point); err_unmap: