From patchwork Wed Apr 27 13:04:20 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Corey Minyard X-Patchwork-Id: 66788 Delivered-To: patch@linaro.org Received: by 10.140.93.198 with SMTP id d64csp2176408qge; Wed, 27 Apr 2016 06:04:57 -0700 (PDT) X-Received: by 10.98.80.150 with SMTP id g22mr11615235pfj.132.1461762297436; Wed, 27 Apr 2016 06:04:57 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id n9si4144055pfb.111.2016.04.27.06.04.57; Wed, 27 Apr 2016 06:04:57 -0700 (PDT) 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; dkim=fail header.i=@gmail.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 S1752824AbcD0NEs (ORCPT + 29 others); Wed, 27 Apr 2016 09:04:48 -0400 Received: from mail-pf0-f194.google.com ([209.85.192.194]:34580 "EHLO mail-pf0-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752561AbcD0NEf (ORCPT ); Wed, 27 Apr 2016 09:04:35 -0400 Received: by mail-pf0-f194.google.com with SMTP id 145so4752806pfz.1 for ; Wed, 27 Apr 2016 06:04:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=lyECr+52OPUOgJtGjr6EAYSPD9kpJ72qba/++c09Dzw=; b=I6iweBr1kpKtds8pblfm56qFsOaeYMdwb6ucI9OrauDPBGznV8stOltSTzQwFTfP4b vVVHate3KMZZ7oEn6dD0MLHhS0hTZwao3vvKUgQ8er/9EMHr1M8qvVrU9ESxRpXdok6R xtFWi5xlUWoQxwbkoN+tZd8bckNals64+Lbk6zXug3kX4fDHvj1dSK2G9aXqM5DN+1Xk nVKkQeETT4kxnCjU8l5JWwYBSomnxtkGzoINb8rujKLUwc5VgVb9MFkscgIfuMR31PGC k2ylubxh2kD440srtpY26ypjyzHspYSLC0S3ckc5Al3DbNyW4aalmCBNGhomuOund231 1eAw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=lyECr+52OPUOgJtGjr6EAYSPD9kpJ72qba/++c09Dzw=; b=WUF5XK0i1jg2x+Hg9p3tPGQOU+xdXTbCqcSk7JLFc281DCIdLIAdZp/ozkAoYW+lQd UXknSibimKqJUh3g4i1cbON2JWUIT+DiSL6uAFK3S5vgzW38yFGGfU0aRBc4/puOq+OP y5WHIT8IZ/VDeNsIFI+nB8axocrkke3vbSJ7yzk9Mlg/MC2nTEmBePSwaH2w9krpWQ5L o4EOVGq1iHIUsIHVyoekrGm2S0Ow5hkNLjgoRtzubx+DyiROKfqSwTX54CRlTsnBOayu nCT/0hAOp00dAVCIGdrmDS73o6rNR1gm/C0Q6oRGTa3hHd42VQabKpbtiDucp61bu//L Ux8Q== X-Gm-Message-State: AOPr4FWugD45yhrVwBS6I59q5+6X5aI/vGAqGH9Qs/7MQAqWwbneDli+m/wMawSTYzKpeg== X-Received: by 10.98.86.141 with SMTP id h13mr11525199pfj.99.1461762274545; Wed, 27 Apr 2016 06:04:34 -0700 (PDT) Received: from serve.minyard.net ([173.71.13.195]) by smtp.gmail.com with ESMTPSA id 28sm6491321pfr.89.2016.04.27.06.04.32 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 27 Apr 2016 06:04:33 -0700 (PDT) Received: from t430.minyard.net (unknown [IPv6:2001:470:b8f6:1b:3c36:6e8c:c70a:c6bd]) by serve.minyard.net (Postfix) with ESMTPA id 1CBE01830; Wed, 27 Apr 2016 08:04:30 -0500 (CDT) Received: by t430.minyard.net (Postfix, from userid 1000) id 31DC4300530; Wed, 27 Apr 2016 08:04:27 -0500 (CDT) From: minyard@acm.org To: openipmi-developer@lists.sourceforge.net, linux-kernel@vger.kernel.org, Jean Delvare Cc: Corey Minyard Subject: [PATCH v3 5/5] ipmi: Convert DMI handling over to a platform device Date: Wed, 27 Apr 2016 08:04:20 -0500 Message-Id: <1461762260-32454-6-git-send-email-minyard@acm.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1461762260-32454-1-git-send-email-minyard@acm.org> References: <1461762260-32454-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 Now that the DMI code creates a platform device for IPMI devices in the firmware, use that instead of handling all the DMI work in the IPMI driver itself. Signed-off-by: Corey Minyard Tested-by: Andy Lutomirski --- drivers/char/ipmi/ipmi_si_intf.c | 143 ++++++++------------------------------- drivers/char/ipmi/ipmi_ssif.c | 119 +++++++++++++++++++++----------- 2 files changed, 109 insertions(+), 153 deletions(-) -- 2.7.4 diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 1e25b52..866539f 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2271,121 +2271,45 @@ static void spmi_find_bmc(void) #endif #ifdef CONFIG_DMI -struct dmi_ipmi_data { - u8 type; - u8 addr_space; - unsigned long base_addr; - u8 irq; - u8 offset; - u8 slave_addr; -}; - -static int decode_dmi(const struct dmi_header *dm, - struct dmi_ipmi_data *dmi) -{ - const u8 *data = (const u8 *)dm; - unsigned long base_addr; - u8 reg_spacing; - u8 len = dm->length; - - dmi->type = data[4]; - - memcpy(&base_addr, data+8, sizeof(unsigned long)); - if (len >= 0x11) { - if (base_addr & 1) { - /* I/O */ - base_addr &= 0xFFFE; - dmi->addr_space = IPMI_IO_ADDR_SPACE; - } else - /* Memory */ - dmi->addr_space = IPMI_MEM_ADDR_SPACE; - - /* If bit 4 of byte 0x10 is set, then the lsb for the address - is odd. */ - dmi->base_addr = base_addr | ((data[0x10] & 0x10) >> 4); - - dmi->irq = data[0x11]; - - /* The top two bits of byte 0x10 hold the register spacing. */ - reg_spacing = (data[0x10] & 0xC0) >> 6; - switch (reg_spacing) { - case 0x00: /* Byte boundaries */ - dmi->offset = 1; - break; - case 0x01: /* 32-bit boundaries */ - dmi->offset = 4; - break; - case 0x02: /* 16-byte boundaries */ - dmi->offset = 16; - break; - default: - /* Some other interface, just ignore it. */ - return -EIO; - } - } else { - /* Old DMI spec. */ - /* - * Note that technically, the lower bit of the base - * address should be 1 if the address is I/O and 0 if - * the address is in memory. So many systems get that - * wrong (and all that I have seen are I/O) so we just - * ignore that bit and assume I/O. Systems that use - * memory should use the newer spec, anyway. - */ - dmi->base_addr = base_addr & 0xfffe; - dmi->addr_space = IPMI_IO_ADDR_SPACE; - dmi->offset = 1; - } - - dmi->slave_addr = data[6]; - - return 0; -} - -static void try_init_dmi(struct dmi_ipmi_data *ipmi_data) +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 (!si_trydmi || !ipmi_data) + return -ENODEV; + info = smi_info_alloc(); if (!info) { - printk(KERN_ERR PFX "Could not allocate SI data\n"); - return; + pr_err(PFX "Could not allocate SI data\n"); + return -ENOMEM; } info->addr_source = SI_SMBIOS; - printk(KERN_INFO PFX "probing via SMBIOS\n"); + pr_info(PFX "probing via SMBIOS\n"); switch (ipmi_data->type) { - case 0x01: /* KCS */ + case IPMI_DMI_TYPE_KCS: info->si_type = SI_KCS; break; - case 0x02: /* SMIC */ + case IPMI_DMI_TYPE_SMIC: info->si_type = SI_SMIC; break; - case 0x03: /* BT */ + case IPMI_DMI_TYPE_BT: info->si_type = SI_BT; break; default: kfree(info); - return; + return -EINVAL; } - switch (ipmi_data->addr_space) { - case IPMI_MEM_ADDR_SPACE: - info->io_setup = mem_setup; - info->io.addr_type = IPMI_MEM_ADDR_SPACE; - break; - - case IPMI_IO_ADDR_SPACE: + if (ipmi_data->is_io_space) { info->io_setup = port_setup; info->io.addr_type = IPMI_IO_ADDR_SPACE; - break; - - default: - kfree(info); - printk(KERN_WARNING PFX "Unknown SMBIOS I/O Address type: %d\n", - ipmi_data->addr_space); - return; + } else { + info->io_setup = mem_setup; + info->io.addr_type = IPMI_MEM_ADDR_SPACE; } info->io.addr_data = ipmi_data->base_addr; @@ -2401,6 +2325,8 @@ static void try_init_dmi(struct dmi_ipmi_data *ipmi_data) 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, @@ -2408,21 +2334,13 @@ static void try_init_dmi(struct dmi_ipmi_data *ipmi_data) if (add_smi(info)) kfree(info); -} -static void dmi_find_bmc(void) + return 0; +} +#else +static int dmi_ipmi_probe(struct platform_device *pdev) { - const struct dmi_device *dev = NULL; - struct dmi_ipmi_data data; - int rv; - - while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) { - memset(&data, 0, sizeof(data)); - rv = decode_dmi((const struct dmi_header *) dev->device_data, - &data); - if (!rv) - try_init_dmi(&data); - } + return -ENODEV; } #endif /* CONFIG_DMI */ @@ -2810,7 +2728,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) @@ -3527,7 +3448,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; } @@ -3818,11 +3739,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(); @@ -3983,6 +3899,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 8b3be8b..a8448705 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; @@ -1439,6 +1441,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; } } @@ -1675,8 +1678,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; @@ -1701,7 +1715,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; @@ -1731,9 +1746,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); @@ -1872,7 +1892,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) @@ -1901,48 +1921,30 @@ static void spmi_find_bmc(void) { } #endif #ifdef CONFIG_DMI -static int decode_dmi(const struct dmi_device *dmi_dev) +static int dmi_ipmi_probe(struct platform_device *pdev) { - struct dmi_header *dm = dmi_dev->device_data; - u8 *data = (u8 *) dm; - u8 len = dm->length; - unsigned short myaddr; - int slave_addr; - - if (num_addrs >= MAX_SSIF_BMCS) - return -1; + struct dmi_device *dmi_dev = to_dmi_device(pdev->dev.fwnode); + struct dmi_dev_ipmi *ipmi_data = to_dmi_dev_ipmi(dmi_dev); - if (len < 9) - return -1; - - if (data[0x04] != 4) /* Not SSIF */ - return -1; + if (!ssif_trydmi || !ipmi_data) + return -ENODEV; - if ((data[8] >> 1) == 0) { - /* - * Some broken systems put the I2C address in - * the slave address field. We try to - * accommodate them here. - */ - myaddr = data[6] >> 1; - slave_addr = 0; - } else { - myaddr = data[8] >> 1; - slave_addr = data[6]; + if (!ipmi_data->good_data) { + pr_err(PFX "DMI data for this device was invalid.\n"); + return -EINVAL; } - return new_ssif_client(myaddr, NULL, 0, 0, SI_SMBIOS); -} - -static void dmi_iterator(void) -{ - const struct dmi_device *dev = NULL; + if (ipmi_data->type != IPMI_DMI_TYPE_SSIF) + return -ENODEV; - while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) - decode_dmi(dev); + return new_ssif_client(ipmi_data->base_addr, NULL, 0, + ipmi_data->slave_addr, SI_SMBIOS, &pdev->dev); } #else -static void dmi_iterator(void) { } +static int dmi_ipmi_probe(struct platform_device *pdev) +{ + return -ENODEV; +} #endif static const struct i2c_device_id ssif_id[] = { @@ -1963,6 +1965,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; @@ -1977,7 +2009,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", @@ -1987,8 +2019,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(); @@ -1998,6 +2029,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); @@ -2009,12 +2045,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");