Merge tag 'tegra-soc2' of git://git.kernel.org/pub/scm/linux/kernel/git/olof/tegra...
Arnd Bergmann [Sun, 4 Mar 2012 21:09:11 +0000 (21:09 +0000)]
From: Olof Johansson <olof@lixom.net>
Tegra 30 SMP support

I did this as a separate topic branch because it depends on both the
soc and the soc-drivers branch, so it brings both of those in as a base.

This branch contains work to enable SMP support on Tegra30 and reworks
some of the SMP bringup for T20 as well.

It also contains a device tree patch that builds on top of the SMP/clock
changes in the rest of the branch, so it made more sense to apply it
here than deal with the merge conflicts back and forth.

* tag 'tegra-soc2' of git://git.kernel.org/pub/scm/linux/kernel/git/olof/tegra:
  ARM: dt: Explicitly configure all serial ports on Tegra Cardhu
  ARM: tegra: support for secondary cores on Tegra30
  ARM: tegra: support for Tegra30 CPU powerdomains
  ARM: tegra: add support for Tegra30 powerdomains
  ARM: tegra: export tegra_powergate_is_powered()
  ARM: tegra: prepare powergate.c for multiple variants
  ARM: tegra: rework Tegra secondary CPU core bringup
  ARM: tegra: functions to access the flowcontroller
  ARM: tegra: initialize Tegra chipid early
  ARM: tegra: export Tegra chipid
  ARM: tegra: cleanup use of chipid register

Signed-off-by: Arnd Bergmann <arnd@arndb.de>

103 files changed:
Documentation/ABI/testing/sysfs-devices-soc [new file with mode: 0644]
Documentation/dynamic-debug-howto.txt
Documentation/filesystems/debugfs.txt
arch/arm/mach-ux500/Kconfig
arch/arm/mach-ux500/board-mop500-sdi.c
arch/arm/mach-ux500/board-mop500.c
arch/arm/mach-ux500/board-mop500.h
arch/arm/mach-ux500/board-u5500-sdi.c
arch/arm/mach-ux500/board-u5500.c
arch/arm/mach-ux500/cpu-db5500.c
arch/arm/mach-ux500/cpu-db8500.c
arch/arm/mach-ux500/cpu.c
arch/arm/mach-ux500/devices-common.c
arch/arm/mach-ux500/devices-common.h
arch/arm/mach-ux500/devices-db5500.h
arch/arm/mach-ux500/devices-db8500.h
arch/arm/mach-ux500/dma-db5500.c
arch/arm/mach-ux500/include/mach/db8500-regs.h
arch/arm/mach-ux500/include/mach/setup.h
arch/arm/mach-ux500/include/mach/usb.h
arch/arm/mach-ux500/usb.c
arch/x86/Kconfig
arch/x86/crypto/aesni-intel_glue.c
arch/x86/crypto/crc32c-intel.c
arch/x86/crypto/ghash-clmulni-intel_glue.c
arch/x86/include/asm/cpu_device_id.h [new file with mode: 0644]
arch/x86/include/asm/cpufeature.h
arch/x86/kernel/cpu/Makefile
arch/x86/kernel/cpu/match.c [new file with mode: 0644]
arch/x86/kernel/cpu/scattered.c
arch/x86/kernel/microcode_core.c
drivers/acpi/processor_driver.c
drivers/acpi/processor_perflib.c
drivers/base/Kconfig
drivers/base/Makefile
drivers/base/bus.c
drivers/base/cpu.c
drivers/base/driver.c
drivers/base/soc.c [new file with mode: 0644]
drivers/cpufreq/cpufreq-nforce2.c
drivers/cpufreq/e_powersaver.c
drivers/cpufreq/elanfreq.c
drivers/cpufreq/gx-suspmod.c
drivers/cpufreq/longhaul.c
drivers/cpufreq/longrun.c
drivers/cpufreq/p4-clockmod.c
drivers/cpufreq/powernow-k6.c
drivers/cpufreq/powernow-k7.c
drivers/cpufreq/powernow-k8.c
drivers/cpufreq/sc520_freq.c
drivers/cpufreq/speedstep-centrino.c
drivers/cpufreq/speedstep-ich.c
drivers/cpufreq/speedstep-lib.c
drivers/cpufreq/speedstep-smi.c
drivers/crypto/padlock-aes.c
drivers/crypto/padlock-sha.c
drivers/hid/hid-core.c
drivers/hv/channel_mgmt.c
drivers/hv/hv.c
drivers/hv/hv_kvp.c
drivers/hv/hv_kvp.h [deleted file]
drivers/hv/hv_util.c
drivers/hv/hyperv_vmbus.h
drivers/hwmon/coretemp.c
drivers/hwmon/via-cputemp.c
drivers/idle/intel_idle.c
drivers/input/gameport/gameport.c
drivers/input/serio/serio.c
drivers/media/video/cx18/cx18-alsa-main.c
drivers/media/video/ivtv/ivtvfb.c
drivers/media/video/s5p-fimc/fimc-mdevice.c
drivers/media/video/s5p-tv/mixer_video.c
drivers/net/phy/phy_device.c
drivers/pci/pci-driver.c
drivers/pci/xen-pcifront.c
drivers/pcmcia/ds.c
drivers/s390/cio/ccwgroup.c
drivers/s390/cio/device.c
drivers/s390/net/smsgiucv_app.c
drivers/ssb/main.c
drivers/usb/core/driver.c
drivers/usb/dwc3/dwc3-pci.c
drivers/w1/masters/w1-gpio.c
fs/debugfs/inode.c
fs/sysfs/dir.c
fs/sysfs/inode.c
fs/sysfs/mount.c
fs/sysfs/sysfs.h
include/acpi/processor.h
include/linux/connector.h
include/linux/cpu.h
include/linux/device.h
include/linux/dynamic_debug.h
include/linux/hyperv.h
include/linux/mod_devicetable.h
include/linux/netdevice.h
include/linux/pci.h
include/linux/printk.h
include/linux/sys_soc.h [new file with mode: 0644]
lib/dma-debug.c
lib/dynamic_debug.c
scripts/mod/file2alias.c
tools/hv/hv_kvp_daemon.c

diff --git a/Documentation/ABI/testing/sysfs-devices-soc b/Documentation/ABI/testing/sysfs-devices-soc
new file mode 100644 (file)
index 0000000..6d9cc25
--- /dev/null
@@ -0,0 +1,58 @@
+What:          /sys/devices/socX
+Date:          January 2012
+contact:       Lee Jones <lee.jones@linaro.org>
+Description:
+               The /sys/devices/ directory contains a sub-directory for each
+               System-on-Chip (SoC) device on a running platform. Information
+               regarding each SoC can be obtained by reading sysfs files. This
+               functionality is only available if implemented by the platform.
+
+               The directory created for each SoC will also house information
+               about devices which are commonly contained in /sys/devices/platform.
+               It has been agreed that if an SoC device exists, its supported
+               devices would be better suited to appear as children of that SoC.
+
+What:          /sys/devices/socX/machine
+Date:          January 2012
+contact:       Lee Jones <lee.jones@linaro.org>
+Description:
+               Read-only attribute common to all SoCs. Contains the SoC machine
+               name (e.g. Ux500).
+
+What:          /sys/devices/socX/family
+Date:          January 2012
+contact:       Lee Jones <lee.jones@linaro.org>
+Description:
+               Read-only attribute common to all SoCs. Contains SoC family name
+               (e.g. DB8500).
+
+What:          /sys/devices/socX/soc_id
+Date:          January 2012
+contact:       Lee Jones <lee.jones@linaro.org>
+Description:
+               Read-only attribute supported by most SoCs. In the case of
+               ST-Ericsson's chips this contains the SoC serial number.
+
+What:          /sys/devices/socX/revision
+Date:          January 2012
+contact:       Lee Jones <lee.jones@linaro.org>
+Description:
+               Read-only attribute supported by most SoCs. Contains the SoC's
+               manufacturing revision number.
+
+What:          /sys/devices/socX/process
+Date:          January 2012
+contact:       Lee Jones <lee.jones@linaro.org>
+Description:
+               Read-only attribute supported ST-Ericsson's silicon. Contains the
+               the process by which the silicon chip was manufactured.
+
+What:          /sys/bus/soc
+Date:          January 2012
+contact:       Lee Jones <lee.jones@linaro.org>
+Description:
+               The /sys/bus/soc/ directory contains the usual sub-folders
+               expected under most buses. /sys/bus/soc/devices is of particular
+               interest, as it contains a symlink for each SoC device found on
+               the system. Each symlink points back into the aforementioned
+               /sys/devices/socX devices.
index f959909..74e6c77 100644 (file)
@@ -12,7 +12,7 @@ dynamically enabled per-callsite.
 Dynamic debug has even more useful features:
 
  * Simple query language allows turning on and off debugging statements by
-   matching any combination of:
+   matching any combination of 0 or 1 of:
 
    - source filename
    - function name
@@ -79,31 +79,24 @@ Command Language Reference
 ==========================
 
 At the lexical level, a command comprises a sequence of words separated
-by whitespace characters.  Note that newlines are treated as word
-separators and do *not* end a command or allow multiple commands to
-be done together.  So these are all equivalent:
+by spaces or tabs.  So these are all equivalent:
 
 nullarbor:~ # echo -c 'file svcsock.c line 1603 +p' >
                                <debugfs>/dynamic_debug/control
 nullarbor:~ # echo -c '  file   svcsock.c     line  1603 +p  ' >
                                <debugfs>/dynamic_debug/control
-nullarbor:~ # echo -c 'file svcsock.c\nline 1603 +p' >
-                               <debugfs>/dynamic_debug/control
 nullarbor:~ # echo -n 'file svcsock.c line 1603 +p' >
                                <debugfs>/dynamic_debug/control
 
-Commands are bounded by a write() system call.  If you want to do
-multiple commands you need to do a separate "echo" for each, like:
+Command submissions are bounded by a write() system call.
+Multiple commands can be written together, separated by ';' or '\n'.
 
-nullarbor:~ # echo 'file svcsock.c line 1603 +p' > /proc/dprintk ;\
-> echo 'file svcsock.c line 1563 +p' > /proc/dprintk
+  ~# echo "func pnpacpi_get_resources +p; func pnp_assign_mem +p" \
+     > <debugfs>/dynamic_debug/control
 
-or even like:
+If your query set is big, you can batch them too:
 
-nullarbor:~ # (
-> echo 'file svcsock.c line 1603 +p' ;\
-> echo 'file svcsock.c line 1563 +p' ;\
-> ) > /proc/dprintk
+  ~# cat query-batch-file > <debugfs>/dynamic_debug/control
 
 At the syntactical level, a command comprises a sequence of match
 specifications, followed by a flags change specification.
@@ -144,11 +137,12 @@ func
     func svc_tcp_accept
 
 file
-    The given string is compared against either the full
-    pathname or the basename of the source file of each
-    callsite.  Examples:
+    The given string is compared against either the full pathname, the
+    src-root relative pathname, or the basename of the source file of
+    each callsite.  Examples:
 
     file svcsock.c
+    file kernel/freezer.c
     file /usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svcsock.c
 
 module
index 6872c91..4e25758 100644 (file)
@@ -14,7 +14,10 @@ Debugfs is typically mounted with a command like:
 
     mount -t debugfs none /sys/kernel/debug
 
-(Or an equivalent /etc/fstab line). 
+(Or an equivalent /etc/fstab line).
+The debugfs root directory is accessible by anyone by default. To
+restrict access to the tree the "uid", "gid" and "mode" mount
+options can be used.
 
 Note that the debugfs API is exported GPL-only to modules.
 
index 52af004..5cfa539 100644 (file)
@@ -28,6 +28,7 @@ config MACH_U8500
        bool "U8500 Development platform"
        depends on UX500_SOC_DB8500
        select TPS6105X
+       select SOC_BUS
        help
          Include support for the mop500 development platform.
 
index 5dde4d4..479ebe0 100644 (file)
@@ -104,7 +104,7 @@ static struct mmci_platform_data mop500_sdi0_data = {
 #endif
 };
 
-static void sdi0_configure(void)
+static void sdi0_configure(struct device *parent)
 {
        int ret;
 
@@ -123,15 +123,15 @@ static void sdi0_configure(void)
        gpio_direction_output(sdi0_en, 1);
 
        /* Add the device, force v2 to subrevision 1 */
-       db8500_add_sdi0(&mop500_sdi0_data, U8500_SDI_V2_PERIPHID);
+       db8500_add_sdi0(parent, &mop500_sdi0_data, U8500_SDI_V2_PERIPHID);
 }
 
-void mop500_sdi_tc35892_init(void)
+void mop500_sdi_tc35892_init(struct device *parent)
 {
        mop500_sdi0_data.gpio_cd = GPIO_SDMMC_CD;
        sdi0_en = GPIO_SDMMC_EN;
        sdi0_vsel = GPIO_SDMMC_1V8_3V_SEL;
-       sdi0_configure();
+       sdi0_configure(parent);
 }
 
 /*
@@ -246,12 +246,13 @@ static struct mmci_platform_data mop500_sdi4_data = {
 #endif
 };
 
-void __init mop500_sdi_init(void)
+void __init mop500_sdi_init(struct device *parent)
 {
        /* PoP:ed eMMC */
-       db8500_add_sdi2(&mop500_sdi2_data, U8500_SDI_V2_PERIPHID);
+       db8500_add_sdi2(parent, &mop500_sdi2_data, U8500_SDI_V2_PERIPHID);
        /* On-board eMMC */
-       db8500_add_sdi4(&mop500_sdi4_data, U8500_SDI_V2_PERIPHID);
+       db8500_add_sdi4(parent, &mop500_sdi4_data, U8500_SDI_V2_PERIPHID);
+
        /*
         * On boards with the TC35892 GPIO expander, sdi0 will finally
         * be added when the TC35892 initializes and calls
@@ -259,31 +260,31 @@ void __init mop500_sdi_init(void)
         */
 }
 
-void __init snowball_sdi_init(void)
+void __init snowball_sdi_init(struct device *parent)
 {
        /* On Snowball MMC_CAP_SD_HIGHSPEED isn't supported (Hardware issue?) */
        mop500_sdi0_data.capabilities &= ~MMC_CAP_SD_HIGHSPEED;
        /* On-board eMMC */
-       db8500_add_sdi4(&mop500_sdi4_data, U8500_SDI_V2_PERIPHID);
+       db8500_add_sdi4(parent, &mop500_sdi4_data, U8500_SDI_V2_PERIPHID);
        /* External Micro SD slot */
        mop500_sdi0_data.gpio_cd = SNOWBALL_SDMMC_CD_GPIO;
        mop500_sdi0_data.cd_invert = true;
        sdi0_en = SNOWBALL_SDMMC_EN_GPIO;
        sdi0_vsel = SNOWBALL_SDMMC_1V8_3V_GPIO;
-       sdi0_configure();
+       sdi0_configure(parent);
 }
 
-void __init hrefv60_sdi_init(void)
+void __init hrefv60_sdi_init(struct device *parent)
 {
        /* PoP:ed eMMC */
-       db8500_add_sdi2(&mop500_sdi2_data, U8500_SDI_V2_PERIPHID);
+       db8500_add_sdi2(parent, &mop500_sdi2_data, U8500_SDI_V2_PERIPHID);
        /* On-board eMMC */
-       db8500_add_sdi4(&mop500_sdi4_data, U8500_SDI_V2_PERIPHID);
+       db8500_add_sdi4(parent, &mop500_sdi4_data, U8500_SDI_V2_PERIPHID);
        /* External Micro SD slot */
        mop500_sdi0_data.gpio_cd = HREFV60_SDMMC_CD_GPIO;
        sdi0_en = HREFV60_SDMMC_EN_GPIO;
        sdi0_vsel = HREFV60_SDMMC_1V8_3V_GPIO;
-       sdi0_configure();
+       sdi0_configure(parent);
        /* WLAN SDIO channel */
-       db8500_add_sdi1(&mop500_sdi1_data, U8500_SDI_V2_PERIPHID);
+       db8500_add_sdi1(parent, &mop500_sdi1_data, U8500_SDI_V2_PERIPHID);
 }
