Merge branch 'depends/driver-core' into ux500/dt
Conflicts: drivers/base/cpu.c
This commit is contained in:
commit
ab2f75ce55
58
Documentation/ABI/testing/sysfs-devices-soc
Normal file
58
Documentation/ABI/testing/sysfs-devices-soc
Normal 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.
|
@ -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
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
13
arch/x86/include/asm/cpu_device_id.h
Normal file
13
arch/x86/include/asm/cpu_device_id.h
Normal 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
|
@ -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 */
|
||||
|
@ -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
|
||||
|
92
arch/x86/kernel/cpu/match.c
Normal file
92
arch/x86/kernel/cpu/match.c
Normal 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;
|
||||
}
|
@ -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 },
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -176,6 +176,9 @@ config GENERIC_CPU_DEVICES
|
||||
bool
|
||||
default n
|
||||
|
||||
config SOC_BUS
|
||||
bool
|
||||
|
||||
source "drivers/base/regmap/Kconfig"
|
||||
|
||||
config DMA_SHARED_BUFFER
|
||||
|
@ -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
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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
183
drivers/base/soc.c
Normal 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);
|
@ -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
|
||||
*
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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!")) {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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(¢rino_driver);
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
|
@ -1293,7 +1293,6 @@ static int __init ivtvfb_init(void)
|
||||
|
||||
drv = driver_find("ivtv", &pci_bus_type);
|
||||
err = driver_for_each_device(drv, NULL, ®istered, 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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,6 @@ static struct v4l2_subdev *find_and_register_subdev(
|
||||
}
|
||||
|
||||
done:
|
||||
put_driver(drv);
|
||||
return sd;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
222
fs/sysfs/dir.c
222
fs/sysfs/dir.c
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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...) \
|
||||
({ \
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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...) \
|
||||
({ \
|
||||
|
@ -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,
|
||||
|
@ -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
37
include/linux/sys_soc.h
Normal 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 */
|
@ -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;
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user