From patchwork Wed May 17 19:56:24 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Corey Minyard X-Patchwork-Id: 100010 Delivered-To: patch@linaro.org Received: by 10.140.96.100 with SMTP id j91csp392316qge; Wed, 17 May 2017 12:57:36 -0700 (PDT) X-Received: by 10.99.113.75 with SMTP id b11mr482624pgn.173.1495051056831; Wed, 17 May 2017 12:57:36 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1495051056; cv=none; d=google.com; s=arc-20160816; b=dqiwq71Z5qV0sCUuZ+Eho2/e4DRoL9N8u4U+jMo3uSKJWi9gTpvffKNsHWk/bfFZYD i/F8cyw3Ul9FEmjr8AZJDfQkJAy1HAkWxg5StKwIB8wmO3Un7G6Jv91h/LZqyVMOZHn7 F453Y77a4lC4uGvpvhdGTsZzbUSKCKuWPxaqQUzNn3djwEWGA1zuAyLqYzIxyZBHgjwI BXjNQpWyjxJTR/MrTcjIGEY5aHl/dbC3rlt6rEqQSOv9J4NgjS4OwAbGh8GXCBQ2fpqL 1n3Xyga/DTzwTfPD9nprfjVSptpuFaAU3cnpSQDnDA5oQSBUxZxideWTMtf5t2/fhVC/ uY6g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=EYPCYK4LCUn+ub6ktkp7bGvxauAFbWrO0IYukr4qWNA=; b=yTn7wfJrZcfeB2UYPpeWBi51YHqbewylIfZF2WbIVg+2TiwigH6Tg1P7tNhtOAD9Ok J9JKzt++jKET1pC6tsckQTyFcyCBj1hv+TCGSKEUtXtaCOzzgkrHhaXZC+ylVpTL+Wpw CkhMbrXNl/Zs0bjB/cPdrGOIYpk0rdnVySVNi6agnJaAlzxeer61x8rg8mpilJHca2kL ywrbfxswO6oUtfvgWZ2/ZY+cv4m+ukncZf7XycbwzO+fiWtEyNaf8XxxuzFxZXOIIJRP 8srNQv488txcQLEqPdkIJZCc3u+uVmryNOltGNVlthXnaH2kJ5mihZPAvVAZQEArYtGt Wn9w== ARC-Authentication-Results: i=1; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id m86si2941529pfi.202.2017.05.17.12.57.36; Wed, 17 May 2017 12:57:36 -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 S1754085AbdEQT5M (ORCPT + 25 others); Wed, 17 May 2017 15:57:12 -0400 Received: from mail-oi0-f68.google.com ([209.85.218.68]:33284 "EHLO mail-oi0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753486AbdEQT4g (ORCPT ); Wed, 17 May 2017 15:56:36 -0400 Received: by mail-oi0-f68.google.com with SMTP id h4so3903132oib.0 for ; Wed, 17 May 2017 12:56:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=EYPCYK4LCUn+ub6ktkp7bGvxauAFbWrO0IYukr4qWNA=; b=SVs4JBqBNkpAtdKgZNpmi8MdwdFHAY5dC9bFaBdI1zatmB+OFR28YYbl6mM55KtjKP ADQLIkRAp7TIgEcn18htt/aMaDF/JI5RWw+5wHKLsQgpmt2HOKGXypV2Vp/EQ6ltJUrw EAUoIBl4ogcyRjgjN/O7/ao2vTh9LOrMHnNkScwfTs4HKGntwfLnseCSGLAu9usC4u9g LFz/aV0eW3DFrkf0/r5wydtp1weH3G6iBDImHo3qx8DyKITQo5Ld+fHQpdzUWXS7Y+9I 2xMU8D7mNmb2uTw6gIhrq1rwP/MbXHGqu+LqxSjtkX+hmjQqrtbUwcEoxesiMiuelLGf nhLA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=EYPCYK4LCUn+ub6ktkp7bGvxauAFbWrO0IYukr4qWNA=; b=WVFFSW6vtoOZF1VP8YM087ZNYOOEz65p5YHkYi0n7BEanV6g+zT27iRHIFbMNEZ2Z9 I9JVaLQ7OxVa2S0h2H98URNa+X6NbUzCPxdL9onsp8YSgdxwhVDMR4wQ4fSs/bKIGoB7 QL6+85x7AzNRDky6FrKvCoI0DfRjMyzwagt1MQhT0MM4uQW9O1Yu+PcEdXwInGC76Ybk wTE12aojVPIGBKzEyafoxVitCB/nQovuXOqLspi/ayiXTZO6Hbw8/qTEAPZahHUPjjzi F5G6Lc0I5hPM+8JbTmrOVllvTEI2Wy7KevGMdIqIflRTxEMsQNh0U5FjF6XrPHAERoGX lDOw== X-Gm-Message-State: AODbwcBALcyJQ7sm1gagIp3iQbt9K/4v9doRW7l9sANDh7p91EG2U6i2 MyVl1PhmPTe3Hg== X-Received: by 10.202.98.68 with SMTP id w65mr287217oib.173.1495050995689; Wed, 17 May 2017 12:56:35 -0700 (PDT) Received: from serve.minyard.net ([47.184.154.34]) by smtp.gmail.com with ESMTPSA id w197sm1521590oie.8.2017.05.17.12.56.32 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 17 May 2017 12:56:33 -0700 (PDT) Received: from t430.minyard.net (t430m.minyard.net [192.168.27.3]) by serve.minyard.net (Postfix) with ESMTPA id E90831322; Wed, 17 May 2017 14:56:30 -0500 (CDT) Received: by t430.minyard.net (Postfix, from userid 1000) id 3536D3029B3; Wed, 17 May 2017 14:56:28 -0500 (CDT) From: minyard@acm.org To: Jean Delvare Cc: openipmi-developer@lists.sourceforge.net, linux-kernel@vger.kernel.org, Andy Lutomirski , Corey Minyard Subject: [PATCH v5 5/5] ipmi: Convert DMI handling over to a platform device Date: Wed, 17 May 2017 14:56:24 -0500 Message-Id: <1495050984-5602-6-git-send-email-minyard@acm.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1495050984-5602-1-git-send-email-minyard@acm.org> References: <1495050984-5602-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 | 137 ++++++++------------------------------- drivers/char/ipmi/ipmi_ssif.c | 119 ++++++++++++++++++++++------------ 2 files changed, 106 insertions(+), 150 deletions(-) -- 2.7.4 diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index b2b618f..17611a8 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2274,121 +2274,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) { pr_err(PFX "Could not allocate SI data\n"); - return; + return -ENOMEM; } info->addr_source = SI_SMBIOS; 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); - pr_warn(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; @@ -2404,6 +2328,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, @@ -2411,21 +2337,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 */ @@ -2813,7 +2731,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) @@ -3786,11 +3707,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(); @@ -3938,6 +3854,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 1d4fd84..109ca4e 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -180,6 +180,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; @@ -1469,6 +1471,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; } } @@ -1706,8 +1709,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; @@ -1732,7 +1746,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; @@ -1762,9 +1777,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); @@ -1903,7 +1923,7 @@ static int try_init_spmi(struct SPMITable *spmi) myaddr = spmi->addr.address & 0x7f; - 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) @@ -1932,48 +1952,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, slave_addr, 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[] = { @@ -1994,6 +1996,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; @@ -2008,7 +2040,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", @@ -2018,8 +2050,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(); @@ -2029,6 +2060,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); @@ -2040,12 +2076,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");