dect
/
linux-2.6
Archived
13
0
Fork 0

Merge branch 'depends/driver-core' into ux500/dt

Conflicts:
	drivers/base/cpu.c
This commit is contained in:
Arnd Bergmann 2012-03-16 19:15:48 +00:00
commit ab2f75ce55
85 changed files with 1541 additions and 913 deletions

View File

@ -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.

View 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

View 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.

View 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

View 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;

View 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)

View 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)

View File

@ -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

View File

@ -177,6 +177,7 @@
#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 */

View 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

View File

@ -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;
}

View 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 },

View 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);

View 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);

View 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;

View 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

View 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

View 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) {

View 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
};

View 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;
}

183
drivers/base/soc.c Normal file
View File

@ -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);

View 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
*

View 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)
if (!x86_match_cpu(eps_cpu_id) || boot_cpu_data.x86_model < 10)
return -ENODEV;
if (!cpu_has(c, X86_FEATURE_EST))
return -ENODEV;
if (cpufreq_register_driver(&eps_driver))
return -EINVAL;
return 0;

View 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);
}

View 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)

View 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

View 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);
}

View 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);

View 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!")) {

View 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);

View 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);

View 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");

View 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);
}

View 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) {

View 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);

View 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) {

View 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) {

View 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");
if (!x86_match_cpu(padlock_sha_ids) || !cpu_has_phe_enabled)
return -ENODEV;
}
if (!cpu_has_phe_enabled) {
printk(KERN_NOTICE PFX "VIA PadLock detected, but not enabled. Hmm, strange...\n");
return -ENODEV;
}
/* Register the newly added algorithm module if on *
* VIA Nano processor, or else just do as before */

View 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;
}

View 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;

View 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;

View 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

View File

@ -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 */

View 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,

View 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;

View 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)

View 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)

View 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,18 +82,23 @@ 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);
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.
@ -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;

View 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;
}

View 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;

View 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");

View 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);

View 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;
}

View File

@ -58,7 +58,6 @@ static struct v4l2_subdev *find_and_register_subdev(
}
done:
put_driver(drv);
return sd;
}

View 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;

View 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)
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_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);
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);
}

View 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;

View 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);
}

View 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);

View 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;
}

View 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);

View 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);
}

View 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_remove_id);
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);
}
}
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();
}

View 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);

View File

@ -13,12 +13,11 @@
#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;

View File

@ -23,9 +23,13 @@
#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;
return simple_fill_super(sb, DEBUGFS_MAGIC, debug_files);
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;
fail:
kfree(fsi);
sb->s_fs_info = NULL;
return err;
}
static struct dentry *debug_mount(struct file_system_type *fs_type,

View File

@ -22,76 +22,100 @@
#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 **node = &sd->s_parent->s_dir.children.rb_node;
struct rb_node *parent = NULL;
struct rb_node **p;
struct rb_node *parent;
while (*node) {
struct sysfs_dirent *pos;
int result;
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
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->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
}
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
}
hash = sysfs_name_hash(ns, name);
while (node) {
struct sysfs_dirent *sd;
int result;
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;
}
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);

View 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)

View 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,
};

View 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)
{

View 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);

View 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 */

View 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.
*/

View 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...) \
({ \

View 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)

View File

@ -25,6 +25,147 @@
#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 */

View 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 */

View 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...) \
({ \

View 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,

View 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__)

37
include/linux/sys_soc.h Normal file
View File

@ -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 */

View 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;
}

View 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++;
}
ret = ddebug_add_module(iter_start, n, modname);
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;
}
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:

View 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)
{

View File

@ -34,21 +34,12 @@
#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
@ -60,25 +51,8 @@
* 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) {