From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1947330Ab3BHXU4 (ORCPT ); Fri, 8 Feb 2013 18:20:56 -0500 Received: from mga03.intel.com ([143.182.124.21]:8061 "EHLO mga03.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757205Ab3BHXUz (ORCPT ); Fri, 8 Feb 2013 18:20:55 -0500 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.84,632,1355126400"; d="scan'208";a="254556486" From: Darren Hart To: Linux Kernel Mailing List Cc: Darren Hart , Grant Likely , Denis Turischev , Greg Kroah-Hartman , Linus Walleij , Samuel Ortiz Subject: [PATCH] lpc_sch: Accomodate partial population of the MFD devices Date: Fri, 8 Feb 2013 15:20:36 -0800 Message-Id: X-Mailer: git-send-email 1.8.1 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The current probe aborts if any of the 3 base address registers are disabled. On a TunnelCreek system I am working on, this resulted in the SMBIOS and GPIO devices being removed when it couldn't read the base address for the watchdog timer. This patch accommodates partial population of the lpc_sch_cells array and only aborts if all the base address registers are disabled. A max size array is allocated and the individual device cells are added to it after their base addresses are successfully determined. This simplifies the code a bit by removing the need for the separate tunnelcreek cells array and combining some of the add/remove logic. Signed-off-by: Darren Hart Cc: Grant Likely , Cc: Denis Turischev , Cc: Greg Kroah-Hartman , Cc: Linus Walleij Cc: Samuel Ortiz Signed-off-by: Darren Hart --- drivers/mfd/lpc_sch.c | 148 ++++++++++++++++++++++++-------------------------- 1 file changed, 70 insertions(+), 78 deletions(-) diff --git a/drivers/mfd/lpc_sch.c b/drivers/mfd/lpc_sch.c index 5624fcb..9c255f2 100644 --- a/drivers/mfd/lpc_sch.c +++ b/drivers/mfd/lpc_sch.c @@ -45,34 +45,32 @@ static struct resource smbus_sch_resource = { .flags = IORESOURCE_IO, }; - static struct resource gpio_sch_resource = { .flags = IORESOURCE_IO, }; -static struct mfd_cell lpc_sch_cells[] = { - { - .name = "isch_smbus", - .num_resources = 1, - .resources = &smbus_sch_resource, - }, - { - .name = "sch_gpio", - .num_resources = 1, - .resources = &gpio_sch_resource, - }, -}; - static struct resource wdt_sch_resource = { .flags = IORESOURCE_IO, }; -static struct mfd_cell tunnelcreek_cells[] = { - { - .name = "ie6xx_wdt", - .num_resources = 1, - .resources = &wdt_sch_resource, - }, +static struct mfd_cell lpc_sch_cells[3]; + +static struct mfd_cell isch_smbus_cell = { + .name = "isch_smbus", + .num_resources = 1, + .resources = &smbus_sch_resource, +}; + +static struct mfd_cell sch_gpio_cell = { + .name = "sch_gpio", + .num_resources = 1, + .resources = &gpio_sch_resource, +}; + +static struct mfd_cell wdt_sch_cell = { + .name = "ie6xx_wdt", + .num_resources = 1, + .resources = &wdt_sch_resource, }; static DEFINE_PCI_DEVICE_TABLE(lpc_sch_ids) = { @@ -88,79 +86,73 @@ static int lpc_sch_probe(struct pci_dev *dev, { unsigned int base_addr_cfg; unsigned short base_addr; - int i; + int i, cells = 0; int ret; pci_read_config_dword(dev, SMBASE, &base_addr_cfg); - if (!(base_addr_cfg & (1 << 31))) { - dev_err(&dev->dev, "Decode of the SMBus I/O range disabled\n"); - return -ENODEV; - } - base_addr = (unsigned short)base_addr_cfg; - if (base_addr == 0) { - dev_err(&dev->dev, "I/O space for SMBus uninitialized\n"); - return -ENODEV; + base_addr = 0; + if (!(base_addr_cfg & (1 << 31))) + dev_warn(&dev->dev, "Decode of the SMBus I/O range disabled\n"); + else + base_addr = (unsigned short)base_addr_cfg; + if (base_addr == 0) + dev_warn(&dev->dev, "I/O space for SMBus uninitialized\n"); + else { + lpc_sch_cells[cells++] = isch_smbus_cell; + smbus_sch_resource.start = base_addr; + smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1; } - smbus_sch_resource.start = base_addr; - smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1; - pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg); - if (!(base_addr_cfg & (1 << 31))) { - dev_err(&dev->dev, "Decode of the GPIO I/O range disabled\n"); - return -ENODEV; - } - base_addr = (unsigned short)base_addr_cfg; - if (base_addr == 0) { - dev_err(&dev->dev, "I/O space for GPIO uninitialized\n"); - return -ENODEV; - } - - gpio_sch_resource.start = base_addr; - - if (id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB) - gpio_sch_resource.end = base_addr + GPIO_IO_SIZE_CENTERTON - 1; + base_addr = 0; + if (!(base_addr_cfg & (1 << 31))) + dev_warn(&dev->dev, "Decode of the GPIO I/O range disabled\n"); else - gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1; - - for (i=0; i < ARRAY_SIZE(lpc_sch_cells); i++) - lpc_sch_cells[i].id = id->device; - - ret = mfd_add_devices(&dev->dev, 0, - lpc_sch_cells, ARRAY_SIZE(lpc_sch_cells), NULL, - 0, NULL); - if (ret) - goto out_dev; + base_addr = (unsigned short)base_addr_cfg; + if (base_addr == 0) + dev_warn(&dev->dev, "I/O space for GPIO uninitialized\n"); + else { + lpc_sch_cells[cells++] = sch_gpio_cell; + gpio_sch_resource.start = base_addr; + if (id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB) + gpio_sch_resource.end = base_addr + GPIO_IO_SIZE_CENTERTON - 1; + else + gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1; + } if (id->device == PCI_DEVICE_ID_INTEL_ITC_LPC || id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB) { pci_read_config_dword(dev, WDTBASE, &base_addr_cfg); - if (!(base_addr_cfg & (1 << 31))) { - dev_err(&dev->dev, "Decode of the WDT I/O range disabled\n"); - ret = -ENODEV; - goto out_dev; - } - base_addr = (unsigned short)base_addr_cfg; - if (base_addr == 0) { - dev_err(&dev->dev, "I/O space for WDT uninitialized\n"); - ret = -ENODEV; - goto out_dev; + base_addr = 0; + if (!(base_addr_cfg & (1 << 31))) + dev_warn(&dev->dev, "Decode of the WDT I/O range disabled\n"); + else + base_addr = (unsigned short)base_addr_cfg; + if (base_addr == 0) + dev_warn(&dev->dev, "I/O space for WDT uninitialized\n"); + else { + lpc_sch_cells[cells++] = wdt_sch_cell; + wdt_sch_resource.start = base_addr; + wdt_sch_resource.end = base_addr + WDT_IO_SIZE - 1; } + } - wdt_sch_resource.start = base_addr; - wdt_sch_resource.end = base_addr + WDT_IO_SIZE - 1; - - for (i = 0; i < ARRAY_SIZE(tunnelcreek_cells); i++) - tunnelcreek_cells[i].id = id->device; - - ret = mfd_add_devices(&dev->dev, 0, tunnelcreek_cells, - ARRAY_SIZE(tunnelcreek_cells), NULL, - 0, NULL); + if (WARN_ON(cells > ARRAY_SIZE(lpc_sch_cells))) { + dev_err(&dev->dev, "Cell count exceeds array size"); + return -ENODEV; + } + if (cells == 0) { + dev_err(&dev->dev, "All decode registers disabled.\n"); + return -ENODEV; } - return ret; -out_dev: - mfd_remove_devices(&dev->dev); + for (i = 0; i < cells; i++) + lpc_sch_cells[i].id = id->device; + ret = mfd_add_devices(&dev->dev, 0, lpc_sch_cells, cells, NULL, 0, NULL); + + if (ret) + mfd_remove_devices(&dev->dev); + return ret; } -- 1.8.1