index 5c00712..04afcdf 100644 (file)
@@ -226,7 +226,12 @@ static struct tps6105x_platform_data mop500_tps61052_data = {
 
 static void mop500_tc35892_init(struct tc3589x *tc3589x, unsigned int base)
 {
-       mop500_sdi_tc35892_init();
+       struct device *parent = NULL;
+#if 0
+       /* FIXME: Is the sdi actually part of tc3589x? */
+       parent = tc3589x->dev;
+#endif
+       mop500_sdi_tc35892_init(parent);
 }
 
 static struct tc3589x_gpio_platform_data mop500_tc35892_gpio_data = {
@@ -353,12 +358,12 @@ U8500_I2C_CONTROLLER(1, 0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
 U8500_I2C_CONTROLLER(2,        0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
 U8500_I2C_CONTROLLER(3,        0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
 
-static void __init mop500_i2c_init(void)
+static void __init mop500_i2c_init(struct device *parent)
 {
-       db8500_add_i2c0(&u8500_i2c0_data);
-       db8500_add_i2c1(&u8500_i2c1_data);
-       db8500_add_i2c2(&u8500_i2c2_data);
-       db8500_add_i2c3(&u8500_i2c3_data);
+       db8500_add_i2c0(parent, &u8500_i2c0_data);
+       db8500_add_i2c1(parent, &u8500_i2c1_data);
+       db8500_add_i2c2(parent, &u8500_i2c2_data);
+       db8500_add_i2c3(parent, &u8500_i2c3_data);
 }
 
 static struct gpio_keys_button mop500_gpio_keys[] = {
@@ -451,9 +456,9 @@ static struct pl022_ssp_controller ssp0_platform_data = {
        .num_chipselect = 5,
 };
 
-static void __init mop500_spi_init(void)
+static void __init mop500_spi_init(struct device *parent)
 {
-       db8500_add_ssp0(&ssp0_platform_data);
+       db8500_add_ssp0(parent, &ssp0_platform_data);
 }
 
 #ifdef CONFIG_STE_DMA40
@@ -587,11 +592,11 @@ static struct amba_pl011_data uart2_plat = {
 #endif
 };
 
-static void __init mop500_uart_init(void)
+static void __init mop500_uart_init(struct device *parent)
 {
-       db8500_add_uart0(&uart0_plat);
-       db8500_add_uart1(&uart1_plat);
-       db8500_add_uart2(&uart2_plat);
+       db8500_add_uart0(parent, &uart0_plat);
+       db8500_add_uart1(parent, &uart1_plat);
+       db8500_add_uart2(parent, &uart2_plat);
 }
 
 static struct platform_device *snowball_platform_devs[] __initdata = {
@@ -603,21 +608,26 @@ static struct platform_device *snowball_platform_devs[] __initdata = {
 
 static void __init mop500_init_machine(void)
 {
+       struct device *parent = NULL;
        int i2c0_devs;
+       int i;
 
        mop500_gpio_keys[0].gpio = GPIO_PROX_SENSOR;
 
-       u8500_init_devices();
+       parent = u8500_init_devices();
 
        mop500_pins_init();
 
+       for (i = 0; i < ARRAY_SIZE(mop500_platform_devs); i++)
+               mop500_platform_devs[i]->dev.parent = parent;
+
        platform_add_devices(mop500_platform_devs,
                        ARRAY_SIZE(mop500_platform_devs));
 
-       mop500_i2c_init();
-       mop500_sdi_init();
-       mop500_spi_init();
-       mop500_uart_init();
+       mop500_i2c_init(parent);
+       mop500_sdi_init(parent);
+       mop500_spi_init(parent);
+       mop500_uart_init(parent);
 
        i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices);
 
@@ -631,19 +641,24 @@ static void __init mop500_init_machine(void)
 
 static void __init snowball_init_machine(void)
 {
+       struct device *parent = NULL;
        int i2c0_devs;
+       int i;
 
-       u8500_init_devices();
+       parent = u8500_init_devices();
 
        snowball_pins_init();
 
+       for (i = 0; i < ARRAY_SIZE(snowball_platform_devs); i++)
+               snowball_platform_devs[i]->dev.parent = parent;
+
        platform_add_devices(snowball_platform_devs,
                        ARRAY_SIZE(snowball_platform_devs));
 
-       mop500_i2c_init();
-       snowball_sdi_init();
-       mop500_spi_init();
-       mop500_uart_init();
+       mop500_i2c_init(parent);
+       snowball_sdi_init(parent);
+       mop500_spi_init(parent);
+       mop500_uart_init(parent);
 
        i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices);
        i2c_register_board_info(0, mop500_i2c0_devices, i2c0_devs);
@@ -656,7 +671,9 @@ static void __init snowball_init_machine(void)
 
 static void __init hrefv60_init_machine(void)
 {
+       struct device *parent = NULL;
        int i2c0_devs;
+       int i;
 
        /*
         * The HREFv60 board removed a GPIO expander and routed
@@ -665,17 +682,20 @@ static void __init hrefv60_init_machine(void)
         */
        mop500_gpio_keys[0].gpio = HREFV60_PROX_SENSE_GPIO;
 
-       u8500_init_devices();
+       parent = u8500_init_devices();
 
        hrefv60_pins_init();
 
+       for (i = 0; i < ARRAY_SIZE(mop500_platform_devs); i++)
+               mop500_platform_devs[i]->dev.parent = parent;
+
        platform_add_devices(mop500_platform_devs,
                        ARRAY_SIZE(mop500_platform_devs));
 
-       mop500_i2c_init();
-       hrefv60_sdi_init();
-       mop500_spi_init();
-       mop500_uart_init();
+       mop500_i2c_init(parent);
+       hrefv60_sdi_init(parent);
+       mop500_spi_init(parent);
+       mop500_uart_init(parent);
 
        i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices);
 
index f926d3d..3d594c2 100644 (file)
 
 struct i2c_board_info;
 
-extern void mop500_sdi_init(void);
-extern void snowball_sdi_init(void);
-extern void hrefv60_sdi_init(void);
-extern void mop500_sdi_tc35892_init(void);
+extern void mop500_sdi_init(struct device *parent);
+extern void snowball_sdi_init(struct device *parent);
+extern void hrefv60_sdi_init(struct device *parent);
+extern void mop500_sdi_tc35892_init(struct device *parent);
 void __init mop500_u8500uib_init(void);
 void __init mop500_stuib_init(void);
 void __init mop500_pins_init(void);
index 63c3f80..836112e 100644 (file)
@@ -66,9 +66,9 @@ static struct mmci_platform_data u5500_sdi0_data = {
 #endif
 };
 
-void __init u5500_sdi_init(void)
+void __init u5500_sdi_init(struct device *parent)
 {
        nmk_config_pins(u5500_sdi_pins, ARRAY_SIZE(u5500_sdi_pins));
 
-       db5500_add_sdi0(&u5500_sdi0_data);
+       db5500_add_sdi0(parent, &u5500_sdi0_data);
 }
index 9de9e9c..0ff4be7 100644 (file)
@@ -97,9 +97,9 @@ static struct i2c_board_info __initdata u5500_i2c2_devices[] = {
        },
 };
 
-static void __init u5500_i2c_init(void)
+static void __init u5500_i2c_init(struct device *parent)
 {
-       db5500_add_i2c2(&u5500_i2c2_data);
+       db5500_add_i2c2(parent, &u5500_i2c2_data);
        i2c_register_board_info(2, ARRAY_AND_SIZE(u5500_i2c2_devices));
 }
 
@@ -126,20 +126,27 @@ static struct platform_device *u5500_platform_devices[] __initdata = {
        &ab5500_device,
 };
 
-static void __init u5500_uart_init(void)
+static void __init u5500_uart_init(struct device *parent)
 {
-       db5500_add_uart0(NULL);
-       db5500_add_uart1(NULL);
-       db5500_add_uart2(NULL);
+       db5500_add_uart0(parent, NULL);
+       db5500_add_uart1(parent, NULL);
+       db5500_add_uart2(parent, NULL);
 }
 
 static void __init u5500_init_machine(void)
 {
-       u5500_init_devices();
+       struct device *parent = NULL;
+       int i;
+
+       parent = u5500_init_devices();
        nmk_config_pins(u5500_pins, ARRAY_SIZE(u5500_pins));
-       u5500_i2c_init();
-       u5500_sdi_init();
-       u5500_uart_init();
+
+       u5500_i2c_init(parent);
+       u5500_sdi_init(parent);
+       u5500_uart_init(parent);
+
+       for (i = 0; i < ARRAY_SIZE(u5500_platform_devices); i++)
+               u5500_platform_devices[i]->dev.parent = parent;
 
        platform_add_devices(u5500_platform_devices,
                ARRAY_SIZE(u5500_platform_devices));
index 18aa5c0..bca47f3 100644 (file)
@@ -147,13 +147,13 @@ static resource_size_t __initdata db5500_gpio_base[] = {
        U5500_GPIOBANK7_BASE,
 };
 
-static void __init db5500_add_gpios(void)
+static void __init db5500_add_gpios(struct device *parent)
 {
        struct nmk_gpio_platform_data pdata = {
                /* No custom data yet */
        };
 
-       dbx500_add_gpios(ARRAY_AND_SIZE(db5500_gpio_base),
+       dbx500_add_gpios(parent, ARRAY_AND_SIZE(db5500_gpio_base),
                         IRQ_DB5500_GPIO0, &pdata);
 }
 
@@ -212,14 +212,36 @@ static int usb_db5500_tx_dma_cfg[] = {
        DB5500_DMA_DEV38_USB_OTG_OEP_8
 };
 
-void __init u5500_init_devices(void)
+static const char *db5500_read_soc_id(void)
 {
-       db5500_add_gpios();
+       return kasprintf(GFP_KERNEL, "u5500 currently unsupported\n");
+}
+
+static struct device * __init db5500_soc_device_init(void)
+{
+       const char *soc_id = db5500_read_soc_id();
+
+       return ux500_soc_device_init(soc_id);
+}
+
+struct device * __init u5500_init_devices(void)
+{
+       struct device *parent;
+       int i;
+
+       parent = db5500_soc_device_init();
+
+       db5500_add_gpios(parent);
        db5500_pmu_init();
-       db5500_dma_init();
-       db5500_add_rtc();
-       db5500_add_usb(usb_db5500_rx_dma_cfg, usb_db5500_tx_dma_cfg);
+       db5500_dma_init(parent);
+       db5500_add_rtc(parent);
+       db5500_add_usb(parent, usb_db5500_rx_dma_cfg, usb_db5500_tx_dma_cfg);
+
+       for (i = 0; i < ARRAY_SIZE(db5500_platform_devs); i++)
+               db5500_platform_devs[i]->dev.parent = parent;
 
        platform_add_devices(db5500_platform_devs,
                             ARRAY_SIZE(db5500_platform_devs));
+
+       return parent;
 }
index 7176ee7..9bd8163 100644 (file)
@@ -24,6 +24,7 @@
 #include <mach/setup.h>
 #include <mach/devices.h>
 #include <mach/usb.h>
+#include <mach/db8500-regs.h>
 
 #include "devices-db8500.h"
 #include "ste-dma40-db8500.h"
@@ -132,13 +133,13 @@ static resource_size_t __initdata db8500_gpio_base[] = {
        U8500_GPIOBANK8_BASE,
 };
 
-static void __init db8500_add_gpios(void)
+static void __init db8500_add_gpios(struct device *parent)
 {
        struct nmk_gpio_platform_data pdata = {
                .supports_sleepmode = true,
        };
 
-       dbx500_add_gpios(ARRAY_AND_SIZE(db8500_gpio_base),
+       dbx500_add_gpios(parent, ARRAY_AND_SIZE(db8500_gpio_base),
                         IRQ_DB8500_GPIO0, &pdata);
 }
 
@@ -164,17 +165,44 @@ static int usb_db8500_tx_dma_cfg[] = {
        DB8500_DMA_DEV39_USB_OTG_OEP_8
 };
 
+static const char *db8500_read_soc_id(void)
+{
+       void __iomem *uid = __io_address(U8500_BB_UID_BASE);
+
+       return kasprintf(GFP_KERNEL, "%08x%08x%08x%08x%08x",
+                        readl((u32 *)uid+1),
+                        readl((u32 *)uid+1), readl((u32 *)uid+2),
+                        readl((u32 *)uid+3), readl((u32 *)uid+4));
+}
+
+static struct device * __init db8500_soc_device_init(void)
+{
+       const char *soc_id = db8500_read_soc_id();
+
+       return ux500_soc_device_init(soc_id);
+}
+
 /*
  * This function is called from the board init
  */
-void __init u8500_init_devices(void)
+struct device * __init u8500_init_devices(void)
 {
-       db8500_add_rtc();
-       db8500_add_gpios();
-       db8500_add_usb(usb_db8500_rx_dma_cfg, usb_db8500_tx_dma_cfg);
+       struct device *parent;
+       int i;
+
+       parent = db8500_soc_device_init();
+
+       db8500_add_rtc(parent);
+       db8500_add_gpios(parent);
+       db8500_add_usb(parent, usb_db8500_rx_dma_cfg, usb_db8500_tx_dma_cfg);
+
+       platform_device_register_data(parent,
+               "cpufreq-u8500", -1, NULL, 0);
+
+       for (i = 0; i < ARRAY_SIZE(platform_devs); i++)
+               platform_devs[i]->dev.parent = parent;
 
-       platform_device_register_simple("cpufreq-u8500", -1, NULL, 0);
        platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
 
-       return ;
+       return parent;
 }
index f418574..055fb6e 100644 (file)
@@ -2,6 +2,7 @@
  * Copyright (C) ST-Ericsson SA 2010
  *
  * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ * Author: Lee Jones <lee.jones@linaro.org> for ST-Ericsson
  * License terms: GNU General Public License (GPL) version 2
  */
 
 #include <linux/mfd/db8500-prcmu.h>
 #include <linux/mfd/db5500-prcmu.h>
 #include <linux/clksrc-dbx500-prcmu.h>
+#include <linux/sys_soc.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
 
 #include <asm/hardware/gic.h>
 #include <asm/mach/map.h>
@@ -50,3 +55,73 @@ void __init ux500_init_irq(void)
                db8500_prcmu_early_init();
        clk_init();
 }
+
+static const char * __init ux500_get_machine(void)
+{
+       return kasprintf(GFP_KERNEL, "DB%4x", dbx500_partnumber());
+}
+
+static const char * __init ux500_get_family(void)
+{
+       return kasprintf(GFP_KERNEL, "ux500");
+}
+
+static const char * __init ux500_get_revision(void)
+{
+       unsigned int rev = dbx500_revision();
+
+       if (rev == 0x01)
+               return kasprintf(GFP_KERNEL, "%s", "ED");
+       else if (rev >= 0xA0)
+               return kasprintf(GFP_KERNEL, "%d.%d",
+                                (rev >> 4) - 0xA + 1, rev & 0xf);
+
+       return kasprintf(GFP_KERNEL, "%s", "Unknown");
+}
+
+static ssize_t ux500_get_process(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       if (dbx500_id.process == 0x00)
+               return sprintf(buf, "Standard\n");
+
+       return sprintf(buf, "%02xnm\n", dbx500_id.process);
+}
+
+static void __init soc_info_populate(struct soc_device_attribute *soc_dev_attr,
+                                    const char *soc_id)
+{
+       soc_dev_attr->soc_id   = soc_id;
+       soc_dev_attr->machine  = ux500_get_machine();
+       soc_dev_attr->family   = ux500_get_family();
+       soc_dev_attr->revision = ux500_get_revision();
+}
+
+struct device_attribute ux500_soc_attr =
+       __ATTR(process,  S_IRUGO, ux500_get_process,  NULL);
+
+struct device * __init ux500_soc_device_init(const char *soc_id)
+{
+       struct device *parent;
+       struct soc_device *soc_dev;
+       struct soc_device_attribute *soc_dev_attr;
+
+       soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+       if (!soc_dev_attr)
+               return ERR_PTR(-ENOMEM);
+
+       soc_info_populate(soc_dev_attr, soc_id);
+
+       soc_dev = soc_device_register(soc_dev_attr);
+       if (IS_ERR_OR_NULL(soc_dev)) {
+               kfree(soc_dev_attr);
+               return NULL;
+       }
+
+       parent = soc_device_to_device(soc_dev);
+       if (!IS_ERR_OR_NULL(parent))
+               device_create_file(parent, &ux500_soc_attr);
+
+       return parent;
+}
index c563e54..c3bc094 100644 (file)
@@ -20,8 +20,9 @@
 #include "devices-common.h"
 
 struct amba_device *
-dbx500_add_amba_device(const char *name, resource_size_t base,
-                      int irq, void *pdata, unsigned int periphid)
+dbx500_add_amba_device(struct device *parent, const char *name,
+                      resource_size_t base, int irq, void *pdata,
+                      unsigned int periphid)
 {
        struct amba_device *dev;
        int ret;
@@ -46,6 +47,8 @@ dbx500_add_amba_device(const char *name, resource_size_t base,
 
        dev->dev.platform_data = pdata;
 
+       dev->dev.parent = parent;
+
        ret = amba_device_register(dev, &iomem_resource);
        if (ret) {
                kfree(dev);
@@ -56,60 +59,7 @@ dbx500_add_amba_device(const char *name, resource_size_t base,
 }
 
 static struct platform_device *
-dbx500_add_platform_device(const char *name, int id, void *pdata,
-                          struct resource *res, int resnum)
-{
-       struct platform_device *dev;
-       int ret;
-
-       dev = platform_device_alloc(name, id);
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
-       dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
-
-       ret = platform_device_add_resources(dev, res, resnum);
-       if (ret)
-               goto out_free;
-
-       dev->dev.platform_data = pdata;
-
-       ret = platform_device_add(dev);
-       if (ret)
-               goto out_free;
-
-       return dev;
-
-out_free:
-       platform_device_put(dev);
-       return ERR_PTR(ret);
-}
-
-struct platform_device *
-dbx500_add_platform_device_4k1irq(const char *name, int id,
-                                 resource_size_t base,
-                                 int irq, void *pdata)
-{
-       struct resource resources[] = {
-               [0] = {
-                       .start  = base,
-                       .end    = base + SZ_4K - 1,
-                       .flags  = IORESOURCE_MEM,
-               },
-               [1] = {
-                       .start  = irq,
-                       .end    = irq,
-                       .flags  = IORESOURCE_IRQ,
-               }
-       };
-
-       return dbx500_add_platform_device(name, id, pdata, resources,
-                                         ARRAY_SIZE(resources));
-}
-
-static struct platform_device *
-dbx500_add_gpio(int id, resource_size_t addr, int irq,
+dbx500_add_gpio(struct device *parent, int id, resource_size_t addr, int irq,
                struct nmk_gpio_platform_data *pdata)
 {
        struct resource resources[] = {
@@ -125,13 +75,18 @@ dbx500_add_gpio(int id, resource_size_t addr, int irq,
                }
        };
 
-       return platform_device_register_resndata(NULL, "gpio", id,
-                               resources, ARRAY_SIZE(resources),
-                               pdata, sizeof(*pdata));
+       return platform_device_register_resndata(
+               parent,
+               "gpio",
+               id,
+               resources,
+               ARRAY_SIZE(resources),
+               pdata,
+               sizeof(*pdata));
 }
 
-void dbx500_add_gpios(resource_size_t *base, int num, int irq,
-                     struct nmk_gpio_platform_data *pdata)
+void dbx500_add_gpios(struct device *parent, resource_size_t *base, int num,
+                     int irq, struct nmk_gpio_platform_data *pdata)
 {
        int first = 0;
        int i;
@@ -141,6 +96,6 @@ void dbx500_add_gpios(resource_size_t *base, int num, int irq,
                pdata->first_irq = NOMADIK_GPIO_TO_IRQ(first);
                pdata->num_gpio = 32;
 
-               dbx500_add_gpio(i, base[i], irq, pdata);
+               dbx500_add_gpio(parent, i, base[i], irq, pdata);
        }
 }
index 7825705..39c74ec 100644 (file)
@@ -8,80 +8,89 @@
 #ifndef __DEVICES_COMMON_H
 #define __DEVICES_COMMON_H
 
-extern struct amba_device *
-dbx500_add_amba_device(const char *name, resource_size_t base,
-                      int irq, void *pdata, unsigned int periphid);
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/sys_soc.h>
+#include <plat/i2c.h>
 
-extern struct platform_device *
-dbx500_add_platform_device_4k1irq(const char *name, int id,
-                                 resource_size_t base,
-                                 int irq, void *pdata);
+extern struct amba_device *
+dbx500_add_amba_device(struct device *parent, const char *name,
+                      resource_size_t base, int irq, void *pdata,
+                      unsigned int periphid);
 
 struct spi_master_cntlr;
 
 static inline struct amba_device *
-dbx500_add_msp_spi(const char *name, resource_size_t base, int irq,
+dbx500_add_msp_spi(struct device *parent, const char *name,
+                  resource_size_t base, int irq,
                   struct spi_master_cntlr *pdata)
 {
-       return dbx500_add_amba_device(name, base, irq, pdata, 0);
+       return dbx500_add_amba_device(parent, name, base, irq,
+                                     pdata, 0);
 }
 
 static inline struct amba_device *
-dbx500_add_spi(const char *name, resource_size_t base, int irq,
-              struct spi_master_cntlr *pdata,
+dbx500_add_spi(struct device *parent, const char *name, resource_size_t base,
+              int irq, struct spi_master_cntlr *pdata,
               u32 periphid)
 {
-       return dbx500_add_amba_device(name, base, irq, pdata, periphid);
+       return dbx500_add_amba_device(parent, name, base, irq,
+                                     pdata, periphid);
 }
 
 struct mmci_platform_data;
 
 static inline struct amba_device *
-dbx500_add_sdi(const char *name, resource_size_t base, int irq,
-              struct mmci_platform_data *pdata,
-              u32 periphid)
+dbx500_add_sdi(struct device *parent, const char *name, resource_size_t base,
+              int irq, struct mmci_platform_data *pdata, u32 periphid)
 {
-       return dbx500_add_amba_device(name, base, irq, pdata, periphid);
+       return dbx500_add_amba_device(parent, name, base, irq,
+                                     pdata, periphid);
 }
 
 struct amba_pl011_data;
 
 static inline struct amba_device *
-dbx500_add_uart(const char *name, resource_size_t base, int irq,
-               struct amba_pl011_data *pdata)
+dbx500_add_uart(struct device *parent, const char *name, resource_size_t base,
+               int irq, struct amba_pl011_data *pdata)
 {
-       return dbx500_add_amba_device(name, base, irq, pdata, 0);
+       return dbx500_add_amba_device(parent, name, base, irq, pdata, 0);
 }
 
 struct nmk_i2c_controller;
 
 static inline struct platform_device *
-dbx500_add_i2c(int id, resource_size_t base, int irq,
-              struct nmk_i2c_controller *pdata)
-{
-       return dbx500_add_platform_device_4k1irq("nmk-i2c", id, base, irq,
-                                                pdata);
-}
-
-struct msp_i2s_platform_data;
-
-static inline struct platform_device *
-dbx500_add_msp_i2s(int id, resource_size_t base, int irq,
-                  struct msp_i2s_platform_data *pdata)
+dbx500_add_i2c(struct device *parent, int id, resource_size_t base, int irq,
+              struct nmk_i2c_controller *data)
 {
-       return dbx500_add_platform_device_4k1irq("MSP_I2S", id, base, irq,
-                                                pdata);
+       struct resource res[] = {
+               DEFINE_RES_MEM(base, SZ_4K),
+               DEFINE_RES_IRQ(irq),
+       };
+
+       struct platform_device_info pdevinfo = {
+               .parent = parent,
+               .name = "nmk-i2c",
+               .id = id,
+               .res = res,
+               .num_res = ARRAY_SIZE(res),
+               .data = data,
+               .size_data = sizeof(*data),
+               .dma_mask = DMA_BIT_MASK(32),
+       };
+
+       return platform_device_register_full(&pdevinfo);
 }
 
 static inline struct amba_device *
-dbx500_add_rtc(resource_size_t base, int irq)
+dbx500_add_rtc(struct device *parent, resource_size_t base, int irq)
 {
-       return dbx500_add_amba_device("rtc-pl031", base, irq, NULL, 0);
+       return dbx500_add_amba_device(parent, "rtc-pl031", base, irq, NULL, 0);
 }
 
 struct nmk_gpio_platform_data;
 
-void dbx500_add_gpios(resource_size_t *base, int num, int irq,
-                     struct nmk_gpio_platform_data *pdata);
+void dbx500_add_gpios(struct device *parent, resource_size_t *base, int num,
+                     int irq, struct nmk_gpio_platform_data *pdata);
 
 #endif
index 0c4bccd..e709555 100644 (file)
 
 #include "devices-common.h"
 
-#define db5500_add_i2c1(pdata) \
-       dbx500_add_i2c(1, U5500_I2C1_BASE, IRQ_DB5500_I2C1, pdata)
-#define db5500_add_i2c2(pdata) \
-       dbx500_add_i2c(2, U5500_I2C2_BASE, IRQ_DB5500_I2C2, pdata)
-#define db5500_add_i2c3(pdata) \
-       dbx500_add_i2c(3, U5500_I2C3_BASE, IRQ_DB5500_I2C3, pdata)
+#define db5500_add_i2c1(parent, pdata) \
+       dbx500_add_i2c(parent, 1, U5500_I2C1_BASE, IRQ_DB5500_I2C1, pdata)
+#define db5500_add_i2c2(parent, pdata) \
+       dbx500_add_i2c(parent, 2, U5500_I2C2_BASE, IRQ_DB5500_I2C2, pdata)
+#define db5500_add_i2c3(parent, pdata) \
+       dbx500_add_i2c(parent, 3, U5500_I2C3_BASE, IRQ_DB5500_I2C3, pdata)
 
-#define db5500_add_msp0_i2s(pdata) \
-       dbx500_add_msp_i2s(0, U5500_MSP0_BASE, IRQ_DB5500_MSP0, pdata)
-#define db5500_add_msp1_i2s(pdata) \
-       dbx500_add_msp_i2s(1, U5500_MSP1_BASE, IRQ_DB5500_MSP1, pdata)
-#define db5500_add_msp2_i2s(pdata) \
-       dbx500_add_msp_i2s(2, U5500_MSP2_BASE, IRQ_DB5500_MSP2, pdata)
+#define db5500_add_msp0_spi(parent, pdata) \
+       dbx500_add_msp_spi(parent, "msp0", U5500_MSP0_BASE, \
+                          IRQ_DB5500_MSP0, pdata)
+#define db5500_add_msp1_spi(parent, pdata) \
+       dbx500_add_msp_spi(parent, "msp1", U5500_MSP1_BASE, \
+                          IRQ_DB5500_MSP1, pdata)
+#define db5500_add_msp2_spi(parent, pdata) \
+       dbx500_add_msp_spi(parent, "msp2", U5500_MSP2_BASE, \
+                          IRQ_DB5500_MSP2, pdata)
 
-#define db5500_add_msp0_spi(pdata) \
-       dbx500_add_msp_spi("msp0", U5500_MSP0_BASE, IRQ_DB5500_MSP0, pdata)
-#define db5500_add_msp1_spi(pdata) \
-       dbx500_add_msp_spi("msp1", U5500_MSP1_BASE, IRQ_DB5500_MSP1, pdata)
-#define db5500_add_msp2_spi(pdata) \
-       dbx500_add_msp_spi("msp2", U5500_MSP2_BASE, IRQ_DB5500_MSP2, pdata)
+#define db5500_add_msp0_spi(parent, pdata) \
+       dbx500_add_msp_spi(parent, "msp0", U5500_MSP0_BASE, \
+                         IRQ_DB5500_MSP0, pdata)
+#define db5500_add_msp1_spi(parent, pdata) \
+       dbx500_add_msp_spi(parent, "msp1", U5500_MSP1_BASE, \
+                         IRQ_DB5500_MSP1, pdata)
+#define db5500_add_msp2_spi(parent, pdata) \
+       dbx500_add_msp_spi(parent, "msp2", U5500_MSP2_BASE, \
+                         IRQ_DB5500_MSP2, pdata)
 
-#define db5500_add_rtc() \
-       dbx500_add_rtc(U5500_RTC_BASE, IRQ_DB5500_RTC);
+#define db5500_add_rtc(parent) \
+       dbx500_add_rtc(parent, U5500_RTC_BASE, IRQ_DB5500_RTC);
 
-#define db5500_add_usb(rx_cfg, tx_cfg) \
-       ux500_add_usb(U5500_USBOTG_BASE, IRQ_DB5500_USBOTG, rx_cfg, tx_cfg)
+#define db5500_add_usb(parent, rx_cfg, tx_cfg) \
+       ux500_add_usb(parent, U5500_USBOTG_BASE, \
+                     IRQ_DB5500_USBOTG, rx_cfg, tx_cfg)
 
-#define db5500_add_sdi0(pdata) \
-       dbx500_add_sdi("sdi0", U5500_SDI0_BASE, IRQ_DB5500_SDMMC0, pdata, \
+#define db5500_add_sdi0(parent, pdata) \
+       dbx500_add_sdi(parent, "sdi0", U5500_SDI0_BASE, \
+                      IRQ_DB5500_SDMMC0, pdata,        \
                       0x10480180)
-#define db5500_add_sdi1(pdata) \
-       dbx500_add_sdi("sdi1", U5500_SDI1_BASE, IRQ_DB5500_SDMMC1, pdata, \
+#define db5500_add_sdi1(parent, pdata) \
+       dbx500_add_sdi(parent, "sdi1", U5500_SDI1_BASE, \
+                      IRQ_DB5500_SDMMC1, pdata,        \
                       0x10480180)
-#define db5500_add_sdi2(pdata) \
-       dbx500_add_sdi("sdi2", U5500_SDI2_BASE, IRQ_DB5500_SDMMC2, pdata \
+#define db5500_add_sdi2(parent, pdata) \
+       dbx500_add_sdi(parent, "sdi2", U5500_SDI2_BASE, \
+                      IRQ_DB5500_SDMMC2, pdata         \
                       0x10480180)
-#define db5500_add_sdi3(pdata) \
-       dbx500_add_sdi("sdi3", U5500_SDI3_BASE, IRQ_DB5500_SDMMC3, pdata \
+#define db5500_add_sdi3(parent, pdata) \
+       dbx500_add_sdi(parent, "sdi3", U5500_SDI3_BASE, \
+                      IRQ_DB5500_SDMMC3, pdata         \
                       0x10480180)
-#define db5500_add_sdi4(pdata) \
-       dbx500_add_sdi("sdi4", U5500_SDI4_BASE, IRQ_DB5500_SDMMC4, pdata \
+#define db5500_add_sdi4(parent, pdata) \
+       dbx500_add_sdi(parent, "sdi4", U5500_SDI4_BASE, \
+                      IRQ_DB5500_SDMMC4, pdata         \
                       0x10480180)
 
 /* This one has a bad peripheral ID in the U5500 silicon */
-#define db5500_add_spi0(pdata) \
-       dbx500_add_spi("spi0", U5500_SPI0_BASE, IRQ_DB5500_SPI0, pdata, \
+#define db5500_add_spi0(parent, pdata) \
+       dbx500_add_spi(parent, "spi0", U5500_SPI0_BASE, \
+                      IRQ_DB5500_SPI0, pdata,          \
                       0x10080023)
-#define db5500_add_spi1(pdata) \
-       dbx500_add_spi("spi1", U5500_SPI1_BASE, IRQ_DB5500_SPI1, pdata, \
+#define db5500_add_spi1(parent, pdata) \
+       dbx500_add_spi(parent, "spi1", U5500_SPI1_BASE, \
+                      IRQ_DB5500_SPI1, pdata,          \
                       0x10080023)
-#define db5500_add_spi2(pdata) \
-       dbx500_add_spi("spi2", U5500_SPI2_BASE, IRQ_DB5500_SPI2, pdata \
+#define db5500_add_spi2(parent, pdata) \
+       dbx500_add_spi(parent, "spi2", U5500_SPI2_BASE, \
+                      IRQ_DB5500_SPI2, pdata           \
                       0x10080023)
-#define db5500_add_spi3(pdata) \
-       dbx500_add_spi("spi3", U5500_SPI3_BASE, IRQ_DB5500_SPI3, pdata \
+#define db5500_add_spi3(parent, pdata) \
+       dbx500_add_spi(parent, "spi3", U5500_SPI3_BASE, \
+                      IRQ_DB5500_SPI3, pdata           \
                       0x10080023)
 
-#define db5500_add_uart0(plat) \
-       dbx500_add_uart("uart0", U5500_UART0_BASE, IRQ_DB5500_UART0, plat)
-#define db5500_add_uart1(plat) \
-       dbx500_add_uart("uart1", U5500_UART1_BASE, IRQ_DB5500_UART1, plat)
-#define db5500_add_uart2(plat) \
-       dbx500_add_uart("uart2", U5500_UART2_BASE, IRQ_DB5500_UART2, plat)
-#define db5500_add_uart3(plat) \
-       dbx500_add_uart("uart3", U5500_UART3_BASE, IRQ_DB5500_UART3, plat)
+#define db5500_add_uart0(parent, plat) \
+       dbx500_add_uart(parent, "uart0", U5500_UART0_BASE, \
+                       IRQ_DB5500_UART0, plat)
+#define db5500_add_uart1(parent, plat) \
+       dbx500_add_uart(parent, "uart1", U5500_UART1_BASE, \
+                       IRQ_DB5500_UART1, plat)
+#define db5500_add_uart2(parent, plat) \
+       dbx500_add_uart(parent, "uart2", U5500_UART2_BASE, \
+                       IRQ_DB5500_UART2, plat)
+#define db5500_add_uart3(parent, plat) \
+       dbx500_add_uart(parent, "uart3", U5500_UART3_BASE, \
+                       IRQ_DB5500_UART3, plat)
 
 #endif
index cbd4a9a..9fd93e9 100644 (file)
@@ -14,88 +14,114 @@ struct ske_keypad_platform_data;
 struct pl022_ssp_controller;
 
 static inline struct platform_device *
-db8500_add_ske_keypad(struct ske_keypad_platform_data *pdata)
+db8500_add_ske_keypad(struct device *parent,
+                     struct ske_keypad_platform_data *pdata,
+                     size_t size)
 {
-       return dbx500_add_platform_device_4k1irq("nmk-ske-keypad", -1,
-                                                U8500_SKE_BASE,
-                                                IRQ_DB8500_KB, pdata);
+       struct resource resources[] = {
+               DEFINE_RES_MEM(U8500_SKE_BASE, SZ_4K),
+               DEFINE_RES_IRQ(IRQ_DB8500_KB),
+       };
+
+       return platform_device_register_resndata(parent, "nmk-ske-keypad", -1,
+                                                resources, 2, pdata, size);
 }
 
 static inline struct amba_device *
-db8500_add_ssp(const char *name, resource_size_t base, int irq,
-              struct pl022_ssp_controller *pdata)
+db8500_add_ssp(struct device *parent, const char *name, resource_size_t base,
+              int irq, struct pl022_ssp_controller *pdata)
 {
-       return dbx500_add_amba_device(name, base, irq, pdata, 0);
+       return dbx500_add_amba_device(parent, name, base, irq, pdata, 0);
 }
 
 
-#define db8500_add_i2c0(pdata) \
-       dbx500_add_i2c(0, U8500_I2C0_BASE, IRQ_DB8500_I2C0, pdata)
-#define db8500_add_i2c1(pdata) \
-       dbx500_add_i2c(1, U8500_I2C1_BASE, IRQ_DB8500_I2C1, pdata)
-#define db8500_add_i2c2(pdata) \
-       dbx500_add_i2c(2, U8500_I2C2_BASE, IRQ_DB8500_I2C2, pdata)
-#define db8500_add_i2c3(pdata) \
-       dbx500_add_i2c(3, U8500_I2C3_BASE, IRQ_DB8500_I2C3, pdata)
-#define db8500_add_i2c4(pdata) \
-       dbx500_add_i2c(4, U8500_I2C4_BASE, IRQ_DB8500_I2C4, pdata)
-
-#define db8500_add_msp0_i2s(pdata) \
-       dbx500_add_msp_i2s(0, U8500_MSP0_BASE, IRQ_DB8500_MSP0, pdata)
-#define db8500_add_msp1_i2s(pdata) \
-       dbx500_add_msp_i2s(1, U8500_MSP1_BASE, IRQ_DB8500_MSP1, pdata)
-#define db8500_add_msp2_i2s(pdata) \
-       dbx500_add_msp_i2s(2, U8500_MSP2_BASE, IRQ_DB8500_MSP2, pdata)
-#define db8500_add_msp3_i2s(pdata) \
-       dbx500_add_msp_i2s(3, U8500_MSP3_BASE, IRQ_DB8500_MSP1, pdata)
-
-#define db8500_add_msp0_spi(pdata) \
-       dbx500_add_msp_spi("msp0", U8500_MSP0_BASE, IRQ_DB8500_MSP0, pdata)
-#define db8500_add_msp1_spi(pdata) \
-       dbx500_add_msp_spi("msp1", U8500_MSP1_BASE, IRQ_DB8500_MSP1, pdata)
-#define db8500_add_msp2_spi(pdata) \
-       dbx500_add_msp_spi("msp2", U8500_MSP2_BASE, IRQ_DB8500_MSP2, pdata)
-#define db8500_add_msp3_spi(pdata) \
-       dbx500_add_msp_spi("msp3", U8500_MSP3_BASE, IRQ_DB8500_MSP1, pdata)
-
-#define db8500_add_rtc() \
-       dbx500_add_rtc(U8500_RTC_BASE, IRQ_DB8500_RTC);
-
-#define db8500_add_usb(rx_cfg, tx_cfg) \
-       ux500_add_usb(U8500_USBOTG_BASE, IRQ_DB8500_USBOTG, rx_cfg, tx_cfg)
-
-#define db8500_add_sdi0(pdata, pid) \
-       dbx500_add_sdi("sdi0", U8500_SDI0_BASE, IRQ_DB8500_SDMMC0, pdata, pid)
-#define db8500_add_sdi1(pdata, pid) \
-       dbx500_add_sdi("sdi1", U8500_SDI1_BASE, IRQ_DB8500_SDMMC1, pdata, pid)
-#define db8500_add_sdi2(pdata, pid) \
-       dbx500_add_sdi("sdi2", U8500_SDI2_BASE, IRQ_DB8500_SDMMC2, pdata, pid)
-#define db8500_add_sdi3(pdata, pid) \
-       dbx500_add_sdi("sdi3", U8500_SDI3_BASE, IRQ_DB8500_SDMMC3, pdata, pid)
-#define db8500_add_sdi4(pdata, pid) \
-       dbx500_add_sdi("sdi4", U8500_SDI4_BASE, IRQ_DB8500_SDMMC4, pdata, pid)
-#define db8500_add_sdi5(pdata, pid) \
-       dbx500_add_sdi("sdi5", U8500_SDI5_BASE, IRQ_DB8500_SDMMC5, pdata, pid)
-
-#define db8500_add_ssp0(pdata) \
-       db8500_add_ssp("ssp0", U8500_SSP0_BASE, IRQ_DB8500_SSP0, pdata)
-#define db8500_add_ssp1(pdata) \
-       db8500_add_ssp("ssp1", U8500_SSP1_BASE, IRQ_DB8500_SSP1, pdata)
-
-#define db8500_add_spi0(pdata) \
-       dbx500_add_spi("spi0", U8500_SPI0_BASE, IRQ_DB8500_SPI0, pdata, 0)
-#define db8500_add_spi1(pdata) \
-       dbx500_add_spi("spi1", U8500_SPI1_BASE, IRQ_DB8500_SPI1, pdata, 0)
-#define db8500_add_spi2(pdata) \
-       dbx500_add_spi("spi2", U8500_SPI2_BASE, IRQ_DB8500_SPI2, pdata, 0)
-#define db8500_add_spi3(pdata) \
-       dbx500_add_spi("spi3", U8500_SPI3_BASE, IRQ_DB8500_SPI3, pdata, 0)
-
-#define db8500_add_uart0(pdata) \
-       dbx500_add_uart("uart0", U8500_UART0_BASE, IRQ_DB8500_UART0, pdata)
-#define db8500_add_uart1(pdata) \
-       dbx500_add_uart("uart1", U8500_UART1_BASE, IRQ_DB8500_UART1, pdata)
-#define db8500_add_uart2(pdata) \
-       dbx500_add_uart("uart2", U8500_UART2_BASE, IRQ_DB8500_UART2, pdata)
+#define db8500_add_i2c0(parent, pdata) \
+       dbx500_add_i2c(parent, 0, U8500_I2C0_BASE, IRQ_DB8500_I2C0, pdata)
+#define db8500_add_i2c1(parent, pdata) \
+       dbx500_add_i2c(parent, 1, U8500_I2C1_BASE, IRQ_DB8500_I2C1, pdata)
+#define db8500_add_i2c2(parent, pdata) \
+       dbx500_add_i2c(parent, 2, U8500_I2C2_BASE, IRQ_DB8500_I2C2, pdata)
+#define db8500_add_i2c3(parent, pdata) \
+       dbx500_add_i2c(parent, 3, U8500_I2C3_BASE, IRQ_DB8500_I2C3, pdata)
+#define db8500_add_i2c4(parent, pdata) \
+       dbx500_add_i2c(parent, 4, U8500_I2C4_BASE, IRQ_DB8500_I2C4, pdata)
+
+#define db8500_add_msp0_i2s(parent, pdata) \
+       dbx500_add_msp_i2s(parent, 0, U8500_MSP0_BASE, IRQ_DB8500_MSP0, pdata)
+#define db8500_add_msp1_i2s(parent, pdata) \
+       dbx500_add_msp_i2s(parent, 1, U8500_MSP1_BASE, IRQ_DB8500_MSP1, pdata)
+#define db8500_add_msp2_i2s(parent, pdata) \
+       dbx500_add_msp_i2s(parent, 2, U8500_MSP2_BASE, IRQ_DB8500_MSP2, pdata)
+#define db8500_add_msp3_i2s(parent, pdata) \
+       dbx500_add_msp_i2s(parent, 3, U8500_MSP3_BASE, IRQ_DB8500_MSP1, pdata)
+
+#define db8500_add_msp0_spi(parent, pdata) \
+       dbx500_add_msp_spi(parent, "msp0", U8500_MSP0_BASE, \
+                          IRQ_DB8500_MSP0, pdata)
+#define db8500_add_msp1_spi(parent, pdata) \
+       dbx500_add_msp_spi(parent, "msp1", U8500_MSP1_BASE, \
+                          IRQ_DB8500_MSP1, pdata)
+#define db8500_add_msp2_spi(parent, pdata) \
+       dbx500_add_msp_spi(parent, "msp2", U8500_MSP2_BASE, \
+                          IRQ_DB8500_MSP2, pdata)
+#define db8500_add_msp3_spi(parent, pdata) \
+       dbx500_add_msp_spi(parent, "msp3", U8500_MSP3_BASE, \
+                          IRQ_DB8500_MSP1, pdata)
+
+#define db8500_add_rtc(parent) \
+       dbx500_add_rtc(parent, U8500_RTC_BASE, IRQ_DB8500_RTC);
+
+#define db8500_add_usb(parent, rx_cfg, tx_cfg) \
+       ux500_add_usb(parent, U8500_USBOTG_BASE, \
+                     IRQ_DB8500_USBOTG, rx_cfg, tx_cfg)
+
+#define db8500_add_sdi0(parent, pdata, pid) \
+       dbx500_add_sdi(parent, "sdi0", U8500_SDI0_BASE, \
+                      IRQ_DB8500_SDMMC0, pdata, pid)
+#define db8500_add_sdi1(parent, pdata, pid) \
+       dbx500_add_sdi(parent, "sdi1", U8500_SDI1_BASE, \
+                      IRQ_DB8500_SDMMC1, pdata, pid)
+#define db8500_add_sdi2(parent, pdata, pid) \
+       dbx500_add_sdi(parent, "sdi2", U8500_SDI2_BASE, \
+                      IRQ_DB8500_SDMMC2, pdata, pid)
+#define db8500_add_sdi3(parent, pdata, pid) \
+       dbx500_add_sdi(parent, "sdi3", U8500_SDI3_BASE, \
+                      IRQ_DB8500_SDMMC3, pdata, pid)
+#define db8500_add_sdi4(parent, pdata, pid) \
+       dbx500_add_sdi(parent, "sdi4", U8500_SDI4_BASE, \
+                      IRQ_DB8500_SDMMC4, pdata, pid)
+#define db8500_add_sdi5(parent, pdata, pid) \
+       dbx500_add_sdi(parent, "sdi5", U8500_SDI5_BASE, \
+                      IRQ_DB8500_SDMMC5, pdata, pid)
+
+#define db8500_add_ssp0(parent, pdata) \
+       db8500_add_ssp(parent, "ssp0", U8500_SSP0_BASE, \
+                      IRQ_DB8500_SSP0, pdata)
+#define db8500_add_ssp1(parent, pdata) \
+       db8500_add_ssp(parent, "ssp1", U8500_SSP1_BASE, \
+                      IRQ_DB8500_SSP1, pdata)
+
+#define db8500_add_spi0(parent, pdata) \
+       dbx500_add_spi(parent, "spi0", U8500_SPI0_BASE, \
+                      IRQ_DB8500_SPI0, pdata, 0)
+#define db8500_add_spi1(parent, pdata) \
+       dbx500_add_spi(parent, "spi1", U8500_SPI1_BASE, \
+                      IRQ_DB8500_SPI1, pdata, 0)
+#define db8500_add_spi2(parent, pdata) \
+       dbx500_add_spi(parent, "spi2", U8500_SPI2_BASE, \
+                      IRQ_DB8500_SPI2, pdata, 0)
+#define db8500_add_spi3(parent, pdata) \
+       dbx500_add_spi(parent, "spi3", U8500_SPI3_BASE, \
+                      IRQ_DB8500_SPI3, pdata, 0)
+
+#define db8500_add_uart0(parent, pdata) \
+       dbx500_add_uart(parent, "uart0", U8500_UART0_BASE, \
+                       IRQ_DB8500_UART0, pdata)
+#define db8500_add_uart1(parent, pdata) \
+       dbx500_add_uart(parent, "uart1", U8500_UART1_BASE, \
+                       IRQ_DB8500_UART1, pdata)
+#define db8500_add_uart2(parent, pdata) \
+       dbx500_add_uart(parent, "uart2", U8500_UART2_BASE, \
+                       IRQ_DB8500_UART2, pdata)
 
 #endif
index 1cfab68..41e9470 100644 (file)
@@ -125,10 +125,11 @@ static struct platform_device dma40_device = {
        .resource       = dma40_resources
 };
 
-void __init db5500_dma_init(void)
+void __init db5500_dma_init(struct device *parent)
 {
        int ret;
 
+       dma40_device.dev.parent = parent;
        ret = platform_device_register(&dma40_device);
        if (ret)
                dev_err(&dma40_device.dev, "unable to register device: %d\n", ret);
index 80e10f5..9ec20b9 100644 (file)
 #define U8500_MODEM_BASE       0xe000000
 #define U8500_APE_BASE         0x6000000
 
+/* SoC identification number information */
+#define U8500_BB_UID_BASE      (U8500_BACKUPRAM1_BASE + 0xFC0)
+
 #endif
index a7d363f..74b43bb 100644 (file)
@@ -18,14 +18,16 @@ void __init ux500_map_io(void);
 extern void __init u5500_map_io(void);
 extern void __init u8500_map_io(void);
 
-extern void __init u5500_init_devices(void);
-extern void __init u8500_init_devices(void);
+extern struct device * __init u5500_init_devices(void);
+extern struct device * __init u8500_init_devices(void);
 
 extern void __init ux500_init_irq(void);
 
-extern void __init u5500_sdi_init(void);
+extern void __init u5500_sdi_init(struct device *parent);
 
-extern void __init db5500_dma_init(void);
+extern void __init db5500_dma_init(struct device *parent);
+
+extern struct device *ux500_soc_device_init(const char *soc_id);
 
 /* We re-use nomadik_timer for this platform */
 extern void nmdk_timer_init(void);
index d3739d4..4c1cc50 100644 (file)
@@ -20,6 +20,6 @@ struct ux500_musb_board_data {
        bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
 };
 
-void ux500_add_usb(resource_size_t base, int irq, int *dma_rx_cfg,
-       int *dma_tx_cfg);
+void ux500_add_usb(struct device *parent, resource_size_t base,
+                  int irq, int *dma_rx_cfg, int *dma_tx_cfg);
 #endif
index 9f9e1c2..a74af38 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/platform_device.h>
 #include <linux/usb/musb.h>
 #include <linux/dma-mapping.h>
+
 #include <plat/ste_dma40.h>
 #include <mach/hardware.h>
 #include <mach/usb.h>
@@ -140,8 +141,8 @@ static inline void ux500_usb_dma_update_tx_ch_config(int *dst_dev_type)
                musb_dma_tx_ch[idx].dst_dev_type = dst_dev_type[idx];
 }
 
-void ux500_add_usb(resource_size_t base, int irq, int *dma_rx_cfg,
-       int *dma_tx_cfg)
+void ux500_add_usb(struct device *parent, resource_size_t base, int irq,
+                  int *dma_rx_cfg, int *dma_tx_cfg)
 {
        ux500_musb_device.resource[0].start = base;
        ux500_musb_device.resource[0].end = base + SZ_64K - 1;
@@ -151,5 +152,7 @@ void ux500_add_usb(resource_size_t base, int irq, int *dma_rx_cfg,
        ux500_usb_dma_update_rx_ch_config(dma_rx_cfg);
        ux500_usb_dma_update_tx_ch_config(dma_tx_cfg);
 
+       ux500_musb_device.dev.parent = parent;
+
        platform_device_register(&ux500_musb_device);
 }
index 5bed94e..6339aa4 100644 (file)
@@ -179,6 +179,9 @@ config ARCH_HAS_DEFAULT_IDLE
 config ARCH_HAS_CACHE_LINE_SIZE
        def_bool y
 
+config ARCH_HAS_CPU_AUTOPROBE
+       def_bool y
+
 config HAVE_SETUP_PER_CPU_AREA
        def_bool y
 
index 545d0ce..b3350bd 100644 (file)
@@ -28,6 +28,7 @@
 #include <crypto/aes.h>
 #include <crypto/cryptd.h>
 #include <crypto/ctr.h>
+#include <asm/cpu_device_id.h>
 #include <asm/i387.h>
 #include <asm/aes.h>
 #include <crypto/scatterwalk.h>
@@ -1253,14 +1254,19 @@ static struct crypto_alg __rfc4106_alg = {
 };
 #endif
 
+
+static const struct x86_cpu_id aesni_cpu_id[] = {
+       X86_FEATURE_MATCH(X86_FEATURE_AES),
+       {}
+};
+MODULE_DEVICE_TABLE(x86cpu, aesni_cpu_id);
+
 static int __init aesni_init(void)
 {
        int err;
 
-       if (!cpu_has_aes) {
-               printk(KERN_INFO "Intel AES-NI instructions are not detected.\n");
+       if (!x86_match_cpu(aesni_cpu_id))
                return -ENODEV;
-       }
 
        if ((err = crypto_fpu_init()))
                goto fpu_err;
index b9d0026..493f959 100644 (file)
@@ -31,6 +31,7 @@
 #include <crypto/internal/hash.h>
 
 #include <asm/cpufeature.h>
+#include <asm/cpu_device_id.h>
 
 #define CHKSUM_BLOCK_SIZE      1
 #define CHKSUM_DIGEST_SIZE     4
@@ -173,13 +174,17 @@ static struct shash_alg alg = {
        }
 };
 
+static const struct x86_cpu_id crc32c_cpu_id[] = {
+       X86_FEATURE_MATCH(X86_FEATURE_XMM4_2),
+       {}
+};
+MODULE_DEVICE_TABLE(x86cpu, crc32c_cpu_id);
 
 static int __init crc32c_intel_mod_init(void)
 {
-       if (cpu_has_xmm4_2)
-               return crypto_register_shash(&alg);
-       else
+       if (!x86_match_cpu(crc32c_cpu_id))
                return -ENODEV;
+       return crypto_register_shash(&alg);
 }
 
 static void __exit crc32c_intel_mod_fini(void)
index 976aa64..b4bf0a6 100644 (file)
@@ -20,6 +20,7 @@
 #include <crypto/gf128mul.h>
 #include <crypto/internal/hash.h>
 #include <asm/i387.h>
+#include <asm/cpu_device_id.h>
 
 #define GHASH_BLOCK_SIZE       16
 #define GHASH_DIGEST_SIZE      16
@@ -294,15 +295,18 @@ static struct ahash_alg ghash_async_alg = {
        },
 };
 
+static const struct x86_cpu_id pcmul_cpu_id[] = {
+       X86_FEATURE_MATCH(X86_FEATURE_PCLMULQDQ), /* Pickle-Mickle-Duck */
+       {}
+};
+MODULE_DEVICE_TABLE(x86cpu, pcmul_cpu_id);
+
 static int __init ghash_pclmulqdqni_mod_init(void)
 {
        int err;
 
-       if (!cpu_has_pclmulqdq) {
-               printk(KERN_INFO "Intel PCLMULQDQ-NI instructions are not"
-                      " detected.\n");
+       if (!x86_match_cpu(pcmul_cpu_id))
                return -ENODEV;
-       }
 
        err = crypto_register_shash(&ghash_alg);
        if (err)
diff --git a/arch/x86/include/asm/cpu_device_id.h b/arch/x86/include/asm/cpu_device_id.h
new file mode 100644 (file)
index 0000000..ff501e5
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef _CPU_DEVICE_ID
+#define _CPU_DEVICE_ID 1
+
+/*
+ * Declare drivers belonging to specific x86 CPUs
+ * Similar in spirit to pci_device_id and related PCI functions
+ */
+
+#include <linux/mod_devicetable.h>
+
+extern const struct x86_cpu_id *x86_match_cpu(const struct x86_cpu_id *match);
+
+#endif
index 8d67d42..dcb839e 100644 (file)
 #define X86_FEATURE_PLN                (7*32+ 5) /* Intel Power Limit Notification */
 #define X86_FEATURE_PTS                (7*32+ 6) /* Intel Package Thermal Status */
 #define X86_FEATURE_DTS                (7*32+ 7) /* Digital Thermal Sensor */
+#define X86_FEATURE_HW_PSTATE  (7*32+ 8) /* AMD HW-PState */
 
 /* Virtualization flags: Linux defined, word 8 */
 #define X86_FEATURE_TPR_SHADOW  (8*32+ 0) /* Intel TPR Shadow */
index 25f24dc..6ab6aa2 100644 (file)
@@ -16,6 +16,7 @@ obj-y                 := intel_cacheinfo.o scattered.o topology.o
 obj-y                  += proc.o capflags.o powerflags.o common.o
 obj-y                  += vmware.o hypervisor.o sched.o mshyperv.o
 obj-y                  += rdrand.o
+obj-y                  += match.o
 
 obj-$(CONFIG_X86_32)   += bugs.o
 obj-$(CONFIG_X86_64)   += bugs_64.o
diff --git a/arch/x86/kernel/cpu/match.c b/arch/x86/kernel/cpu/match.c
new file mode 100644 (file)
index 0000000..940e2d4
--- /dev/null
@@ -0,0 +1,92 @@
+#include <asm/cpu_device_id.h>
+#include <asm/processor.h>
+#include <linux/cpu.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+/**
+ * x86_match_cpu - match current CPU again an array of x86_cpu_ids
+ * @match: Pointer to array of x86_cpu_ids. Last entry terminated with
+ *         {}.
+ *
+ * Return the entry if the current CPU matches the entries in the
+ * passed x86_cpu_id match table. Otherwise NULL.  The match table
+ * contains vendor (X86_VENDOR_*), family, model and feature bits or
+ * respective wildcard entries.
+ *
+ * A typical table entry would be to match a specific CPU
+ * { X86_VENDOR_INTEL, 6, 0x12 }
+ * or to match a specific CPU feature
+ * { X86_FEATURE_MATCH(X86_FEATURE_FOOBAR) }
+ *
+ * Fields can be wildcarded with %X86_VENDOR_ANY, %X86_FAMILY_ANY,
+ * %X86_MODEL_ANY, %X86_FEATURE_ANY or 0 (except for vendor)
+ *
+ * Arrays used to match for this should also be declared using
+ * MODULE_DEVICE_TABLE(x86_cpu, ...)
+ *
+ * This always matches against the boot cpu, assuming models and features are
+ * consistent over all CPUs.
+ */
+const struct x86_cpu_id *x86_match_cpu(const struct x86_cpu_id *match)
+{
+       const struct x86_cpu_id *m;
+       struct cpuinfo_x86 *c = &boot_cpu_data;
+
+       for (m = match; m->vendor | m->family | m->model | m->feature; m++) {
+               if (m->vendor != X86_VENDOR_ANY && c->x86_vendor != m->vendor)
+                       continue;
+               if (m->family != X86_FAMILY_ANY && c->x86 != m->family)
+                       continue;
+               if (m->model != X86_MODEL_ANY && c->x86_model != m->model)
+                       continue;
+               if (m->feature != X86_FEATURE_ANY && !cpu_has(c, m->feature))
+                       continue;
+               return m;
+       }
+       return NULL;
+}
+EXPORT_SYMBOL(x86_match_cpu);
+
+ssize_t arch_print_cpu_modalias(struct device *dev,
+                               struct device_attribute *attr,
+                               char *bufptr)
+{
+       int size = PAGE_SIZE;
+       int i, n;
+       char *buf = bufptr;
+
+       n = snprintf(buf, size, "x86cpu:vendor:%04X:family:%04X:"
+                    "model:%04X:feature:",
+               boot_cpu_data.x86_vendor,
+               boot_cpu_data.x86,
+               boot_cpu_data.x86_model);
+       size -= n;
+       buf += n;
+       size -= 2;
+       for (i = 0; i < NCAPINTS*32; i++) {
+               if (boot_cpu_has(i)) {
+                       n = snprintf(buf, size, ",%04X", i);
+                       if (n < 0) {
+                               WARN(1, "x86 features overflow page\n");
+                               break;
+                       }
+                       size -= n;
+                       buf += n;
+               }
+       }
+       *buf++ = ',';
+       *buf++ = '\n';
+       return buf - bufptr;
+}
+
+int arch_cpu_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+       if (buf) {
+               arch_print_cpu_modalias(NULL, NULL, buf);
+               add_uevent_var(env, "MODALIAS=%s", buf);
+               kfree(buf);
+       }
+       return 0;
+}
index c7f64e6..addf9e8 100644 (file)
@@ -40,6 +40,7 @@ void __cpuinit init_scattered_cpuid_features(struct cpuinfo_x86 *c)
                { X86_FEATURE_EPB,              CR_ECX, 3, 0x00000006, 0 },
                { X86_FEATURE_XSAVEOPT,         CR_EAX, 0, 0x0000000d, 1 },
                { X86_FEATURE_CPB,              CR_EDX, 9, 0x80000007, 0 },
+               { X86_FEATURE_HW_PSTATE,        CR_EDX, 7, 0x80000007, 0 },
                { X86_FEATURE_NPT,              CR_EDX, 0, 0x8000000a, 0 },
                { X86_FEATURE_LBRV,             CR_EDX, 1, 0x8000000a, 0 },
                { X86_FEATURE_SVML,             CR_EDX, 2, 0x8000000a, 0 },
index fda91c3..87a0f86 100644 (file)
@@ -86,6 +86,7 @@
 
 #include <asm/microcode.h>
 #include <asm/processor.h>
+#include <asm/cpu_device_id.h>
 
 MODULE_DESCRIPTION("Microcode Update Driver");
 MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
@@ -504,6 +505,20 @@ static struct notifier_block __refdata mc_cpu_notifier = {
        .notifier_call  = mc_cpu_callback,
 };
 
+#ifdef MODULE
+/* Autoload on Intel and AMD systems */
+static const struct x86_cpu_id microcode_id[] = {
+#ifdef CONFIG_MICROCODE_INTEL
+       { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, },
+#endif
+#ifdef CONFIG_MICROCODE_AMD
+       { X86_VENDOR_AMD, X86_FAMILY_ANY, X86_MODEL_ANY, },
+#endif
+       {}
+};
+MODULE_DEVICE_TABLE(x86cpu, microcode_id);
+#endif
+
 static int __init microcode_init(void)
 {
        struct cpuinfo_x86 *c = &cpu_data(0);
index 8ae05ce..2801b41 100644 (file)
@@ -474,6 +474,7 @@ static __ref int acpi_processor_start(struct acpi_processor *pr)
 
 #ifdef CONFIG_CPU_FREQ
        acpi_processor_ppc_has_changed(pr, 0);
+       acpi_processor_load_module(pr);
 #endif
        acpi_processor_get_throttling_info(pr);
        acpi_processor_get_limit_info(pr);
index 85b3237..0af48a8 100644 (file)
@@ -240,6 +240,28 @@ void acpi_processor_ppc_exit(void)
        acpi_processor_ppc_status &= ~PPC_REGISTERED;
 }
 
+/*
+ * Do a quick check if the systems looks like it should use ACPI
+ * cpufreq. We look at a _PCT method being available, but don't
+ * do a whole lot of sanity checks.
+ */
+void acpi_processor_load_module(struct acpi_processor *pr)
+{
+       static int requested;
+       acpi_status status = 0;
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+
+       if (!arch_has_acpi_pdc() || requested)
+               return;
+       status = acpi_evaluate_object(pr->handle, "_PCT", NULL, &buffer);
+       if (!ACPI_FAILURE(status)) {
+               printk(KERN_INFO PREFIX "Requesting acpi_cpufreq\n");
+               request_module_nowait("acpi_cpufreq");
+               requested = 1;
+       }
+       kfree(buffer.pointer);
+}
+
 static int acpi_processor_get_performance_control(struct acpi_processor *pr)
 {
        int result = 0;
index 7be9f79..9aa618a 100644 (file)
@@ -176,6 +176,9 @@ config GENERIC_CPU_DEVICES
        bool
        default n
 
+config SOC_BUS
+       bool
+
 source "drivers/base/regmap/Kconfig"
 
 config DMA_SHARED_BUFFER
index 610f999..b6d1b9c 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_MODULES) += module.o
 endif
 obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o
 obj-$(CONFIG_REGMAP)   += regmap/
+obj-$(CONFIG_SOC_BUS) += soc.o
 
 ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
 
index 40fb122..26a06b8 100644 (file)
@@ -1194,13 +1194,15 @@ EXPORT_SYMBOL_GPL(subsys_interface_register);
 
 void subsys_interface_unregister(struct subsys_interface *sif)
 {
-       struct bus_type *subsys = sif->subsys;
+       struct bus_type *subsys;
        struct subsys_dev_iter iter;
        struct device *dev;
 
-       if (!sif)
+       if (!sif || !sif->subsys)
                return;
 
+       subsys = sif->subsys;
+
        mutex_lock(&subsys->p->mutex);
        list_del_init(&sif->node);
        if (sif->remove_dev) {
index 4dabf50..adf937b 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/device.h>
 #include <linux/node.h>
 #include <linux/gfp.h>
+#include <linux/slab.h>
 #include <linux/percpu.h>
 
 #include "base.h"
@@ -244,6 +245,9 @@ int __cpuinit register_cpu(struct cpu *cpu, int num)
        cpu->dev.id = num;
        cpu->dev.bus = &cpu_subsys;
        cpu->dev.release = cpu_device_release;
+#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE
+       cpu->dev.bus->uevent = arch_cpu_uevent;
+#endif
        error = device_register(&cpu->dev);
        if (!error && cpu->hotpluggable)
                register_cpu_control(cpu);
@@ -268,6 +272,10 @@ struct device *get_cpu_device(unsigned cpu)
 }
 EXPORT_SYMBOL_GPL(get_cpu_device);
 
+#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE
+static DEVICE_ATTR(modalias, 0444, arch_print_cpu_modalias, NULL);
+#endif
+
 static struct attribute *cpu_root_attrs[] = {
 #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
        &dev_attr_probe.attr,
@@ -278,6 +286,9 @@ static struct attribute *cpu_root_attrs[] = {
        &cpu_attrs[2].attr.attr,
        &dev_attr_kernel_max.attr,
        &dev_attr_offline.attr,
+#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE
+       &dev_attr_modalias.attr,
+#endif
        NULL
 };
 
index b631f7c..60e4f77 100644 (file)
@@ -153,34 +153,6 @@ int driver_add_kobj(struct device_driver *drv, struct kobject *kobj,
 }
 EXPORT_SYMBOL_GPL(driver_add_kobj);
 
-/**
- * get_driver - increment driver reference count.
- * @drv: driver.
- */
-struct device_driver *get_driver(struct device_driver *drv)
-{
-       if (drv) {
-               struct driver_private *priv;
-               struct kobject *kobj;
-
-               kobj = kobject_get(&drv->p->kobj);
-               priv = to_driver(kobj);
-               return priv->driver;
-       }
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(get_driver);
-
-/**
- * put_driver - decrement driver's refcount.
- * @drv: driver.
- */
-void put_driver(struct device_driver *drv)
-{
-       kobject_put(&drv->p->kobj);
-}
-EXPORT_SYMBOL_GPL(put_driver);
-
 static int driver_add_groups(struct device_driver *drv,
                             const struct attribute_group **groups)
 {
@@ -234,7 +206,6 @@ int driver_register(struct device_driver *drv)
 
        other = driver_find(drv->name, drv->bus);
        if (other) {
-               put_driver(other);
                printk(KERN_ERR "Error: Driver '%s' is already registered, "
                        "aborting...\n", drv->name);
                return -EBUSY;
@@ -275,7 +246,9 @@ EXPORT_SYMBOL_GPL(driver_unregister);
  * Call kset_find_obj() to iterate over list of drivers on
  * a bus to find driver by name. Return driver if found.
  *
- * Note that kset_find_obj increments driver's reference count.
+ * This routine provides no locking to prevent the driver it returns
+ * from being unregistered or unloaded while the caller is using it.
+ * The caller is responsible for preventing this.
  */
 struct device_driver *driver_find(const char *name, struct bus_type *bus)
 {
@@ -283,6 +256,8 @@ struct device_driver *driver_find(const char *name, struct bus_type *bus)
        struct driver_private *priv;
 
        if (k) {
+               /* Drop reference added by kset_find_obj() */
+               kobject_put(k);
                priv = to_driver(k);
                return priv->driver;
        }
diff --git a/drivers/base/soc.c b/drivers/base/soc.c
new file mode 100644 (file)
index 0000000..05f1503
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ *
+ * Author: Lee Jones <lee.jones@linaro.org> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/sysfs.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/stat.h>
+#include <linux/slab.h>
+#include <linux/idr.h>
+#include <linux/spinlock.h>
+#include <linux/sys_soc.h>
+#include <linux/err.h>
+
+static DEFINE_IDR(soc_ida);
+static DEFINE_SPINLOCK(soc_lock);
+
+static ssize_t soc_info_get(struct device *dev,
+                           struct device_attribute *attr,
+                           char *buf);
+
+struct soc_device {
+       struct device dev;
+       struct soc_device_attribute *attr;
+       int soc_dev_num;
+};
+
+static struct bus_type soc_bus_type = {
+       .name  = "soc",
+};
+
+static DEVICE_ATTR(machine,  S_IRUGO, soc_info_get,  NULL);
+static DEVICE_ATTR(family,   S_IRUGO, soc_info_get,  NULL);
+static DEVICE_ATTR(soc_id,   S_IRUGO, soc_info_get,  NULL);
+static DEVICE_ATTR(revision, S_IRUGO, soc_info_get,  NULL);
+
+struct device *soc_device_to_device(struct soc_device *soc_dev)
+{
+       return &soc_dev->dev;
+}
+
+static mode_t soc_attribute_mode(struct kobject *kobj,
+                                 struct attribute *attr,
+                                 int index)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
+
+       if ((attr == &dev_attr_machine.attr)
+           && (soc_dev->attr->machine != NULL))
+               return attr->mode;
+       if ((attr == &dev_attr_family.attr)
+           && (soc_dev->attr->family != NULL))
+               return attr->mode;
+       if ((attr == &dev_attr_revision.attr)
+           && (soc_dev->attr->revision != NULL))
+               return attr->mode;
+       if ((attr == &dev_attr_soc_id.attr)
+           && (soc_dev->attr->soc_id != NULL))
+               return attr->mode;
+
+       /* Unknown or unfilled attribute. */
+       return 0;
+}
+
+static ssize_t soc_info_get(struct device *dev,
+                           struct device_attribute *attr,
+                           char *buf)
+{
+       struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
+
+       if (attr == &dev_attr_machine)
+               return sprintf(buf, "%s\n", soc_dev->attr->machine);
+       if (attr == &dev_attr_family)
+               return sprintf(buf, "%s\n", soc_dev->attr->family);
+       if (attr == &dev_attr_revision)
+               return sprintf(buf, "%s\n", soc_dev->attr->revision);
+       if (attr == &dev_attr_soc_id)
+               return sprintf(buf, "%s\n", soc_dev->attr->soc_id);
+
+       return -EINVAL;
+
+}
+
+static struct attribute *soc_attr[] = {
+       &dev_attr_machine.attr,
+       &dev_attr_family.attr,
+       &dev_attr_soc_id.attr,
+       &dev_attr_revision.attr,
+       NULL,
+};
+
+static const struct attribute_group soc_attr_group = {
+       .attrs = soc_attr,
+       .is_visible = soc_attribute_mode,
+};
+
+static const struct attribute_group *soc_attr_groups[] = {
+       &soc_attr_group,
+       NULL,
+};
+
+static void soc_release(struct device *dev)
+{
+       struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
+
+       kfree(soc_dev);
+}
+
+struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr)
+{
+       struct soc_device *soc_dev;
+       int ret;
+
+       soc_dev = kzalloc(sizeof(*soc_dev), GFP_KERNEL);
+       if (!soc_dev) {
+               ret = -ENOMEM;
+               goto out1;
+       }
+
+       /* Fetch a unique (reclaimable) SOC ID. */
+       do {
+               if (!ida_pre_get(&soc_ida, GFP_KERNEL)) {
+                       ret = -ENOMEM;
+                       goto out2;
+               }
+
+               spin_lock(&soc_lock);
+               ret = ida_get_new(&soc_ida, &soc_dev->soc_dev_num);
+               spin_unlock(&soc_lock);
+
+       } while (ret == -EAGAIN);
+
+       if (ret)
+                goto out2;
+
+       soc_dev->attr = soc_dev_attr;
+       soc_dev->dev.bus = &soc_bus_type;
+       soc_dev->dev.groups = soc_attr_groups;
+       soc_dev->dev.release = soc_release;
+
+       dev_set_name(&soc_dev->dev, "soc%d", soc_dev->soc_dev_num);
+
+       ret = device_register(&soc_dev->dev);
+       if (ret)
+               goto out3;
+
+       return soc_dev;
+
+out3:
+       ida_remove(&soc_ida, soc_dev->soc_dev_num);
+out2:
+       kfree(soc_dev);
+out1:
+       return ERR_PTR(ret);
+}
+
+/* Ensure soc_dev->attr is freed prior to calling soc_device_unregister. */
+void soc_device_unregister(struct soc_device *soc_dev)
+{
+       ida_remove(&soc_ida, soc_dev->soc_dev_num);
+
+       device_unregister(&soc_dev->dev);
+}
+
+static int __init soc_bus_register(void)
+{
+       spin_lock_init(&soc_lock);
+
+       return bus_register(&soc_bus_type);
+}
+core_initcall(soc_bus_register);
+
+static void __exit soc_bus_unregister(void)
+{
+       ida_destroy(&soc_ida);
+
+       bus_unregister(&soc_bus_type);
+}
+module_exit(soc_bus_unregister);
index 7bac808..13d311e 100644 (file)
@@ -385,6 +385,14 @@ static struct cpufreq_driver nforce2_driver = {
        .owner = THIS_MODULE,
 };
 
+#ifdef MODULE
+static DEFINE_PCI_DEVICE_TABLE(nforce2_ids) = {
+       { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2 },
+       {}
+};
+MODULE_DEVICE_TABLE(pci, nforce2_ids);
+#endif
+
 /**
  * nforce2_detect_chipset - detect the Southbridge which contains FSB PLL logic
  *
index 4bd6815..3fffbe6 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/io.h>
 #include <linux/delay.h>
 
+#include <asm/cpu_device_id.h>
 #include <asm/msr.h>
 #include <asm/tsc.h>
 
@@ -437,18 +438,19 @@ static struct cpufreq_driver eps_driver = {
        .attr           = eps_attr,
 };
 
+
+/* This driver will work only on Centaur C7 processors with
+ * Enhanced SpeedStep/PowerSaver registers */
+static const struct x86_cpu_id eps_cpu_id[] = {
+       { X86_VENDOR_CENTAUR, 6, X86_MODEL_ANY, X86_FEATURE_EST },
+       {}
+};
+MODULE_DEVICE_TABLE(x86cpu, eps_cpu_id);
+
 static int __init eps_init(void)
 {
-       struct cpuinfo_x86 *c = &cpu_data(0);
-
-       /* This driver will work only on Centaur C7 processors with
-        * Enhanced SpeedStep/PowerSaver registers */
-       if (c->x86_vendor != X86_VENDOR_CENTAUR
-           || c->x86 != 6 || c->x86_model < 10)
-               return -ENODEV;
-       if (!cpu_has(c, X86_FEATURE_EST))
+       if (!x86_match_cpu(eps_cpu_id) || boot_cpu_data.x86_model < 10)
                return -ENODEV;
-
        if (cpufreq_register_driver(&eps_driver))
                return -EINVAL;
        return 0;
index c587db4..960671f 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/delay.h>
 #include <linux/cpufreq.h>
 
+#include <asm/cpu_device_id.h>
 #include <asm/msr.h>
 #include <linux/timex.h>
 #include <linux/io.h>
@@ -277,17 +278,16 @@ static struct cpufreq_driver elanfreq_driver = {
        .attr           = elanfreq_attr,
 };
 
+static const struct x86_cpu_id elan_id[] = {
+       { X86_VENDOR_AMD, 4, 10, },
+       {}
+};
+MODULE_DEVICE_TABLE(x86cpu, elan_id);
 
 static int __init elanfreq_init(void)
 {
-       struct cpuinfo_x86 *c = &cpu_data(0);
-
-       /* Test if we have the right hardware */
-       if ((c->x86_vendor != X86_VENDOR_AMD) ||
-               (c->x86 != 4) || (c->x86_model != 10)) {
-               printk(KERN_INFO "elanfreq: error: no Elan processor found!\n");
+       if (!x86_match_cpu(elan_id))
                return -ENODEV;
-       }
        return cpufreq_register_driver(&elanfreq_driver);
 }
 
index ffe1f2c..456bee0 100644 (file)
@@ -82,6 +82,7 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 
+#include <asm/cpu_device_id.h>
 #include <asm/processor-cyrix.h>
 
 /* PCI config registers, all at F0 */
@@ -171,6 +172,7 @@ static struct pci_device_id gx_chipset_tbl[] __initdata = {
        { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5510), },
        { 0, },
 };
+MODULE_DEVICE_TABLE(pci, gx_chipset_tbl);
 
 static void gx_write_byte(int reg, int value)
 {
@@ -185,13 +187,6 @@ static __init struct pci_dev *gx_detect_chipset(void)
 {
        struct pci_dev *gx_pci = NULL;
 
-       /* check if CPU is a MediaGX or a Geode. */
-       if ((boot_cpu_data.x86_vendor != X86_VENDOR_NSC) &&
-           (boot_cpu_data.x86_vendor != X86_VENDOR_CYRIX)) {
-               pr_debug("error: no MediaGX/Geode processor found!\n");
-               return NULL;
-       }
-
        /* detect which companion chip is used */
        for_each_pci_dev(gx_pci) {
                if ((pci_match_id(gx_chipset_tbl, gx_pci)) != NULL)
index f47d26e..53ddbc7 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/acpi.h>
 
 #include <asm/msr.h>
+#include <asm/cpu_device_id.h>
 #include <acpi/processor.h>
 
 #include "longhaul.h"
@@ -951,12 +952,17 @@ static struct cpufreq_driver longhaul_driver = {
        .attr   = longhaul_attr,
 };
 
+static const struct x86_cpu_id longhaul_id[] = {
+       { X86_VENDOR_CENTAUR, 6 },
+       {}
+};
+MODULE_DEVICE_TABLE(x86cpu, longhaul_id);
 
 static int __init longhaul_init(void)
 {
        struct cpuinfo_x86 *c = &cpu_data(0);
 
-       if (c->x86_vendor != X86_VENDOR_CENTAUR || c->x86 != 6)
+       if (!x86_match_cpu(longhaul_id))
                return -ENODEV;
 
 #ifdef CONFIG_SMP
index 34ea359..8bc9f5f 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <asm/msr.h>
 #include <asm/processor.h>
+#include <asm/cpu_device_id.h>
 
 static struct cpufreq_driver   longrun_driver;
 
@@ -288,6 +289,12 @@ static struct cpufreq_driver longrun_driver = {
        .owner          = THIS_MODULE,
 };
 
+static const struct x86_cpu_id longrun_ids[] = {
+       { X86_VENDOR_TRANSMETA, X86_FAMILY_ANY, X86_MODEL_ANY,
+         X86_FEATURE_LONGRUN },
+       {}
+};
+MODULE_DEVICE_TABLE(x86cpu, longrun_ids);
 
 /**
  * longrun_init - initializes the Transmeta Crusoe LongRun CPUFreq driver
@@ -296,12 +303,8 @@ static struct cpufreq_driver longrun_driver = {
  */
 static int __init longrun_init(void)
 {
-       struct cpuinfo_x86 *c = &cpu_data(0);
-
-       if (c->x86_vendor != X86_VENDOR_TRANSMETA ||
-           !cpu_has(c, X86_FEATURE_LONGRUN))
+       if (!x86_match_cpu(longrun_ids))
                return -ENODEV;
-
        return cpufreq_register_driver(&longrun_driver);
 }
 
index 6be3e07..827629c 100644 (file)
@@ -31,6 +31,7 @@
 #include <asm/processor.h>
 #include <asm/msr.h>
 #include <asm/timer.h>
+#include <asm/cpu_device_id.h>
 
 #include "speedstep-lib.h"
 
@@ -289,21 +290,25 @@ static struct cpufreq_driver p4clockmod_driver = {
        .attr           = p4clockmod_attr,
 };
 
+static const struct x86_cpu_id cpufreq_p4_id[] = {
+       { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_ACC },
+       {}
+};
+
+/*
+ * Intentionally no MODULE_DEVICE_TABLE here: this driver should not
+ * be auto loaded.  Please don't add one.
+ */
 
 static int __init cpufreq_p4_init(void)
 {
-       struct cpuinfo_x86 *c = &cpu_data(0);
        int ret;
 
        /*
         * THERM_CONTROL is architectural for IA32 now, so
         * we can rely on the capability checks
         */
-       if (c->x86_vendor != X86_VENDOR_INTEL)
-               return -ENODEV;
-
-       if (!test_cpu_cap(c, X86_FEATURE_ACPI) ||
-                               !test_cpu_cap(c, X86_FEATURE_ACC))
+       if (!x86_match_cpu(cpufreq_p4_id) || !boot_cpu_has(X86_FEATURE_ACPI))
                return -ENODEV;
 
        ret = cpufreq_register_driver(&p4clockmod_driver);
index b3379d6..54dd031 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/timex.h>
 #include <linux/io.h>
 
+#include <asm/cpu_device_id.h>
 #include <asm/msr.h>
 
 #define POWERNOW_IOPORT 0xfff0          /* it doesn't matter where, as long
@@ -210,6 +211,12 @@ static struct cpufreq_driver powernow_k6_driver = {
        .attr           = powernow_k6_attr,
 };
 
+static const struct x86_cpu_id powernow_k6_ids[] = {
+       { X86_VENDOR_AMD, 5, 12 },
+       { X86_VENDOR_AMD, 5, 13 },
+       {}
+};
+
 
 /**
  * powernow_k6_init - initializes the k6 PowerNow! CPUFreq driver
@@ -220,10 +227,7 @@ static struct cpufreq_driver powernow_k6_driver = {
  */
 static int __init powernow_k6_init(void)
 {
-       struct cpuinfo_x86 *c = &cpu_data(0);
-
-       if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 5) ||
-               ((c->x86_model != 12) && (c->x86_model != 13)))
+       if (!x86_match_cpu(powernow_k6_ids))
                return -ENODEV;
 
        if (!request_region(POWERNOW_IOPORT, 16, "PowerNow!")) {
index d71d9f3..501d167 100644 (file)
@@ -28,6 +28,7 @@
 #include <asm/timer.h>         /* Needed for recalibrate_cpu_khz() */
 #include <asm/msr.h>
 #include <asm/system.h>
+#include <asm/cpu_device_id.h>
 
 #ifdef CONFIG_X86_POWERNOW_K7_ACPI
 #include <linux/acpi.h>
@@ -110,18 +111,19 @@ static int check_fsb(unsigned int fsbspeed)
        return delta < 5;
 }
 
+static const struct x86_cpu_id powernow_k7_cpuids[] = {
+       { X86_VENDOR_AMD, 7, },
+       {}
+};
+MODULE_DEVICE_TABLE(x86cpu, powernow_k7_cpuids);
+
 static int check_powernow(void)
 {
        struct cpuinfo_x86 *c = &cpu_data(0);
        unsigned int maxei, eax, ebx, ecx, edx;
 
-       if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 6)) {
-#ifdef MODULE
-               printk(KERN_INFO PFX "This module only works with "
-                               "AMD K7 CPUs\n");
-#endif
+       if (!x86_match_cpu(powernow_k7_cpuids))
                return 0;
-       }
 
        /* Get maximum capabilities */
        maxei = cpuid_eax(0x80000000);
index 8f9b2ce..c0e8164 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/delay.h>
 
 #include <asm/msr.h>
+#include <asm/cpu_device_id.h>
 
 #include <linux/acpi.h>
 #include <linux/mutex.h>
@@ -520,6 +521,15 @@ static int core_voltage_post_transition(struct powernow_k8_data *data,
        return 0;
 }
 
+static const struct x86_cpu_id powernow_k8_ids[] = {
+       /* IO based frequency switching */
+       { X86_VENDOR_AMD, 0xf },
+       /* MSR based frequency switching supported */
+       X86_FEATURE_MATCH(X86_FEATURE_HW_PSTATE),
+       {}
+};
+MODULE_DEVICE_TABLE(x86cpu, powernow_k8_ids);
+
 static void check_supported_cpu(void *_rc)
 {
        u32 eax, ebx, ecx, edx;
@@ -527,13 +537,7 @@ static void check_supported_cpu(void *_rc)
 
        *rc = -ENODEV;
 
-       if (__this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_AMD)
-               return;
-
        eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
-       if (((eax & CPUID_XFAM) != CPUID_XFAM_K8) &&
-           ((eax & CPUID_XFAM) < CPUID_XFAM_10H))
-               return;
 
        if ((eax & CPUID_XFAM) == CPUID_XFAM_K8) {
                if (((eax & CPUID_USE_XFAM_XMOD) != CPUID_USE_XFAM_XMOD) ||
@@ -1553,6 +1557,9 @@ static int __cpuinit powernowk8_init(void)
        unsigned int i, supported_cpus = 0, cpu;
        int rv;
 
+       if (!x86_match_cpu(powernow_k8_ids))
+               return -ENODEV;
+
        for_each_online_cpu(i) {
                int rc;
                smp_call_function_single(i, check_supported_cpu, &rc, 1);
index 1e205e6..e42e073 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/timex.h>
 #include <linux/io.h>
 
+#include <asm/cpu_device_id.h>
 #include <asm/msr.h>
 
 #define MMCR_BASE      0xfffef000      /* The default base address */
@@ -150,18 +151,19 @@ static struct cpufreq_driver sc520_freq_driver = {
        .attr   = sc520_freq_attr,
 };
 
+static const struct x86_cpu_id sc520_ids[] = {
+       { X86_VENDOR_AMD, 4, 9 },
+       {}
+};
+MODULE_DEVICE_TABLE(x86cpu, sc520_ids);
 
 static int __init sc520_freq_init(void)
 {
-       struct cpuinfo_x86 *c = &cpu_data(0);
        int err;
 
-       /* Test if we have the right hardware */
-       if (c->x86_vendor != X86_VENDOR_AMD ||
-           c->x86 != 4 || c->x86_model != 9) {
-               pr_debug("no Elan SC520 processor found!\n");
+       if (!x86_match_cpu(sc520_ids))
                return -ENODEV;
-       }
+
        cpuctl = ioremap((unsigned long)(MMCR_BASE + OFFS_CPUCTL), 1);
        if (!cpuctl) {
                printk(KERN_ERR "sc520_freq: error: failed to remap memory\n");
index 6ea3455..3a953d5 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/msr.h>
 #include <asm/processor.h>
 #include <asm/cpufeature.h>
+#include <asm/cpu_device_id.h>
 
 #define PFX            "speedstep-centrino: "
 #define MAINTAINER     "cpufreq@vger.kernel.org"
@@ -595,6 +596,24 @@ static struct cpufreq_driver centrino_driver = {
        .owner          = THIS_MODULE,
 };
 
+/*
+ * This doesn't replace the detailed checks above because
+ * the generic CPU IDs don't have a way to match for steppings
+ * or ASCII model IDs.
+ */
+static const struct x86_cpu_id centrino_ids[] = {
+       { X86_VENDOR_INTEL, 6, 9, X86_FEATURE_EST },
+       { X86_VENDOR_INTEL, 6, 13, X86_FEATURE_EST },
+       { X86_VENDOR_INTEL, 6, 13, X86_FEATURE_EST },
+       { X86_VENDOR_INTEL, 6, 13, X86_FEATURE_EST },
+       { X86_VENDOR_INTEL, 15, 3, X86_FEATURE_EST },
+       { X86_VENDOR_INTEL, 15, 4, X86_FEATURE_EST },
+       {}
+};
+#if 0
+/* Autoload or not? Do not for now. */
+MODULE_DEVICE_TABLE(x86cpu, centrino_ids);
+#endif
 
 /**
  * centrino_init - initializes the Enhanced SpeedStep CPUFreq driver
@@ -612,11 +631,8 @@ static struct cpufreq_driver centrino_driver = {
  */
 static int __init centrino_init(void)
 {
-       struct cpuinfo_x86 *cpu = &cpu_data(0);
-
-       if (!cpu_has(cpu, X86_FEATURE_EST))
+       if (!x86_match_cpu(centrino_ids))
                return -ENODEV;
-
        return cpufreq_register_driver(&centrino_driver);
 }
 
index a748ce7..7432b3a 100644 (file)
@@ -25,6 +25,8 @@
 #include <linux/pci.h>
 #include <linux/sched.h>
 
+#include <asm/cpu_device_id.h>
+
 #include "speedstep-lib.h"
 
 
@@ -388,6 +390,16 @@ static struct cpufreq_driver speedstep_driver = {
        .attr   = speedstep_attr,
 };
 
+static const struct x86_cpu_id ss_smi_ids[] = {
+       { X86_VENDOR_INTEL, 6, 0xb, },
+       { X86_VENDOR_INTEL, 6, 0x8, },
+       { X86_VENDOR_INTEL, 15, 2 },
+       {}
+};
+#if 0
+/* Autoload or not? Do not for now. */
+MODULE_DEVICE_TABLE(x86cpu, ss_smi_ids);
+#endif
 
 /**
  * speedstep_init - initializes the SpeedStep CPUFreq driver
@@ -398,6 +410,9 @@ static struct cpufreq_driver speedstep_driver = {
  */
 static int __init speedstep_init(void)
 {
+       if (!x86_match_cpu(ss_smi_ids))
+               return -ENODEV;
+
        /* detect processor */
        speedstep_processor = speedstep_detect_processor();
        if (!speedstep_processor) {
index 8af2d2f..7047821 100644 (file)
@@ -249,6 +249,7 @@ EXPORT_SYMBOL_GPL(speedstep_get_frequency);
  *                 DETECT SPEEDSTEP-CAPABLE PROCESSOR                *
  *********************************************************************/
 
+/* Keep in sync with the x86_cpu_id tables in the different modules */
 unsigned int speedstep_detect_processor(void)
 {
        struct cpuinfo_x86 *c = &cpu_data(0);
index c76ead3..6a457fc 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <asm/ist.h>
+#include <asm/cpu_device_id.h>
 
 #include "speedstep-lib.h"
 
@@ -379,6 +380,17 @@ static struct cpufreq_driver speedstep_driver = {
        .attr           = speedstep_attr,
 };
 
+static const struct x86_cpu_id ss_smi_ids[] = {
+       { X86_VENDOR_INTEL, 6, 0xb, },
+       { X86_VENDOR_INTEL, 6, 0x8, },
+       { X86_VENDOR_INTEL, 15, 2 },
+       {}
+};
+#if 0
+/* Not auto loaded currently */
+MODULE_DEVICE_TABLE(x86cpu, ss_smi_ids);
+#endif
+
 /**
  * speedstep_init - initializes the SpeedStep CPUFreq driver
  *
@@ -388,6 +400,9 @@ static struct cpufreq_driver speedstep_driver = {
  */
 static int __init speedstep_init(void)
 {
+       if (!x86_match_cpu(ss_smi_ids))
+               return -ENODEV;
+
        speedstep_processor = speedstep_detect_processor();
 
        switch (speedstep_processor) {
index 29b9469..37b2e94 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/percpu.h>
 #include <linux/smp.h>
 #include <linux/slab.h>
+#include <asm/cpu_device_id.h>
 #include <asm/byteorder.h>
 #include <asm/processor.h>
 #include <asm/i387.h>
@@ -503,12 +504,18 @@ static struct crypto_alg cbc_aes_alg = {
        }
 };
 
+static struct x86_cpu_id padlock_cpu_id[] = {
+       X86_FEATURE_MATCH(X86_FEATURE_XCRYPT),
+       {}
+};
+MODULE_DEVICE_TABLE(x86cpu, padlock_cpu_id);
+
 static int __init padlock_init(void)
 {
        int ret;
        struct cpuinfo_x86 *c = &cpu_data(0);
 
-       if (!cpu_has_xcrypt)
+       if (!x86_match_cpu(padlock_cpu_id))
                return -ENODEV;
 
        if (!cpu_has_xcrypt_enabled) {
index 06bdb4b..9266c0e 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/scatterlist.h>
+#include <asm/cpu_device_id.h>
 #include <asm/i387.h>
 
 struct padlock_sha_desc {
@@ -526,6 +527,12 @@ static struct shash_alg sha256_alg_nano = {
        }
 };
 
+static struct x86_cpu_id padlock_sha_ids[] = {
+       X86_FEATURE_MATCH(X86_FEATURE_PHE),
+       {}
+};
+MODULE_DEVICE_TABLE(x86cpu, padlock_sha_ids);
+
 static int __init padlock_init(void)
 {
        int rc = -ENODEV;
@@ -533,15 +540,8 @@ static int __init padlock_init(void)
        struct shash_alg *sha1;
        struct shash_alg *sha256;
 
-       if (!cpu_has_phe) {
-               printk(KERN_NOTICE PFX "VIA PadLock Hash Engine not detected.\n");
-               return -ENODEV;
-       }
-
-       if (!cpu_has_phe_enabled) {
-               printk(KERN_NOTICE PFX "VIA PadLock detected, but not enabled. Hmm, strange...\n");
+       if (!x86_match_cpu(padlock_sha_ids) || !cpu_has_phe_enabled)
                return -ENODEV;
-       }
 
        /* Register the newly added algorithm module if on *
        * VIA Nano processor, or else just do as before */
index af08ce7..bce53fa 100644 (file)
@@ -1619,11 +1619,7 @@ static ssize_t store_new_id(struct device_driver *drv, const char *buf,
        list_add_tail(&dynid->list, &hdrv->dyn_list);
        spin_unlock(&hdrv->dyn_lock);
 
-       ret = 0;
-       if (get_driver(&hdrv->driver)) {
-               ret = driver_attach(&hdrv->driver);
-               put_driver(&hdrv->driver);
-       }
+       ret = driver_attach(&hdrv->driver);
 
        return ret ? : count;
 }
index 36484db..9ffbfc5 100644 (file)
@@ -37,81 +37,6 @@ struct vmbus_channel_message_table_entry {
        void (*message_handler)(struct vmbus_channel_message_header *msg);
 };
 
-#define MAX_MSG_TYPES                    4
-#define MAX_NUM_DEVICE_CLASSES_SUPPORTED 8
-
-static const uuid_le
-       supported_device_classes[MAX_NUM_DEVICE_CLASSES_SUPPORTED] = {
-       /* {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */
-       /* Storage - SCSI */
-       {
-               .b  = {
-                       0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d,
-                       0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f
-               }
-       },
-
-       /* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */
-       /* Network */
-       {
-               .b = {
-                       0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46,
-                       0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E
-               }
-       },
-
-       /* {CFA8B69E-5B4A-4cc0-B98B-8BA1A1F3F95A} */
-       /* Input */
-       {
-               .b = {
-                       0x9E, 0xB6, 0xA8, 0xCF, 0x4A, 0x5B, 0xc0, 0x4c,
-                       0xB9, 0x8B, 0x8B, 0xA1, 0xA1, 0xF3, 0xF9, 0x5A
-               }
-       },
-
-       /* {32412632-86cb-44a2-9b5c-50d1417354f5} */
-       /* IDE */
-       {
-               .b = {
-                       0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44,
-                       0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5
-               }
-       },
-       /* 0E0B6031-5213-4934-818B-38D90CED39DB */
-       /* Shutdown */
-       {
-               .b = {
-                       0x31, 0x60, 0x0B, 0X0E, 0x13, 0x52, 0x34, 0x49,
-                       0x81, 0x8B, 0x38, 0XD9, 0x0C, 0xED, 0x39, 0xDB
-               }
-       },
-       /* {9527E630-D0AE-497b-ADCE-E80AB0175CAF} */
-       /* TimeSync */
-       {
-               .b = {
-                       0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49,
-                       0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf
-               }
-       },
-       /* {57164f39-9115-4e78-ab55-382f3bd5422d} */
-       /* Heartbeat */
-       {
-               .b = {
-                       0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e,
-                       0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d
-               }
-       },
-       /* {A9A0F4E7-5A45-4d96-B827-8A841E8C03E6} */
-       /* KVP */
-       {
-               .b = {
-                       0xe7, 0xf4, 0xa0, 0xa9, 0x45, 0x5a, 0x96, 0x4d,
-                       0xb8, 0x27, 0x8a, 0x84, 0x1e, 0x8c, 0x3,  0xe6
-       }
-       },
-
-};
-
 
 /**
  * vmbus_prep_negotiate_resp() - Create default response for Hyper-V Negotiate message
@@ -321,20 +246,8 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
        struct vmbus_channel *newchannel;
        uuid_le *guidtype;
        uuid_le *guidinstance;
-       int i;
-       int fsupported = 0;
 
        offer = (struct vmbus_channel_offer_channel *)hdr;
-       for (i = 0; i < MAX_NUM_DEVICE_CLASSES_SUPPORTED; i++) {
-               if (!uuid_le_cmp(offer->offer.if_type,
-                               supported_device_classes[i])) {
-                       fsupported = 1;
-                       break;
-               }
-       }
-
-       if (!fsupported)
-               return;
 
        guidtype = &offer->offer.if_type;
        guidinstance = &offer->offer.if_instance;
index 12aa97f..15956bd 100644 (file)
@@ -155,9 +155,9 @@ int hv_init(void)
        union hv_x64_msr_hypercall_contents hypercall_msr;
        void *virtaddr = NULL;
 
-       memset(hv_context.synic_event_page, 0, sizeof(void *) * MAX_NUM_CPUS);
+       memset(hv_context.synic_event_page, 0, sizeof(void *) * NR_CPUS);
        memset(hv_context.synic_message_page, 0,
-              sizeof(void *) * MAX_NUM_CPUS);
+              sizeof(void *) * NR_CPUS);
 
        if (!query_hypervisor_presence())
                goto cleanup;
index 0e8343f..0ef4c1f 100644 (file)
@@ -28,8 +28,6 @@
 #include <linux/workqueue.h>
 #include <linux/hyperv.h>
 
-#include "hv_kvp.h"
-
 
 
 /*
@@ -73,15 +71,20 @@ kvp_register(void)
 {
 
        struct cn_msg *msg;
+       struct hv_kvp_msg *kvp_msg;
+       char *version;
 
-       msg = kzalloc(sizeof(*msg) + strlen(HV_DRV_VERSION) + 1 , GFP_ATOMIC);
+       msg = kzalloc(sizeof(*msg) + sizeof(struct hv_kvp_msg), GFP_ATOMIC);
 
        if (msg) {
+               kvp_msg = (struct hv_kvp_msg *)msg->data;
+               version = kvp_msg->body.kvp_version;
                msg->id.idx =  CN_KVP_IDX;
                msg->id.val = CN_KVP_VAL;
-               msg->seq = KVP_REGISTER;
-               strcpy(msg->data, HV_DRV_VERSION);
-               msg->len = strlen(HV_DRV_VERSION) + 1;
+
+               kvp_msg->kvp_hdr.operation = KVP_OP_REGISTER;
+               strcpy(version, HV_DRV_VERSION);
+               msg->len = sizeof(struct hv_kvp_msg);
                cn_netlink_send(msg, 0, GFP_ATOMIC);
                kfree(msg);
        }
@@ -103,23 +106,24 @@ kvp_work_func(struct work_struct *dummy)
 static void
 kvp_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
 {
-       struct hv_ku_msg *message;
+       struct hv_kvp_msg *message;
+       struct hv_kvp_msg_enumerate *data;
 
-       message = (struct hv_ku_msg *)msg->data;
-       if (msg->seq == KVP_REGISTER) {
+       message = (struct hv_kvp_msg *)msg->data;
+       if (message->kvp_hdr.operation == KVP_OP_REGISTER) {
                pr_info("KVP: user-mode registering done.\n");
                kvp_register();
        }
 
-       if (msg->seq == KVP_USER_SET) {
+       if (message->kvp_hdr.operation == KVP_OP_ENUMERATE) {
+               data = &message->body.kvp_enum_data;
                /*
                 * Complete the transaction by forwarding the key value
                 * to the host. But first, cancel the timeout.
                 */
                if (cancel_delayed_work_sync(&kvp_work))
-                       kvp_respond_to_host(message->kvp_key,
-                                               message->kvp_value,
-                                               !strlen(message->kvp_key));
+                       kvp_respond_to_host(data->data.key, data->data.value,
+                                       !strlen(data->data.key));
        }
 }
 
@@ -127,6 +131,7 @@ static void
 kvp_send_key(struct work_struct *dummy)
 {
        struct cn_msg *msg;
+       struct hv_kvp_msg *message;
        int index = kvp_transaction.index;
 
        msg = kzalloc(sizeof(*msg) + sizeof(struct hv_kvp_msg) , GFP_ATOMIC);
@@ -134,9 +139,11 @@ kvp_send_key(struct work_struct *dummy)
        if (msg) {
                msg->id.idx =  CN_KVP_IDX;
                msg->id.val = CN_KVP_VAL;
-               msg->seq = KVP_KERNEL_GET;
-               ((struct hv_ku_msg *)msg->data)->kvp_index = index;
-               msg->len = sizeof(struct hv_ku_msg);
+
+               message = (struct hv_kvp_msg *)msg->data;
+               message->kvp_hdr.operation = KVP_OP_ENUMERATE;
+               message->body.kvp_enum_data.index = index;
+               msg->len = sizeof(struct hv_kvp_msg);
                cn_netlink_send(msg, 0, GFP_ATOMIC);
                kfree(msg);
        }
@@ -193,7 +200,7 @@ kvp_respond_to_host(char *key, char *value, int error)
        kvp_msg = (struct hv_kvp_msg *)
                        &recv_buffer[sizeof(struct vmbuspipe_hdr) +
                        sizeof(struct icmsg_hdr)];
-       kvp_data = &kvp_msg->kvp_data;
+       kvp_data = &kvp_msg->body.kvp_enum_data;
        key_name = key;
 
        /*
@@ -268,7 +275,7 @@ void hv_kvp_onchannelcallback(void *context)
                                sizeof(struct vmbuspipe_hdr) +
                                sizeof(struct icmsg_hdr)];
 
-                       kvp_data = &kvp_msg->kvp_data;
+                       kvp_data = &kvp_msg->body.kvp_enum_data;
 
                        /*
                         * We only support the "get" operation on
diff --git a/drivers/hv/hv_kvp.h b/drivers/hv/hv_kvp.h
deleted file mode 100644 (file)
index 9b765d7..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * An implementation of HyperV key value pair (KVP) functionality for Linux.
- *
- *
- * Copyright (C) 2010, Novell, Inc.
- * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
- *
- * 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, GOOD TITLE or
- * NON INFRINGEMENT.  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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-#ifndef        _KVP_H
-#define        _KVP_H_
-
-/*
- * Maximum value size - used for both key names and value data, and includes
- * any applicable NULL terminators.
- *
- * Note:  This limit is somewhat arbitrary, but falls easily within what is
- * supported for all native guests (back to Win 2000) and what is reasonable
- * for the IC KVP exchange functionality.  Note that Windows Me/98/95 are
- * limited to 255 character key names.
- *
- * MSDN recommends not storing data values larger than 2048 bytes in the
- * registry.
- *
- * Note:  This value is used in defining the KVP exchange message - this value
- * cannot be modified without affecting the message size and compatibility.
- */
-
-/*
- * bytes, including any null terminators
- */
-#define HV_KVP_EXCHANGE_MAX_VALUE_SIZE          (2048)
-
-
-/*
- * Maximum key size - the registry limit for the length of an entry name
- * is 256 characters, including the null terminator
- */
-
-#define HV_KVP_EXCHANGE_MAX_KEY_SIZE            (512)
-
-/*
- * In Linux, we implement the KVP functionality in two components:
- * 1) The kernel component which is packaged as part of the hv_utils driver
- * is responsible for communicating with the host and responsible for
- * implementing the host/guest protocol. 2) A user level daemon that is
- * responsible for data gathering.
- *
- * Host/Guest Protocol: The host iterates over an index and expects the guest
- * to assign a key name to the index and also return the value corresponding to
- * the key. The host will have atmost one KVP transaction outstanding at any
- * given point in time. The host side iteration stops when the guest returns
- * an error. Microsoft has specified the following mapping of key names to
- * host specified index:
- *
- *     Index           Key Name
- *     0               FullyQualifiedDomainName
- *     1               IntegrationServicesVersion
- *     2               NetworkAddressIPv4
- *     3               NetworkAddressIPv6
- *     4               OSBuildNumber
- *     5               OSName
- *     6               OSMajorVersion
- *     7               OSMinorVersion
- *     8               OSVersion
- *     9               ProcessorArchitecture
- *
- * The Windows host expects the Key Name and Key Value to be encoded in utf16.
- *
- * Guest Kernel/KVP Daemon Protocol: As noted earlier, we implement all of the
- * data gathering functionality in a user mode daemon. The user level daemon
- * is also responsible for binding the key name to the index as well. The
- * kernel and user-level daemon communicate using a connector channel.
- *
- * The user mode component first registers with the
- * the kernel component. Subsequently, the kernel component requests, data
- * for the specified keys. In response to this message the user mode component
- * fills in the value corresponding to the specified key. We overload the
- * sequence field in the cn_msg header to define our KVP message types.
- *
- *
- * The kernel component simply acts as a conduit for communication between the
- * Windows host and the user-level daemon. The kernel component passes up the
- * index received from the Host to the user-level daemon. If the index is
- * valid (supported), the corresponding key as well as its
- * value (both are strings) is returned. If the index is invalid
- * (not supported), a NULL key string is returned.
- */
-
-/*
- *
- * The following definitions are shared with the user-mode component; do not
- * change any of this without making the corresponding changes in
- * the KVP user-mode component.
- */
-
-#define CN_KVP_VAL             0x1 /* This supports queries from the kernel */
-#define CN_KVP_USER_VAL       0x2 /* This supports queries from the user */
-
-enum hv_ku_op {
-       KVP_REGISTER = 0, /* Register the user mode component */
-       KVP_KERNEL_GET, /* Kernel is requesting the value */
-       KVP_KERNEL_SET, /* Kernel is providing the value */
-       KVP_USER_GET,  /* User is requesting the value */
-       KVP_USER_SET  /* User is providing the value */
-};
-
-struct hv_ku_msg {
-       __u32 kvp_index; /* Key index */
-       __u8  kvp_key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; /* Key name */
-       __u8  kvp_value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; /* Key  value */
-};
-
-
-
-
-#ifdef __KERNEL__
-
-/*
- * Registry value types.
- */
-
-#define REG_SZ 1
-
-enum hv_kvp_exchg_op {
-       KVP_OP_GET = 0,
-       KVP_OP_SET,
-       KVP_OP_DELETE,
-       KVP_OP_ENUMERATE,
-       KVP_OP_COUNT /* Number of operations, must be last. */
-};
-
-enum hv_kvp_exchg_pool {
-       KVP_POOL_EXTERNAL = 0,
-       KVP_POOL_GUEST,
-       KVP_POOL_AUTO,
-       KVP_POOL_AUTO_EXTERNAL,
-       KVP_POOL_AUTO_INTERNAL,
-       KVP_POOL_COUNT /* Number of pools, must be last. */
-};
-
-struct hv_kvp_hdr {
-       u8 operation;
-       u8 pool;
-};
-
-struct hv_kvp_exchg_msg_value {
-       u32 value_type;
-       u32 key_size;
-       u32 value_size;
-       u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
-       u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
-};
-
-struct hv_kvp_msg_enumerate {
-       u32 index;
-       struct hv_kvp_exchg_msg_value data;
-};
-
-struct hv_kvp_msg {
-       struct hv_kvp_hdr       kvp_hdr;
-       struct hv_kvp_msg_enumerate     kvp_data;
-};
-
-int hv_kvp_init(struct hv_util_service *);
-void hv_kvp_deinit(void);
-void hv_kvp_onchannelcallback(void *);
-
-#endif /* __KERNEL__ */
-#endif /* _KVP_H */
-
index 55d58f2..dbb8b8e 100644 (file)
@@ -28,9 +28,6 @@
 #include <linux/reboot.h>
 #include <linux/hyperv.h>
 
-#include "hv_kvp.h"
-
-
 static void shutdown_onchannelcallback(void *context);
 static struct hv_util_service util_shutdown = {
        .util_cb = shutdown_onchannelcallback,
index 6d7d286..699f0d8 100644 (file)
@@ -457,7 +457,6 @@ static const uuid_le VMBUS_SERVICE_ID = {
        },
 };
 
-#define MAX_NUM_CPUS   32
 
 
 struct hv_input_signal_event_buffer {
@@ -483,8 +482,8 @@ struct hv_context {
        /* 8-bytes aligned of the buffer above */
        struct hv_input_signal_event *signal_event_param;
 
-       void *synic_message_page[MAX_NUM_CPUS];
-       void *synic_event_page[MAX_NUM_CPUS];
+       void *synic_message_page[NR_CPUS];
+       void *synic_event_page[NR_CPUS];
 };
 
 extern struct hv_context hv_context;
index a6c6ec3..249ac46 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/moduleparam.h>
 #include <asm/msr.h>
 #include <asm/processor.h>
+#include <asm/cpu_device_id.h>
 
 #define DRVNAME        "coretemp"
 
@@ -759,13 +760,23 @@ static struct notifier_block coretemp_cpu_notifier __refdata = {
        .notifier_call = coretemp_cpu_callback,
 };
 
+static const struct x86_cpu_id coretemp_ids[] = {
+       { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, X86_FEATURE_DTS },
+       {}
+};
+MODULE_DEVICE_TABLE(x86cpu, coretemp_ids);
+
 static int __init coretemp_init(void)
 {
        int i, err = -ENODEV;
 
-       /* quick check if we run Intel */
-       if (cpu_data(0).x86_vendor != X86_VENDOR_INTEL)
-               goto exit;
+       /*
+        * CPUID.06H.EAX[0] indicates whether the CPU has thermal
+        * sensors. We check this bit only, all the early CPUs
+        * without thermal sensors will be filtered out.
+        */
+       if (!x86_match_cpu(coretemp_ids))
+               return -ENODEV;
 
        err = platform_driver_register(&coretemp_driver);
        if (err)
index 8eac67d..8689664 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/cpu.h>
 #include <asm/msr.h>
 #include <asm/processor.h>
+#include <asm/cpu_device_id.h>
 
 #define DRVNAME        "via_cputemp"
 
@@ -308,15 +309,20 @@ static struct notifier_block via_cputemp_cpu_notifier __refdata = {
        .notifier_call = via_cputemp_cpu_callback,
 };
 
+static const struct x86_cpu_id cputemp_ids[] = {
+       { X86_VENDOR_CENTAUR, 6, 0xa, }, /* C7 A */
+       { X86_VENDOR_CENTAUR, 6, 0xd, }, /* C7 D */
+       { X86_VENDOR_CENTAUR, 6, 0xf, }, /* Nano */
+       {}
+};
+MODULE_DEVICE_TABLE(x86cpu, cputemp_ids);
+
 static int __init via_cputemp_init(void)
 {
        int i, err;
 
-       if (cpu_data(0).x86_vendor != X86_VENDOR_CENTAUR) {
-               printk(KERN_DEBUG DRVNAME ": Not a VIA CPU\n");
-               err = -ENODEV;
-               goto exit;
-       }
+       if (!x86_match_cpu(cputemp_ids))
+               return -ENODEV;
 
        err = platform_driver_register(&via_cputemp_driver);
        if (err)
index 54ab97b..237fe57 100644 (file)
@@ -62,6 +62,7 @@
 #include <linux/notifier.h>
 #include <linux/cpu.h>
 #include <linux/module.h>
+#include <asm/cpu_device_id.h>
 #include <asm/mwait.h>
 #include <asm/msr.h>
 
@@ -81,6 +82,17 @@ static unsigned int mwait_substates;
 /* Reliable LAPIC Timer States, bit 1 for C1 etc.  */
 static unsigned int lapic_timer_reliable_states = (1 << 1);     /* Default to only C1 */
 
+struct idle_cpu {
+       struct cpuidle_state *state_table;
+
+       /*
+        * Hardware C-state auto-demotion may not always be optimal.
+        * Indicate which enable bits to clear here.
+        */
+       unsigned long auto_demotion_disable_flags;
+};
+
+static const struct idle_cpu *icpu;
 static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
 static int intel_idle(struct cpuidle_device *dev,
                        struct cpuidle_driver *drv, int index);
@@ -88,12 +100,6 @@ static int intel_idle(struct cpuidle_device *dev,
 static struct cpuidle_state *cpuidle_state_table;
 
 /*
- * Hardware C-state auto-demotion may not always be optimal.
- * Indicate which enable bits to clear here.
- */
-static unsigned long long auto_demotion_disable_flags;
-
-/*
  * Set this flag for states where the HW flushes the TLB for us
  * and so we don't need cross-calls to keep it consistent.
  * If this flag is set, SW flushes the TLB, so even if the
@@ -319,27 +325,72 @@ static void auto_demotion_disable(void *dummy)
        unsigned long long msr_bits;
 
        rdmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits);
-       msr_bits &= ~auto_demotion_disable_flags;
+       msr_bits &= ~(icpu->auto_demotion_disable_flags);
        wrmsrl(MSR_NHM_SNB_PKG_CST_CFG_CTL, msr_bits);
 }
 
+static const struct idle_cpu idle_cpu_nehalem = {
+       .state_table = nehalem_cstates,
+};
+
+static const struct idle_cpu idle_cpu_westmere = {
+       .state_table = nehalem_cstates,
+       .auto_demotion_disable_flags = NHM_C1_AUTO_DEMOTE | NHM_C3_AUTO_DEMOTE,
+};
+
+static const struct idle_cpu idle_cpu_atom = {
+       .state_table = atom_cstates,
+};
+
+static const struct idle_cpu idle_cpu_lincroft = {
+       .state_table = atom_cstates,
+       .auto_demotion_disable_flags = ATM_LNC_C6_AUTO_DEMOTE,
+};
+
+static const struct idle_cpu idle_cpu_snb = {
+       .state_table = snb_cstates,
+};
+
+#define ICPU(model, cpu) \
+       { X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (unsigned long)&cpu }
+
+static const struct x86_cpu_id intel_idle_ids[] = {
+       ICPU(0x1a, idle_cpu_nehalem),
+       ICPU(0x1e, idle_cpu_nehalem),
+       ICPU(0x1f, idle_cpu_nehalem),
+       ICPU(0x25, idle_cpu_westmere),
+       ICPU(0x2c, idle_cpu_westmere),
+       ICPU(0x2f, idle_cpu_westmere),
+       ICPU(0x1c, idle_cpu_atom),
+       ICPU(0x26, idle_cpu_lincroft),
+       ICPU(0x2f, idle_cpu_westmere),
+       ICPU(0x2a, idle_cpu_snb),
+       ICPU(0x2d, idle_cpu_snb),
+       {}
+};
+MODULE_DEVICE_TABLE(x86cpu, intel_idle_ids);
+
 /*
  * intel_idle_probe()
  */
 static int intel_idle_probe(void)
 {
        unsigned int eax, ebx, ecx;
+       const struct x86_cpu_id *id;
 
        if (max_cstate == 0) {
                pr_debug(PREFIX "disabled\n");
                return -EPERM;
        }
 
-       if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
-               return -ENODEV;
-
-       if (!boot_cpu_has(X86_FEATURE_MWAIT))
+       id = x86_match_cpu(intel_idle_ids);
+       if (!id) {
+               if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
+                   boot_cpu_data.x86 == 6)
+                       pr_debug(PREFIX "does not run on family %d model %d\n",
+                               boot_cpu_data.x86, boot_cpu_data.x86_model);
                return -ENODEV;
+       }
 
        if (boot_cpu_data.cpuid_level < CPUID_MWAIT_LEAF)
                return -ENODEV;
@@ -353,43 +404,8 @@ static int intel_idle_probe(void)
 
        pr_debug(PREFIX "MWAIT substates: 0x%x\n", mwait_substates);
 
-
-       if (boot_cpu_data.x86 != 6)     /* family 6 */
-               return -ENODEV;
-
-       switch (boot_cpu_data.x86_model) {
-
-       case 0x1A:      /* Core i7, Xeon 5500 series */
-       case 0x1E:      /* Core i7 and i5 Processor - Lynnfield Jasper Forest */
-       case 0x1F:      /* Core i7 and i5 Processor - Nehalem */
-       case 0x2E:      /* Nehalem-EX Xeon */
-       case 0x2F:      /* Westmere-EX Xeon */
-       case 0x25:      /* Westmere */
-       case 0x2C:      /* Westmere */
-               cpuidle_state_table = nehalem_cstates;
-               auto_demotion_disable_flags =
-                       (NHM_C1_AUTO_DEMOTE | NHM_C3_AUTO_DEMOTE);
-               break;
-
-       case 0x1C:      /* 28 - Atom Processor */
-               cpuidle_state_table = atom_cstates;
-               break;
-
-       case 0x26:      /* 38 - Lincroft Atom Processor */
-               cpuidle_state_table = atom_cstates;
-               auto_demotion_disable_flags = ATM_LNC_C6_AUTO_DEMOTE;
-               break;
-
-       case 0x2A:      /* SNB */
-       case 0x2D:      /* SNB Xeon */
-               cpuidle_state_table = snb_cstates;
-               break;
-
-       default:
-               pr_debug(PREFIX "does not run on family %d model %d\n",
-                       boot_cpu_data.x86, boot_cpu_data.x86_model);
-               return -ENODEV;
-       }
+       icpu = (const struct idle_cpu *)id->driver_data;
+       cpuidle_state_table = icpu->state_table;
 
        if (boot_cpu_has(X86_FEATURE_ARAT))     /* Always Reliable APIC Timer */
                lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE;
@@ -470,7 +486,7 @@ static int intel_idle_cpuidle_driver_init(void)
                drv->state_count += 1;
        }
 
-       if (auto_demotion_disable_flags)
+       if (icpu->auto_demotion_disable_flags)
                on_each_cpu(auto_demotion_disable, NULL, 1);
 
        return 0;
@@ -522,7 +538,7 @@ int intel_idle_cpu_init(int cpu)
                return -EIO;
        }
 
-       if (auto_demotion_disable_flags)
+       if (icpu->auto_demotion_disable_flags)
                smp_call_function_single(cpu, auto_demotion_disable, NULL, 1);
 
        return 0;
index c351aa4..da739d9 100644 (file)
@@ -449,7 +449,6 @@ static ssize_t gameport_rebind_driver(struct device *dev, struct device_attribut
        } else if ((drv = driver_find(buf, &gameport_bus)) != NULL) {
                gameport_disconnect_port(gameport);
                error = gameport_bind_driver(gameport, to_gameport_driver(drv));
-               put_driver(drv);
        } else {
                error = -EINVAL;
        }
index ba70058..d0f7533 100644 (file)
@@ -441,7 +441,6 @@ static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *
        } else if ((drv = driver_find(buf, &serio_bus)) != NULL) {
                serio_disconnect_port(serio);
                error = serio_bind_driver(serio, to_serio_driver(drv));
-               put_driver(drv);
                serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT);
        } else {
                error = -EINVAL;
index a1e6c2a..e118361 100644 (file)
@@ -285,7 +285,6 @@ static void __exit cx18_alsa_exit(void)
 
        drv = driver_find("cx18", &pci_bus_type);
        ret = driver_for_each_device(drv, NULL, NULL, cx18_alsa_exit_callback);
-       put_driver(drv);
 
        cx18_ext_init = NULL;
        printk(KERN_INFO "cx18-alsa: module unload complete\n");
index d0fbfcf..e5e7fa9 100644 (file)
@@ -1293,7 +1293,6 @@ static int __init ivtvfb_init(void)
 
        drv = driver_find("ivtv", &pci_bus_type);
        err = driver_for_each_device(drv, NULL, &registered, ivtvfb_callback_init);
-       put_driver(drv);
        if (!registered) {
                printk(KERN_ERR "ivtvfb:  no cards found\n");
                return -ENODEV;
@@ -1310,7 +1309,6 @@ static void ivtvfb_cleanup(void)
 
        drv = driver_find("ivtv", &pci_bus_type);
        err = driver_for_each_device(drv, NULL, NULL, ivtvfb_callback_cleanup);
-       put_driver(drv);
 }
 
 module_init(ivtvfb_init);
index 8ea4ee1..63eccb5 100644 (file)
@@ -344,16 +344,13 @@ static int fimc_md_register_platform_entities(struct fimc_md *fmd)
                return -ENODEV;
        ret = driver_for_each_device(driver, NULL, fmd,
                                     fimc_register_callback);
-       put_driver(driver);
        if (ret)
                return ret;
 
        driver = driver_find(CSIS_DRIVER_NAME, &platform_bus_type);
-       if (driver) {
+       if (driver)
                ret = driver_for_each_device(driver, NULL, fmd,
                                             csis_register_callback);
-               put_driver(driver);
-       }
        return ret;
 }
 
index 7884bae..f7ca5cc 100644 (file)
@@ -58,7 +58,6 @@ static struct v4l2_subdev *find_and_register_subdev(
        }
 
 done:
-       put_driver(drv);
        return sd;
 }
 
index f320f46..e8c42d6 100644 (file)
@@ -915,9 +915,7 @@ static int phy_probe(struct device *dev)
 
        phydev = to_phy_device(dev);
 
-       /* Make sure the driver is held.
-        * XXX -- Is this correct? */
-       drv = get_driver(phydev->dev.driver);
+       drv = phydev->dev.driver;
        phydrv = to_phy_driver(drv);
        phydev->drv = phydrv;
 
@@ -957,8 +955,6 @@ static int phy_remove(struct device *dev)
 
        if (phydev->drv->remove)
                phydev->drv->remove(phydev);
-
-       put_driver(dev->driver);
        phydev->drv = NULL;
 
        return 0;
index 3623d65..8d9616b 100644 (file)
@@ -72,9 +72,7 @@ int pci_add_dynid(struct pci_driver *drv,
        list_add_tail(&dynid->node, &drv->dynids.list);
        spin_unlock(&drv->dynids.lock);
 
-       get_driver(&drv->driver);
        retval = driver_attach(&drv->driver);
-       put_driver(&drv->driver);
 
        return retval;
 }
@@ -190,43 +188,34 @@ store_remove_id(struct device_driver *driver, const char *buf, size_t count)
 static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_remove_id);
 
 static int
-pci_create_newid_file(struct pci_driver *drv)
+pci_create_newid_files(struct pci_driver *drv)
 {
        int error = 0;
-       if (drv->probe != NULL)
-               error = driver_create_file(&drv->driver, &driver_attr_new_id);
-       return error;
-}
-
-static void pci_remove_newid_file(struct pci_driver *drv)
-{
-       driver_remove_file(&drv->driver, &driver_attr_new_id);
-}
 
-static int
-pci_create_removeid_file(struct pci_driver *drv)
-{
-       int error = 0;
-       if (drv->probe != NULL)
-               error = driver_create_file(&drv->driver,&driver_attr_remove_id);
+       if (drv->probe != NULL) {
+               error = driver_create_file(&drv->driver, &driver_attr_new_id);
+               if (error == 0) {
+                       error = driver_create_file(&drv->driver,
+                                       &driver_attr_remove_id);
+                       if (error)
+                               driver_remove_file(&drv->driver,
+                                               &driver_attr_new_id);
+               }
+       }
        return error;
 }
 
-static void pci_remove_removeid_file(struct pci_driver *drv)
+static void pci_remove_newid_files(struct pci_driver *drv)
 {
        driver_remove_file(&drv->driver, &driver_attr_remove_id);
+       driver_remove_file(&drv->driver, &driver_attr_new_id);
 }
 #else /* !CONFIG_HOTPLUG */
-static inline int pci_create_newid_file(struct pci_driver *drv)
+static inline int pci_create_newid_files(struct pci_driver *drv)
 {
        return 0;
 }
-static inline void pci_remove_newid_file(struct pci_driver *drv) {}
-static inline int pci_create_removeid_file(struct pci_driver *drv)
-{
-       return 0;
-}
-static inline void pci_remove_removeid_file(struct pci_driver *drv) {}
+static inline void pci_remove_newid_files(struct pci_driver *drv) {}
 #endif
 
 /**
@@ -1138,18 +1127,12 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner,
        if (error)
                goto out;
 
-       error = pci_create_newid_file(drv);
+       error = pci_create_newid_files(drv);
        if (error)
                goto out_newid;
-
-       error = pci_create_removeid_file(drv);
-       if (error)
-               goto out_removeid;
 out:
        return error;
 
-out_removeid:
-       pci_remove_newid_file(drv);
 out_newid:
        driver_unregister(&drv->driver);
        goto out;
@@ -1168,8 +1151,7 @@ out_newid:
 void
 pci_unregister_driver(struct pci_driver *drv)
 {
-       pci_remove_removeid_file(drv);
-       pci_remove_newid_file(drv);
+       pci_remove_newid_files(drv);
        driver_unregister(&drv->driver);
        pci_free_dynids(drv);
 }
index 1620088..4010901 100644 (file)
@@ -593,7 +593,7 @@ static pci_ers_result_t pcifront_common_process(int cmd,
        }
        pdrv = pcidev->driver;
 
-       if (get_driver(&pdrv->driver)) {
+       if (pdrv) {
                if (pdrv->err_handler && pdrv->err_handler->error_detected) {
                        dev_dbg(&pcidev->dev,
                                "trying to call AER service\n");
@@ -623,7 +623,6 @@ static pci_ers_result_t pcifront_common_process(int cmd,
                                }
                        }
                }
-               put_driver(&pdrv->driver);
        }
        if (!flag)
                result = PCI_ERS_RESULT_NONE;
index 1932029..079629b 100644 (file)
@@ -127,10 +127,7 @@ pcmcia_store_new_id(struct device_driver *driver, const char *buf, size_t count)
        list_add_tail(&dynid->node, &pdrv->dynids.list);
        mutex_unlock(&pdrv->dynids.lock);
 
-       if (get_driver(&pdrv->drv)) {
-               retval = driver_attach(&pdrv->drv);
-               put_driver(&pdrv->drv);
-       }
+       retval = driver_attach(&pdrv->drv);
 
        if (retval)
                return retval;
@@ -160,6 +157,11 @@ pcmcia_create_newid_file(struct pcmcia_driver *drv)
        return error;
 }
 
+static void
+pcmcia_remove_newid_file(struct pcmcia_driver *drv)
+{
+       driver_remove_file(&drv->drv, &driver_attr_new_id);
+}
 
 /**
  * pcmcia_register_driver - register a PCMCIA driver with the bus core
@@ -204,6 +206,7 @@ EXPORT_SYMBOL(pcmcia_register_driver);
 void pcmcia_unregister_driver(struct pcmcia_driver *driver)
 {
        pr_debug("unregistering driver %s\n", driver->name);
+       pcmcia_remove_newid_file(driver);
        driver_unregister(&driver->drv);
        pcmcia_free_dynids(driver);
 }
index 4f1989d..5f1dc6f 100644 (file)
@@ -580,7 +580,6 @@ void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver)
        struct device *dev;
 
        /* We don't want ccwgroup devices to live longer than their driver. */
-       get_driver(&cdriver->driver);
        while ((dev = driver_find_device(&cdriver->driver, NULL, NULL,
                                         __ccwgroup_match_all))) {
                struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
@@ -592,7 +591,6 @@ void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver)
                mutex_unlock(&gdev->reg_mutex);
                put_device(dev);
        }
-       put_driver(&cdriver->driver);
        driver_unregister(&cdriver->driver);
 }
 EXPORT_SYMBOL(ccwgroup_driver_unregister);
index 4726985..02d0152 100644 (file)
@@ -1676,15 +1676,9 @@ struct ccw_device *get_ccwdev_by_busid(struct ccw_driver *cdrv,
                                       const char *bus_id)
 {
        struct device *dev;
-       struct device_driver *drv;
 
-       drv = get_driver(&cdrv->driver);
-       if (!drv)
-               return NULL;
-
-       dev = driver_find_device(drv, NULL, (void *)bus_id,
+       dev = driver_find_device(&cdrv->driver, NULL, (void *)bus_id,
                                 __ccwdev_check_busid);
-       put_driver(drv);
 
        return dev ? to_ccwdev(dev) : NULL;
 }
index 4d2ea40..32515a2 100644 (file)
@@ -168,7 +168,7 @@ static int __init smsgiucv_app_init(void)
        rc = dev_set_name(smsg_app_dev, KMSG_COMPONENT);
        if (rc) {
                kfree(smsg_app_dev);
-               goto fail_put_driver;
+               goto fail;
        }
        smsg_app_dev->bus = &iucv_bus;
        smsg_app_dev->parent = iucv_root;
@@ -177,7 +177,7 @@ static int __init smsgiucv_app_init(void)
        rc = device_register(smsg_app_dev);
        if (rc) {
                put_device(smsg_app_dev);
-               goto fail_put_driver;
+               goto fail;
        }
 
        /* convert sender to uppercase characters */
@@ -191,12 +191,11 @@ static int __init smsgiucv_app_init(void)
        rc = smsg_register_callback(SMSG_PREFIX, smsg_app_callback);
        if (rc) {
                device_unregister(smsg_app_dev);
-               goto fail_put_driver;
+               goto fail;
        }
 
        rc = 0;
-fail_put_driver:
-       put_driver(smsgiucv_drv);
+fail:
        return rc;
 }
 module_init(smsgiucv_app_init);
index bb6317f..ff109ae 100644 (file)
@@ -140,19 +140,6 @@ static void ssb_device_put(struct ssb_device *dev)
                put_device(dev->dev);
 }
 
-static inline struct ssb_driver *ssb_driver_get(struct ssb_driver *drv)
-{
-       if (drv)
-               get_driver(&drv->drv);
-       return drv;
-}
-
-static inline void ssb_driver_put(struct ssb_driver *drv)
-{
-       if (drv)
-               put_driver(&drv->drv);
-}
-
 static int ssb_device_resume(struct device *dev)
 {
        struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
@@ -250,11 +237,9 @@ int ssb_devices_freeze(struct ssb_bus *bus, struct ssb_freeze_context *ctx)
                        ssb_device_put(sdev);
                        continue;
                }
-               sdrv = ssb_driver_get(drv_to_ssb_drv(sdev->dev->driver));
-               if (!sdrv || SSB_WARN_ON(!sdrv->remove)) {
-                       ssb_device_put(sdev);
+               sdrv = drv_to_ssb_drv(sdev->dev->driver);
+               if (SSB_WARN_ON(!sdrv->remove))
                        continue;
-               }
                sdrv->remove(sdev);
                ctx->device_frozen[i] = 1;
        }
@@ -293,7 +278,6 @@ int ssb_devices_thaw(struct ssb_freeze_context *ctx)
                                   dev_name(sdev->dev));
                        result = err;
                }
-               ssb_driver_put(sdrv);
                ssb_device_put(sdev);
        }
 
index d40ff95..4fee024 100644 (file)
@@ -71,10 +71,7 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,
        list_add_tail(&dynid->node, &dynids->list);
        spin_unlock(&dynids->lock);
 
-       if (get_driver(driver)) {
-               retval = driver_attach(driver);
-               put_driver(driver);
-       }
+       retval = driver_attach(driver);
 
        if (retval)
                return retval;
@@ -132,43 +129,39 @@ store_remove_id(struct device_driver *driver, const char *buf, size_t count)
 }
 static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_remove_id);
 
-static int usb_create_newid_file(struct usb_driver *usb_drv)
+static int usb_create_newid_files(struct usb_driver *usb_drv)
 {
        int error = 0;
 
        if (usb_drv->no_dynamic_id)
                goto exit;
 
-       if (usb_drv->probe != NULL)
+       if (usb_drv->probe != NULL) {
                error = driver_create_file(&usb_drv->drvwrap.driver,
                                           &driver_attr_new_id);
+               if (error == 0) {
+                       error = driver_create_file(&usb_drv->drvwrap.driver,
+                                       &driver_attr_remove_id);
+                       if (error)
+                               driver_remove_file(&usb_drv->drvwrap.driver,
+                                               &driver_attr_new_id);
+               }
+       }
 exit:
        return error;
 }
 
-static void usb_remove_newid_file(struct usb_driver *usb_drv)
+static void usb_remove_newid_files(struct usb_driver *usb_drv)
 {
        if (usb_drv->no_dynamic_id)
                return;
 
-       if (usb_drv->probe != NULL)
+       if (usb_drv->probe != NULL) {
                driver_remove_file(&usb_drv->drvwrap.driver,
-                                  &driver_attr_new_id);
-}
-
-static int
-usb_create_removeid_file(struct usb_driver *drv)
-{
-       int error = 0;
-       if (drv->probe != NULL)
-               error = driver_create_file(&drv->drvwrap.driver,
                                &driver_attr_remove_id);
-       return error;
-}
-
-static void usb_remove_removeid_file(struct usb_driver *drv)
-{
-       driver_remove_file(&drv->drvwrap.driver, &driver_attr_remove_id);
+               driver_remove_file(&usb_drv->drvwrap.driver,
+                                  &driver_attr_new_id);
+       }
 }
 
 static void usb_free_dynids(struct usb_driver *usb_drv)
@@ -183,22 +176,12 @@ static void usb_free_dynids(struct usb_driver *usb_drv)
        spin_unlock(&usb_drv->dynids.lock);
 }
 #else
-static inline int usb_create_newid_file(struct usb_driver *usb_drv)
+static inline int usb_create_newid_files(struct usb_driver *usb_drv)
 {
        return 0;
 }
 
-static void usb_remove_newid_file(struct usb_driver *usb_drv)
-{
-}
-
-static int
-usb_create_removeid_file(struct usb_driver *drv)
-{
-       return 0;
-}
-
-static void usb_remove_removeid_file(struct usb_driver *drv)
+static void usb_remove_newid_files(struct usb_driver *usb_drv)
 {
 }
 
@@ -875,22 +858,16 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
 
        usbfs_update_special();
 
-       retval = usb_create_newid_file(new_driver);
+       retval = usb_create_newid_files(new_driver);
        if (retval)
                goto out_newid;
 
-       retval = usb_create_removeid_file(new_driver);
-       if (retval)
-               goto out_removeid;
-
        pr_info("%s: registered new interface driver %s\n",
                        usbcore_name, new_driver->name);
 
 out:
        return retval;
 
-out_removeid:
-       usb_remove_newid_file(new_driver);
 out_newid:
        driver_unregister(&new_driver->drvwrap.driver);
 
@@ -917,10 +894,9 @@ void usb_deregister(struct usb_driver *driver)
        pr_info("%s: deregistering interface driver %s\n",
                        usbcore_name, driver->name);
 
-       usb_remove_removeid_file(driver);
-       usb_remove_newid_file(driver);
-       usb_free_dynids(driver);
+       usb_remove_newid_files(driver);
        driver_unregister(&driver->drvwrap.driver);
+       usb_free_dynids(driver);
 
        usbfs_update_special();
 }
index 64e1f7c..c68e427 100644 (file)
@@ -171,14 +171,4 @@ MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer");
 
-static int __devinit dwc3_pci_init(void)
-{
-       return pci_register_driver(&dwc3_pci_driver);
-}
-module_init(dwc3_pci_init);
-
-static void __exit dwc3_pci_exit(void)
-{
-       pci_unregister_driver(&dwc3_pci_driver);
-}
-module_exit(dwc3_pci_exit);
+module_pci_driver(dwc3_pci_driver);
index fcbe742..df600d1 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/w1-gpio.h>
+#include <linux/gpio.h>
 
 #include "../w1.h"
 #include "../w1_int.h"
 
-#include <asm/gpio.h>
-
 static void w1_gpio_write_bit_dir(void *data, u8 bit)
 {
        struct w1_gpio_platform_data *pdata = data;
index 956d5dd..b80bc84 100644 (file)
 #include <linux/debugfs.h>
 #include <linux/fsnotify.h>
 #include <linux/string.h>
+#include <linux/seq_file.h>
+#include <linux/parser.h>
 #include <linux/magic.h>
 #include <linux/slab.h>
 
+#define DEBUGFS_DEFAULT_MODE   0755
+
 static struct vfsmount *debugfs_mount;
 static int debugfs_mount_count;
 static bool debugfs_registered;
@@ -125,11 +129,154 @@ static inline int debugfs_positive(struct dentry *dentry)
        return dentry->d_inode && !d_unhashed(dentry);
 }
 
+struct debugfs_mount_opts {
+       uid_t uid;
+       gid_t gid;
+       umode_t mode;
+};
+
+enum {
+       Opt_uid,
+       Opt_gid,
+       Opt_mode,
+       Opt_err
+};
+
+static const match_table_t tokens = {
+       {Opt_uid, "uid=%u"},
+       {Opt_gid, "gid=%u"},
+       {Opt_mode, "mode=%o"},
+       {Opt_err, NULL}
+};
+
+struct debugfs_fs_info {
+       struct debugfs_mount_opts mount_opts;
+};
+
+static int debugfs_parse_options(char *data, struct debugfs_mount_opts *opts)
+{
+       substring_t args[MAX_OPT_ARGS];
+       int option;
+       int token;
+       char *p;
+
+       opts->mode = DEBUGFS_DEFAULT_MODE;
+
+       while ((p = strsep(&data, ",")) != NULL) {
+               if (!*p)
+                       continue;
+
+               token = match_token(p, tokens, args);
+               switch (token) {
+               case Opt_uid:
+                       if (match_int(&args[0], &option))
+                               return -EINVAL;
+                       opts->uid = option;
+                       break;
+               case Opt_gid:
+                       if (match_octal(&args[0], &option))
+                               return -EINVAL;
+                       opts->gid = option;
+                       break;
+               case Opt_mode:
+                       if (match_octal(&args[0], &option))
+                               return -EINVAL;
+                       opts->mode = option & S_IALLUGO;
+                       break;
+               /*
+                * We might like to report bad mount options here;
+                * but traditionally debugfs has ignored all mount options
+                */
+               }
+       }
+
+       return 0;
+}
+
+static int debugfs_apply_options(struct super_block *sb)
+{
+       struct debugfs_fs_info *fsi = sb->s_fs_info;
+       struct inode *inode = sb->s_root->d_inode;
+       struct debugfs_mount_opts *opts = &fsi->mount_opts;
+
+       inode->i_mode &= ~S_IALLUGO;
+       inode->i_mode |= opts->mode;
+
+       inode->i_uid = opts->uid;
+       inode->i_gid = opts->gid;
+
+       return 0;
+}
+
+static int debugfs_remount(struct super_block *sb, int *flags, char *data)
+{
+       int err;
+       struct debugfs_fs_info *fsi = sb->s_fs_info;
+
+       err = debugfs_parse_options(data, &fsi->mount_opts);
+       if (err)
+               goto fail;
+
+       debugfs_apply_options(sb);
+
+fail:
+       return err;
+}
+
+static int debugfs_show_options(struct seq_file *m, struct dentry *root)
+{
+       struct debugfs_fs_info *fsi = root->d_sb->s_fs_info;
+       struct debugfs_mount_opts *opts = &fsi->mount_opts;
+
+       if (opts->uid != 0)
+               seq_printf(m, ",uid=%u", opts->uid);
+       if (opts->gid != 0)
+               seq_printf(m, ",gid=%u", opts->gid);
+       if (opts->mode != DEBUGFS_DEFAULT_MODE)
+               seq_printf(m, ",mode=%o", opts->mode);
+
+       return 0;
+}
+
+static const struct super_operations debugfs_super_operations = {
+       .statfs         = simple_statfs,
+       .remount_fs     = debugfs_remount,
+       .show_options   = debugfs_show_options,
+};
+
 static int debug_fill_super(struct super_block *sb, void *data, int silent)
 {
        static struct tree_descr debug_files[] = {{""}};
+       struct debugfs_fs_info *fsi;
+       int err;
+
+       save_mount_options(sb, data);
+
+       fsi = kzalloc(sizeof(struct debugfs_fs_info), GFP_KERNEL);
+       sb->s_fs_info = fsi;
+       if (!fsi) {
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       err = debugfs_parse_options(data, &fsi->mount_opts);
+       if (err)
+               goto fail;
+
+       err  =  simple_fill_super(sb, DEBUGFS_MAGIC, debug_files);
+       if (err)
+               goto fail;
+
+       sb->s_op = &debugfs_super_operations;
+
+       debugfs_apply_options(sb);
+
+       return 0;
 
-       return simple_fill_super(sb, DEBUGFS_MAGIC, debug_files);
+fail:
+       kfree(fsi);
+       sb->s_fs_info = NULL;
+       return err;
 }
 
 static struct dentry *debug_mount(struct file_system_type *fs_type,
index 7fdf6a7..dd3779c 100644 (file)
 #include <linux/mutex.h>
 #include <linux/slab.h>
 #include <linux/security.h>
+#include <linux/hash.h>
 #include "sysfs.h"
 
 DEFINE_MUTEX(sysfs_mutex);
 DEFINE_SPINLOCK(sysfs_assoc_lock);
 
+#define to_sysfs_dirent(X) rb_entry((X), struct sysfs_dirent, s_rb);
+
 static DEFINE_SPINLOCK(sysfs_ino_lock);
 static DEFINE_IDA(sysfs_ino_ida);
 
 /**
- *     sysfs_link_sibling - link sysfs_dirent into sibling list
+ *     sysfs_name_hash
+ *     @ns:   Namespace tag to hash
+ *     @name: Null terminated string to hash
+ *
+ *     Returns 31 bit hash of ns + name (so it fits in an off_t )
+ */
+static unsigned int sysfs_name_hash(const void *ns, const char *name)
+{
+       unsigned long hash = init_name_hash();
+       unsigned int len = strlen(name);
+       while (len--)
+               hash = partial_name_hash(*name++, hash);
+       hash = ( end_name_hash(hash) ^ hash_ptr( (void *)ns, 31 ) );
+       hash &= 0x7fffffffU;
+       /* Reserve hash numbers 0, 1 and INT_MAX for magic directory entries */
+       if (hash < 1)
+               hash += 2;
+       if (hash >= INT_MAX)
+               hash = INT_MAX - 1;
+       return hash;
+}
+
+static int sysfs_name_compare(unsigned int hash, const void *ns,
+       const char *name, const struct sysfs_dirent *sd)
+{
+       if (hash != sd->s_hash)
+               return hash - sd->s_hash;
+       if (ns != sd->s_ns)
+               return ns - sd->s_ns;
+       return strcmp(name, sd->s_name);
+}
+
+static int sysfs_sd_compare(const struct sysfs_dirent *left,
+                           const struct sysfs_dirent *right)
+{
+       return sysfs_name_compare(left->s_hash, left->s_ns, left->s_name,
+                                 right);
+}
+
+/**
+ *     sysfs_link_subling - link sysfs_dirent into sibling rbtree
  *     @sd: sysfs_dirent of interest
  *
- *     Link @sd into its sibling list which starts from
+ *     Link @sd into its sibling rbtree which starts from
  *     sd->s_parent->s_dir.children.
  *
  *     Locking:
  *     mutex_lock(sysfs_mutex)
+ *
+ *     RETURNS:
+ *     0 on susccess -EEXIST on failure.
  */
-static void sysfs_link_sibling(struct sysfs_dirent *sd)
+static int sysfs_link_sibling(struct sysfs_dirent *sd)
 {
-       struct sysfs_dirent *parent_sd = sd->s_parent;
-
-       struct rb_node **p;
-       struct rb_node *parent;
-
-       if (sysfs_type(sd) == SYSFS_DIR)
-               parent_sd->s_dir.subdirs++;
-
-       p = &parent_sd->s_dir.inode_tree.rb_node;
-       parent = NULL;
-       while (*p) {
-               parent = *p;
-#define node   rb_entry(parent, struct sysfs_dirent, inode_node)
-               if (sd->s_ino < node->s_ino) {
-                       p = &node->inode_node.rb_left;
-               } else if (sd->s_ino > node->s_ino) {
-                       p = &node->inode_node.rb_right;
-               } else {
-                       printk(KERN_CRIT "sysfs: inserting duplicate inode '%lx'\n",
-                              (unsigned long) sd->s_ino);
-                       BUG();
-               }
-#undef node
-       }
-       rb_link_node(&sd->inode_node, parent, p);
-       rb_insert_color(&sd->inode_node, &parent_sd->s_dir.inode_tree);
-
-       p = &parent_sd->s_dir.name_tree.rb_node;
-       parent = NULL;
-       while (*p) {
-               int c;
-               parent = *p;
-#define node   rb_entry(parent, struct sysfs_dirent, name_node)
-               c = strcmp(sd->s_name, node->s_name);
-               if (c < 0) {
-                       p = &node->name_node.rb_left;
-               } else {
-                       p = &node->name_node.rb_right;
-               }
-#undef node
+       struct rb_node **node = &sd->s_parent->s_dir.children.rb_node;
+       struct rb_node *parent = NULL;
+
+       while (*node) {
+               struct sysfs_dirent *pos;
+               int result;
+
+               pos = to_sysfs_dirent(*node);
+               parent = *node;
+               result = sysfs_sd_compare(sd, pos);
+               if (result < 0)
+                       node = &pos->s_rb.rb_left;
+               else if (result > 0)
+                       node = &pos->s_rb.rb_right;
+               else
+                       return -EEXIST;
        }
-       rb_link_node(&sd->name_node, parent, p);
-       rb_insert_color(&sd->name_node, &parent_sd->s_dir.name_tree);
+       /* add new node and rebalance the tree */
+       rb_link_node(&sd->s_rb, parent, node);
+       rb_insert_color(&sd->s_rb, &sd->s_parent->s_dir.children);
+       return 0;
 }
 
 /**
- *     sysfs_unlink_sibling - unlink sysfs_dirent from sibling list
+ *     sysfs_unlink_sibling - unlink sysfs_dirent from sibling rbtree
  *     @sd: sysfs_dirent of interest
  *
- *     Unlink @sd from its sibling list which starts from
+ *     Unlink @sd from its sibling rbtree which starts from
  *     sd->s_parent->s_dir.children.
  *
  *     Locking:
@@ -99,11 +123,7 @@ static void sysfs_link_sibling(struct sysfs_dirent *sd)
  */
 static void sysfs_unlink_sibling(struct sysfs_dirent *sd)
 {
-       if (sysfs_type(sd) == SYSFS_DIR)
-               sd->s_parent->s_dir.subdirs--;
-
-       rb_erase(&sd->inode_node, &sd->s_parent->s_dir.inode_tree);
-       rb_erase(&sd->name_node, &sd->s_parent->s_dir.name_tree);
+       rb_erase(&sd->s_rb, &sd->s_parent->s_dir.children);
 }
 
 /**
@@ -198,7 +218,7 @@ static void sysfs_deactivate(struct sysfs_dirent *sd)
        rwsem_release(&sd->dep_map, 1, _RET_IP_);
 }
 
-static int sysfs_alloc_ino(ino_t *pino)
+static int sysfs_alloc_ino(unsigned int *pino)
 {
        int ino, rc;
 
@@ -217,7 +237,7 @@ static int sysfs_alloc_ino(ino_t *pino)
        return rc;
 }
 
-static void sysfs_free_ino(ino_t ino)
+static void sysfs_free_ino(unsigned int ino)
 {
        spin_lock(&sysfs_ino_lock);
        ida_remove(&sysfs_ino_ida, ino);
@@ -402,6 +422,7 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
 int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
 {
        struct sysfs_inode_attrs *ps_iattr;
+       int ret;
 
        if (!!sysfs_ns_type(acxt->parent_sd) != !!sd->s_ns) {
                WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n",
@@ -410,12 +431,12 @@ int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
                return -EINVAL;
        }
 
-       if (sysfs_find_dirent(acxt->parent_sd, sd->s_ns, sd->s_name))
-               return -EEXIST;
-
+       sd->s_hash = sysfs_name_hash(sd->s_ns, sd->s_name);
        sd->s_parent = sysfs_get(acxt->parent_sd);
 
-       sysfs_link_sibling(sd);
+       ret = sysfs_link_sibling(sd);
+       if (ret)
+               return ret;
 
        /* Update timestamps on the parent */
        ps_iattr = acxt->parent_sd->s_iattr;
@@ -565,8 +586,8 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
                                       const void *ns,
                                       const unsigned char *name)
 {
-       struct rb_node *p = parent_sd->s_dir.name_tree.rb_node;
-       struct sysfs_dirent *found = NULL;
+       struct rb_node *node = parent_sd->s_dir.children.rb_node;
+       unsigned int hash;
 
        if (!!sysfs_ns_type(parent_sd) != !!ns) {
                WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n",
@@ -575,33 +596,21 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
                return NULL;
        }
 
-       while (p) {
-               int c;
-#define node   rb_entry(p, struct sysfs_dirent, name_node)
-               c = strcmp(name, node->s_name);
-               if (c < 0) {
-                       p = node->name_node.rb_left;
-               } else if (c > 0) {
-                       p = node->name_node.rb_right;
-               } else {
-                       found = node;
-                       p = node->name_node.rb_left;
-               }
-#undef node
-       }
-
-       if (found) {
-               while (found->s_ns != ns) {
-                       p = rb_next(&found->name_node);
-                       if (!p)
-                               return NULL;
-                       found = rb_entry(p, struct sysfs_dirent, name_node);
-                       if (strcmp(name, found->s_name))
-                               return NULL;
-               }
+       hash = sysfs_name_hash(ns, name);
+       while (node) {
+               struct sysfs_dirent *sd;
+               int result;
+
+               sd = to_sysfs_dirent(node);
+               result = sysfs_name_compare(hash, ns, name, sd);
+               if (result < 0)
+                       node = node->rb_left;
+               else if (result > 0)
+                       node = node->rb_right;
+               else
+                       return sd;
        }
-
-       return found;
+       return NULL;
 }
 
 /**
@@ -804,9 +813,9 @@ static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd)
 
        pr_debug("sysfs %s: removing dir\n", dir_sd->s_name);
        sysfs_addrm_start(&acxt, dir_sd);
-       pos = rb_first(&dir_sd->s_dir.inode_tree);
+       pos = rb_first(&dir_sd->s_dir.children);
        while (pos) {
-               struct sysfs_dirent *sd = rb_entry(pos, struct sysfs_dirent, inode_node);
+               struct sysfs_dirent *sd = to_sysfs_dirent(pos);
                pos = rb_next(pos);
                if (sysfs_type(sd) != SYSFS_DIR)
                        sysfs_remove_one(&acxt, sd);
@@ -863,6 +872,7 @@ int sysfs_rename(struct sysfs_dirent *sd,
 
                dup_name = sd->s_name;
                sd->s_name = new_name;
+               sd->s_hash = sysfs_name_hash(sd->s_ns, sd->s_name);
        }
 
        /* Move to the appropriate place in the appropriate directories rbtree. */
@@ -919,38 +929,36 @@ static int sysfs_dir_release(struct inode *inode, struct file *filp)
 }
 
 static struct sysfs_dirent *sysfs_dir_pos(const void *ns,
-       struct sysfs_dirent *parent_sd, ino_t ino, struct sysfs_dirent *pos)
+       struct sysfs_dirent *parent_sd, loff_t hash, struct sysfs_dirent *pos)
 {
        if (pos) {
                int valid = !(pos->s_flags & SYSFS_FLAG_REMOVED) &&
                        pos->s_parent == parent_sd &&
-                       ino == pos->s_ino;
+                       hash == pos->s_hash;
                sysfs_put(pos);
                if (!valid)
                        pos = NULL;
        }
-       if (!pos && (ino > 1) && (ino < INT_MAX)) {
-               struct rb_node *p = parent_sd->s_dir.inode_tree.rb_node;
-               while (p) {
-#define node   rb_entry(p, struct sysfs_dirent, inode_node)
-                       if (ino < node->s_ino) {
-                               pos = node;
-                               p = node->inode_node.rb_left;
-                       } else if (ino > node->s_ino) {
-                               p = node->inode_node.rb_right;
-                       } else {
-                               pos = node;
+       if (!pos && (hash > 1) && (hash < INT_MAX)) {
+               struct rb_node *node = parent_sd->s_dir.children.rb_node;
+               while (node) {
+                       pos = to_sysfs_dirent(node);
+
+                       if (hash < pos->s_hash)
+                               node = node->rb_left;
+                       else if (hash > pos->s_hash)
+                               node = node->rb_right;
+                       else
                                break;
-                       }
-#undef node
                }
        }
+       /* Skip over entries in the wrong namespace */
        while (pos && pos->s_ns != ns) {
-               struct rb_node *p = rb_next(&pos->inode_node);
-               if (!p)
+               struct rb_node *node = rb_next(&pos->s_rb);
+               if (!node)
                        pos = NULL;
                else
-                       pos = rb_entry(p, struct sysfs_dirent, inode_node);
+                       pos = to_sysfs_dirent(node);
        }
        return pos;
 }
@@ -960,11 +968,11 @@ static struct sysfs_dirent *sysfs_dir_next_pos(const void *ns,
 {
        pos = sysfs_dir_pos(ns, parent_sd, ino, pos);
        if (pos) do {
-               struct rb_node *p = rb_next(&pos->inode_node);
-               if (!p)
+               struct rb_node *node = rb_next(&pos->s_rb);
+               if (!node)
                        pos = NULL;
                else
-                       pos = rb_entry(p, struct sysfs_dirent, inode_node);
+                       pos = to_sysfs_dirent(node);
        } while (pos && pos->s_ns != ns);
        return pos;
 }
@@ -1006,7 +1014,7 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
                len = strlen(name);
                ino = pos->s_ino;
                type = dt_type(pos);
-               filp->f_pos = ino;
+               filp->f_pos = pos->s_hash;
                filp->private_data = sysfs_get(pos);
 
                mutex_unlock(&sysfs_mutex);
index 85eb816..4291fd1 100644 (file)
@@ -216,9 +216,6 @@ static void sysfs_refresh_inode(struct sysfs_dirent *sd, struct inode *inode)
                                            iattrs->ia_secdata,
                                            iattrs->ia_secdata_len);
        }
-
-       if (sysfs_type(sd) == SYSFS_DIR)
-               set_nlink(inode, sd->s_dir.subdirs + 2);
 }
 
 int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
index e34f0d9..140f26a 100644 (file)
@@ -36,7 +36,7 @@ struct sysfs_dirent sysfs_root = {
        .s_name         = "",
        .s_count        = ATOMIC_INIT(1),
        .s_flags        = SYSFS_DIR | (KOBJ_NS_TYPE_NONE << SYSFS_NS_TYPE_SHIFT),
-       .s_mode         = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
+       .s_mode         = S_IFDIR | S_IRUGO | S_IXUGO,
        .s_ino          = 1,
 };
 
index 7484a36..6289a00 100644 (file)
@@ -19,10 +19,8 @@ struct sysfs_open_dirent;
 struct sysfs_elem_dir {
        struct kobject          *kobj;
 
-       unsigned long           subdirs;
-
-       struct rb_root          inode_tree;
-       struct rb_root          name_tree;
+       /* children rbtree starts here and goes through sd->s_rb */
+       struct rb_root          children;
 };
 
 struct sysfs_elem_symlink {
@@ -62,8 +60,7 @@ struct sysfs_dirent {
        struct sysfs_dirent     *s_parent;
        const char              *s_name;
 
-       struct rb_node          inode_node;
-       struct rb_node          name_node;
+       struct rb_node          s_rb;
 
        union {
                struct completion       *completion;
@@ -71,6 +68,7 @@ struct sysfs_dirent {
        } u;
 
        const void              *s_ns; /* namespace tag */
+       unsigned int            s_hash; /* ns + name hash */
        union {
                struct sysfs_elem_dir           s_dir;
                struct sysfs_elem_symlink       s_symlink;
@@ -78,9 +76,9 @@ struct sysfs_dirent {
                struct sysfs_elem_bin_attr      s_bin_attr;
        };
 
-       unsigned int            s_flags;
+       unsigned short          s_flags;
        umode_t                 s_mode;
-       ino_t                   s_ino;
+       unsigned int            s_ino;
        struct sysfs_inode_attrs *s_iattr;
 };
 
@@ -95,11 +93,11 @@ struct sysfs_dirent {
 #define SYSFS_ACTIVE_REF               (SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR)
 
 /* identify any namespace tag on sysfs_dirents */
-#define SYSFS_NS_TYPE_MASK             0xff00
+#define SYSFS_NS_TYPE_MASK             0xf00
 #define SYSFS_NS_TYPE_SHIFT            8
 
 #define SYSFS_FLAG_MASK                        ~(SYSFS_NS_TYPE_MASK|SYSFS_TYPE_MASK)
-#define SYSFS_FLAG_REMOVED             0x020000
+#define SYSFS_FLAG_REMOVED             0x02000
 
 static inline unsigned int sysfs_type(struct sysfs_dirent *sd)
 {
index 8cf7e98..9d65047 100644 (file)
@@ -225,6 +225,7 @@ struct acpi_processor_errata {
        } piix4;
 };
 
+extern void acpi_processor_load_module(struct acpi_processor *pr);
 extern int acpi_processor_preregister_performance(struct
                                                  acpi_processor_performance
                                                  __percpu *performance);
index 3c9c54f..7638407 100644 (file)
@@ -43,6 +43,7 @@
 #define CN_IDX_DRBD                    0x8
 #define CN_VAL_DRBD                    0x1
 #define CN_KVP_IDX                     0x9     /* HyperV KVP */
+#define CN_KVP_VAL                     0x1     /* queries from the kernel */
 
 #define CN_NETLINK_USERS               10      /* Highest index + 1 */
 
index 1f65875..6e53b48 100644 (file)
@@ -44,6 +44,13 @@ extern ssize_t arch_cpu_release(const char *, size_t);
 #endif
 struct notifier_block;
 
+#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE
+extern int arch_cpu_uevent(struct device *dev, struct kobj_uevent_env *env);
+extern ssize_t arch_print_cpu_modalias(struct device *dev,
+                                      struct device_attribute *attr,
+                                      char *bufptr);
+#endif
+
 /*
  * CPU notifier priorities.
  */
index b63fb39..f62e216 100644 (file)
@@ -238,8 +238,6 @@ struct device_driver {
 extern int __must_check driver_register(struct device_driver *drv);
 extern void driver_unregister(struct device_driver *drv);
 
-extern struct device_driver *get_driver(struct device_driver *drv);
-extern void put_driver(struct device_driver *drv);
 extern struct device_driver *driver_find(const char *name,
                                         struct bus_type *bus);
 extern int driver_probe_done(void);
@@ -946,14 +944,14 @@ int _dev_info(const struct device *dev, const char *fmt, ...)
 
 #define dev_info(dev, fmt, arg...) _dev_info(dev, fmt, ##arg)
 
-#if defined(DEBUG)
-#define dev_dbg(dev, format, arg...)           \
-       dev_printk(KERN_DEBUG, dev, format, ##arg)
-#elif defined(CONFIG_DYNAMIC_DEBUG)
+#if defined(CONFIG_DYNAMIC_DEBUG)
 #define dev_dbg(dev, format, ...)                   \
 do {                                                \
        dynamic_dev_dbg(dev, format, ##__VA_ARGS__); \
 } while (0)
+#elif defined(DEBUG)
+#define dev_dbg(dev, format, arg...)           \
+       dev_printk(KERN_DEBUG, dev, format, ##arg)
 #else
 #define dev_dbg(dev, format, arg...)                           \
 ({                                                             \
index 0564e3c..7e3c53a 100644 (file)
@@ -15,20 +15,24 @@ struct _ddebug {
        const char *function;
        const char *filename;
        const char *format;
-       unsigned int lineno:24;
+       unsigned int lineno:18;
        /*
         * The flags field controls the behaviour at the callsite.
         * The bits here are changed dynamically when the user
         * writes commands to <debugfs>/dynamic_debug/control
         */
-#define _DPRINTK_FLAGS_PRINT   (1<<0)  /* printk() a message using the format */
+#define _DPRINTK_FLAGS_NONE    0
+#define _DPRINTK_FLAGS_PRINT   (1<<0) /* printk() a message using the format */
 #define _DPRINTK_FLAGS_INCL_MODNAME    (1<<1)
 #define _DPRINTK_FLAGS_INCL_FUNCNAME   (1<<2)
 #define _DPRINTK_FLAGS_INCL_LINENO     (1<<3)
 #define _DPRINTK_FLAGS_INCL_TID                (1<<4)
+#if defined DEBUG
+#define _DPRINTK_FLAGS_DEFAULT _DPRINTK_FLAGS_PRINT
+#else
 #define _DPRINTK_FLAGS_DEFAULT 0
+#endif
        unsigned int flags:8;
-       char enabled;
 } __attribute__((aligned(8)));
 
 
@@ -62,21 +66,20 @@ int __dynamic_netdev_dbg(struct _ddebug *descriptor,
                .format = (fmt),                                \
                .lineno = __LINE__,                             \
                .flags =  _DPRINTK_FLAGS_DEFAULT,               \
-               .enabled = false,                               \
        }
 
 #define dynamic_pr_debug(fmt, ...)                             \
 do {                                                           \
        DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt);         \
-       if (unlikely(descriptor.enabled))                       \
+       if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT))  \
                __dynamic_pr_debug(&descriptor, pr_fmt(fmt),    \
                                   ##__VA_ARGS__);              \
 } while (0)
 
 #define dynamic_dev_dbg(dev, fmt, ...)                         \
 do {                                                           \
-       DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \
-       if (unlikely(descriptor.enabled))                       \
+       DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt);         \
+       if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT))  \
                __dynamic_dev_dbg(&descriptor, dev, fmt,        \
                                  ##__VA_ARGS__);               \
 } while (0)
@@ -84,7 +87,7 @@ do {                                                          \
 #define dynamic_netdev_dbg(dev, fmt, ...)                      \
 do {                                                           \
        DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt);         \
-       if (unlikely(descriptor.enabled))                       \
+       if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT))  \
                __dynamic_netdev_dbg(&descriptor, dev, fmt,     \
                                     ##__VA_ARGS__);            \
 } while (0)
index 0ae065a..e57a6c6 100644 (file)
 #ifndef _HYPERV_H
 #define _HYPERV_H
 
+#include <linux/types.h>
+
+/*
+ * An implementation of HyperV key value pair (KVP) functionality for Linux.
+ *
+ *
+ * Copyright (C) 2010, Novell, Inc.
+ * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
+ *
+ */
+
+/*
+ * Maximum value size - used for both key names and value data, and includes
+ * any applicable NULL terminators.
+ *
+ * Note:  This limit is somewhat arbitrary, but falls easily within what is
+ * supported for all native guests (back to Win 2000) and what is reasonable
+ * for the IC KVP exchange functionality.  Note that Windows Me/98/95 are
+ * limited to 255 character key names.
+ *
+ * MSDN recommends not storing data values larger than 2048 bytes in the
+ * registry.
+ *
+ * Note:  This value is used in defining the KVP exchange message - this value
+ * cannot be modified without affecting the message size and compatibility.
+ */
+
+/*
+ * bytes, including any null terminators
+ */
+#define HV_KVP_EXCHANGE_MAX_VALUE_SIZE          (2048)
+
+
+/*
+ * Maximum key size - the registry limit for the length of an entry name
+ * is 256 characters, including the null terminator
+ */
+
+#define HV_KVP_EXCHANGE_MAX_KEY_SIZE            (512)
+
+/*
+ * In Linux, we implement the KVP functionality in two components:
+ * 1) The kernel component which is packaged as part of the hv_utils driver
+ * is responsible for communicating with the host and responsible for
+ * implementing the host/guest protocol. 2) A user level daemon that is
+ * responsible for data gathering.
+ *
+ * Host/Guest Protocol: The host iterates over an index and expects the guest
+ * to assign a key name to the index and also return the value corresponding to
+ * the key. The host will have atmost one KVP transaction outstanding at any
+ * given point in time. The host side iteration stops when the guest returns
+ * an error. Microsoft has specified the following mapping of key names to
+ * host specified index:
+ *
+ *     Index           Key Name
+ *     0               FullyQualifiedDomainName
+ *     1               IntegrationServicesVersion
+ *     2               NetworkAddressIPv4
+ *     3               NetworkAddressIPv6
+ *     4               OSBuildNumber
+ *     5               OSName
+ *     6               OSMajorVersion
+ *     7               OSMinorVersion
+ *     8               OSVersion
+ *     9               ProcessorArchitecture
+ *
+ * The Windows host expects the Key Name and Key Value to be encoded in utf16.
+ *
+ * Guest Kernel/KVP Daemon Protocol: As noted earlier, we implement all of the
+ * data gathering functionality in a user mode daemon. The user level daemon
+ * is also responsible for binding the key name to the index as well. The
+ * kernel and user-level daemon communicate using a connector channel.
+ *
+ * The user mode component first registers with the
+ * the kernel component. Subsequently, the kernel component requests, data
+ * for the specified keys. In response to this message the user mode component
+ * fills in the value corresponding to the specified key. We overload the
+ * sequence field in the cn_msg header to define our KVP message types.
+ *
+ *
+ * The kernel component simply acts as a conduit for communication between the
+ * Windows host and the user-level daemon. The kernel component passes up the
+ * index received from the Host to the user-level daemon. If the index is
+ * valid (supported), the corresponding key as well as its
+ * value (both are strings) is returned. If the index is invalid
+ * (not supported), a NULL key string is returned.
+ */
+
+
+/*
+ * Registry value types.
+ */
+
+#define REG_SZ 1
+
+enum hv_kvp_exchg_op {
+       KVP_OP_GET = 0,
+       KVP_OP_SET,
+       KVP_OP_DELETE,
+       KVP_OP_ENUMERATE,
+       KVP_OP_REGISTER,
+       KVP_OP_COUNT /* Number of operations, must be last. */
+};
+
+enum hv_kvp_exchg_pool {
+       KVP_POOL_EXTERNAL = 0,
+       KVP_POOL_GUEST,
+       KVP_POOL_AUTO,
+       KVP_POOL_AUTO_EXTERNAL,
+       KVP_POOL_AUTO_INTERNAL,
+       KVP_POOL_COUNT /* Number of pools, must be last. */
+};
+
+struct hv_kvp_hdr {
+       __u8 operation;
+       __u8 pool;
+       __u16 pad;
+} __attribute__((packed));
+
+struct hv_kvp_exchg_msg_value {
+       __u32 value_type;
+       __u32 key_size;
+       __u32 value_size;
+       __u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
+       __u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
+} __attribute__((packed));
+
+struct hv_kvp_msg_enumerate {
+       __u32 index;
+       struct hv_kvp_exchg_msg_value data;
+} __attribute__((packed));
+
+struct hv_kvp_msg {
+       struct hv_kvp_hdr       kvp_hdr;
+       union {
+               struct hv_kvp_msg_enumerate     kvp_enum_data;
+               char    kvp_version[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
+       } body;
+} __attribute__((packed));
+
+#ifdef __KERNEL__
 #include <linux/scatterlist.h>
 #include <linux/list.h>
 #include <linux/uuid.h>
@@ -870,4 +1011,9 @@ struct hyperv_service_callback {
 extern void vmbus_prep_negotiate_resp(struct icmsg_hdr *,
                                      struct icmsg_negotiate *, u8 *);
 
+int hv_kvp_init(struct hv_util_service *);
+void hv_kvp_deinit(void);
+void hv_kvp_onchannelcallback(void *);
+
+#endif /* __KERNEL__ */
 #endif /* _HYPERV_H */
index 83ac071..fb69ad1 100644 (file)
@@ -560,4 +560,25 @@ struct amba_id {
 #endif
 };
 
+/*
+ * Match x86 CPUs for CPU specific drivers.
+ * See documentation of "x86_match_cpu" for details.
+ */
+
+struct x86_cpu_id {
+       __u16 vendor;
+       __u16 family;
+       __u16 model;
+       __u16 feature;  /* bit index */
+       kernel_ulong_t driver_data;
+};
+
+#define X86_FEATURE_MATCH(x) \
+       { X86_VENDOR_ANY, X86_FAMILY_ANY, X86_MODEL_ANY, x }
+
+#define X86_VENDOR_ANY 0xffff
+#define X86_FAMILY_ANY 0
+#define X86_MODEL_ANY  0
+#define X86_FEATURE_ANY 0      /* Same as FPU, you can't test for that */
+
 #endif /* LINUX_MOD_DEVICETABLE_H */
index 0eac07c..f486f63 100644 (file)
@@ -2687,14 +2687,14 @@ int netdev_info(const struct net_device *dev, const char *format, ...);
 #define MODULE_ALIAS_NETDEV(device) \
        MODULE_ALIAS("netdev-" device)
 
-#if defined(DEBUG)
-#define netdev_dbg(__dev, format, args...)                     \
-       netdev_printk(KERN_DEBUG, __dev, format, ##args)
-#elif defined(CONFIG_DYNAMIC_DEBUG)
+#if defined(CONFIG_DYNAMIC_DEBUG)
 #define netdev_dbg(__dev, format, args...)                     \
 do {                                                           \
        dynamic_netdev_dbg(__dev, format, ##args);              \
 } while (0)
+#elif defined(DEBUG)
+#define netdev_dbg(__dev, format, args...)                     \
+       netdev_printk(KERN_DEBUG, __dev, format, ##args)
 #else
 #define netdev_dbg(__dev, format, args...)                     \
 ({                                                             \
index a16b1df..d4afd70 100644 (file)
@@ -946,6 +946,19 @@ int __must_check __pci_register_driver(struct pci_driver *, struct module *,
        __pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
 
 void pci_unregister_driver(struct pci_driver *dev);
+
+/**
+ * module_pci_driver() - Helper macro for registering a PCI driver
+ * @__pci_driver: pci_driver struct
+ *
+ * Helper macro for PCI drivers which do not do anything special in module
+ * init/exit. This eliminates a lot of boilerplate. Each module may only
+ * use this macro once, and calling it replaces module_init() and module_exit()
+ */
+#define module_pci_driver(__pci_driver) \
+       module_driver(__pci_driver, pci_register_driver, \
+                      pci_unregister_driver)
+
 void pci_remove_behind_bridge(struct pci_dev *dev);
 struct pci_driver *pci_dev_driver(const struct pci_dev *dev);
 int pci_add_dynid(struct pci_driver *drv,
index f0e22f7..f9abd93 100644 (file)
@@ -180,13 +180,13 @@ extern void dump_stack(void) __cold;
 #endif
 
 /* If you are writing a driver, please use dev_dbg instead */
-#if defined(DEBUG)
-#define pr_debug(fmt, ...) \
-       printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
-#elif defined(CONFIG_DYNAMIC_DEBUG)
+#if defined(CONFIG_DYNAMIC_DEBUG)
 /* dynamic_pr_debug() uses pr_fmt() internally so we don't need it here */
 #define pr_debug(fmt, ...) \
        dynamic_pr_debug(fmt, ##__VA_ARGS__)
+#elif defined(DEBUG)
+#define pr_debug(fmt, ...) \
+       printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
 #else
 #define pr_debug(fmt, ...) \
        no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
diff --git a/include/linux/sys_soc.h b/include/linux/sys_soc.h
new file mode 100644 (file)
index 0000000..2739ccb
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ * Author: Lee Jones <lee.jones@linaro.org> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+#ifndef __SOC_BUS_H
+#define __SOC_BUS_H
+
+#include <linux/device.h>
+
+struct soc_device_attribute {
+       const char *machine;
+       const char *family;
+       const char *revision;
+       const char *soc_id;
+};
+
+/**
+ * soc_device_register - register SoC as a device
+ * @soc_plat_dev_attr: Attributes passed from platform to be attributed to a SoC
+ */
+struct soc_device *soc_device_register(
+       struct soc_device_attribute *soc_plat_dev_attr);
+
+/**
+ * soc_device_unregister - unregister SoC device
+ * @dev: SoC device to be unregistered
+ */
+void soc_device_unregister(struct soc_device *soc_dev);
+
+/**
+ * soc_device_to_device - helper function to fetch struct device
+ * @soc: Previously registered SoC device container
+ */
+struct device *soc_device_to_device(struct soc_device *soc);
+
+#endif /* __SOC_BUS_H */
index fea790a..13ef233 100644 (file)
@@ -170,7 +170,7 @@ static bool driver_filter(struct device *dev)
                return false;
 
        /* driver filter on but not yet initialized */
-       drv = get_driver(dev->driver);
+       drv = dev->driver;
        if (!drv)
                return false;
 
@@ -185,7 +185,6 @@ static bool driver_filter(struct device *dev)
        }
 
        read_unlock_irqrestore(&driver_name_lock, flags);
-       put_driver(drv);
 
        return ret;
 }
index dcdade3..310c753 100644 (file)
@@ -60,6 +60,7 @@ struct ddebug_iter {
 static DEFINE_MUTEX(ddebug_lock);
 static LIST_HEAD(ddebug_tables);
 static int verbose = 0;
+module_param(verbose, int, 0644);
 
 /* Return the last part of a pathname */
 static inline const char *basename(const char *path)
@@ -68,12 +69,24 @@ static inline const char *basename(const char *path)
        return tail ? tail+1 : path;
 }
 
+/* Return the path relative to source root */
+static inline const char *trim_prefix(const char *path)
+{
+       int skip = strlen(__FILE__) - strlen("lib/dynamic_debug.c");
+
+       if (strncmp(path, __FILE__, skip))
+               skip = 0; /* prefix mismatch, don't skip */
+
+       return path + skip;
+}
+
 static struct { unsigned flag:8; char opt_char; } opt_array[] = {
        { _DPRINTK_FLAGS_PRINT, 'p' },
        { _DPRINTK_FLAGS_INCL_MODNAME, 'm' },
        { _DPRINTK_FLAGS_INCL_FUNCNAME, 'f' },
        { _DPRINTK_FLAGS_INCL_LINENO, 'l' },
        { _DPRINTK_FLAGS_INCL_TID, 't' },
+       { _DPRINTK_FLAGS_NONE, '_' },
 };
 
 /* format a string into buf[] which describes the _ddebug's flags */
@@ -83,58 +96,74 @@ static char *ddebug_describe_flags(struct _ddebug *dp, char *buf,
        char *p = buf;
        int i;
 
-       BUG_ON(maxlen < 4);
+       BUG_ON(maxlen < 6);
        for (i = 0; i < ARRAY_SIZE(opt_array); ++i)
                if (dp->flags & opt_array[i].flag)
                        *p++ = opt_array[i].opt_char;
        if (p == buf)
-               *p++ = '-';
+               *p++ = '_';
        *p = '\0';
 
        return buf;
 }
 
+#define vpr_info_dq(q, msg)                                            \
+do {                                                                   \
+       if (verbose)                                                    \
+               /* trim last char off format print */                   \
+               pr_info("%s: func=\"%s\" file=\"%s\" "                  \
+                       "module=\"%s\" format=\"%.*s\" "                \
+                       "lineno=%u-%u",                                 \
+                       msg,                                            \
+                       q->function ? q->function : "",                 \
+                       q->filename ? q->filename : "",                 \
+                       q->module ? q->module : "",                     \
+                       (int)(q->format ? strlen(q->format) - 1 : 0),   \
+                       q->format ? q->format : "",                     \
+                       q->first_lineno, q->last_lineno);               \
+} while (0)
+
 /*
- * Search the tables for _ddebug's which match the given
- * `query' and apply the `flags' and `mask' to them.  Tells
- * the user which ddebug's were changed, or whether none
- * were matched.
+ * Search the tables for _ddebug's which match the given `query' and
+ * apply the `flags' and `mask' to them.  Returns number of matching
+ * callsites, normally the same as number of changes.  If verbose,
+ * logs the changes.  Takes ddebug_lock.
  */
-static void ddebug_change(const struct ddebug_query *query,
-                          unsigned int flags, unsigned int mask)
+static int ddebug_change(const struct ddebug_query *query,
+                       unsigned int flags, unsigned int mask)
 {
        int i;
        struct ddebug_table *dt;
        unsigned int newflags;
        unsigned int nfound = 0;
-       char flagbuf[8];
+       char flagbuf[10];
 
        /* search for matching ddebugs */
        mutex_lock(&ddebug_lock);
        list_for_each_entry(dt, &ddebug_tables, link) {
 
                /* match against the module name */
-               if (query->module != NULL &&
-                   strcmp(query->module, dt->mod_name))
+               if (query->module && strcmp(query->module, dt->mod_name))
                        continue;
 
                for (i = 0 ; i < dt->num_ddebugs ; i++) {
                        struct _ddebug *dp = &dt->ddebugs[i];
 
                        /* match against the source filename */
-                       if (query->filename != NULL &&
+                       if (query->filename &&
                            strcmp(query->filename, dp->filename) &&
-                           strcmp(query->filename, basename(dp->filename)))
+                           strcmp(query->filename, basename(dp->filename)) &&
+                           strcmp(query->filename, trim_prefix(dp->filename)))
                                continue;
 
                        /* match against the function */
-                       if (query->function != NULL &&
+                       if (query->function &&
                            strcmp(query->function, dp->function))
                                continue;
 
                        /* match against the format */
-                       if (query->format != NULL &&
-                           strstr(dp->format, query->format) == NULL)
+                       if (query->format &&
+                           !strstr(dp->format, query->format))
                                continue;
 
                        /* match against the line number range */
@@ -151,13 +180,9 @@ static void ddebug_change(const struct ddebug_query *query,
                        if (newflags == dp->flags)
                                continue;
                        dp->flags = newflags;
-                       if (newflags)
-                               dp->enabled = 1;
-                       else
-                               dp->enabled = 0;
                        if (verbose)
-                               pr_info("changed %s:%d [%s]%s %s\n",
-                                       dp->filename, dp->lineno,
+                               pr_info("changed %s:%d [%s]%s =%s\n",
+                                       trim_prefix(dp->filename), dp->lineno,
                                        dt->mod_name, dp->function,
                                        ddebug_describe_flags(dp, flagbuf,
                                                        sizeof(flagbuf)));
@@ -167,6 +192,8 @@ static void ddebug_change(const struct ddebug_query *query,
 
        if (!nfound && verbose)
                pr_info("no matches for query\n");
+
+       return nfound;
 }
 
 /*
@@ -186,8 +213,10 @@ static int ddebug_tokenize(char *buf, char *words[], int maxwords)
                buf = skip_spaces(buf);
                if (!*buf)
                        break;  /* oh, it was trailing whitespace */
+               if (*buf == '#')
+                       break;  /* token starts comment, skip rest of line */
 
-               /* Run `end' over a word, either whitespace separated or quoted */
+               /* find `end' of word, whitespace separated or quoted */
                if (*buf == '"' || *buf == '\'') {
                        int quote = *buf++;
                        for (end = buf ; *end && *end != quote ; end++)
@@ -199,8 +228,8 @@ static int ddebug_tokenize(char *buf, char *words[], int maxwords)
                                ;
                        BUG_ON(end == buf);
                }
-               /* Here `buf' is the start of the word, `end' is one past the end */
 
+               /* `buf' is start of word, `end' is one past its end */
                if (nwords == maxwords)
                        return -EINVAL; /* ran out of words[] before bytes */
                if (*end)
@@ -279,6 +308,19 @@ static char *unescape(char *str)
        return str;
 }
 
+static int check_set(const char **dest, char *src, char *name)
+{
+       int rc = 0;
+
+       if (*dest) {
+               rc = -EINVAL;
+               pr_err("match-spec:%s val:%s overridden by %s",
+                       name, *dest, src);
+       }
+       *dest = src;
+       return rc;
+}
+
 /*
  * Parse words[] as a ddebug query specification, which is a series
  * of (keyword, value) pairs chosen from these possibilities:
@@ -290,11 +332,15 @@ static char *unescape(char *str)
  * format <escaped-string-to-find-in-format>
  * line <lineno>
  * line <first-lineno>-<last-lineno> // where either may be empty
+ *
+ * Only 1 of each type is allowed.
+ * Returns 0 on success, <0 on error.
  */
 static int ddebug_parse_query(char *words[], int nwords,
                               struct ddebug_query *query)
 {
        unsigned int i;
+       int rc;
 
        /* check we have an even number of words */
        if (nwords % 2 != 0)
@@ -303,41 +349,43 @@ static int ddebug_parse_query(char *words[], int nwords,
 
        for (i = 0 ; i < nwords ; i += 2) {
                if (!strcmp(words[i], "func"))
-                       query->function = words[i+1];
+                       rc = check_set(&query->function, words[i+1], "func");
                else if (!strcmp(words[i], "file"))
-                       query->filename = words[i+1];
+                       rc = check_set(&query->filename, words[i+1], "file");
                else if (!strcmp(words[i], "module"))
-                       query->module = words[i+1];
+                       rc = check_set(&query->module, words[i+1], "module");
                else if (!strcmp(words[i], "format"))
-                       query->format = unescape(words[i+1]);
+                       rc = check_set(&query->format, unescape(words[i+1]),
+                               "format");
                else if (!strcmp(words[i], "line")) {
                        char *first = words[i+1];
                        char *last = strchr(first, '-');
+                       if (query->first_lineno || query->last_lineno) {
+                               pr_err("match-spec:line given 2 times\n");
+                               return -EINVAL;
+                       }
                        if (last)
                                *last++ = '\0';
                        if (parse_lineno(first, &query->first_lineno) < 0)
                                return -EINVAL;
-                       if (last != NULL) {
+                       if (last) {
                                /* range <first>-<last> */
-                               if (parse_lineno(last, &query->last_lineno) < 0)
+                               if (parse_lineno(last, &query->last_lineno)
+                                   < query->first_lineno) {
+                                       pr_err("last-line < 1st-line\n");
                                        return -EINVAL;
+                               }
                        } else {
                                query->last_lineno = query->first_lineno;
                        }
                } else {
-                       if (verbose)
-                               pr_err("unknown keyword \"%s\"\n", words[i]);
+                       pr_err("unknown keyword \"%s\"\n", words[i]);
                        return -EINVAL;
                }
+               if (rc)
+                       return rc;
        }
-
-       if (verbose)
-               pr_info("q->function=\"%s\" q->filename=\"%s\" "
-                       "q->module=\"%s\" q->format=\"%s\" q->lineno=%u-%u\n",
-                       query->function, query->filename,
-                       query->module, query->format, query->first_lineno,
-                       query->last_lineno);
-
+       vpr_info_dq(query, "parsed");
        return 0;
 }
 
@@ -375,8 +423,6 @@ static int ddebug_parse_flags(const char *str, unsigned int *flagsp,
                if (i < 0)
                        return -EINVAL;
        }
-       if (flags == 0)
-               return -EINVAL;
        if (verbose)
                pr_info("flags=0x%x\n", flags);
 
@@ -405,7 +451,7 @@ static int ddebug_exec_query(char *query_string)
        unsigned int flags = 0, mask = 0;
        struct ddebug_query query;
 #define MAXWORDS 9
-       int nwords;
+       int nwords, nfound;
        char *words[MAXWORDS];
 
        nwords = ddebug_tokenize(query_string, words, MAXWORDS);
@@ -417,8 +463,47 @@ static int ddebug_exec_query(char *query_string)
                return -EINVAL;
 
        /* actually go and implement the change */
-       ddebug_change(&query, flags, mask);
-       return 0;
+       nfound = ddebug_change(&query, flags, mask);
+       vpr_info_dq((&query), (nfound) ? "applied" : "no-match");
+
+       return nfound;
+}
+
+/* handle multiple queries in query string, continue on error, return
+   last error or number of matching callsites.  Module name is either
+   in param (for boot arg) or perhaps in query string.
+*/
+static int ddebug_exec_queries(char *query)
+{
+       char *split;
+       int i, errs = 0, exitcode = 0, rc, nfound = 0;
+
+       for (i = 0; query; query = split) {
+               split = strpbrk(query, ";\n");
+               if (split)
+                       *split++ = '\0';
+
+               query = skip_spaces(query);
+               if (!query || !*query || *query == '#')
+                       continue;
+
+               if (verbose)
+                       pr_info("query %d: \"%s\"\n", i, query);
+
+               rc = ddebug_exec_query(query);
+               if (rc < 0) {
+                       errs++;
+                       exitcode = rc;
+               } else
+                       nfound += rc;
+               i++;
+       }
+       pr_info("processed %d queries, with %d matches, %d errs\n",
+                i, nfound, errs);
+
+       if (exitcode)
+               return exitcode;
+       return nfound;
 }
 
 #define PREFIX_SIZE 64
@@ -452,7 +537,8 @@ static char *dynamic_emit_prefix(const struct _ddebug *desc, char *buf)
                pos += snprintf(buf + pos, remaining(pos), "%s:",
                                        desc->function);
        if (desc->flags & _DPRINTK_FLAGS_INCL_LINENO)
-               pos += snprintf(buf + pos, remaining(pos), "%d:", desc->lineno);
+               pos += snprintf(buf + pos, remaining(pos), "%d:",
+                                       desc->lineno);
        if (pos - pos_after_tid)
                pos += snprintf(buf + pos, remaining(pos), " ");
        if (pos >= PREFIX_SIZE)
@@ -527,14 +613,16 @@ EXPORT_SYMBOL(__dynamic_netdev_dbg);
 
 #endif
 
-static __initdata char ddebug_setup_string[1024];
+#define DDEBUG_STRING_SIZE 1024
+static __initdata char ddebug_setup_string[DDEBUG_STRING_SIZE];
+
 static __init int ddebug_setup_query(char *str)
 {
-       if (strlen(str) >= 1024) {
+       if (strlen(str) >= DDEBUG_STRING_SIZE) {
                pr_warn("ddebug boot param string too large\n");
                return 0;
        }
-       strcpy(ddebug_setup_string, str);
+       strlcpy(ddebug_setup_string, str, DDEBUG_STRING_SIZE);
        return 1;
 }
 
@@ -544,25 +632,33 @@ __setup("ddebug_query=", ddebug_setup_query);
  * File_ops->write method for <debugfs>/dynamic_debug/conrol.  Gathers the
  * command text from userspace, parses and executes it.
  */
+#define USER_BUF_PAGE 4096
 static ssize_t ddebug_proc_write(struct file *file, const char __user *ubuf,
                                  size_t len, loff_t *offp)
 {
-       char tmpbuf[256];
+       char *tmpbuf;
        int ret;
 
        if (len == 0)
                return 0;
-       /* we don't check *offp -- multiple writes() are allowed */
-       if (len > sizeof(tmpbuf)-1)
+       if (len > USER_BUF_PAGE - 1) {
+               pr_warn("expected <%d bytes into control\n", USER_BUF_PAGE);
                return -E2BIG;
-       if (copy_from_user(tmpbuf, ubuf, len))
+       }
+       tmpbuf = kmalloc(len + 1, GFP_KERNEL);
+       if (!tmpbuf)
+               return -ENOMEM;
+       if (copy_from_user(tmpbuf, ubuf, len)) {
+               kfree(tmpbuf);
                return -EFAULT;
+       }
        tmpbuf[len] = '\0';
        if (verbose)
                pr_info("read %d bytes from userspace\n", (int)len);
 
-       ret = ddebug_exec_query(tmpbuf);
-       if (ret)
+       ret = ddebug_exec_queries(tmpbuf);
+       kfree(tmpbuf);
+       if (ret < 0)
                return ret;
 
        *offp += len;
@@ -668,7 +764,7 @@ static int ddebug_proc_show(struct seq_file *m, void *p)
 {
        struct ddebug_iter *iter = m->private;
        struct _ddebug *dp = p;
-       char flagsbuf[8];
+       char flagsbuf[10];
 
        if (verbose)
                pr_info("called m=%p p=%p\n", m, p);
@@ -679,10 +775,10 @@ static int ddebug_proc_show(struct seq_file *m, void *p)
                return 0;
        }
 
-       seq_printf(m, "%s:%u [%s]%s %s \"",
-                  dp->filename, dp->lineno,
-                  iter->table->mod_name, dp->function,
-                  ddebug_describe_flags(dp, flagsbuf, sizeof(flagsbuf)));
+       seq_printf(m, "%s:%u [%s]%s =%s \"",
+               trim_prefix(dp->filename), dp->lineno,
+               iter->table->mod_name, dp->function,
+               ddebug_describe_flags(dp, flagsbuf, sizeof(flagsbuf)));
        seq_escape(m, dp->format, "\t\r\n\"");
        seq_puts(m, "\"\n");
 
@@ -708,10 +804,11 @@ static const struct seq_operations ddebug_proc_seqops = {
 };
 
 /*
- * File_ops->open method for <debugfs>/dynamic_debug/control.  Does the seq_file
- * setup dance, and also creates an iterator to walk the _ddebugs.
- * Note that we create a seq_file always, even for O_WRONLY files
- * where it's not needed, as doing so simplifies the ->release method.
+ * File_ops->open method for <debugfs>/dynamic_debug/control.  Does
+ * the seq_file setup dance, and also creates an iterator to walk the
+ * _ddebugs.  Note that we create a seq_file always, even for O_WRONLY
+ * files where it's not needed, as doing so simplifies the ->release
+ * method.
  */
 static int ddebug_proc_open(struct inode *inode, struct file *file)
 {
@@ -846,33 +943,40 @@ static int __init dynamic_debug_init(void)
        int ret = 0;
        int n = 0;
 
-       if (__start___verbose != __stop___verbose) {
-               iter = __start___verbose;
-               modname = iter->modname;
-               iter_start = iter;
-               for (; iter < __stop___verbose; iter++) {
-                       if (strcmp(modname, iter->modname)) {
-                               ret = ddebug_add_module(iter_start, n, modname);
-                               if (ret)
-                                       goto out_free;
-                               n = 0;
-                               modname = iter->modname;
-                               iter_start = iter;
-                       }
-                       n++;
+       if (__start___verbose == __stop___verbose) {
+               pr_warn("_ddebug table is empty in a "
+                       "CONFIG_DYNAMIC_DEBUG build");
+               return 1;
+       }
+       iter = __start___verbose;
+       modname = iter->modname;
+       iter_start = iter;
+       for (; iter < __stop___verbose; iter++) {
+               if (strcmp(modname, iter->modname)) {
+                       ret = ddebug_add_module(iter_start, n, modname);
+                       if (ret)
+                               goto out_free;
+                       n = 0;
+                       modname = iter->modname;
+                       iter_start = iter;
                }
-               ret = ddebug_add_module(iter_start, n, modname);
+               n++;
        }
+       ret = ddebug_add_module(iter_start, n, modname);
+       if (ret)
+               goto out_free;
 
        /* ddebug_query boot param got passed -> set it up */
        if (ddebug_setup_string[0] != '\0') {
-               ret = ddebug_exec_query(ddebug_setup_string);
-               if (ret)
+               ret = ddebug_exec_queries(ddebug_setup_string);
+               if (ret < 0)
                        pr_warn("Invalid ddebug boot param %s",
                                ddebug_setup_string);
                else
-                       pr_info("ddebug initialized with string %s",
-                               ddebug_setup_string);
+                       pr_info("%d changes by ddebug_query\n", ret);
+
+               /* keep tables even on ddebug_query parse error */
+               ret = 0;
        }
 
 out_free:
index d0de2a2..8df3694 100644 (file)
@@ -1003,6 +1003,30 @@ static int do_amba_entry(const char *filename,
 }
 ADD_TO_DEVTABLE("amba", struct amba_id, do_amba_entry);
 
+/* LOOKS like x86cpu:vendor:VVVV:family:FFFF:model:MMMM:feature:*,FEAT,*
+ * All fields are numbers. It would be nicer to use strings for vendor
+ * and feature, but getting those out of the build system here is too
+ * complicated.
+ */
+
+static int do_x86cpu_entry(const char *filename, struct x86_cpu_id *id,
+                          char *alias)
+{
+       id->feature = TO_NATIVE(id->feature);
+       id->family = TO_NATIVE(id->family);
+       id->model = TO_NATIVE(id->model);
+       id->vendor = TO_NATIVE(id->vendor);
+
+       strcpy(alias, "x86cpu:");
+       ADD(alias, "vendor:",  id->vendor != X86_VENDOR_ANY, id->vendor);
+       ADD(alias, ":family:", id->family != X86_FAMILY_ANY, id->family);
+       ADD(alias, ":model:",  id->model  != X86_MODEL_ANY,  id->model);
+       ADD(alias, ":feature:*,", id->feature != X86_FEATURE_ANY, id->feature);
+       strcat(alias, ",*");
+       return 1;
+}
+ADD_TO_DEVTABLE("x86cpu", struct x86_cpu_id, do_x86cpu_entry);
+
 /* Does namelen bytes of name exactly match the symbol? */
 static bool sym_is(const char *name, unsigned namelen, const char *symbol)
 {
index 11224ed..4ebf703 100644 (file)
 #include <errno.h>
 #include <arpa/inet.h>
 #include <linux/connector.h>
+#include <linux/hyperv.h>
 #include <linux/netlink.h>
 #include <ifaddrs.h>
 #include <netdb.h>
 #include <syslog.h>
 
-/*
- * KYS: TODO. Need to register these in the kernel.
- *
- * The following definitions are shared with the in-kernel component; do not
- * change any of this without making the corresponding changes in
- * the KVP kernel component.
- */
-#define CN_KVP_IDX             0x9     /* MSFT KVP functionality */
-#define CN_KVP_VAL             0x1 /* This supports queries from the kernel */
-#define CN_KVP_USER_VAL                0x2 /* This supports queries from the user  */
 
 /*
  * KVP protocol: The user mode component first registers with the
  * We use this infrastructure for also supporting queries from user mode
  * application for state that may be maintained in the KVP kernel component.
  *
- * XXXKYS: Have a shared header file between the user and kernel (TODO)
  */
 
-enum kvp_op {
-       KVP_REGISTER = 0, /* Register the user mode component*/
-       KVP_KERNEL_GET, /*Kernel is requesting the value for the specified key*/
-       KVP_KERNEL_SET, /*Kernel is providing the value for the specified key*/
-       KVP_USER_GET, /*User is requesting the value for the specified key*/
-       KVP_USER_SET /*User is providing the value for the specified key*/
-};
-
-#define HV_KVP_EXCHANGE_MAX_KEY_SIZE   512
-#define HV_KVP_EXCHANGE_MAX_VALUE_SIZE 2048
-
-struct hv_ku_msg {
-       __u32   kvp_index;
-       __u8  kvp_key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; /* Key name */
-       __u8  kvp_value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; /* Key  value */
-};
 
 enum key_index {
        FullyQualifiedDomainName = 0,
@@ -93,10 +67,6 @@ enum key_index {
        ProcessorArchitecture
 };
 
-/*
- * End of shared definitions.
- */
-
 static char kvp_send_buffer[4096];
 static char kvp_recv_buffer[4096];
 static struct sockaddr_nl addr;
@@ -332,7 +302,7 @@ int main(void)
        struct pollfd pfd;
        struct nlmsghdr *incoming_msg;
        struct cn_msg   *incoming_cn_msg;
-       struct hv_ku_msg *hv_msg;
+       struct hv_kvp_msg *hv_msg;
        char    *p;
        char    *key_value;
        char    *key_name;
@@ -370,9 +340,11 @@ int main(void)
        message = (struct cn_msg *)kvp_send_buffer;
        message->id.idx = CN_KVP_IDX;
        message->id.val = CN_KVP_VAL;
-       message->seq = KVP_REGISTER;
+
+       hv_msg = (struct hv_kvp_msg *)message->data;
+       hv_msg->kvp_hdr.operation = KVP_OP_REGISTER;
        message->ack = 0;
-       message->len = 0;
+       message->len = sizeof(struct hv_kvp_msg);
 
        len = netlink_send(fd, message);
        if (len < 0) {
@@ -398,14 +370,15 @@ int main(void)
 
                incoming_msg = (struct nlmsghdr *)kvp_recv_buffer;
                incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
+               hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
 
-               switch (incoming_cn_msg->seq) {
-               case KVP_REGISTER:
+               switch (hv_msg->kvp_hdr.operation) {
+               case KVP_OP_REGISTER:
                        /*
                         * Driver is registering with us; stash away the version
                         * information.
                         */
-                       p = (char *)incoming_cn_msg->data;
+                       p = (char *)hv_msg->body.kvp_version;
                        lic_version = malloc(strlen(p) + 1);
                        if (lic_version) {
                                strcpy(lic_version, p);
@@ -416,17 +389,15 @@ int main(void)
                        }
                        continue;
 
-               case KVP_KERNEL_GET:
-                       break;
                default:
-                       continue;
+                       break;
                }
 
-               hv_msg = (struct hv_ku_msg *)incoming_cn_msg->data;
-               key_name = (char *)hv_msg->kvp_key;
-               key_value = (char *)hv_msg->kvp_value;
+               hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
+               key_name = (char *)hv_msg->body.kvp_enum_data.data.key;
+               key_value = (char *)hv_msg->body.kvp_enum_data.data.value;
 
-               switch (hv_msg->kvp_index) {
+               switch (hv_msg->body.kvp_enum_data.index) {
                case FullyQualifiedDomainName:
                        kvp_get_domain_name(key_value,
                                        HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
@@ -486,9 +457,8 @@ int main(void)
 
                incoming_cn_msg->id.idx = CN_KVP_IDX;
                incoming_cn_msg->id.val = CN_KVP_VAL;
-               incoming_cn_msg->seq = KVP_USER_SET;
                incoming_cn_msg->ack = 0;
-               incoming_cn_msg->len = sizeof(struct hv_ku_msg);
+               incoming_cn_msg->len = sizeof(struct hv_kvp_msg);
 
                len = netlink_send(fd, incoming_cn_msg);
                if (len < 0) {