From d79d32440c33cf60f1e0efbeb8144b1647be0b50 Mon Sep 17 00:00:00 2001 From: Patrick Pannuto Date: Fri, 6 Aug 2010 17:12:41 -0700 Subject: driver core: platform: Use drv->driver.bus instead of assuming platform_bus_type In theory (although not *yet* in practice), a driver being passed to platform_driver_probe might have driver.bus set to something other than platform_bus_type. Locking drv->driver.bus is always correct. Signed-off-by: Patrick Pannuto Signed-off-by: Greg Kroah-Hartman --- drivers/base/platform.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/base/platform.c b/drivers/base/platform.c index c6c933f58102..579906f88b09 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -488,12 +488,12 @@ int __init_or_module platform_driver_probe(struct platform_driver *drv, * if the probe was successful, and make sure any forced probes of * new devices fail. */ - spin_lock(&platform_bus_type.p->klist_drivers.k_lock); + spin_lock(&drv->driver.bus->p->klist_drivers.k_lock); drv->probe = NULL; if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list)) retval = -ENODEV; drv->driver.probe = platform_drv_probe_fail; - spin_unlock(&platform_bus_type.p->klist_drivers.k_lock); + spin_unlock(&drv->driver.bus->p->klist_drivers.k_lock); if (code != retval) platform_driver_unregister(drv); -- cgit From 1037246cacd45d951227c8798f181b3ba5c8bcbe Mon Sep 17 00:00:00 2001 From: Kulikov Vasiliy Date: Tue, 3 Aug 2010 19:44:23 +0400 Subject: uio: do not use PCI resources before pci_enable_device() IRQ and resource[] may not have correct values until after PCI hotplug setup occurs at pci_enable_device() time. The semantic match that finds this problem is as follows: // @@ identifier x; identifier request ~= "pci_request.*|pci_resource.*"; @@ ( * x->irq | * x->resource | * request(x, ...) ) ... *pci_enable_device(x) // Signed-off-by: Kulikov Vasiliy Acked-by: Michael S. Tsirkin Signed-off-by: Hans J. Koch Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_pci_generic.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/uio/uio_pci_generic.c b/drivers/uio/uio_pci_generic.c index 85c9884a67fd..fc22e1e6f215 100644 --- a/drivers/uio/uio_pci_generic.c +++ b/drivers/uio/uio_pci_generic.c @@ -128,12 +128,6 @@ static int __devinit probe(struct pci_dev *pdev, struct uio_pci_generic_dev *gdev; int err; - if (!pdev->irq) { - dev_warn(&pdev->dev, "No IRQ assigned to device: " - "no support for interrupts?\n"); - return -ENODEV; - } - err = pci_enable_device(pdev); if (err) { dev_err(&pdev->dev, "%s: pci_enable_device failed: %d\n", @@ -141,6 +135,13 @@ static int __devinit probe(struct pci_dev *pdev, return err; } + if (!pdev->irq) { + dev_warn(&pdev->dev, "No IRQ assigned to device: " + "no support for interrupts?\n"); + pci_disable_device(pdev); + return -ENODEV; + } + err = verify_pci_2_3(pdev); if (err) goto err_verify; -- cgit From c64a0926710153b9d44c979d2942f4a8648fd74e Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Wed, 25 Aug 2010 12:50:00 -0700 Subject: driver core: platform_bus: allow runtime override of dev_pm_ops Currently, the platform_bus allows customization of several of the busses dev_pm_ops methods by using weak symbols so that platform code can override them. The weak-symbol approach is not scalable when wanting to support multiple platforms in a single kernel binary. Instead, provide __init methods for platform code to customize the dev_pm_ops methods at runtime. NOTE: after these dynamic methods are merged, the weak symbols should be removed from drivers/base/platform.c. AFAIK, this will only affect SH and sh-mobile which should be converted to use this runtime approach instead of the weak symbols. After SH & sh-mobile are converted, the weak symobols could be removed. Tested on OMAP3. Cc: Magnus Damm Acked-by: Grant Likely Signed-off-by: Kevin Hilman Signed-off-by: Greg Kroah-Hartman --- drivers/base/platform.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'drivers') diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 579906f88b09..a01abf9ebf7b 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -976,6 +976,41 @@ struct bus_type platform_bus_type = { }; EXPORT_SYMBOL_GPL(platform_bus_type); +/** + * platform_bus_get_pm_ops() - return pointer to busses dev_pm_ops + * + * This function can be used by platform code to get the current + * set of dev_pm_ops functions used by the platform_bus_type. + */ +const struct dev_pm_ops * __init platform_bus_get_pm_ops(void) +{ + return platform_bus_type.pm; +} + +/** + * platform_bus_set_pm_ops() - update dev_pm_ops for the platform_bus_type + * + * @pm: pointer to new dev_pm_ops struct to be used for platform_bus_type + * + * Platform code can override the dev_pm_ops methods of + * platform_bus_type by using this function. It is expected that + * platform code will first do a platform_bus_get_pm_ops(), then + * kmemdup it, then customize selected methods and pass a pointer to + * the new struct dev_pm_ops to this function. + * + * Since platform-specific code is customizing methods for *all* + * devices (not just platform-specific devices) it is expected that + * any custom overrides of these functions will keep existing behavior + * and simply extend it. For example, any customization of the + * runtime PM methods should continue to call the pm_generic_* + * functions as the default ones do in addition to the + * platform-specific behavior. + */ +void __init platform_bus_set_pm_ops(const struct dev_pm_ops *pm) +{ + platform_bus_type.pm = pm; +} + int __init platform_bus_init(void) { int error; -- cgit From cf4ece53460c64a04a643ef13f6b6cb4bf3a8342 Mon Sep 17 00:00:00 2001 From: Masayuki Ohtak Date: Wed, 1 Sep 2010 21:16:30 +0900 Subject: add Packet hub driver for Topcliff Platform controller hub Packet hub driver of Topcliff PCH Topcliff PCH is the platform controller hub that is going to be used in Intel's upcoming general embedded platform. All IO peripherals in Topcliff PCH are actually devices sitting on AMBA bus. Packet hub is a special converter device in Topcliff PCH that translate AMBA transactions to PCI Express transactions and vice versa. Thus packet hub helps present all IO peripherals in Topcliff PCH as PCIE devices to IA system. Topcliff PCH has MAC address and Option ROM data. These data are in SROM which is connected to PCIE bus. Packet hub driver of Topcliff PCH can access MAC address and Option ROM data in SROM via sysfs interface. Signed-off-by: Greg Kroah-Hartman --- drivers/misc/Kconfig | 12 + drivers/misc/Makefile | 1 + drivers/misc/pch_phub.c | 717 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 730 insertions(+) create mode 100644 drivers/misc/pch_phub.c (limited to 'drivers') diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index b74331260744..6f46e27ed682 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -390,6 +390,18 @@ config BMP085 To compile this driver as a module, choose M here: the module will be called bmp085. +config PCH_PHUB + tristate "PCH Packet Hub of Intel Topcliff" + depends on PCI + help + This driver is for PCH(Platform controller Hub) PHUB(Packet Hub) of + Intel Topcliff which is an IOH(Input/Output Hub) for x86 embedded + processor. The Topcliff has MAC address and Option ROM data in SROM. + This driver can access MAC address and Option ROM data in SROM. + + To compile this driver as a module, choose M here: the module will + be called pch_phub. + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 42eab95cde2a..9f2986b4da2f 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -35,3 +35,4 @@ obj-y += eeprom/ obj-y += cb710/ obj-$(CONFIG_VMWARE_BALLOON) += vmw_balloon.o obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o +obj-$(CONFIG_PCH_PHUB) += pch_phub.o diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c new file mode 100644 index 000000000000..ed56e4f91fa0 --- /dev/null +++ b/drivers/misc/pch_phub.c @@ -0,0 +1,717 @@ +/* + * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PHUB_STATUS 0x00 /* Status Register offset */ +#define PHUB_CONTROL 0x04 /* Control Register offset */ +#define PHUB_TIMEOUT 0x05 /* Time out value for Status Register */ +#define PCH_PHUB_ROM_WRITE_ENABLE 0x01 /* Enabling for writing ROM */ +#define PCH_PHUB_ROM_WRITE_DISABLE 0x00 /* Disabling for writing ROM */ +#define PCH_PHUB_ROM_START_ADDR 0x14 /* ROM data area start address offset */ + +/* MAX number of INT_REDUCE_CONTROL registers */ +#define MAX_NUM_INT_REDUCE_CONTROL_REG 128 +#define PCI_DEVICE_ID_PCH1_PHUB 0x8801 +#define PCH_MINOR_NOS 1 +#define CLKCFG_CAN_50MHZ 0x12000000 +#define CLKCFG_CANCLK_MASK 0xFF000000 + +/* SROM ACCESS Macro */ +#define PCH_WORD_ADDR_MASK (~((1 << 2) - 1)) + +/* Registers address offset */ +#define PCH_PHUB_ID_REG 0x0000 +#define PCH_PHUB_QUEUE_PRI_VAL_REG 0x0004 +#define PCH_PHUB_RC_QUEUE_MAXSIZE_REG 0x0008 +#define PCH_PHUB_BRI_QUEUE_MAXSIZE_REG 0x000C +#define PCH_PHUB_COMP_RESP_TIMEOUT_REG 0x0010 +#define PCH_PHUB_BUS_SLAVE_CONTROL_REG 0x0014 +#define PCH_PHUB_DEADLOCK_AVOID_TYPE_REG 0x0018 +#define PCH_PHUB_INTPIN_REG_WPERMIT_REG0 0x0020 +#define PCH_PHUB_INTPIN_REG_WPERMIT_REG1 0x0024 +#define PCH_PHUB_INTPIN_REG_WPERMIT_REG2 0x0028 +#define PCH_PHUB_INTPIN_REG_WPERMIT_REG3 0x002C +#define PCH_PHUB_INT_REDUCE_CONTROL_REG_BASE 0x0040 +#define CLKCFG_REG_OFFSET 0x500 + +#define PCH_PHUB_OROM_SIZE 15360 + +/** + * struct pch_phub_reg - PHUB register structure + * @phub_id_reg: PHUB_ID register val + * @q_pri_val_reg: QUEUE_PRI_VAL register val + * @rc_q_maxsize_reg: RC_QUEUE_MAXSIZE register val + * @bri_q_maxsize_reg: BRI_QUEUE_MAXSIZE register val + * @comp_resp_timeout_reg: COMP_RESP_TIMEOUT register val + * @bus_slave_control_reg: BUS_SLAVE_CONTROL_REG register val + * @deadlock_avoid_type_reg: DEADLOCK_AVOID_TYPE register val + * @intpin_reg_wpermit_reg0: INTPIN_REG_WPERMIT register 0 val + * @intpin_reg_wpermit_reg1: INTPIN_REG_WPERMIT register 1 val + * @intpin_reg_wpermit_reg2: INTPIN_REG_WPERMIT register 2 val + * @intpin_reg_wpermit_reg3: INTPIN_REG_WPERMIT register 3 val + * @int_reduce_control_reg: INT_REDUCE_CONTROL registers val + * @clkcfg_reg: CLK CFG register val + * @pch_phub_base_address: Register base address + * @pch_phub_extrom_base_address: external rom base address + */ +struct pch_phub_reg { + u32 phub_id_reg; + u32 q_pri_val_reg; + u32 rc_q_maxsize_reg; + u32 bri_q_maxsize_reg; + u32 comp_resp_timeout_reg; + u32 bus_slave_control_reg; + u32 deadlock_avoid_type_reg; + u32 intpin_reg_wpermit_reg0; + u32 intpin_reg_wpermit_reg1; + u32 intpin_reg_wpermit_reg2; + u32 intpin_reg_wpermit_reg3; + u32 int_reduce_control_reg[MAX_NUM_INT_REDUCE_CONTROL_REG]; + u32 clkcfg_reg; + void __iomem *pch_phub_base_address; + void __iomem *pch_phub_extrom_base_address; +}; + +/* SROM SPEC for MAC address assignment offset */ +static const int pch_phub_mac_offset[ETH_ALEN] = {0x3, 0x2, 0x1, 0x0, 0xb, 0xa}; + +static DEFINE_MUTEX(pch_phub_mutex); + +/** + * pch_phub_read_modify_write_reg() - Reading modifying and writing register + * @reg_addr_offset: Register offset address value. + * @data: Writing value. + * @mask: Mask value. + */ +static void pch_phub_read_modify_write_reg(struct pch_phub_reg *chip, + unsigned int reg_addr_offset, + unsigned int data, unsigned int mask) +{ + void __iomem *reg_addr = chip->pch_phub_base_address + reg_addr_offset; + iowrite32(((ioread32(reg_addr) & ~mask)) | data, reg_addr); +} + +/* pch_phub_save_reg_conf - saves register configuration */ +static void pch_phub_save_reg_conf(struct pci_dev *pdev) +{ + unsigned int i; + struct pch_phub_reg *chip = pci_get_drvdata(pdev); + + void __iomem *p = chip->pch_phub_base_address; + + chip->phub_id_reg = ioread32(p + PCH_PHUB_ID_REG); + chip->q_pri_val_reg = ioread32(p + PCH_PHUB_QUEUE_PRI_VAL_REG); + chip->rc_q_maxsize_reg = ioread32(p + PCH_PHUB_RC_QUEUE_MAXSIZE_REG); + chip->bri_q_maxsize_reg = ioread32(p + PCH_PHUB_BRI_QUEUE_MAXSIZE_REG); + chip->comp_resp_timeout_reg = + ioread32(p + PCH_PHUB_COMP_RESP_TIMEOUT_REG); + chip->bus_slave_control_reg = + ioread32(p + PCH_PHUB_BUS_SLAVE_CONTROL_REG); + chip->deadlock_avoid_type_reg = + ioread32(p + PCH_PHUB_DEADLOCK_AVOID_TYPE_REG); + chip->intpin_reg_wpermit_reg0 = + ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG0); + chip->intpin_reg_wpermit_reg1 = + ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG1); + chip->intpin_reg_wpermit_reg2 = + ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG2); + chip->intpin_reg_wpermit_reg3 = + ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG3); + dev_dbg(&pdev->dev, "%s : " + "chip->phub_id_reg=%x, " + "chip->q_pri_val_reg=%x, " + "chip->rc_q_maxsize_reg=%x, " + "chip->bri_q_maxsize_reg=%x, " + "chip->comp_resp_timeout_reg=%x, " + "chip->bus_slave_control_reg=%x, " + "chip->deadlock_avoid_type_reg=%x, " + "chip->intpin_reg_wpermit_reg0=%x, " + "chip->intpin_reg_wpermit_reg1=%x, " + "chip->intpin_reg_wpermit_reg2=%x, " + "chip->intpin_reg_wpermit_reg3=%x\n", __func__, + chip->phub_id_reg, + chip->q_pri_val_reg, + chip->rc_q_maxsize_reg, + chip->bri_q_maxsize_reg, + chip->comp_resp_timeout_reg, + chip->bus_slave_control_reg, + chip->deadlock_avoid_type_reg, + chip->intpin_reg_wpermit_reg0, + chip->intpin_reg_wpermit_reg1, + chip->intpin_reg_wpermit_reg2, + chip->intpin_reg_wpermit_reg3); + for (i = 0; i < MAX_NUM_INT_REDUCE_CONTROL_REG; i++) { + chip->int_reduce_control_reg[i] = + ioread32(p + PCH_PHUB_INT_REDUCE_CONTROL_REG_BASE + 4 * i); + dev_dbg(&pdev->dev, "%s : " + "chip->int_reduce_control_reg[%d]=%x\n", + __func__, i, chip->int_reduce_control_reg[i]); + } + chip->clkcfg_reg = ioread32(p + CLKCFG_REG_OFFSET); +} + +/* pch_phub_restore_reg_conf - restore register configuration */ +static void pch_phub_restore_reg_conf(struct pci_dev *pdev) +{ + unsigned int i; + struct pch_phub_reg *chip = pci_get_drvdata(pdev); + void __iomem *p; + p = chip->pch_phub_base_address; + + iowrite32(chip->phub_id_reg, p + PCH_PHUB_ID_REG); + iowrite32(chip->q_pri_val_reg, p + PCH_PHUB_QUEUE_PRI_VAL_REG); + iowrite32(chip->rc_q_maxsize_reg, p + PCH_PHUB_RC_QUEUE_MAXSIZE_REG); + iowrite32(chip->bri_q_maxsize_reg, p + PCH_PHUB_BRI_QUEUE_MAXSIZE_REG); + iowrite32(chip->comp_resp_timeout_reg, + p + PCH_PHUB_COMP_RESP_TIMEOUT_REG); + iowrite32(chip->bus_slave_control_reg, + p + PCH_PHUB_BUS_SLAVE_CONTROL_REG); + iowrite32(chip->deadlock_avoid_type_reg, + p + PCH_PHUB_DEADLOCK_AVOID_TYPE_REG); + iowrite32(chip->intpin_reg_wpermit_reg0, + p + PCH_PHUB_INTPIN_REG_WPERMIT_REG0); + iowrite32(chip->intpin_reg_wpermit_reg1, + p + PCH_PHUB_INTPIN_REG_WPERMIT_REG1); + iowrite32(chip->intpin_reg_wpermit_reg2, + p + PCH_PHUB_INTPIN_REG_WPERMIT_REG2); + iowrite32(chip->intpin_reg_wpermit_reg3, + p + PCH_PHUB_INTPIN_REG_WPERMIT_REG3); + dev_dbg(&pdev->dev, "%s : " + "chip->phub_id_reg=%x, " + "chip->q_pri_val_reg=%x, " + "chip->rc_q_maxsize_reg=%x, " + "chip->bri_q_maxsize_reg=%x, " + "chip->comp_resp_timeout_reg=%x, " + "chip->bus_slave_control_reg=%x, " + "chip->deadlock_avoid_type_reg=%x, " + "chip->intpin_reg_wpermit_reg0=%x, " + "chip->intpin_reg_wpermit_reg1=%x, " + "chip->intpin_reg_wpermit_reg2=%x, " + "chip->intpin_reg_wpermit_reg3=%x\n", __func__, + chip->phub_id_reg, + chip->q_pri_val_reg, + chip->rc_q_maxsize_reg, + chip->bri_q_maxsize_reg, + chip->comp_resp_timeout_reg, + chip->bus_slave_control_reg, + chip->deadlock_avoid_type_reg, + chip->intpin_reg_wpermit_reg0, + chip->intpin_reg_wpermit_reg1, + chip->intpin_reg_wpermit_reg2, + chip->intpin_reg_wpermit_reg3); + for (i = 0; i < MAX_NUM_INT_REDUCE_CONTROL_REG; i++) { + iowrite32(chip->int_reduce_control_reg[i], + p + PCH_PHUB_INT_REDUCE_CONTROL_REG_BASE + 4 * i); + dev_dbg(&pdev->dev, "%s : " + "chip->int_reduce_control_reg[%d]=%x\n", + __func__, i, chip->int_reduce_control_reg[i]); + } + + iowrite32(chip->clkcfg_reg, p + CLKCFG_REG_OFFSET); +} + +/** + * pch_phub_read_serial_rom() - Reading Serial ROM + * @offset_address: Serial ROM offset address to read. + * @data: Read buffer for specified Serial ROM value. + */ +static void pch_phub_read_serial_rom(struct pch_phub_reg *chip, + unsigned int offset_address, u8 *data) +{ + void __iomem *mem_addr = chip->pch_phub_extrom_base_address + + offset_address; + + *data = ioread8(mem_addr); +} + +/** + * pch_phub_write_serial_rom() - Writing Serial ROM + * @offset_address: Serial ROM offset address. + * @data: Serial ROM value to write. + */ +static int pch_phub_write_serial_rom(struct pch_phub_reg *chip, + unsigned int offset_address, u8 data) +{ + void __iomem *mem_addr = chip->pch_phub_extrom_base_address + + (offset_address & PCH_WORD_ADDR_MASK); + int i; + unsigned int word_data; + unsigned int pos; + unsigned int mask; + pos = (offset_address % 4) * 8; + mask = ~(0xFF << pos); + + iowrite32(PCH_PHUB_ROM_WRITE_ENABLE, + chip->pch_phub_extrom_base_address + PHUB_CONTROL); + + word_data = ioread32(mem_addr); + iowrite32((word_data & mask) | (u32)data << pos, mem_addr); + + i = 0; + while (ioread8(chip->pch_phub_extrom_base_address + + PHUB_STATUS) != 0x00) { + msleep(1); + if (i == PHUB_TIMEOUT) + return -ETIMEDOUT; + i++; + } + + iowrite32(PCH_PHUB_ROM_WRITE_DISABLE, + chip->pch_phub_extrom_base_address + PHUB_CONTROL); + + return 0; +} + +/** + * pch_phub_read_serial_rom_val() - Read Serial ROM value + * @offset_address: Serial ROM address offset value. + * @data: Serial ROM value to read. + */ +static void pch_phub_read_serial_rom_val(struct pch_phub_reg *chip, + unsigned int offset_address, u8 *data) +{ + unsigned int mem_addr; + + mem_addr = PCH_PHUB_ROM_START_ADDR + + pch_phub_mac_offset[offset_address]; + + pch_phub_read_serial_rom(chip, mem_addr, data); +} + +/** + * pch_phub_write_serial_rom_val() - writing Serial ROM value + * @offset_address: Serial ROM address offset value. + * @data: Serial ROM value. + */ +static int pch_phub_write_serial_rom_val(struct pch_phub_reg *chip, + unsigned int offset_address, u8 data) +{ + int retval; + unsigned int mem_addr; + + mem_addr = PCH_PHUB_ROM_START_ADDR + + pch_phub_mac_offset[offset_address]; + + retval = pch_phub_write_serial_rom(chip, mem_addr, data); + + return retval; +} + +/* pch_phub_gbe_serial_rom_conf - makes Serial ROM header format configuration + * for Gigabit Ethernet MAC address + */ +static int pch_phub_gbe_serial_rom_conf(struct pch_phub_reg *chip) +{ + int retval; + + retval = pch_phub_write_serial_rom(chip, 0x0b, 0xbc); + retval |= pch_phub_write_serial_rom(chip, 0x0a, 0x10); + retval |= pch_phub_write_serial_rom(chip, 0x09, 0x01); + retval |= pch_phub_write_serial_rom(chip, 0x08, 0x02); + + retval |= pch_phub_write_serial_rom(chip, 0x0f, 0x00); + retval |= pch_phub_write_serial_rom(chip, 0x0e, 0x00); + retval |= pch_phub_write_serial_rom(chip, 0x0d, 0x00); + retval |= pch_phub_write_serial_rom(chip, 0x0c, 0x80); + + retval |= pch_phub_write_serial_rom(chip, 0x13, 0xbc); + retval |= pch_phub_write_serial_rom(chip, 0x12, 0x10); + retval |= pch_phub_write_serial_rom(chip, 0x11, 0x01); + retval |= pch_phub_write_serial_rom(chip, 0x10, 0x18); + + retval |= pch_phub_write_serial_rom(chip, 0x1b, 0xbc); + retval |= pch_phub_write_serial_rom(chip, 0x1a, 0x10); + retval |= pch_phub_write_serial_rom(chip, 0x19, 0x01); + retval |= pch_phub_write_serial_rom(chip, 0x18, 0x19); + + retval |= pch_phub_write_serial_rom(chip, 0x23, 0xbc); + retval |= pch_phub_write_serial_rom(chip, 0x22, 0x10); + retval |= pch_phub_write_serial_rom(chip, 0x21, 0x01); + retval |= pch_phub_write_serial_rom(chip, 0x20, 0x3a); + + retval |= pch_phub_write_serial_rom(chip, 0x27, 0x01); + retval |= pch_phub_write_serial_rom(chip, 0x26, 0x00); + retval |= pch_phub_write_serial_rom(chip, 0x25, 0x00); + retval |= pch_phub_write_serial_rom(chip, 0x24, 0x00); + + return retval; +} + +/** + * pch_phub_read_gbe_mac_addr() - Read Gigabit Ethernet MAC address + * @offset_address: Gigabit Ethernet MAC address offset value. + * @data: Buffer of the Gigabit Ethernet MAC address value. + */ +static void pch_phub_read_gbe_mac_addr(struct pch_phub_reg *chip, u8 *data) +{ + int i; + for (i = 0; i < ETH_ALEN; i++) + pch_phub_read_serial_rom_val(chip, i, &data[i]); +} + +/** + * pch_phub_write_gbe_mac_addr() - Write MAC address + * @offset_address: Gigabit Ethernet MAC address offset value. + * @data: Gigabit Ethernet MAC address value. + */ +static int pch_phub_write_gbe_mac_addr(struct pch_phub_reg *chip, u8 *data) +{ + int retval; + int i; + + retval = pch_phub_gbe_serial_rom_conf(chip); + if (retval) + return retval; + + for (i = 0; i < ETH_ALEN; i++) { + retval = pch_phub_write_serial_rom_val(chip, i, data[i]); + if (retval) + return retval; + } + + return retval; +} + +static ssize_t pch_phub_bin_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t off, size_t count) +{ + unsigned int rom_signature; + unsigned char rom_length; + unsigned int tmp; + unsigned int addr_offset; + unsigned int orom_size; + int ret; + int err; + + struct pch_phub_reg *chip = + dev_get_drvdata(container_of(kobj, struct device, kobj)); + + ret = mutex_lock_interruptible(&pch_phub_mutex); + if (ret) { + err = -ERESTARTSYS; + goto return_err_nomutex; + } + + /* Get Rom signature */ + pch_phub_read_serial_rom(chip, 0x80, (unsigned char *)&rom_signature); + rom_signature &= 0xff; + pch_phub_read_serial_rom(chip, 0x81, (unsigned char *)&tmp); + rom_signature |= (tmp & 0xff) << 8; + if (rom_signature == 0xAA55) { + pch_phub_read_serial_rom(chip, 0x82, &rom_length); + orom_size = rom_length * 512; + if (orom_size < off) { + addr_offset = 0; + goto return_ok; + } + if (orom_size < count) { + addr_offset = 0; + goto return_ok; + } + + for (addr_offset = 0; addr_offset < count; addr_offset++) { + pch_phub_read_serial_rom(chip, 0x80 + addr_offset + off, + &buf[addr_offset]); + } + } else { + err = -ENODATA; + goto return_err; + } +return_ok: + mutex_unlock(&pch_phub_mutex); + return addr_offset; + +return_err: + mutex_unlock(&pch_phub_mutex); +return_err_nomutex: + return err; +} + +static ssize_t pch_phub_bin_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + int err; + unsigned int addr_offset; + int ret; + struct pch_phub_reg *chip = + dev_get_drvdata(container_of(kobj, struct device, kobj)); + + ret = mutex_lock_interruptible(&pch_phub_mutex); + if (ret) + return -ERESTARTSYS; + + if (off > PCH_PHUB_OROM_SIZE) { + addr_offset = 0; + goto return_ok; + } + if (count > PCH_PHUB_OROM_SIZE) { + addr_offset = 0; + goto return_ok; + } + + for (addr_offset = 0; addr_offset < count; addr_offset++) { + if (PCH_PHUB_OROM_SIZE < off + addr_offset) + goto return_ok; + + ret = pch_phub_write_serial_rom(chip, 0x80 + addr_offset + off, + buf[addr_offset]); + if (ret) { + err = ret; + goto return_err; + } + } + +return_ok: + mutex_unlock(&pch_phub_mutex); + return addr_offset; + +return_err: + mutex_unlock(&pch_phub_mutex); + return err; +} + +static ssize_t show_pch_mac(struct device *dev, struct device_attribute *attr, + char *buf) +{ + u8 mac[8]; + struct pch_phub_reg *chip = dev_get_drvdata(dev); + + pch_phub_read_gbe_mac_addr(chip, mac); + + return sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); +} + +static ssize_t store_pch_mac(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + u8 mac[6]; + struct pch_phub_reg *chip = dev_get_drvdata(dev); + + if (count != 18) + return -EINVAL; + + sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", + (u32 *)&mac[0], (u32 *)&mac[1], (u32 *)&mac[2], (u32 *)&mac[3], + (u32 *)&mac[4], (u32 *)&mac[5]); + + pch_phub_write_gbe_mac_addr(chip, mac); + + return count; +} + +static DEVICE_ATTR(pch_mac, S_IRUGO | S_IWUSR, show_pch_mac, store_pch_mac); + +static struct bin_attribute pch_bin_attr = { + .attr = { + .name = "pch_firmware", + .mode = S_IRUGO | S_IWUSR, + }, + .size = PCH_PHUB_OROM_SIZE + 1, + .read = pch_phub_bin_read, + .write = pch_phub_bin_write, +}; + +static int __devinit pch_phub_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int retval; + + int ret; + unsigned int rom_size; + struct pch_phub_reg *chip; + + chip = kzalloc(sizeof(struct pch_phub_reg), GFP_KERNEL); + if (chip == NULL) + return -ENOMEM; + + ret = pci_enable_device(pdev); + if (ret) { + dev_err(&pdev->dev, + "%s : pci_enable_device FAILED(ret=%d)", __func__, ret); + goto err_pci_enable_dev; + } + dev_dbg(&pdev->dev, "%s : pci_enable_device returns %d\n", __func__, + ret); + + ret = pci_request_regions(pdev, KBUILD_MODNAME); + if (ret) { + dev_err(&pdev->dev, + "%s : pci_request_regions FAILED(ret=%d)", __func__, ret); + goto err_req_regions; + } + dev_dbg(&pdev->dev, "%s : " + "pci_request_regions returns %d\n", __func__, ret); + + chip->pch_phub_base_address = pci_iomap(pdev, 1, 0); + + + if (chip->pch_phub_base_address == 0) { + dev_err(&pdev->dev, "%s : pci_iomap FAILED", __func__); + ret = -ENOMEM; + goto err_pci_iomap; + } + dev_dbg(&pdev->dev, "%s : pci_iomap SUCCESS and value " + "in pch_phub_base_address variable is 0x%08x\n", __func__, + (unsigned int)chip->pch_phub_base_address); + chip->pch_phub_extrom_base_address = pci_map_rom(pdev, &rom_size); + + if (chip->pch_phub_extrom_base_address == 0) { + dev_err(&pdev->dev, "%s : pci_map_rom FAILED", __func__); + ret = -ENOMEM; + goto err_pci_map; + } + dev_dbg(&pdev->dev, "%s : " + "pci_map_rom SUCCESS and value in " + "pch_phub_extrom_base_address variable is 0x%08x\n", __func__, + (unsigned int)chip->pch_phub_extrom_base_address); + + pci_set_drvdata(pdev, chip); + + retval = sysfs_create_file(&pdev->dev.kobj, &dev_attr_pch_mac.attr); + if (retval) + goto err_sysfs_create; + + retval = sysfs_create_bin_file(&pdev->dev.kobj, &pch_bin_attr); + if (retval) + goto exit_bin_attr; + + pch_phub_read_modify_write_reg(chip, (unsigned int)CLKCFG_REG_OFFSET, + CLKCFG_CAN_50MHZ, CLKCFG_CANCLK_MASK); + + /* set the prefech value */ + iowrite32(0x000affaa, chip->pch_phub_base_address + 0x14); + /* set the interrupt delay value */ + iowrite32(0x25, chip->pch_phub_base_address + 0x44); + + return 0; +exit_bin_attr: + sysfs_remove_file(&pdev->dev.kobj, &dev_attr_pch_mac.attr); + +err_sysfs_create: + pci_unmap_rom(pdev, chip->pch_phub_extrom_base_address); +err_pci_map: + pci_iounmap(pdev, chip->pch_phub_base_address); +err_pci_iomap: + pci_release_regions(pdev); +err_req_regions: + pci_disable_device(pdev); +err_pci_enable_dev: + kfree(chip); + dev_err(&pdev->dev, "%s returns %d\n", __func__, ret); + return ret; +} + +static void __devexit pch_phub_remove(struct pci_dev *pdev) +{ + struct pch_phub_reg *chip = pci_get_drvdata(pdev); + + sysfs_remove_file(&pdev->dev.kobj, &dev_attr_pch_mac.attr); + sysfs_remove_bin_file(&pdev->dev.kobj, &pch_bin_attr); + pci_unmap_rom(pdev, chip->pch_phub_extrom_base_address); + pci_iounmap(pdev, chip->pch_phub_base_address); + pci_release_regions(pdev); + pci_disable_device(pdev); + kfree(chip); +} + +#ifdef CONFIG_PM + +static int pch_phub_suspend(struct pci_dev *pdev, pm_message_t state) +{ + int ret; + + pch_phub_save_reg_conf(pdev); + ret = pci_save_state(pdev); + if (ret) { + dev_err(&pdev->dev, + " %s -pci_save_state returns %d\n", __func__, ret); + return ret; + } + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_disable_device(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +static int pch_phub_resume(struct pci_dev *pdev) +{ + int ret; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + ret = pci_enable_device(pdev); + if (ret) { + dev_err(&pdev->dev, + "%s-pci_enable_device failed(ret=%d) ", __func__, ret); + return ret; + } + + pci_enable_wake(pdev, PCI_D3hot, 0); + pch_phub_restore_reg_conf(pdev); + + return 0; +} +#else +#define pch_phub_suspend NULL +#define pch_phub_resume NULL +#endif /* CONFIG_PM */ + +static struct pci_device_id pch_phub_pcidev_id[] = { + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PCH1_PHUB)}, + {0,} +}; + +static struct pci_driver pch_phub_driver = { + .name = "pch_phub", + .id_table = pch_phub_pcidev_id, + .probe = pch_phub_probe, + .remove = __devexit_p(pch_phub_remove), + .suspend = pch_phub_suspend, + .resume = pch_phub_resume +}; + +static int __init pch_phub_pci_init(void) +{ + return pci_register_driver(&pch_phub_driver); +} + +static void __exit pch_phub_pci_exit(void) +{ + pci_unregister_driver(&pch_phub_driver); +} + +module_init(pch_phub_pci_init); +module_exit(pch_phub_pci_exit); + +MODULE_DESCRIPTION("PCH Packet Hub PCI Driver"); +MODULE_LICENSE("GPL"); -- cgit From da0d7f982d538f4a5bcdddb84df4a484a3b1770b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 1 Sep 2010 18:06:09 -0700 Subject: pch_phub: fix build warnings This patch fixes up all of the build warnings for the pch_phub driver. Cc: Masayuki Ohtake Signed-off-by: Greg Kroah-Hartman --- drivers/misc/pch_phub.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c index ed56e4f91fa0..744b804aca15 100644 --- a/drivers/misc/pch_phub.c +++ b/drivers/misc/pch_phub.c @@ -546,7 +546,7 @@ static int __devinit pch_phub_probe(struct pci_dev *pdev, int retval; int ret; - unsigned int rom_size; + ssize_t rom_size; struct pch_phub_reg *chip; chip = kzalloc(sizeof(struct pch_phub_reg), GFP_KERNEL); @@ -580,8 +580,8 @@ static int __devinit pch_phub_probe(struct pci_dev *pdev, goto err_pci_iomap; } dev_dbg(&pdev->dev, "%s : pci_iomap SUCCESS and value " - "in pch_phub_base_address variable is 0x%08x\n", __func__, - (unsigned int)chip->pch_phub_base_address); + "in pch_phub_base_address variable is %p\n", __func__, + chip->pch_phub_base_address); chip->pch_phub_extrom_base_address = pci_map_rom(pdev, &rom_size); if (chip->pch_phub_extrom_base_address == 0) { @@ -591,8 +591,8 @@ static int __devinit pch_phub_probe(struct pci_dev *pdev, } dev_dbg(&pdev->dev, "%s : " "pci_map_rom SUCCESS and value in " - "pch_phub_extrom_base_address variable is 0x%08x\n", __func__, - (unsigned int)chip->pch_phub_extrom_base_address); + "pch_phub_extrom_base_address variable is %p\n", __func__, + chip->pch_phub_extrom_base_address); pci_set_drvdata(pdev, chip); -- cgit From 5cfc64ceb6222aabec640ba76e89529a8fc2c1f0 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 7 Sep 2010 17:31:49 +0400 Subject: base/platform: Safe handling for NULL platform data and resources Some users of platform_device_add_{data,resources}() assume that NULL data and resources will be handled specially, i.e. just ignored. But the platform core ends up calling kmemdup(NULL, 0, ...), which returns a non-NULL result (i.e. ZERO_SIZE_PTR), which causes drivers to oops on a valid code, something like: if (platform_data) stuff = platform_data->stuff; This patch makes the platform core a bit more safe for such cases. Signed-off-by: Anton Vorontsov Signed-off-by: Greg Kroah-Hartman --- drivers/base/platform.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/platform.c b/drivers/base/platform.c index a01abf9ebf7b..c794fec1c435 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -192,6 +192,9 @@ int platform_device_add_resources(struct platform_device *pdev, { struct resource *r; + if (!res) + return 0; + r = kmemdup(res, sizeof(struct resource) * num, GFP_KERNEL); if (r) { pdev->resource = r; @@ -215,8 +218,12 @@ EXPORT_SYMBOL_GPL(platform_device_add_resources); int platform_device_add_data(struct platform_device *pdev, const void *data, size_t size) { - void *d = kmemdup(data, size, GFP_KERNEL); + void *d; + + if (!data) + return 0; + d = kmemdup(data, size, GFP_KERNEL); if (d) { pdev->dev.platform_data = d; return 0; -- cgit From 807508c8ff9af6ce8f25c5ca5f3eb06a8e7d3286 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Tue, 7 Sep 2010 17:31:54 +0400 Subject: base/platform: Simplifications for NULL platform data/resources handling There's no need to explicitly check for data and resources being NULL, as platform_device_add_{data,resources}() do this internally nowadays. This makes the code more linear and less indented. Signed-off-by: Anton Vorontsov Signed-off-by: Greg Kroah-Hartman --- drivers/base/platform.c | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/base/platform.c b/drivers/base/platform.c index c794fec1c435..3966e62ad019 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -380,17 +380,13 @@ struct platform_device *__init_or_module platform_device_register_resndata( pdev->dev.parent = parent; - if (res) { - ret = platform_device_add_resources(pdev, res, num); - if (ret) - goto err; - } + ret = platform_device_add_resources(pdev, res, num); + if (ret) + goto err; - if (data) { - ret = platform_device_add_data(pdev, data, size); - if (ret) - goto err; - } + ret = platform_device_add_data(pdev, data, size); + if (ret) + goto err; ret = platform_device_add(pdev); if (ret) { @@ -537,17 +533,13 @@ struct platform_device * __init_or_module platform_create_bundle( goto err_out; } - if (res) { - error = platform_device_add_resources(pdev, res, n_res); - if (error) - goto err_pdev_put; - } + error = platform_device_add_resources(pdev, res, n_res); + if (error) + goto err_pdev_put; - if (data) { - error = platform_device_add_data(pdev, data, size); - if (error) - goto err_pdev_put; - } + error = platform_device_add_data(pdev, data, size); + if (error) + goto err_pdev_put; error = platform_device_add(pdev); if (error) -- cgit From 39aba963d937edb20db7d9d93e6dda5d2adfdcdd Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sat, 4 Sep 2010 22:33:14 -0700 Subject: driver core: remove CONFIG_SYSFS_DEPRECATED_V2 but keep it for block devices This patch removes the old CONFIG_SYSFS_DEPRECATED_V2 config option, but it keeps the logic around to handle block devices in the old manner as some people like to run new kernel versions on old (pre 2007/2008) distros. Signed-off-by: Kay Sievers Cc: Jens Axboe Cc: Stephen Hemminger Cc: "Eric W. Biederman" Cc: Alan Stern Cc: "James E.J. Bottomley" Cc: Andrew Morton Cc: Alexey Kuznetsov Cc: Randy Dunlap Cc: Tejun Heo Cc: "David S. Miller" Cc: Jaroslav Kysela Cc: Takashi Iwai Cc: Ingo Molnar Cc: Peter Zijlstra Cc: David Howells Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 22 ------ drivers/base/class.c | 19 ----- drivers/base/core.c | 194 ++++++----------------------------------------- drivers/scsi/hosts.c | 2 - drivers/scsi/scsi_scan.c | 2 - 5 files changed, 25 insertions(+), 214 deletions(-) (limited to 'drivers') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index eb1b7fa20dce..33c270a64db7 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -440,22 +440,6 @@ static void device_remove_attrs(struct bus_type *bus, struct device *dev) } } -#ifdef CONFIG_SYSFS_DEPRECATED -static int make_deprecated_bus_links(struct device *dev) -{ - return sysfs_create_link(&dev->kobj, - &dev->bus->p->subsys.kobj, "bus"); -} - -static void remove_deprecated_bus_links(struct device *dev) -{ - sysfs_remove_link(&dev->kobj, "bus"); -} -#else -static inline int make_deprecated_bus_links(struct device *dev) { return 0; } -static inline void remove_deprecated_bus_links(struct device *dev) { } -#endif - /** * bus_add_device - add device to bus * @dev: device being added @@ -482,15 +466,10 @@ int bus_add_device(struct device *dev) &dev->bus->p->subsys.kobj, "subsystem"); if (error) goto out_subsys; - error = make_deprecated_bus_links(dev); - if (error) - goto out_deprecated; klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices); } return 0; -out_deprecated: - sysfs_remove_link(&dev->kobj, "subsystem"); out_subsys: sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev)); out_id: @@ -530,7 +509,6 @@ void bus_remove_device(struct device *dev) { if (dev->bus) { sysfs_remove_link(&dev->kobj, "subsystem"); - remove_deprecated_bus_links(dev); sysfs_remove_link(&dev->bus->p->devices_kset->kobj, dev_name(dev)); device_remove_attrs(dev->bus, dev); diff --git a/drivers/base/class.c b/drivers/base/class.c index 8e231d05b400..1078969889fd 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -276,25 +276,6 @@ void class_destroy(struct class *cls) class_unregister(cls); } -#ifdef CONFIG_SYSFS_DEPRECATED -char *make_class_name(const char *name, struct kobject *kobj) -{ - char *class_name; - int size; - - size = strlen(name) + strlen(kobject_name(kobj)) + 2; - - class_name = kmalloc(size, GFP_KERNEL); - if (!class_name) - return NULL; - - strcpy(class_name, name); - strcat(class_name, ":"); - strcat(class_name, kobject_name(kobj)); - return class_name; -} -#endif - /** * class_dev_iter_init - initialize class device iterator * @iter: class iterator to initialize diff --git a/drivers/base/core.c b/drivers/base/core.c index d1b2c9adc271..6cf9069f3150 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -203,37 +203,6 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, if (dev->driver) add_uevent_var(env, "DRIVER=%s", dev->driver->name); -#ifdef CONFIG_SYSFS_DEPRECATED - if (dev->class) { - struct device *parent = dev->parent; - - /* find first bus device in parent chain */ - while (parent && !parent->bus) - parent = parent->parent; - if (parent && parent->bus) { - const char *path; - - path = kobject_get_path(&parent->kobj, GFP_KERNEL); - if (path) { - add_uevent_var(env, "PHYSDEVPATH=%s", path); - kfree(path); - } - - add_uevent_var(env, "PHYSDEVBUS=%s", parent->bus->name); - - if (parent->driver) - add_uevent_var(env, "PHYSDEVDRIVER=%s", - parent->driver->name); - } - } else if (dev->bus) { - add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name); - - if (dev->driver) - add_uevent_var(env, "PHYSDEVDRIVER=%s", - dev->driver->name); - } -#endif - /* have the bus specific function add its stuff */ if (dev->bus && dev->bus->uevent) { retval = dev->bus->uevent(dev, env); @@ -578,24 +547,6 @@ void device_initialize(struct device *dev) set_dev_node(dev, -1); } -#ifdef CONFIG_SYSFS_DEPRECATED -static struct kobject *get_device_parent(struct device *dev, - struct device *parent) -{ - /* class devices without a parent live in /sys/class// */ - if (dev->class && (!parent || parent->class != dev->class)) - return &dev->class->p->class_subsys.kobj; - /* all other devices keep their parent */ - else if (parent) - return &parent->kobj; - - return NULL; -} - -static inline void cleanup_device_parent(struct device *dev) {} -static inline void cleanup_glue_dir(struct device *dev, - struct kobject *glue_dir) {} -#else static struct kobject *virtual_device_parent(struct device *dev) { static struct kobject *virtual_dir = NULL; @@ -666,6 +617,14 @@ static struct kobject *get_device_parent(struct device *dev, struct kobject *parent_kobj; struct kobject *k; +#ifdef CONFIG_SYSFS_DEPRECATED + /* block disks show up in /sys/block */ + if (dev->class == &block_class) { + if (parent && parent->class == &block_class) + return &parent->kobj; + return &block_class.p->class_subsys.kobj; + } +#endif /* * If we have no parent, we live in "virtual". * Class-devices with a non class-device as parent, live @@ -719,7 +678,6 @@ static void cleanup_device_parent(struct device *dev) { cleanup_glue_dir(dev, dev->kobj.parent); } -#endif static void setup_parent(struct device *dev, struct device *parent) { @@ -742,70 +700,29 @@ static int device_add_class_symlinks(struct device *dev) if (error) goto out; -#ifdef CONFIG_SYSFS_DEPRECATED - /* stacked class devices need a symlink in the class directory */ - if (dev->kobj.parent != &dev->class->p->class_subsys.kobj && - device_is_not_partition(dev)) { - error = sysfs_create_link(&dev->class->p->class_subsys.kobj, - &dev->kobj, dev_name(dev)); - if (error) - goto out_subsys; - } - if (dev->parent && device_is_not_partition(dev)) { - struct device *parent = dev->parent; - char *class_name; - - /* - * stacked class devices have the 'device' link - * pointing to the bus device instead of the parent - */ - while (parent->class && !parent->bus && parent->parent) - parent = parent->parent; - - error = sysfs_create_link(&dev->kobj, - &parent->kobj, + error = sysfs_create_link(&dev->kobj, &dev->parent->kobj, "device"); if (error) - goto out_busid; - - class_name = make_class_name(dev->class->name, - &dev->kobj); - if (class_name) - error = sysfs_create_link(&dev->parent->kobj, - &dev->kobj, class_name); - kfree(class_name); - if (error) - goto out_device; + goto out_subsys; } - return 0; -out_device: - if (dev->parent && device_is_not_partition(dev)) - sysfs_remove_link(&dev->kobj, "device"); -out_busid: - if (dev->kobj.parent != &dev->class->p->class_subsys.kobj && - device_is_not_partition(dev)) - sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, - dev_name(dev)); -#else +#ifdef CONFIG_SYSFS_DEPRECATED + /* /sys/block has directories and does not need symlinks */ + if (dev->class == &block_class) + return 0; +#endif + /* link in the class directory pointing to the device */ error = sysfs_create_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev)); if (error) - goto out_subsys; + goto out_device; - if (dev->parent && device_is_not_partition(dev)) { - error = sysfs_create_link(&dev->kobj, &dev->parent->kobj, - "device"); - if (error) - goto out_busid; - } return 0; -out_busid: - sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev)); -#endif +out_device: + sysfs_remove_link(&dev->kobj, "device"); out_subsys: sysfs_remove_link(&dev->kobj, "subsystem"); @@ -818,30 +735,14 @@ static void device_remove_class_symlinks(struct device *dev) if (!dev->class) return; -#ifdef CONFIG_SYSFS_DEPRECATED - if (dev->parent && device_is_not_partition(dev)) { - char *class_name; - - class_name = make_class_name(dev->class->name, &dev->kobj); - if (class_name) { - sysfs_remove_link(&dev->parent->kobj, class_name); - kfree(class_name); - } - sysfs_remove_link(&dev->kobj, "device"); - } - - if (dev->kobj.parent != &dev->class->p->class_subsys.kobj && - device_is_not_partition(dev)) - sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, - dev_name(dev)); -#else if (dev->parent && device_is_not_partition(dev)) sysfs_remove_link(&dev->kobj, "device"); - - sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev)); -#endif - sysfs_remove_link(&dev->kobj, "subsystem"); +#ifdef CONFIG_SYSFS_DEPRECATED + if (dev->class == &block_class) + return; +#endif + sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev)); } /** @@ -1613,41 +1514,23 @@ int device_rename(struct device *dev, const char *new_name) pr_debug("device: '%s': %s: renaming to '%s'\n", dev_name(dev), __func__, new_name); -#ifdef CONFIG_SYSFS_DEPRECATED - if ((dev->class) && (dev->parent)) - old_class_name = make_class_name(dev->class->name, &dev->kobj); -#endif - old_device_name = kstrdup(dev_name(dev), GFP_KERNEL); if (!old_device_name) { error = -ENOMEM; goto out; } -#ifndef CONFIG_SYSFS_DEPRECATED if (dev->class) { error = sysfs_rename_link(&dev->class->p->class_subsys.kobj, &dev->kobj, old_device_name, new_name); if (error) goto out; } -#endif + error = kobject_rename(&dev->kobj, new_name); if (error) goto out; -#ifdef CONFIG_SYSFS_DEPRECATED - if (old_class_name) { - new_class_name = make_class_name(dev->class->name, &dev->kobj); - if (new_class_name) { - error = sysfs_rename_link(&dev->parent->kobj, - &dev->kobj, - old_class_name, - new_class_name); - } - } -#endif - out: put_device(dev); @@ -1664,40 +1547,13 @@ static int device_move_class_links(struct device *dev, struct device *new_parent) { int error = 0; -#ifdef CONFIG_SYSFS_DEPRECATED - char *class_name; - class_name = make_class_name(dev->class->name, &dev->kobj); - if (!class_name) { - error = -ENOMEM; - goto out; - } - if (old_parent) { - sysfs_remove_link(&dev->kobj, "device"); - sysfs_remove_link(&old_parent->kobj, class_name); - } - if (new_parent) { - error = sysfs_create_link(&dev->kobj, &new_parent->kobj, - "device"); - if (error) - goto out; - error = sysfs_create_link(&new_parent->kobj, &dev->kobj, - class_name); - if (error) - sysfs_remove_link(&dev->kobj, "device"); - } else - error = 0; -out: - kfree(class_name); - return error; -#else if (old_parent) sysfs_remove_link(&dev->kobj, "device"); if (new_parent) error = sysfs_create_link(&dev->kobj, &new_parent->kobj, "device"); return error; -#endif } /** diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 8a8f803439e1..ba7f87acc00d 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -411,9 +411,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) device_initialize(&shost->shost_gendev); dev_set_name(&shost->shost_gendev, "host%d", shost->host_no); -#ifndef CONFIG_SYSFS_DEPRECATED shost->shost_gendev.bus = &scsi_bus_type; -#endif shost->shost_gendev.type = &scsi_host_type; device_initialize(&shost->shost_dev); diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 3d0a1e6e9c48..087821fac8fe 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -417,9 +417,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, starget->reap_ref = 1; dev->parent = get_device(parent); dev_set_name(dev, "target%d:%d:%d", shost->host_no, channel, id); -#ifndef CONFIG_SYSFS_DEPRECATED dev->bus = &scsi_bus_type; -#endif dev->type = &scsi_target_type; starget->id = id; starget->channel = channel; -- cgit From e52eec13cd6b7f30ab19081b387813e03e592ae5 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Wed, 8 Sep 2010 16:54:17 +0200 Subject: SYSFS: Allow boot time switching between deprecated and modern sysfs layout I have some systems which need legacy sysfs due to old tools that are making assumptions that a directory can never be a symlink to another directory, and it's a big hazzle to compile separate kernels for them. This patch turns CONFIG_SYSFS_DEPRECATED into a run time option that can be switched on/off the kernel command line. This way the same binary can be used in both cases with just a option on the command line. The old CONFIG_SYSFS_DEPRECATED_V2 option is still there to set the default. I kept the weird name to not break existing config files. Also the compat code can be still completely disabled by undefining CONFIG_SYSFS_DEPRECATED_SWITCH -- just the optimizer takes care of this now instead of lots of ifdefs. This makes the code look nicer. v2: This is an updated version on top of Kay's patch to only handle the block devices. I tested it on my old systems and that seems to work. Cc: axboe@kernel.dk Signed-off-by: Andi Kleen Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/base/class.c | 4 ++-- drivers/base/core.c | 26 +++++++++++++++++--------- 2 files changed, 19 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/base/class.c b/drivers/base/class.c index 1078969889fd..9c63a5687d69 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -184,9 +184,9 @@ int __class_register(struct class *cls, struct lock_class_key *key) if (!cls->dev_kobj) cls->dev_kobj = sysfs_dev_char_kobj; -#if defined(CONFIG_SYSFS_DEPRECATED) && defined(CONFIG_BLOCK) +#if defined(CONFIG_BLOCK) /* let the block class directory show up in the root of sysfs */ - if (cls != &block_class) + if (!sysfs_deprecated || cls != &block_class) cp->class_subsys.kobj.kset = class_kset; #else cp->class_subsys.kobj.kset = class_kset; diff --git a/drivers/base/core.c b/drivers/base/core.c index 6cf9069f3150..f7f906f0a2f2 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -26,6 +26,19 @@ #include "base.h" #include "power/power.h" +#ifdef CONFIG_SYSFS_DEPRECATED +#ifdef CONFIG_SYSFS_DEPRECATED_V2 +long sysfs_deprecated = 1; +#else +long sysfs_deprecated = 0; +#endif +static __init int sysfs_deprecated_setup(char *arg) +{ + return strict_strtol(arg, 10, &sysfs_deprecated); +} +early_param("sysfs.deprecated", sysfs_deprecated_setup); +#endif + int (*platform_notify)(struct device *dev) = NULL; int (*platform_notify_remove)(struct device *dev) = NULL; static struct kobject *dev_kobj; @@ -617,14 +630,13 @@ static struct kobject *get_device_parent(struct device *dev, struct kobject *parent_kobj; struct kobject *k; -#ifdef CONFIG_SYSFS_DEPRECATED /* block disks show up in /sys/block */ - if (dev->class == &block_class) { + if (sysfs_deprecated && dev->class == &block_class) { if (parent && parent->class == &block_class) return &parent->kobj; return &block_class.p->class_subsys.kobj; } -#endif + /* * If we have no parent, we live in "virtual". * Class-devices with a non class-device as parent, live @@ -707,11 +719,9 @@ static int device_add_class_symlinks(struct device *dev) goto out_subsys; } -#ifdef CONFIG_SYSFS_DEPRECATED /* /sys/block has directories and does not need symlinks */ - if (dev->class == &block_class) + if (sysfs_deprecated && dev->class == &block_class) return 0; -#endif /* link in the class directory pointing to the device */ error = sysfs_create_link(&dev->class->p->class_subsys.kobj, @@ -738,10 +748,8 @@ static void device_remove_class_symlinks(struct device *dev) if (dev->parent && device_is_not_partition(dev)) sysfs_remove_link(&dev->kobj, "device"); sysfs_remove_link(&dev->kobj, "subsystem"); -#ifdef CONFIG_SYSFS_DEPRECATED - if (dev->class == &block_class) + if (sysfs_deprecated && dev->class == &block_class) return; -#endif sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev)); } -- cgit From 3d4f9d76b0641b7984f95982e390927fc5998ad6 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 14 Sep 2010 11:36:27 -0700 Subject: uio: Fix lack of locking in init_uio_class There is no locking in init_uio_class so multiple drivers can race and create multiple uio classes. Fix this by simplifying the code. In particular always register the uio class during module_init and make things simpler. Signed-off-by: Eric W. Biederman Reviewed-by: Thomas Gleixner Signed-off-by: Hans J. Koch Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio.c | 58 ++++++++++++++----------------------------------------- 1 file changed, 15 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index bff1afbde5a4..bc774cce0a4d 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -45,10 +45,7 @@ static DEFINE_IDR(uio_idr); static const struct file_operations uio_fops; /* UIO class infrastructure */ -static struct uio_class { - struct kref kref; - struct class *class; -} *uio_class; +static struct class *uio_class; /* Protect idr accesses */ static DEFINE_MUTEX(minor_lock); @@ -757,55 +754,35 @@ static void uio_major_cleanup(void) static int init_uio_class(void) { - int ret = 0; - - if (uio_class != NULL) { - kref_get(&uio_class->kref); - goto exit; - } + struct class *class; + int ret; /* This is the first time in here, set everything up properly */ ret = uio_major_init(); if (ret) goto exit; - uio_class = kzalloc(sizeof(*uio_class), GFP_KERNEL); - if (!uio_class) { - ret = -ENOMEM; - goto err_kzalloc; - } - - kref_init(&uio_class->kref); - uio_class->class = class_create(THIS_MODULE, "uio"); - if (IS_ERR(uio_class->class)) { - ret = IS_ERR(uio_class->class); + class = class_create(THIS_MODULE, "uio"); + if (IS_ERR(class)) { + ret = IS_ERR(class); printk(KERN_ERR "class_create failed for uio\n"); goto err_class_create; } + uio_class = class; return 0; err_class_create: - kfree(uio_class); - uio_class = NULL; -err_kzalloc: uio_major_cleanup(); exit: return ret; } -static void release_uio_class(struct kref *kref) +static void release_uio_class(void) { /* Ok, we cheat as we know we only have one uio_class */ - class_destroy(uio_class->class); - kfree(uio_class); - uio_major_cleanup(); + class_destroy(uio_class); uio_class = NULL; -} - -static void uio_class_destroy(void) -{ - if (uio_class) - kref_put(&uio_class->kref, release_uio_class); + uio_major_cleanup(); } /** @@ -828,10 +805,6 @@ int __uio_register_device(struct module *owner, info->uio_dev = NULL; - ret = init_uio_class(); - if (ret) - return ret; - idev = kzalloc(sizeof(*idev), GFP_KERNEL); if (!idev) { ret = -ENOMEM; @@ -847,7 +820,7 @@ int __uio_register_device(struct module *owner, if (ret) goto err_get_minor; - idev->dev = device_create(uio_class->class, parent, + idev->dev = device_create(uio_class, parent, MKDEV(uio_major, idev->minor), idev, "uio%d", idev->minor); if (IS_ERR(idev->dev)) { @@ -874,13 +847,12 @@ int __uio_register_device(struct module *owner, err_request_irq: uio_dev_del_attributes(idev); err_uio_dev_add_attributes: - device_destroy(uio_class->class, MKDEV(uio_major, idev->minor)); + device_destroy(uio_class, MKDEV(uio_major, idev->minor)); err_device_create: uio_free_minor(idev); err_get_minor: kfree(idev); err_kzalloc: - uio_class_destroy(); return ret; } EXPORT_SYMBOL_GPL(__uio_register_device); @@ -907,9 +879,8 @@ void uio_unregister_device(struct uio_info *info) uio_dev_del_attributes(idev); dev_set_drvdata(idev->dev, NULL); - device_destroy(uio_class->class, MKDEV(uio_major, idev->minor)); + device_destroy(uio_class, MKDEV(uio_major, idev->minor)); kfree(idev); - uio_class_destroy(); return; } @@ -917,11 +888,12 @@ EXPORT_SYMBOL_GPL(uio_unregister_device); static int __init uio_init(void) { - return 0; + return init_uio_class(); } static void __exit uio_exit(void) { + release_uio_class(); } module_init(uio_init) -- cgit From 70a9156bad9d9d1476df35dde582b9f411bf5914 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 14 Sep 2010 11:36:54 -0700 Subject: uio: Don't clear driver data Currently uio sets it's driver data to NULL just as it is unregistering attributes. sysfs maks the guaranatee that it will not call attributes after device_destroy is called so this is unncessary and leads to lots of unnecessary code in uio.c Signed-off-by: Eric W. Biederman Reviewed-by: Thomas Gleixner Signed-off-by: Hans J. Koch Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index bc774cce0a4d..8132288920b2 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -229,10 +229,7 @@ static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf) { struct uio_device *idev = dev_get_drvdata(dev); - if (idev) - return sprintf(buf, "%s\n", idev->info->name); - else - return -ENODEV; + return sprintf(buf, "%s\n", idev->info->name); } static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); @@ -240,10 +237,7 @@ static ssize_t show_version(struct device *dev, struct device_attribute *attr, char *buf) { struct uio_device *idev = dev_get_drvdata(dev); - if (idev) - return sprintf(buf, "%s\n", idev->info->version); - else - return -ENODEV; + return sprintf(buf, "%s\n", idev->info->version); } static DEVICE_ATTR(version, S_IRUGO, show_version, NULL); @@ -251,11 +245,7 @@ static ssize_t show_event(struct device *dev, struct device_attribute *attr, char *buf) { struct uio_device *idev = dev_get_drvdata(dev); - if (idev) - return sprintf(buf, "%u\n", - (unsigned int)atomic_read(&idev->event)); - else - return -ENODEV; + return sprintf(buf, "%u\n", (unsigned int)atomic_read(&idev->event)); } static DEVICE_ATTR(event, S_IRUGO, show_event, NULL); @@ -878,7 +868,6 @@ void uio_unregister_device(struct uio_info *info) uio_dev_del_attributes(idev); - dev_set_drvdata(idev->dev, NULL); device_destroy(uio_class, MKDEV(uio_major, idev->minor)); kfree(idev); -- cgit From 6427a7655afd7f07dfa83736defd1d94656c83e5 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 14 Sep 2010 11:37:36 -0700 Subject: uio: Cleanup irq handling. Change the value of UIO_IRQ_NONE -2 to 0. 0 is well defined in the rest of the kernel as the value to indicate an irq has not been assigned. Update the calls to request_irq and free_irq to only ignore UIO_IRQ_NONE and UIO_IRQ_CUSTOM allowing the rest of the kernel's possible irq numbers to be used. Signed-off-by: Eric W. Biederman Reviewed-by: Thomas Gleixner Signed-off-by: Hans J. Koch Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index 8132288920b2..0fd2cda74244 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -512,7 +512,7 @@ static unsigned int uio_poll(struct file *filep, poll_table *wait) struct uio_listener *listener = filep->private_data; struct uio_device *idev = listener->dev; - if (idev->info->irq == UIO_IRQ_NONE) + if (!idev->info->irq) return -EIO; poll_wait(filep, &idev->wait, wait); @@ -530,7 +530,7 @@ static ssize_t uio_read(struct file *filep, char __user *buf, ssize_t retval; s32 event_count; - if (idev->info->irq == UIO_IRQ_NONE) + if (!idev->info->irq) return -EIO; if (count != sizeof(s32)) @@ -578,7 +578,7 @@ static ssize_t uio_write(struct file *filep, const char __user *buf, ssize_t retval; s32 irq_on; - if (idev->info->irq == UIO_IRQ_NONE) + if (!idev->info->irq) return -EIO; if (count != sizeof(s32)) @@ -825,9 +825,9 @@ int __uio_register_device(struct module *owner, info->uio_dev = idev; - if (idev->info->irq >= 0) { - ret = request_irq(idev->info->irq, uio_interrupt, - idev->info->irq_flags, idev->info->name, idev); + if (info->irq && (info->irq != UIO_IRQ_CUSTOM)) { + ret = request_irq(info->irq, uio_interrupt, + info->irq_flags, info->name, idev); if (ret) goto err_request_irq; } @@ -863,7 +863,7 @@ void uio_unregister_device(struct uio_info *info) uio_free_minor(idev); - if (info->irq >= 0) + if (info->irq && (info->irq != UIO_IRQ_CUSTOM)) free_irq(info->irq, idev); uio_dev_del_attributes(idev); -- cgit From 91960a46c658b719c03fba80f1c60a96393bbcfd Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 14 Sep 2010 11:38:06 -0700 Subject: uio: Support 2^MINOR_BITS minors register_chrdev limits uio devices to 256 minor numbers which causes problems on one system I have with 384+ uio devices. So instead set UIO_MAX_DEVICES to the maximum number of minors and use alloc_chrdev_region to reserve the uio minors. The final result is that the code works the same but the uio driver now supports any minor the idr allocator comes up with. Signed-off-by: Eric W. Biederman Reviewed-by: Thomas Gleixner Signed-off-by: Hans J. Koch Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio.c | 43 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index 0fd2cda74244..3d4d65b0626f 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -23,9 +23,10 @@ #include #include #include +#include #include -#define UIO_MAX_DEVICES 255 +#define UIO_MAX_DEVICES (1U << MINORBITS) struct uio_device { struct module *owner; @@ -41,6 +42,7 @@ struct uio_device { }; static int uio_major; +static struct cdev *uio_cdev; static DEFINE_IDR(uio_idr); static const struct file_operations uio_fops; @@ -731,15 +733,44 @@ static const struct file_operations uio_fops = { static int uio_major_init(void) { - uio_major = register_chrdev(0, "uio", &uio_fops); - if (uio_major < 0) - return uio_major; - return 0; + static const char name[] = "uio"; + struct cdev *cdev = NULL; + dev_t uio_dev = 0; + int result; + + result = alloc_chrdev_region(&uio_dev, 0, UIO_MAX_DEVICES, name); + if (result) + goto out; + + result = -ENOMEM; + cdev = cdev_alloc(); + if (!cdev) + goto out_unregister; + + cdev->owner = THIS_MODULE; + cdev->ops = &uio_fops; + kobject_set_name(&cdev->kobj, "%s", name); + + result = cdev_add(cdev, uio_dev, UIO_MAX_DEVICES); + if (result) + goto out_put; + + uio_major = MAJOR(uio_dev); + uio_cdev = cdev; + result = 0; +out: + return result; +out_put: + kobject_put(&cdev->kobj); +out_unregister: + unregister_chrdev_region(uio_dev, UIO_MAX_DEVICES); + goto out; } static void uio_major_cleanup(void) { - unregister_chrdev(uio_major, "uio"); + unregister_chrdev_region(MKDEV(uio_major, 0), UIO_MAX_DEVICES); + cdev_del(uio_cdev); } static int init_uio_class(void) -- cgit From c66fdab64fd791bdd49fed4f5785643251ddf586 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Tue, 14 Sep 2010 11:38:36 -0700 Subject: uio: Statically allocate uio_class and use class .dev_attrs. Instead of adding uio class attributes manually after the uio device has been created and we have sent a uevent to userspace, use the class attribute mechanism. This removes races and makes the code simpler. At the same time don't bother to dynamically allocate a struct class for uio, just declare one statically. Less code is needed and it is easier to set the class parameters.tune the class Signed-off-by: Eric W. Biederman Reviewed-by: Thomas Gleixner Signed-off-by: Hans J. Koch Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio.c | 53 ++++++++++++++++++----------------------------------- 1 file changed, 18 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index 3d4d65b0626f..3fe9a9da42d1 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -46,9 +46,6 @@ static struct cdev *uio_cdev; static DEFINE_IDR(uio_idr); static const struct file_operations uio_fops; -/* UIO class infrastructure */ -static struct class *uio_class; - /* Protect idr accesses */ static DEFINE_MUTEX(minor_lock); @@ -233,7 +230,6 @@ static ssize_t show_name(struct device *dev, struct uio_device *idev = dev_get_drvdata(dev); return sprintf(buf, "%s\n", idev->info->name); } -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); static ssize_t show_version(struct device *dev, struct device_attribute *attr, char *buf) @@ -241,7 +237,6 @@ static ssize_t show_version(struct device *dev, struct uio_device *idev = dev_get_drvdata(dev); return sprintf(buf, "%s\n", idev->info->version); } -static DEVICE_ATTR(version, S_IRUGO, show_version, NULL); static ssize_t show_event(struct device *dev, struct device_attribute *attr, char *buf) @@ -249,17 +244,18 @@ static ssize_t show_event(struct device *dev, struct uio_device *idev = dev_get_drvdata(dev); return sprintf(buf, "%u\n", (unsigned int)atomic_read(&idev->event)); } -static DEVICE_ATTR(event, S_IRUGO, show_event, NULL); -static struct attribute *uio_attrs[] = { - &dev_attr_name.attr, - &dev_attr_version.attr, - &dev_attr_event.attr, - NULL, +static struct device_attribute uio_class_attributes[] = { + __ATTR(name, S_IRUGO, show_name, NULL), + __ATTR(version, S_IRUGO, show_version, NULL), + __ATTR(event, S_IRUGO, show_event, NULL), + {} }; -static struct attribute_group uio_attr_grp = { - .attrs = uio_attrs, +/* UIO class infrastructure */ +static struct class uio_class = { + .name = "uio", + .dev_attrs = uio_class_attributes, }; /* @@ -276,10 +272,6 @@ static int uio_dev_add_attributes(struct uio_device *idev) struct uio_port *port; struct uio_portio *portio; - ret = sysfs_create_group(&idev->dev->kobj, &uio_attr_grp); - if (ret) - goto err_group; - for (mi = 0; mi < MAX_UIO_MAPS; mi++) { mem = &idev->info->mem[mi]; if (mem->size == 0) @@ -347,8 +339,6 @@ err_map: kobject_put(&map->kobj); } kobject_put(idev->map_dir); - sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp); -err_group: dev_err(idev->dev, "error creating sysfs files (%d)\n", ret); return ret; } @@ -374,8 +364,6 @@ static void uio_dev_del_attributes(struct uio_device *idev) kobject_put(&port->portio->kobj); } kobject_put(idev->portio_dir); - - sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp); } static int uio_get_minor(struct uio_device *idev) @@ -775,7 +763,6 @@ static void uio_major_cleanup(void) static int init_uio_class(void) { - struct class *class; int ret; /* This is the first time in here, set everything up properly */ @@ -783,16 +770,14 @@ static int init_uio_class(void) if (ret) goto exit; - class = class_create(THIS_MODULE, "uio"); - if (IS_ERR(class)) { - ret = IS_ERR(class); - printk(KERN_ERR "class_create failed for uio\n"); - goto err_class_create; + ret = class_register(&uio_class); + if (ret) { + printk(KERN_ERR "class_register failed for uio\n"); + goto err_class_register; } - uio_class = class; return 0; -err_class_create: +err_class_register: uio_major_cleanup(); exit: return ret; @@ -800,9 +785,7 @@ exit: static void release_uio_class(void) { - /* Ok, we cheat as we know we only have one uio_class */ - class_destroy(uio_class); - uio_class = NULL; + class_unregister(&uio_class); uio_major_cleanup(); } @@ -841,7 +824,7 @@ int __uio_register_device(struct module *owner, if (ret) goto err_get_minor; - idev->dev = device_create(uio_class, parent, + idev->dev = device_create(&uio_class, parent, MKDEV(uio_major, idev->minor), idev, "uio%d", idev->minor); if (IS_ERR(idev->dev)) { @@ -868,7 +851,7 @@ int __uio_register_device(struct module *owner, err_request_irq: uio_dev_del_attributes(idev); err_uio_dev_add_attributes: - device_destroy(uio_class, MKDEV(uio_major, idev->minor)); + device_destroy(&uio_class, MKDEV(uio_major, idev->minor)); err_device_create: uio_free_minor(idev); err_get_minor: @@ -899,7 +882,7 @@ void uio_unregister_device(struct uio_info *info) uio_dev_del_attributes(idev); - device_destroy(uio_class, MKDEV(uio_major, idev->minor)); + device_destroy(&uio_class, MKDEV(uio_major, idev->minor)); kfree(idev); return; -- cgit From 5fc6e9cbce3342379719fc0f8294c45bb888f5cc Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 18 Sep 2010 13:23:08 -0700 Subject: FW_LOADER: fix kconfig dependency warning on HOTPLUG Fix kconfig dependency warning for FW_LOADER. Lots of drivers select FW_LOADER without bothering to depend on HOTPLUG and/or without selecting HOTPLUG. A kernel builds fine when FW_LOADER is enabled, whether HOTPLUG is enabled or not, and a kernel config file (make oldconfig) is not changed by this patch. (Yes, drivers/base/firmware_class.c uses interfaces from linux/kobject.h, which does have some CONFIG_HOTPLUG dependencies, but this patch does not change that.) warning: (MICROCODE || MICROCODE_INTEL && MICROCODE || MICROCODE_AMD && MICROCODE || PCMCIA_LOAD_CIS && PCCARD && PCMCIA && EXPERIMENTAL || USB_IRDA && NET && IRDA && USB || BT_HCIBCM203X && NET && BT && USB || BT_HCIBFUSB && NET && BT && USB || BT_HCIBT3C && NET && BT && PCMCIA || BT_MRVL_SDIO && NET ... !STAGING_EXCLUDE_BUILD && USB && (X86 || ARM) && WLAN || DRM_NOUVEAU && STAGING && !STAGING_EXCLUDE_BUILD && DRM && PCI || TI_ST && STAGING && !STAGING_EXCLUDE_BUILD && RFKILL || DELL_RBU && X86) selects FW_LOADER which has unmet direct dependencies (HOTPLUG) (5200 byte line reduced a lot) Signed-off-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman --- drivers/base/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index ef38aff737eb..fd96345bc35c 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -71,7 +71,6 @@ config PREVENT_FIRMWARE_BUILD config FW_LOADER tristate "Userspace firmware loading support" if EMBEDDED - depends on HOTPLUG default y ---help--- This option is provided for the case where no in-kernel-tree modules -- cgit From 7a868088ee48d1816c10f9be6d32aef4cf30bcf7 Mon Sep 17 00:00:00 2001 From: matt mooney Date: Fri, 24 Sep 2010 12:17:11 -0700 Subject: driver-core: base: change to new flag variable Replace EXTRA_CFLAGS with ccflags-y. Signed-off-by: matt mooney Acked-by: WANG Cong Signed-off-by: Greg Kroah-Hartman --- drivers/base/Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/base/Makefile b/drivers/base/Makefile index c12c7f2f2a6f..5f51c3b4451e 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -19,7 +19,5 @@ obj-$(CONFIG_MODULES) += module.o endif obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o -ifeq ($(CONFIG_DEBUG_DRIVER),y) -EXTRA_CFLAGS += -DDEBUG -endif +ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG -- cgit From ead454feb6cbfe0fa6a1eeb30aa9abc338dacf62 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 24 Sep 2010 14:36:49 -0700 Subject: driver core: fix build for CONFIG_BLOCK not enabled Fix build errors when CONFIG_BLOCK is not enabled: drivers/base/core.c: In function 'get_device_parent': drivers/base/core.c:634: error: 'block_class' undeclared (first use in this function) drivers/base/core.c: In function 'device_add_class_symlinks': drivers/base/core.c:723: error: 'block_class' undeclared (first use in this function) drivers/base/core.c: In function 'device_remove_class_symlinks': drivers/base/core.c:751: error: 'block_class' undeclared (first use in this function) Signed-off-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/base/core.c b/drivers/base/core.c index f7f906f0a2f2..2cb49a93b1e6 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -630,12 +630,14 @@ static struct kobject *get_device_parent(struct device *dev, struct kobject *parent_kobj; struct kobject *k; +#ifdef CONFIG_BLOCK /* block disks show up in /sys/block */ if (sysfs_deprecated && dev->class == &block_class) { if (parent && parent->class == &block_class) return &parent->kobj; return &block_class.p->class_subsys.kobj; } +#endif /* * If we have no parent, we live in "virtual". @@ -719,9 +721,11 @@ static int device_add_class_symlinks(struct device *dev) goto out_subsys; } +#ifdef CONFIG_BLOCK /* /sys/block has directories and does not need symlinks */ if (sysfs_deprecated && dev->class == &block_class) return 0; +#endif /* link in the class directory pointing to the device */ error = sysfs_create_link(&dev->class->p->class_subsys.kobj, @@ -748,8 +752,10 @@ static void device_remove_class_symlinks(struct device *dev) if (dev->parent && device_is_not_partition(dev)) sysfs_remove_link(&dev->kobj, "device"); sysfs_remove_link(&dev->kobj, "subsystem"); +#ifdef CONFIG_BLOCK if (sysfs_deprecated && dev->class == &block_class) return; +#endif sysfs_delete_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev_name(dev)); } -- cgit From 98383031ed77c6eb49ab612166fef9c0efe1604a Mon Sep 17 00:00:00 2001 From: Robin Holt Date: Wed, 29 Sep 2010 14:00:55 -0500 Subject: driver core: Introduce find_memory_block_hinted which utilizes kset_find_obj_hinted. Introduce a find_memory_block_hinted() which utilizes the recently added kset_find_obj_hinted(). Signed-off-by: Robin Holt To: Dave Hansen To: Matt Tolentino Reviewed-by: KAMEZAWA Hiroyuki Signed-off-by: Greg Kroah-Hartman --- drivers/base/memory.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 933442f40321..a7994409b9a5 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -468,28 +468,23 @@ static int add_memory_block(int nid, struct mem_section *section, return ret; } -/* - * For now, we have a linear search to go find the appropriate - * memory_block corresponding to a particular phys_index. If - * this gets to be a real problem, we can always use a radix - * tree or something here. - * - * This could be made generic for all sysdev classes. - */ -struct memory_block *find_memory_block(struct mem_section *section) +struct memory_block *find_memory_block_hinted(struct mem_section *section, + struct memory_block *hint) { struct kobject *kobj; struct sys_device *sysdev; struct memory_block *mem; char name[sizeof(MEMORY_CLASS_NAME) + 9 + 1]; + kobj = hint ? &hint->sysdev.kobj : NULL; + /* * This only works because we know that section == sysdev->id * slightly redundant with sysdev_register() */ sprintf(&name[0], "%s%d", MEMORY_CLASS_NAME, __section_nr(section)); - kobj = kset_find_obj(&memory_sysdev_class.kset, name); + kobj = kset_find_obj_hinted(&memory_sysdev_class.kset, name, kobj); if (!kobj) return NULL; @@ -499,6 +494,19 @@ struct memory_block *find_memory_block(struct mem_section *section) return mem; } +/* + * For now, we have a linear search to go find the appropriate + * memory_block corresponding to a particular phys_index. If + * this gets to be a real problem, we can always use a radix + * tree or something here. + * + * This could be made generic for all sysdev classes. + */ +struct memory_block *find_memory_block(struct mem_section *section) +{ + return find_memory_block_hinted(section, NULL); +} + int remove_memory_block(unsigned long node_id, struct mem_section *section, int phys_device) { -- cgit From 63d027a63888e993545d10fdfe4107d543f01bca Mon Sep 17 00:00:00 2001 From: Robin Holt Date: Wed, 29 Sep 2010 14:00:56 -0500 Subject: driver core: Convert link_mem_sections to use find_memory_block_hinted. Modify link_mem_sections() to pass in the previous mem_block as a hint to locating the next mem_block. Since they are typically added in order this results in a massive saving in time during boot of a very large system. For example, on a 16TB x86_64 machine, it reduced the total time spent linking all node's memory sections from 1 hour, 27 minutes to 46 seconds. Signed-off-by: Robin Holt To: Gary Hade To: Badari Pulavarty To: Ingo Molnar Reviewed-by: KAMEZAWA Hiroyuki Signed-off-by: Greg Kroah-Hartman --- drivers/base/node.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/base/node.c b/drivers/base/node.c index 2872e86837b2..ee53558b452f 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -409,25 +409,27 @@ static int link_mem_sections(int nid) unsigned long start_pfn = NODE_DATA(nid)->node_start_pfn; unsigned long end_pfn = start_pfn + NODE_DATA(nid)->node_spanned_pages; unsigned long pfn; + struct memory_block *mem_blk = NULL; int err = 0; for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) { unsigned long section_nr = pfn_to_section_nr(pfn); struct mem_section *mem_sect; - struct memory_block *mem_blk; int ret; if (!present_section_nr(section_nr)) continue; mem_sect = __nr_to_section(section_nr); - mem_blk = find_memory_block(mem_sect); + mem_blk = find_memory_block_hinted(mem_sect, mem_blk); ret = register_mem_sect_under_node(mem_blk, nid); if (!err) err = ret; /* discard ref obtained in find_memory_block() */ - kobject_put(&mem_blk->sysdev.kobj); } + + if (mem_blk) + kobject_put(&mem_blk->sysdev.kobj); return err; } -- cgit From 1ce873abed551a4a0f35e25af9eeec4efdcf341b Mon Sep 17 00:00:00 2001 From: dann frazier Date: Fri, 15 Oct 2010 10:14:34 -0600 Subject: hpilo: Despecificate driver from iLO generation This driver supports iLO, iLO2 and iLO3. However, comments and Kconfig reference only iLO and iLO2. Let's just call it "iLO" to avoid having to update strings for each iLO generation. This is similar to the change made to hpwdt in commit 36e3ff44cebd7e46756dec88f30c982bebefdab7. Signed-off-by: dann frazier Signed-off-by: Greg Kroah-Hartman --- drivers/misc/Kconfig | 10 +++++----- drivers/misc/hpilo.c | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 6f46e27ed682..db2fbe2d4146 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -248,15 +248,15 @@ config CS5535_CLOCK_EVENT_SRC generic PIT, and are suitable for use as high-res timers. config HP_ILO - tristate "Channel interface driver for HP iLO/iLO2 processor" + tristate "Channel interface driver for the HP iLO processor" depends on PCI default n help The channel interface driver allows applications to communicate - with iLO/iLO2 management processors present on HP ProLiant - servers. Upon loading, the driver creates /dev/hpilo/dXccbN files, - which can be used to gather data from the management processor, - via read and write system calls. + with iLO management processors present on HP ProLiant servers. + Upon loading, the driver creates /dev/hpilo/dXccbN files, which + can be used to gather data from the management processor, via + read and write system calls. To compile this driver as a module, choose M here: the module will be called hpilo. diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c index 557a8c2a7336..d4158ec8c860 100644 --- a/drivers/misc/hpilo.c +++ b/drivers/misc/hpilo.c @@ -1,5 +1,5 @@ /* - * Driver for HP iLO/iLO2 management processor. + * Driver for the HP iLO management processor. * * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. * David Altobelli -- cgit From e4619c857d1d769b1172a75ba6b6ebd1186a9c58 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Tue, 19 Oct 2010 12:44:20 -0500 Subject: Driver core: Move find_memory_block routine Move the find_memory_block() routine up to avoid needing a forward declaration in subsequent patches. Signed-off-by: Nathan Fontenot Reviewed-by: Robin Holt Reviewed-By: KAMEZAWA Hiroyuki Signed-off-by: Greg Kroah-Hartman --- drivers/base/memory.c | 66 +++++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/base/memory.c b/drivers/base/memory.c index a7994409b9a5..63c25601572d 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -435,39 +435,6 @@ int __weak arch_get_memory_phys_device(unsigned long start_pfn) return 0; } -static int add_memory_block(int nid, struct mem_section *section, - unsigned long state, enum mem_add_context context) -{ - struct memory_block *mem = kzalloc(sizeof(*mem), GFP_KERNEL); - unsigned long start_pfn; - int ret = 0; - - if (!mem) - return -ENOMEM; - - mem->phys_index = __section_nr(section); - mem->state = state; - mutex_init(&mem->state_mutex); - start_pfn = section_nr_to_pfn(mem->phys_index); - mem->phys_device = arch_get_memory_phys_device(start_pfn); - - ret = register_memory(mem, section); - if (!ret) - ret = mem_create_simple_file(mem, phys_index); - if (!ret) - ret = mem_create_simple_file(mem, state); - if (!ret) - ret = mem_create_simple_file(mem, phys_device); - if (!ret) - ret = mem_create_simple_file(mem, removable); - if (!ret) { - if (context == HOTPLUG) - ret = register_mem_sect_under_node(mem, nid); - } - - return ret; -} - struct memory_block *find_memory_block_hinted(struct mem_section *section, struct memory_block *hint) { @@ -507,6 +474,39 @@ struct memory_block *find_memory_block(struct mem_section *section) return find_memory_block_hinted(section, NULL); } +static int add_memory_block(int nid, struct mem_section *section, + unsigned long state, enum mem_add_context context) +{ + struct memory_block *mem = kzalloc(sizeof(*mem), GFP_KERNEL); + unsigned long start_pfn; + int ret = 0; + + if (!mem) + return -ENOMEM; + + mem->phys_index = __section_nr(section); + mem->state = state; + mutex_init(&mem->state_mutex); + start_pfn = section_nr_to_pfn(mem->phys_index); + mem->phys_device = arch_get_memory_phys_device(start_pfn); + + ret = register_memory(mem, section); + if (!ret) + ret = mem_create_simple_file(mem, phys_index); + if (!ret) + ret = mem_create_simple_file(mem, state); + if (!ret) + ret = mem_create_simple_file(mem, phys_device); + if (!ret) + ret = mem_create_simple_file(mem, removable); + if (!ret) { + if (context == HOTPLUG) + ret = register_mem_sect_under_node(mem, nid); + } + + return ret; +} + int remove_memory_block(unsigned long node_id, struct mem_section *section, int phys_device) { -- cgit From 2938ffbd466d2811a6012609684a2298eef35065 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Tue, 19 Oct 2010 12:45:24 -0500 Subject: Driver core: Add mutex for adding/removing memory blocks Add a new mutex for use in adding and removing of memory blocks. This is needed to avoid any race conditions in which the same memory block could be added and removed at the same time. Signed-off-by: Nathan Fontenot Reviewed-by: Robin Holt Reviewed-By: KAMEZAWA Hiroyuki Signed-off-by: Greg Kroah-Hartman --- drivers/base/memory.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 63c25601572d..5185bcff2de9 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -27,6 +27,8 @@ #include #include +static DEFINE_MUTEX(mem_sysfs_mutex); + #define MEMORY_CLASS_NAME "memory" static struct sysdev_class memory_sysdev_class = { @@ -484,6 +486,8 @@ static int add_memory_block(int nid, struct mem_section *section, if (!mem) return -ENOMEM; + mutex_lock(&mem_sysfs_mutex); + mem->phys_index = __section_nr(section); mem->state = state; mutex_init(&mem->state_mutex); @@ -504,6 +508,7 @@ static int add_memory_block(int nid, struct mem_section *section, ret = register_mem_sect_under_node(mem, nid); } + mutex_unlock(&mem_sysfs_mutex); return ret; } @@ -512,6 +517,7 @@ int remove_memory_block(unsigned long node_id, struct mem_section *section, { struct memory_block *mem; + mutex_lock(&mem_sysfs_mutex); mem = find_memory_block(section); unregister_mem_sect_under_nodes(mem); mem_remove_simple_file(mem, phys_index); @@ -520,6 +526,7 @@ int remove_memory_block(unsigned long node_id, struct mem_section *section, mem_remove_simple_file(mem, removable); unregister_memory(mem, section); + mutex_unlock(&mem_sysfs_mutex); return 0; } -- cgit From 07681215975e05a1454b0afdeef07deb0db626ee Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Tue, 19 Oct 2010 12:46:19 -0500 Subject: Driver core: Add section count to memory_block struct Add a section count property to the memory_block struct to track the number of memory sections that have been added/removed from a memory block. This allows us to know when the last memory section of a memory block has been removed so we can remove the memory block. Signed-off-by: Nathan Fontenot Reviewed-by: Robin Holt Reviewed-by: KAMEZAWA Hiroyuki Signed-off-by: Greg Kroah-Hartman --- drivers/base/memory.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 5185bcff2de9..cafeaaf0428f 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -490,6 +490,7 @@ static int add_memory_block(int nid, struct mem_section *section, mem->phys_index = __section_nr(section); mem->state = state; + mem->section_count++; mutex_init(&mem->state_mutex); start_pfn = section_nr_to_pfn(mem->phys_index); mem->phys_device = arch_get_memory_phys_device(start_pfn); @@ -519,12 +520,16 @@ int remove_memory_block(unsigned long node_id, struct mem_section *section, mutex_lock(&mem_sysfs_mutex); mem = find_memory_block(section); - unregister_mem_sect_under_nodes(mem); - mem_remove_simple_file(mem, phys_index); - mem_remove_simple_file(mem, state); - mem_remove_simple_file(mem, phys_device); - mem_remove_simple_file(mem, removable); - unregister_memory(mem, section); + + mem->section_count--; + if (mem->section_count == 0) { + unregister_mem_sect_under_nodes(mem); + mem_remove_simple_file(mem, phys_index); + mem_remove_simple_file(mem, state); + mem_remove_simple_file(mem, phys_device); + mem_remove_simple_file(mem, removable); + unregister_memory(mem, section); + } mutex_unlock(&mem_sysfs_mutex); return 0; -- cgit From 5abd935661e01289ba143c3b2c1ba300c65bcc5f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 20 Oct 2010 11:22:42 -0700 Subject: driver core: Display error codes when class suspend fails Aid diagnostics by printing the error code from failed suspends, which doesn't otherwise seem to get displayed. Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- drivers/base/sys.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 9354dc10a363..1667aaf4fde6 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -432,13 +432,13 @@ int sysdev_suspend(pm_message_t state) /* resume current sysdev */ cls_driver: drv = NULL; - printk(KERN_ERR "Class suspend failed for %s\n", - kobject_name(&sysdev->kobj)); + printk(KERN_ERR "Class suspend failed for %s: %d\n", + kobject_name(&sysdev->kobj), ret); aux_driver: if (drv) - printk(KERN_ERR "Class driver suspend failed for %s\n", - kobject_name(&sysdev->kobj)); + printk(KERN_ERR "Class driver suspend failed for %s: %d\n", + kobject_name(&sysdev->kobj), ret); list_for_each_entry(err_drv, &cls->drivers, entry) { if (err_drv == drv) break; -- cgit