diff options
Diffstat (limited to 'drivers')
147 files changed, 2634 insertions, 1109 deletions
diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig index f739a70b1c70..c34aa51af4ee 100644 --- a/drivers/acpi/apei/Kconfig +++ b/drivers/acpi/apei/Kconfig @@ -10,9 +10,11 @@ config ACPI_APEI error injection. config ACPI_APEI_GHES - tristate "APEI Generic Hardware Error Source" + bool "APEI Generic Hardware Error Source" depends on ACPI_APEI && X86 select ACPI_HED + select LLIST + select GENERIC_ALLOCATOR help Generic Hardware Error Source provides a way to report platform hardware errors (such as that from chipset). It @@ -30,6 +32,13 @@ config ACPI_APEI_PCIEAER PCIe AER errors may be reported via APEI firmware first mode. Turn on this option to enable the corresponding support. +config ACPI_APEI_MEMORY_FAILURE + bool "APEI memory error recovering support" + depends on ACPI_APEI && MEMORY_FAILURE + help + Memory errors may be reported via APEI firmware first mode. + Turn on this option to enable the memory recovering support. + config ACPI_APEI_EINJ tristate "APEI Error INJection (EINJ)" depends on ACPI_APEI && DEBUG_FS diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c index 4a904a4bf05f..8041248fce9b 100644 --- a/drivers/acpi/apei/apei-base.c +++ b/drivers/acpi/apei/apei-base.c @@ -157,9 +157,10 @@ EXPORT_SYMBOL_GPL(apei_exec_noop); * Interpret the specified action. Go through whole action table, * execute all instructions belong to the action. */ -int apei_exec_run(struct apei_exec_context *ctx, u8 action) +int __apei_exec_run(struct apei_exec_context *ctx, u8 action, + bool optional) { - int rc; + int rc = -ENOENT; u32 i, ip; struct acpi_whea_header *entry; apei_exec_ins_func_t run; @@ -198,9 +199,9 @@ rewind: goto rewind; } - return 0; + return !optional && rc < 0 ? rc : 0; } -EXPORT_SYMBOL_GPL(apei_exec_run); +EXPORT_SYMBOL_GPL(__apei_exec_run); typedef int (*apei_exec_entry_func_t)(struct apei_exec_context *ctx, struct acpi_whea_header *entry, @@ -603,3 +604,29 @@ struct dentry *apei_get_debugfs_dir(void) return dapei; } EXPORT_SYMBOL_GPL(apei_get_debugfs_dir); + +int apei_osc_setup(void) +{ + static u8 whea_uuid_str[] = "ed855e0c-6c90-47bf-a62a-26de0fc5ad5c"; + acpi_handle handle; + u32 capbuf[3]; + struct acpi_osc_context context = { + .uuid_str = whea_uuid_str, + .rev = 1, + .cap.length = sizeof(capbuf), + .cap.pointer = capbuf, + }; + + capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; + capbuf[OSC_SUPPORT_TYPE] = 0; + capbuf[OSC_CONTROL_TYPE] = 0; + + if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle)) + || ACPI_FAILURE(acpi_run_osc(handle, &context))) + return -EIO; + else { + kfree(context.ret.pointer); + return 0; + } +} +EXPORT_SYMBOL_GPL(apei_osc_setup); diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h index ef0581f2094d..f57050e7a5e7 100644 --- a/drivers/acpi/apei/apei-internal.h +++ b/drivers/acpi/apei/apei-internal.h @@ -50,7 +50,18 @@ static inline u64 apei_exec_ctx_get_output(struct apei_exec_context *ctx) return ctx->value; } -int apei_exec_run(struct apei_exec_context *ctx, u8 action); +int __apei_exec_run(struct apei_exec_context *ctx, u8 action, bool optional); + +static inline int apei_exec_run(struct apei_exec_context *ctx, u8 action) +{ + return __apei_exec_run(ctx, action, 0); +} + +/* It is optional whether the firmware provides the action */ +static inline int apei_exec_run_optional(struct apei_exec_context *ctx, u8 action) +{ + return __apei_exec_run(ctx, action, 1); +} /* Common instruction implementation */ @@ -113,4 +124,6 @@ void apei_estatus_print(const char *pfx, const struct acpi_hest_generic_status *estatus); int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus); int apei_estatus_check(const struct acpi_hest_generic_status *estatus); + +int apei_osc_setup(void); #endif diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c index f74b2ea11f21..589b96c38704 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj.c @@ -46,7 +46,8 @@ * Some BIOSes allow parameters to the SET_ERROR_TYPE entries in the * EINJ table through an unpublished extension. Use with caution as * most will ignore the parameter and make their own choice of address - * for error injection. + * for error injection. This extension is used only if + * param_extension module parameter is specified. */ struct einj_parameter { u64 type; @@ -65,6 +66,9 @@ struct einj_parameter { ((struct acpi_whea_header *)((char *)(tab) + \ sizeof(struct acpi_table_einj))) +static bool param_extension; +module_param(param_extension, bool, 0); + static struct acpi_table_einj *einj_tab; static struct apei_resources einj_resources; @@ -285,7 +289,7 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2) einj_exec_ctx_init(&ctx); - rc = apei_exec_run(&ctx, ACPI_EINJ_BEGIN_OPERATION); + rc = apei_exec_run_optional(&ctx, ACPI_EINJ_BEGIN_OPERATION); if (rc) return rc; apei_exec_ctx_set_input(&ctx, type); @@ -323,7 +327,7 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2) rc = __einj_error_trigger(trigger_paddr); if (rc) return rc; - rc = apei_exec_run(&ctx, ACPI_EINJ_END_OPERATION); + rc = apei_exec_run_optional(&ctx, ACPI_EINJ_END_OPERATION); return rc; } @@ -489,14 +493,6 @@ static int __init einj_init(void) einj_debug_dir, NULL, &error_type_fops); if (!fentry) goto err_cleanup; - fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR, - einj_debug_dir, &error_param1); - if (!fentry) - goto err_cleanup; - fentry = debugfs_create_x64("param2", S_IRUSR | S_IWUSR, - einj_debug_dir, &error_param2); - if (!fentry) - goto err_cleanup; fentry = debugfs_create_file("error_inject", S_IWUSR, einj_debug_dir, NULL, &error_inject_fops); if (!fentry) @@ -513,12 +509,23 @@ static int __init einj_init(void) rc = apei_exec_pre_map_gars(&ctx); if (rc) goto err_release; - param_paddr = einj_get_parameter_address(); - if (param_paddr) { - einj_param = ioremap(param_paddr, sizeof(*einj_param)); - rc = -ENOMEM; - if (!einj_param) - goto err_unmap; + if (param_extension) { + param_paddr = einj_get_parameter_address(); + if (param_paddr) { + einj_param = ioremap(param_paddr, sizeof(*einj_param)); + rc = -ENOMEM; + if (!einj_param) + goto err_unmap; + fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR, + einj_debug_dir, &error_param1); + if (!fentry) + goto err_unmap; + fentry = debugfs_create_x64("param2", S_IRUSR | S_IWUSR, + einj_debug_dir, &error_param2); + if (!fentry) + goto err_unmap; + } else + pr_warn(EINJ_PFX "Parameter extension is not supported.\n"); } pr_info(EINJ_PFX "Error INJection is initialized.\n"); @@ -526,6 +533,8 @@ static int __init einj_init(void) return 0; err_unmap: + if (einj_param) + iounmap(einj_param); apei_exec_post_unmap_gars(&ctx); err_release: apei_resources_release(&einj_resources); diff --git a/drivers/acpi/apei/erst-dbg.c b/drivers/acpi/apei/erst-dbg.c index a4cfb64c86a1..903549df809b 100644 --- a/drivers/acpi/apei/erst-dbg.c +++ b/drivers/acpi/apei/erst-dbg.c @@ -33,7 +33,7 @@ #define ERST_DBG_PFX "ERST DBG: " -#define ERST_DBG_RECORD_LEN_MAX 4096 +#define ERST_DBG_RECORD_LEN_MAX 0x4000 static void *erst_dbg_buf; static unsigned int erst_dbg_buf_len; @@ -213,6 +213,10 @@ static struct miscdevice erst_dbg_dev = { static __init int erst_dbg_init(void) { + if (erst_disable) { + pr_info(ERST_DBG_PFX "ERST support is disabled.\n"); + return -ENODEV; + } return misc_register(&erst_dbg_dev); } diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 6053f4780df9..2ca59dc69f7f 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -642,7 +642,7 @@ static int __erst_write_to_storage(u64 offset) int rc; erst_exec_ctx_init(&ctx); - rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_WRITE); + rc = apei_exec_run_optional(&ctx, ACPI_ERST_BEGIN_WRITE); if (rc) return rc; apei_exec_ctx_set_input(&ctx, offset); @@ -666,7 +666,7 @@ static int __erst_write_to_storage(u64 offset) if (rc) return rc; val = apei_exec_ctx_get_output(&ctx); - rc = apei_exec_run(&ctx, ACPI_ERST_END); + rc = apei_exec_run_optional(&ctx, ACPI_ERST_END); if (rc) return rc; @@ -681,7 +681,7 @@ static int __erst_read_from_storage(u64 record_id, u64 offset) int rc; erst_exec_ctx_init(&ctx); - rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_READ); + rc = apei_exec_run_optional(&ctx, ACPI_ERST_BEGIN_READ); if (rc) return rc; apei_exec_ctx_set_input(&ctx, offset); @@ -709,7 +709,7 @@ static int __erst_read_from_storage(u64 record_id, u64 offset) if (rc) return rc; val = apei_exec_ctx_get_output(&ctx); - rc = apei_exec_run(&ctx, ACPI_ERST_END); + rc = apei_exec_run_optional(&ctx, ACPI_ERST_END); if (rc) return rc; @@ -724,7 +724,7 @@ static int __erst_clear_from_storage(u64 record_id) int rc; erst_exec_ctx_init(&ctx); - rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_CLEAR); + rc = apei_exec_run_optional(&ctx, ACPI_ERST_BEGIN_CLEAR); if (rc) return rc; apei_exec_ctx_set_input(&ctx, record_id); @@ -748,7 +748,7 @@ static int __erst_clear_from_storage(u64 record_id) if (rc) return rc; val = apei_exec_ctx_get_output(&ctx); - rc = apei_exec_run(&ctx, ACPI_ERST_END); + rc = apei_exec_run_optional(&ctx, ACPI_ERST_END); if (rc) return rc; diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index f703b2881153..0784f99a4665 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -12,7 +12,7 @@ * For more information about Generic Hardware Error Source, please * refer to ACPI Specification version 4.0, section 17.3.2.6 * - * Copyright 2010 Intel Corp. + * Copyright 2010,2011 Intel Corp. * Author: Huang Ying <ying.huang@intel.com> * * This program is free software; you can redistribute it and/or @@ -42,6 +42,9 @@ #include <linux/mutex.h> #include <linux/ratelimit.h> #include <linux/vmalloc.h> +#include <linux/irq_work.h> +#include <linux/llist.h> +#include <linux/genalloc.h> #include <acpi/apei.h> #include <acpi/atomicio.h> #include <acpi/hed.h> @@ -53,6 +56,30 @@ #define GHES_PFX "GHES: " #define GHES_ESTATUS_MAX_SIZE 65536 +#define GHES_ESOURCE_PREALLOC_MAX_SIZE 65536 + +#define GHES_ESTATUS_POOL_MIN_ALLOC_ORDER 3 + +/* This is just an estimation for memory pool allocation */ +#define GHES_ESTATUS_CACHE_AVG_SIZE 512 + +#define GHES_ESTATUS_CACHES_SIZE 4 + +#define GHES_ESTATUS_IN_CACHE_MAX_NSEC 10000000000ULL +/* Prevent too many caches are allocated because of RCU */ +#define GHES_ESTATUS_CACHE_ALLOCED_MAX (GHES_ESTATUS_CACHES_SIZE * 3 / 2) + +#define GHES_ESTATUS_CACHE_LEN(estatus_len) \ + (sizeof(struct ghes_estatus_cache) + (estatus_len)) +#define GHES_ESTATUS_FROM_CACHE(estatus_cache) \ + ((struct acpi_hest_generic_status *) \ + ((struct ghes_estatus_cache *)(estatus_cache) + 1)) + +#define GHES_ESTATUS_NODE_LEN(estatus_len) \ + (sizeof(struct ghes_estatus_node) + (estatus_len)) +#define GHES_ESTATUS_FROM_NODE(estatus_node) \ + ((struct acpi_hest_generic_status *) \ + ((struct ghes_estatus_node *)(estatus_node) + 1)) /* * One struct ghes is created for each generic hardware error source. @@ -77,6 +104,22 @@ struct ghes { }; }; +struct ghes_estatus_node { + struct llist_node llnode; + struct acpi_hest_generic *generic; +}; + +struct ghes_estatus_cache { + u32 estatus_len; + atomic_t count; + struct acpi_hest_generic *generic; + unsigned long long time_in; + struct rcu_head rcu; +}; + +int ghes_disable; +module_param_named(disable, ghes_disable, bool, 0); + static int ghes_panic_timeout __read_mostly = 30; /* @@ -121,6 +164,22 @@ static struct vm_struct *ghes_ioremap_area; static DEFINE_RAW_SPINLOCK(ghes_ioremap_lock_nmi); static DEFINE_SPINLOCK(ghes_ioremap_lock_irq); +/* + * printk is not safe in NMI context. So in NMI handler, we allocate + * required memory from lock-less memory allocator + * (ghes_estatus_pool), save estatus into it, put them into lock-less + * list (ghes_estatus_llist), then delay printk into IRQ context via + * irq_work (ghes_proc_irq_work). ghes_estatus_size_request record + * required pool size by all NMI error source. + */ +static struct gen_pool *ghes_estatus_pool; +static unsigned long ghes_estatus_pool_size_request; +static struct llist_head ghes_estatus_llist; +static struct irq_work ghes_proc_irq_work; + +struct ghes_estatus_cache *ghes_estatus_caches[GHES_ESTATUS_CACHES_SIZE]; +static atomic_t ghes_estatus_cache_alloced; + static int ghes_ioremap_init(void) { ghes_ioremap_area = __get_vm_area(PAGE_SIZE * GHES_IOREMAP_PAGES, @@ -180,6 +239,55 @@ static void ghes_iounmap_irq(void __iomem *vaddr_ptr) __flush_tlb_one(vaddr); } +static int ghes_estatus_pool_init(void) +{ + ghes_estatus_pool = gen_pool_create(GHES_ESTATUS_POOL_MIN_ALLOC_ORDER, -1); + if (!ghes_estatus_pool) + return -ENOMEM; + return 0; +} + +static void ghes_estatus_pool_free_chunk_page(struct gen_pool *pool, + struct gen_pool_chunk *chunk, + void *data) +{ + free_page(chunk->start_addr); +} + +static void ghes_estatus_pool_exit(void) +{ + gen_pool_for_each_chunk(ghes_estatus_pool, + ghes_estatus_pool_free_chunk_page, NULL); + gen_pool_destroy(ghes_estatus_pool); +} + +static int ghes_estatus_pool_expand(unsigned long len) +{ + unsigned long i, pages, size, addr; + int ret; + + ghes_estatus_pool_size_request += PAGE_ALIGN(len); + size = gen_pool_size(ghes_estatus_pool); + if (size >= ghes_estatus_pool_size_request) + return 0; + pages = (ghes_estatus_pool_size_request - size) / PAGE_SIZE; + for (i = 0; i < pages; i++) { + addr = __get_free_page(GFP_KERNEL); + if (!addr) + return -ENOMEM; + ret = gen_pool_add(ghes_estatus_pool, addr, PAGE_SIZE, -1); + if (ret) + return ret; + } + + return 0; +} + +static void ghes_estatus_pool_shrink(unsigned long len) +{ + ghes_estatus_pool_size_request -= PAGE_ALIGN(len); +} + static struct ghes *ghes_new(struct acpi_hest_generic *generic) { struct ghes *ghes; @@ -341,43 +449,196 @@ static void ghes_clear_estatus(struct ghes *ghes) ghes->flags &= ~GHES_TO_CLEAR; } -static void ghes_do_proc(struct ghes *ghes) +static void ghes_do_proc(const struct acpi_hest_generic_status *estatus) { - int sev, processed = 0; + int sev, sec_sev; struct acpi_hest_generic_data *gdata; - sev = ghes_severity(ghes->estatus->error_severity); - apei_estatus_for_each_section(ghes->estatus, gdata) { -#ifdef CONFIG_X86_MCE + sev = ghes_severity(estatus->error_severity); + apei_estatus_for_each_section(estatus, gdata) { + sec_sev = ghes_severity(gdata->error_severity); if (!uuid_le_cmp(*(uuid_le *)gdata->section_type, CPER_SEC_PLATFORM_MEM)) { - apei_mce_report_mem_error( - sev == GHES_SEV_CORRECTED, - (struct cper_sec_mem_err *)(gdata+1)); - processed = 1; - } + struct cper_sec_mem_err *mem_err; + mem_err = (struct cper_sec_mem_err *)(gdata+1); +#ifdef CONFIG_X86_MCE + apei_mce_report_mem_error(sev == GHES_SEV_CORRECTED, + mem_err); #endif +#ifdef CONFIG_ACPI_APEI_MEMORY_FAILURE + if (sev == GHES_SEV_RECOVERABLE && + sec_sev == GHES_SEV_RECOVERABLE && + mem_err->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS) { + unsigned long pfn; + pfn = mem_err->physical_addr >> PAGE_SHIFT; + memory_failure_queue(pfn, 0, 0); + } +#endif + } } } -static void ghes_print_estatus(const char *pfx, struct ghes *ghes) +static void __ghes_print_estatus(const char *pfx, + const struct acpi_hest_generic *generic, + const struct acpi_hest_generic_status *estatus) { - /* Not more than 2 messages every 5 seconds */ - static DEFINE_RATELIMIT_STATE(ratelimit, 5*HZ, 2); - if (pfx == NULL) { - if (ghes_severity(ghes->estatus->error_severity) <= + if (ghes_severity(estatus->error_severity) <= GHES_SEV_CORRECTED) pfx = KERN_WARNING HW_ERR; else pfx = KERN_ERR HW_ERR; } - if (__ratelimit(&ratelimit)) { - printk( - "%s""Hardware error from APEI Generic Hardware Error Source: %d\n", - pfx, ghes->generic->header.source_id); - apei_estatus_print(pfx, ghes->estatus); + printk("%s""Hardware error from APEI Generic Hardware Error Source: %d\n", + pfx, generic->header.source_id); + apei_estatus_print(pfx, estatus); +} + +static int ghes_print_estatus(const char *pfx, + const struct acpi_hest_generic *generic, + const struct acpi_hest_generic_status *estatus) +{ + /* Not more than 2 messages every 5 seconds */ + static DEFINE_RATELIMIT_STATE(ratelimit_corrected, 5*HZ, 2); + static DEFINE_RATELIMIT_STATE(ratelimit_uncorrected, 5*HZ, 2); + struct ratelimit_state *ratelimit; + + if (ghes_severity(estatus->error_severity) <= GHES_SEV_CORRECTED) + ratelimit = &ratelimit_corrected; + else + ratelimit = &ratelimit_uncorrected; + if (__ratelimit(ratelimit)) { + __ghes_print_estatus(pfx, generic, estatus); + return 1; } + return 0; +} + +/* + * GHES error status reporting throttle, to report more kinds of + * errors, instead of just most frequently occurred errors. + */ +static int ghes_estatus_cached(struct acpi_hest_generic_status *estatus) +{ + u32 len; + int i, cached = 0; + unsigned long long now; + struct ghes_estatus_cache *cache; + struct acpi_hest_generic_status *cache_estatus; + + len = apei_estatus_len(estatus); + rcu_read_lock(); + for (i = 0; i < GHES_ESTATUS_CACHES_SIZE; i++) { + cache = rcu_dereference(ghes_estatus_caches[i]); + if (cache == NULL) + continue; + if (len != cache->estatus_len) + continue; + cache_estatus = GHES_ESTATUS_FROM_CACHE(cache); + if (memcmp(estatus, cache_estatus, len)) + continue; + atomic_inc(&cache->count); + now = sched_clock(); + if (now - cache->time_in < GHES_ESTATUS_IN_CACHE_MAX_NSEC) + cached = 1; + break; + } + rcu_read_unlock(); + return cached; +} + +static struct ghes_estatus_cache *ghes_estatus_cache_alloc( + struct acpi_hest_generic *generic, + struct acpi_hest_generic_status *estatus) +{ + int alloced; + u32 len, cache_len; + struct ghes_estatus_cache *cache; + struct acpi_hest_generic_status *cache_estatus; + + alloced = atomic_add_return(1, &ghes_estatus_cache_alloced); + if (alloced > GHES_ESTATUS_CACHE_ALLOCED_MAX) { + atomic_dec(&ghes_estatus_cache_alloced); + return NULL; + } + len = apei_estatus_len(estatus); + cache_len = GHES_ESTATUS_CACHE_LEN(len); + cache = (void *)gen_pool_alloc(ghes_estatus_pool, cache_len); + if (!cache) { + atomic_dec(&ghes_estatus_cache_alloced); + return NULL; + } + cache_estatus = GHES_ESTATUS_FROM_CACHE(cache); + memcpy(cache_estatus, estatus, len); + cache->estatus_len = len; + atomic_set(&cache->count, 0); + cache->generic = generic; + cache->time_in = sched_clock(); + return cache; +} + +static void ghes_estatus_cache_free(struct ghes_estatus_cache *cache) +{ + u32 len; + + len = apei_estatus_len(GHES_ESTATUS_FROM_CACHE(cache)); + len = GHES_ESTATUS_CACHE_LEN(len); + gen_pool_free(ghes_estatus_pool, (unsigned long)cache, len); + atomic_dec(&ghes_estatus_cache_alloced); +} + +static void ghes_estatus_cache_rcu_free(struct rcu_head *head) +{ + struct ghes_estatus_cache *cache; + + cache = container_of(head, struct ghes_estatus_cache, rcu); + ghes_estatus_cache_free(cache); +} + +static void ghes_estatus_cache_add( + struct acpi_hest_generic *generic, + struct acpi_hest_generic_status *estatus) +{ + int i, slot = -1, count; + unsigned long long now, duration, period, max_period = 0; + struct ghes_estatus_cache *cache, *slot_cache = NULL, *new_cache; + + new_cache = ghes_estatus_cache_alloc(generic, estatus); + if (new_cache == NULL) + return; + rcu_read_lock(); + now = sched_clock(); + for (i = 0; i < GHES_ESTATUS_CACHES_SIZE; i++) { + cache = rcu_dereference(ghes_estatus_caches[i]); + if (cache == NULL) { + slot = i; + slot_cache = NULL; + break; + } + duration = now - cache->time_in; + if (duration >= GHES_ESTATUS_IN_CACHE_MAX_NSEC) { + slot = i; + slot_cache = cache; + break; + } + count = atomic_read(&cache->count); + period = duration; + do_div(period, (count + 1)); + if (period > max_period) { + max_period = period; + slot = i; + slot_cache = cache; + } + } + /* new_cache must be put into array after its contents are written */ + smp_wmb(); + if (slot != -1 && cmpxchg(ghes_estatus_caches + slot, + slot_cache, new_cache) == slot_cache) { + if (slot_cache) + call_rcu(&slot_cache->rcu, ghes_estatus_cache_rcu_free); + } else + ghes_estatus_cache_free(new_cache); + rcu_read_unlock(); } static int ghes_proc(struct ghes *ghes) @@ -387,9 +648,11 @@ static int ghes_proc(struct ghes *ghes) rc = ghes_read_estatus(ghes, 0); if (rc) goto out; - ghes_print_estatus(NULL, ghes); - ghes_do_proc(ghes); - + if (!ghes_estatus_cached(ghes->estatus)) { + if (ghes_print_estatus(NULL, ghes->generic, ghes->estatus)) + ghes_estatus_cache_add(ghes->generic, ghes->estatus); + } + ghes_do_proc(ghes->estatus); out: ghes_clear_estatus(ghes); return 0; @@ -447,6 +710,45 @@ static int ghes_notify_sci(struct notifier_block *this, return ret; } +static void ghes_proc_in_irq(struct irq_work *irq_work) +{ + struct llist_node *llnode, *next, *tail = NULL; + struct ghes_estatus_node *estatus_node; + struct acpi_hest_generic *generic; + struct acpi_hest_generic_status *estatus; + u32 len, node_len; + + /* + * Because the time order of estatus in list is reversed, + * revert it back to proper order. + */ + llnode = llist_del_all(&ghes_estatus_llist); + while (llnode) { + next = llnode->next; + llnode->next = tail; + tail = llnode; + llnode = next; + } + llnode = tail; + while (llnode) { + next = llnode->next; + estatus_node = llist_entry(llnode, struct ghes_estatus_node, + llnode); + estatus = GHES_ESTATUS_FROM_NODE(estatus_node); + len = apei_estatus_len(estatus); + node_len = GHES_ESTATUS_NODE_LEN(len); + ghes_do_proc(estatus); + if (!ghes_estatus_cached(estatus)) { + generic = estatus_node->generic; + if (ghes_print_estatus(NULL, generic, estatus)) + ghes_estatus_cache_add(generic, estatus); + } + gen_pool_free(ghes_estatus_pool, (unsigned long)estatus_node, + node_len); + llnode = next; + } +} + static int ghes_notify_nmi(struct notifier_block *this, unsigned long cmd, void *data) { @@ -476,7 +778,8 @@ static int ghes_notify_nmi(struct notifier_block *this, if (sev_global >= GHES_SEV_PANIC) { oops_begin(); - ghes_print_estatus(KERN_EMERG HW_ERR, ghes_global); + __ghes_print_estatus(KERN_EMERG HW_ERR, ghes_global->generic, + ghes_global->estatus); /* reboot to log the error! */ if (panic_timeout == 0) panic_timeout = ghes_panic_timeout; @@ -484,12 +787,34 @@ static int ghes_notify_nmi(struct notifier_block *this, } list_for_each_entry_rcu(ghes, &ghes_nmi, list) { +#ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG + u32 len, node_len; + struct ghes_estatus_node *estatus_node; + struct acpi_hest_generic_status *estatus; +#endif if (!(ghes->flags & GHES_TO_CLEAR)) continue; - /* Do not print estatus because printk is not NMI safe */ - ghes_do_proc(ghes); +#ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG + if (ghes_estatus_cached(ghes->estatus)) + goto next; + /* Save estatus for further processing in IRQ context */ + len = apei_estatus_len(ghes->estatus); + node_len = GHES_ESTATUS_NODE_LEN(len); + estatus_node = (void *)gen_pool_alloc(ghes_estatus_pool, + node_len); + if (estatus_node) { + estatus_node->generic = ghes->generic; + estatus = GHES_ESTATUS_FROM_NODE(estatus_node); + memcpy(estatus, ghes->estatus, len); + llist_add(&estatus_node->llnode, &ghes_estatus_llist); + } +next: +#endif ghes_clear_estatus(ghes); } +#ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG + irq_work_queue(&ghes_proc_irq_work); +#endif out: raw_spin_unlock(&ghes_nmi_lock); @@ -504,10 +829,26 @@ static struct notifier_block ghes_notifier_nmi = { .notifier_call = ghes_notify_nmi, }; +static unsigned long ghes_esource_prealloc_size( + const struct acpi_hest_generic *generic) +{ + unsigned long block_length, prealloc_records, prealloc_size; + + block_length = min_t(unsigned long, generic->error_block_length, + GHES_ESTATUS_MAX_SIZE); + prealloc_records = max_t(unsigned long, + generic->records_to_preallocate, 1); + prealloc_size = min_t(unsigned long, block_length * prealloc_records, + GHES_ESOURCE_PREALLOC_MAX_SIZE); + + return prealloc_size; +} + static int __devinit ghes_probe(struct platform_device *ghes_dev) { struct acpi_hest_generic *generic; struct ghes *ghes = NULL; + unsigned long len; int rc = -EINVAL; generic = *(struct acpi_hest_generic **)ghes_dev->dev.platform_data; @@ -573,6 +914,8 @@ static int __devinit ghes_probe(struct platform_device *ghes_dev) mutex_unlock(&ghes_list_mutex); break; case ACPI_HEST_NOTIFY_NMI: + len = ghes_esource_prealloc_size(generic); + ghes_estatus_pool_expand(len); mutex_lock(&ghes_list_mutex); if (list_empty(&ghes_nmi)) register_die_notifier(&ghes_notifier_nmi); @@ -597,6 +940,7 @@ static int __devexit ghes_remove(struct platform_device *ghes_dev) { struct ghes *ghes; struct acpi_hest_generic *generic; + unsigned long len; ghes = platform_get_drvdata(ghes_dev); generic = ghes->generic; @@ -627,6 +971,8 @@ static int __devexit ghes_remove(struct platform_device *ghes_dev) * freed after NMI handler finishes. */ synchronize_rcu(); + len = ghes_esource_prealloc_size(generic); + ghes_estatus_pool_shrink(len); break; default: BUG(); @@ -662,15 +1008,43 @@ static int __init ghes_init(void) return -EINVAL; } + if (ghes_disable) { + pr_info(GHES_PFX "GHES is not enabled!\n"); + return -EINVAL; + } + + init_irq_work(&ghes_proc_irq_work, ghes_proc_in_irq); + rc = ghes_ioremap_init(); if (rc) goto err; - rc = platform_driver_register(&ghes_platform_driver); + rc = ghes_estatus_pool_init(); if (rc) goto err_ioremap_exit; + rc = ghes_estatus_pool_expand(GHES_ESTATUS_CACHE_AVG_SIZE * + GHES_ESTATUS_CACHE_ALLOCED_MAX); + if (rc) + goto err_pool_exit; + + rc = platform_driver_register(&ghes_platform_driver); + if (rc) + goto err_pool_exit; + + rc = apei_osc_setup(); + if (rc == 0 && osc_sb_apei_support_acked) + pr_info(GHES_PFX "APEI firmware first mode is enabled by APEI bit and WHEA _OSC.\n"); + else if (rc == 0 && !osc_sb_apei_support_acked) + pr_info(GHES_PFX "APEI firmware first mode is enabled by WHEA _OSC.\n"); + else if (rc && osc_sb_apei_support_acked) + pr_info(GHES_PFX "APEI firmware first mode is enabled by APEI bit.\n"); + else + pr_info(GHES_PFX "Failed to enable APEI firmware first mode.\n"); + return 0; +err_pool_exit: + ghes_estatus_pool_exit(); err_ioremap_exit: ghes_ioremap_exit(); err: @@ -680,6 +1054,7 @@ err: static void __exit ghes_exit(void) { platform_driver_unregister(&ghes_platform_driver); + ghes_estatus_pool_exit(); ghes_ioremap_exit(); } diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c index 181bc2f7bb74..05fee06f4d6e 100644 --- a/drivers/acpi/apei/hest.c +++ b/drivers/acpi/apei/hest.c @@ -231,16 +231,17 @@ void __init acpi_hest_init(void) goto err; } - rc = apei_hest_parse(hest_parse_ghes_count, &ghes_count); - if (rc) - goto err; - - rc = hest_ghes_dev_register(ghes_count); - if (!rc) { - pr_info(HEST_PFX "Table parsing has been initialized.\n"); - return; + if (!ghes_disable) { + rc = apei_hest_parse(hest_parse_ghes_count, &ghes_count); + if (rc) + goto err; + rc = hest_ghes_dev_register(ghes_count); + if (rc) + goto err; } + pr_info(HEST_PFX "Table parsing has been initialized.\n"); + return; err: hest_disable = 1; } diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 87c0a8daa99a..7711d94a0409 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -99,6 +99,7 @@ enum { struct acpi_battery { struct mutex lock; + struct mutex sysfs_lock; struct power_supply bat; struct acpi_device *device; struct notifier_block pm_nb; @@ -573,16 +574,16 @@ static int sysfs_add_battery(struct acpi_battery *battery) static void sysfs_remove_battery(struct acpi_battery *battery) { - mutex_lock(&battery->lock); + mutex_lock(&battery->sysfs_lock); if (!battery->bat.dev) { - mutex_unlock(&battery->lock); + mutex_unlock(&battery->sysfs_lock); return; } device_remove_file(battery->bat.dev, &alarm_attr); power_supply_unregister(&battery->bat); battery->bat.dev = NULL; - mutex_unlock(&battery->lock); + mutex_unlock(&battery->sysfs_lock); } /* @@ -982,6 +983,7 @@ static int acpi_battery_add(struct acpi_device *device) strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); device->driver_data = battery; mutex_init(&battery->lock); + mutex_init(&battery->sysfs_lock); if (ACPI_SUCCESS(acpi_get_handle(battery->device->handle, "_BIX", &handle))) set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags); @@ -1010,6 +1012,7 @@ static int acpi_battery_add(struct acpi_device *device) fail: sysfs_remove_battery(battery); mutex_destroy(&battery->lock); + mutex_destroy(&battery->sysfs_lock); kfree(battery); return result; } @@ -1027,6 +1030,7 @@ static int acpi_battery_remove(struct acpi_device *device, int type) #endif sysfs_remove_battery(battery); mutex_destroy(&battery->lock); + mutex_destroy(&battery->sysfs_lock); kfree(battery); return 0; } diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index d1e06c182cdb..437ddbf0c49a 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -39,6 +39,7 @@ #include <linux/pci.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> +#include <acpi/apei.h> #include <linux/dmi.h> #include <linux/suspend.h> @@ -519,6 +520,7 @@ out_kfree: } EXPORT_SYMBOL(acpi_run_osc); +bool osc_sb_apei_support_acked; static u8 sb_uuid_str[] = "0811B06E-4A27-44F9-8D60-3CBBC22E7B48"; static void acpi_bus_osc_support(void) { @@ -541,11 +543,19 @@ static void acpi_bus_osc_support(void) #if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_PPC_OST_SUPPORT; #endif + + if (!ghes_disable) + capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_APEI_SUPPORT; if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle))) return; - if (ACPI_SUCCESS(acpi_run_osc(handle, &context))) + if (ACPI_SUCCESS(acpi_run_osc(handle, &context))) { + u32 *capbuf_ret = context.ret.pointer; + if (context.ret.length > OSC_SUPPORT_TYPE) + osc_sb_apei_support_acked = + capbuf_ret[OSC_SUPPORT_TYPE] & OSC_SB_APEI_SUPPORT; kfree(context.ret.pointer); - /* do we need to check the returned cap? Sounds no */ + } + /* do we need to check other returned cap? Sounds no */ } /* -------------------------------------------------------------------------- diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index be8714aa9dd6..e18566a0fedd 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -80,7 +80,6 @@ static void genpd_set_active(struct generic_pm_domain *genpd) int pm_genpd_poweron(struct generic_pm_domain *genpd) { struct generic_pm_domain *parent = genpd->parent; - DEFINE_WAIT(wait); int ret = 0; start: @@ -112,7 +111,7 @@ int pm_genpd_poweron(struct generic_pm_domain *genpd) } if (genpd->power_on) { - int ret = genpd->power_on(genpd); + ret = genpd->power_on(genpd); if (ret) goto out; } diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 8dc247c974af..acb3f83b8079 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -226,11 +226,17 @@ static int rpm_idle(struct device *dev, int rpmflags) callback = NULL; if (callback) { - spin_unlock_irq(&dev->power.lock); + if (dev->power.irq_safe) + spin_unlock(&dev->power.lock); + else + spin_unlock_irq(&dev->power.lock); callback(dev); - spin_lock_irq(&dev->power.lock); + if (dev->power.irq_safe) + spin_lock(&dev->power.lock); + else + spin_lock_irq(&dev->power.lock); } dev->power.idle_notification = false; diff --git a/drivers/char/random.c b/drivers/char/random.c index 729281961f22..c35a785005b0 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1300,345 +1300,14 @@ ctl_table random_table[] = { }; #endif /* CONFIG_SYSCTL */ -/******************************************************************** - * - * Random functions for networking - * - ********************************************************************/ - -/* - * TCP initial sequence number picking. This uses the random number - * generator to pick an initial secret value. This value is hashed - * along with the TCP endpoint information to provide a unique - * starting point for each pair of TCP endpoints. This defeats - * attacks which rely on guessing the initial TCP sequence number. - * This algorithm was suggested by Steve Bellovin. - * - * Using a very strong hash was taking an appreciable amount of the total - * TCP connection establishment time, so this is a weaker hash, - * compensated for by changing the secret periodically. - */ - -/* F, G and H are basic MD4 functions: selection, majority, parity */ -#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) -#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z))) -#define H(x, y, z) ((x) ^ (y) ^ (z)) - -/* - * The generic round function. The application is so specific that - * we don't bother protecting all the arguments with parens, as is generally - * good macro practice, in favor of extra legibility. - * Rotation is separate from addition to prevent recomputation - */ -#define ROUND(f, a, b, c, d, x, s) \ - (a += f(b, c, d) + x, a = (a << s) | (a >> (32 - s))) -#define K1 0 -#define K2 013240474631UL -#define K3 015666365641UL - -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - -static __u32 twothirdsMD4Transform(__u32 const buf[4], __u32 const in[12]) -{ - __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; - - /* Round 1 */ - ROUND(F, a, b, c, d, in[ 0] + K1, 3); - ROUND(F, d, a, b, c, in[ 1] + K1, 7); - ROUND(F, c, d, a, b, in[ 2] + K1, 11); - ROUND(F, b, c, d, a, in[ 3] + K1, 19); - ROUND(F, a, b, c, d, in[ 4] + K1, 3); - ROUND(F, d, a, b, c, in[ 5] + K1, 7); - ROUND(F, c, d, a, b, in[ 6] + K1, 11); - ROUND(F, b, c, d, a, in[ 7] + K1, 19); - ROUND(F, a, b, c, d, in[ 8] + K1, 3); - ROUND(F, d, a, b, c, in[ 9] + K1, 7); - ROUND(F, c, d, a, b, in[10] + K1, 11); - ROUND(F, b, c, d, a, in[11] + K1, 19); - - /* Round 2 */ - ROUND(G, a, b, c, d, in[ 1] + K2, 3); - ROUND(G, d, a, b, c, in[ 3] + K2, 5); - ROUND(G, c, d, a, b, in[ 5] + K2, 9); - ROUND(G, b, c, d, a, in[ 7] + K2, 13); - ROUND(G, a, b, c, d, in[ 9] + K2, 3); - ROUND(G, d, a, b, c, in[11] + K2, 5); - ROUND(G, c, d, a, b, in[ 0] + K2, 9); - ROUND(G, b, c, d, a, in[ 2] + K2, 13); - ROUND(G, a, b, c, d, in[ 4] + K2, 3); - ROUND(G, d, a, b, c, in[ 6] + K2, 5); - ROUND(G, c, d, a, b, in[ 8] + K2, 9); - ROUND(G, b, c, d, a, in[10] + K2, 13); - - /* Round 3 */ - ROUND(H, a, b, c, d, in[ 3] + K3, 3); - ROUND(H, d, a, b, c, in[ 7] + K3, 9); - ROUND(H, c, d, a, b, in[11] + K3, 11); - ROUND(H, b, c, d, a, in[ 2] + K3, 15); - ROUND(H, a, b, c, d, in[ 6] + K3, 3); - ROUND(H, d, a, b, c, in[10] + K3, 9); - ROUND(H, c, d, a, b, in[ 1] + K3, 11); - ROUND(H, b, c, d, a, in[ 5] + K3, 15); - ROUND(H, a, b, c, d, in[ 9] + K3, 3); - ROUND(H, d, a, b, c, in[ 0] + K3, 9); - ROUND(H, c, d, a, b, in[ 4] + K3, 11); - ROUND(H, b, c, d, a, in[ 8] + K3, 15); - - return buf[1] + b; /* "most hashed" word */ - /* Alternative: return sum of all words? */ -} -#endif - -#undef ROUND -#undef F -#undef G -#undef H -#undef K1 -#undef K2 -#undef K3 - -/* This should not be decreased so low that ISNs wrap too fast. */ -#define REKEY_INTERVAL (300 * HZ) -/* - * Bit layout of the tcp sequence numbers (before adding current time): - * bit 24-31: increased after every key exchange - * bit 0-23: hash(source,dest) - * - * The implementation is similar to the algorithm described - * in the Appendix of RFC 1185, except that - * - it uses a 1 MHz clock instead of a 250 kHz clock - * - it performs a rekey every 5 minutes, which is equivalent - * to a (source,dest) tulple dependent forward jump of the - * clock by 0..2^(HASH_BITS+1) - * - * Thus the average ISN wraparound time is 68 minutes instead of - * 4.55 hours. - * - * SMP cleanup and lock avoidance with poor man's RCU. - * Manfred Spraul <manfred@colorfullife.com> - * - */ -#define COUNT_BITS 8 -#define COUNT_MASK ((1 << COUNT_BITS) - 1) -#define HASH_BITS 24 -#define HASH_MASK ((1 << HASH_BITS) - 1) +static u32 random_int_secret[MD5_MESSAGE_BYTES / 4] ____cacheline_aligned; -static struct keydata { - __u32 count; /* already shifted to the final position */ - __u32 secret[12]; -} ____cacheline_aligned ip_keydata[2]; - -static unsigned int ip_cnt; - -static void rekey_seq_generator(struct work_struct *work); - -static DECLARE_DELAYED_WORK(rekey_work, rekey_seq_generator); - -/* - * Lock avoidance: - * The ISN generation runs lockless - it's just a hash over random data. - * State changes happen every 5 minutes when the random key is replaced. - * Synchronization is performed by having two copies of the hash function - * state and rekey_seq_generator always updates the inactive copy. - * The copy is then activated by updating ip_cnt. - * The implementation breaks down if someone blocks the thread - * that processes SYN requests for more than 5 minutes. Should never - * happen, and even if that happens only a not perfectly compliant - * ISN is generated, nothing fatal. - */ -static void rekey_seq_generator(struct work_struct *work) +static int __init random_int_secret_init(void) { - struct keydata *keyptr = &ip_keydata[1 ^ (ip_cnt & 1)]; - - get_random_bytes(keyptr->secret, sizeof(keyptr->secret)); - keyptr->count = (ip_cnt & COUNT_MASK) << HASH_BITS; - smp_wmb(); - ip_cnt++; - schedule_delayed_work(&rekey_work, - round_jiffies_relative(REKEY_INTERVAL)); -} - -static inline struct keydata *get_keyptr(void) -{ - struct keydata *keyptr = &ip_keydata[ip_cnt & 1]; - - smp_rmb(); - - return keyptr; -} - -static __init int seqgen_init(void) -{ - rekey_seq_generator(NULL); + get_random_bytes(random_int_secret, sizeof(random_int_secret)); return 0; } -late_initcall(seqgen_init); - -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -__u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr, - __be16 sport, __be16 dport) -{ - __u32 seq; - __u32 hash[12]; - struct keydata *keyptr = get_keyptr(); - - /* The procedure is the same as for IPv4, but addresses are longer. - * Thus we must use twothirdsMD4Transform. - */ - - memcpy(hash, saddr, 16); - hash[4] = ((__force u16)sport << 16) + (__force u16)dport; - memcpy(&hash[5], keyptr->secret, sizeof(__u32) * 7); - - seq = twothirdsMD4Transform((const __u32 *)daddr, hash) & HASH_MASK; - seq += keyptr->count; - - seq += ktime_to_ns(ktime_get_real()); - - return seq; -} -EXPORT_SYMBOL(secure_tcpv6_sequence_number); -#endif - -/* The code below is shamelessly stolen from secure_tcp_sequence_number(). - * All blames to Andrey V. Savochkin <saw@msu.ru>. - */ -__u32 secure_ip_id(__be32 daddr) -{ - struct keydata *keyptr; - __u32 hash[4]; - - keyptr = get_keyptr(); - - /* - * Pick a unique starting offset for each IP destination. - * The dest ip address is placed in the starting vector, - * which is then hashed with random data. - */ - hash[0] = (__force __u32)daddr; - hash[1] = keyptr->secret[9]; - hash[2] = keyptr->secret[10]; - hash[3] = keyptr->secret[11]; - - return half_md4_transform(hash, keyptr->secret); -} - -__u32 secure_ipv6_id(const __be32 daddr[4]) -{ - const struct keydata *keyptr; - __u32 hash[4]; - - keyptr = get_keyptr(); - - hash[0] = (__force __u32)daddr[0]; - hash[1] = (__force __u32)daddr[1]; - hash[2] = (__force __u32)daddr[2]; - hash[3] = (__force __u32)daddr[3]; - - return half_md4_transform(hash, keyptr->secret); -} - -#ifdef CONFIG_INET - -__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, - __be16 sport, __be16 dport) -{ - __u32 seq; - __u32 hash[4]; - struct keydata *keyptr = get_keyptr(); - - /* - * Pick a unique starting offset for each TCP connection endpoints - * (saddr, daddr, sport, dport). - * Note that the words are placed into the starting vector, which is - * then mixed with a partial MD4 over random data. - */ - hash[0] = (__force u32)saddr; - hash[1] = (__force u32)daddr; - hash[2] = ((__force u16)sport << 16) + (__force u16)dport; - hash[3] = keyptr->secret[11]; - - seq = half_md4_transform(hash, keyptr->secret) & HASH_MASK; - seq += keyptr->count; - /* - * As close as possible to RFC 793, which - * suggests using a 250 kHz clock. - * Further reading shows this assumes 2 Mb/s networks. - * For 10 Mb/s Ethernet, a 1 MHz clock is appropriate. - * For 10 Gb/s Ethernet, a 1 GHz clock should be ok, but - * we also need to limit the resolution so that the u32 seq - * overlaps less than one time per MSL (2 minutes). - * Choosing a clock of 64 ns period is OK. (period of 274 s) - */ - seq += ktime_to_ns(ktime_get_real()) >> 6; - - return seq; -} - -/* Generate secure starting point for ephemeral IPV4 transport port search */ -u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport) -{ - struct keydata *keyptr = get_keyptr(); - u32 hash[4]; - - /* - * Pick a unique starting offset for each ephemeral port search - * (saddr, daddr, dport) and 48bits of random data. - */ - hash[0] = (__force u32)saddr; - hash[1] = (__force u32)daddr; - hash[2] = (__force u32)dport ^ keyptr->secret[10]; - hash[3] = keyptr->secret[11]; - - return half_md4_transform(hash, keyptr->secret); -} -EXPORT_SYMBOL_GPL(secure_ipv4_port_ephemeral); - -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, - __be16 dport) -{ - struct keydata *keyptr = get_keyptr(); - u32 hash[12]; - - memcpy(hash, saddr, 16); - hash[4] = (__force u32)dport; - memcpy(&hash[5], keyptr->secret, sizeof(__u32) * 7); - - return twothirdsMD4Transform((const __u32 *)daddr, hash); -} -#endif - -#if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE) -/* Similar to secure_tcp_sequence_number but generate a 48 bit value - * bit's 32-47 increase every key exchange - * 0-31 hash(source, dest) - */ -u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr, - __be16 sport, __be16 dport) -{ - u64 seq; - __u32 hash[4]; - struct keydata *keyptr = get_keyptr(); - - hash[0] = (__force u32)saddr; - hash[1] = (__force u32)daddr; - hash[2] = ((__force u16)sport << 16) + (__force u16)dport; - hash[3] = keyptr->secret[11]; - - seq = half_md4_transform(hash, keyptr->secret); - seq |= ((u64)keyptr->count) << (32 - HASH_BITS); - - seq += ktime_to_ns(ktime_get_real()); - seq &= (1ull << 48) - 1; - - return seq; -} -EXPORT_SYMBOL(secure_dccp_sequence_number); -#endif - -#endif /* CONFIG_INET */ - +late_initcall(random_int_secret_init); /* * Get a random word for internal kernel use only. Similar to urandom but @@ -1646,17 +1315,15 @@ EXPORT_SYMBOL(secure_dccp_sequence_number); * value is not cryptographically secure but for several uses the cost of * depleting entropy is too high */ -DEFINE_PER_CPU(__u32 [4], get_random_int_hash); +DEFINE_PER_CPU(__u32 [MD5_DIGEST_WORDS], get_random_int_hash); unsigned int get_random_int(void) { - struct keydata *keyptr; __u32 *hash = get_cpu_var(get_random_int_hash); - int ret; + unsigned int ret; - keyptr = get_keyptr(); hash[0] += current->pid + jiffies + get_cycles(); - - ret = half_md4_transform(hash, keyptr->secret); + md5_transform(hash, random_int_secret); + ret = hash[0]; put_cpu_var(get_random_int_hash); return ret; diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c index 3ee1fdb31ea7..e55814bc0d06 100644 --- a/drivers/connector/cn_proc.c +++ b/drivers/connector/cn_proc.c @@ -57,6 +57,7 @@ void proc_fork_connector(struct task_struct *task) struct proc_event *ev; __u8 buffer[CN_PROC_MSG_SIZE]; struct timespec ts; + struct task_struct *parent; if (atomic_read(&proc_event_num_listeners) < 1) return; @@ -67,8 +68,11 @@ void proc_fork_connector(struct task_struct *task) ktime_get_ts(&ts); /* get high res monotonic timestamp */ put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns); ev->what = PROC_EVENT_FORK; - ev->event_data.fork.parent_pid = task->real_parent->pid; - ev->event_data.fork.parent_tgid = task->real_parent->tgid; + rcu_read_lock(); + parent = rcu_dereference(task->real_parent); + ev->event_data.fork.parent_pid = parent->pid; + ev->event_data.fork.parent_tgid = parent->tgid; + rcu_read_unlock(); ev->event_data.fork.child_pid = task->pid; ev->event_data.fork.child_tgid = task->tgid; diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index bf5092455a8f..d4c542372886 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -25,9 +25,19 @@ DEFINE_PER_CPU(struct cpuidle_device *, cpuidle_devices); DEFINE_MUTEX(cpuidle_lock); LIST_HEAD(cpuidle_detected_devices); -static void (*pm_idle_old)(void); static int enabled_devices; +static int off __read_mostly; +static int initialized __read_mostly; + +int cpuidle_disabled(void) +{ + return off; +} +void disable_cpuidle(void) +{ + off = 1; +} #if defined(CONFIG_ARCH_HAS_CPU_IDLE_WAIT) static void cpuidle_kick_cpus(void) @@ -46,25 +56,23 @@ static int __cpuidle_register_device(struct cpuidle_device *dev); * cpuidle_idle_call - the main idle loop * * NOTE: no locks or semaphores should be used here + * return non-zero on failure */ -static void cpuidle_idle_call(void) +int cpuidle_idle_call(void) { struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); struct cpuidle_state *target_state; int next_state; + if (off) + return -ENODEV; + + if (!initialized) + return -ENODEV; + /* check if the device is ready */ - if (!dev || !dev->enabled) { - if (pm_idle_old) - pm_idle_old(); - else -#if defined(CONFIG_ARCH_HAS_DEFAULT_IDLE) - default_idle(); -#else - local_irq_enable(); -#endif - return; - } + if (!dev || !dev->enabled) + return -EBUSY; #if 0 /* shows regressions, re-enable for 2.6.29 */ @@ -89,7 +97,7 @@ static void cpuidle_idle_call(void) next_state = cpuidle_curr_governor->select(dev); if (need_resched()) { local_irq_enable(); - return; + return 0; } target_state = &dev->states[next_state]; @@ -114,6 +122,8 @@ static void cpuidle_idle_call(void) /* give the governor an opportunity to reflect on the outcome */ if (cpuidle_curr_governor->reflect) cpuidle_curr_governor->reflect(dev); + + return 0; } /** @@ -121,10 +131,10 @@ static void cpuidle_idle_call(void) */ void cpuidle_install_idle_handler(void) { - if (enabled_devices && (pm_idle != cpuidle_idle_call)) { + if (enabled_devices) { /* Make sure all changes finished before we switch to new idle */ smp_wmb(); - pm_idle = cpuidle_idle_call; + initialized = 1; } } @@ -133,8 +143,8 @@ void cpuidle_install_idle_handler(void) */ void cpuidle_uninstall_idle_handler(void) { - if (enabled_devices && pm_idle_old && (pm_idle != pm_idle_old)) { - pm_idle = pm_idle_old; + if (enabled_devices) { + initialized = 0; cpuidle_kick_cpus(); } } @@ -427,7 +437,8 @@ static int __init cpuidle_init(void) { int ret; - pm_idle_old = pm_idle; + if (cpuidle_disabled()) + return -ENODEV; ret = cpuidle_add_class_sysfs(&cpu_sysdev_class); if (ret) @@ -438,4 +449,5 @@ static int __init cpuidle_init(void) return 0; } +module_param(off, int, 0444); core_initcall(cpuidle_init); diff --git a/drivers/cpuidle/cpuidle.h b/drivers/cpuidle/cpuidle.h index 33e50d556f17..38c3fd8b9d76 100644 --- a/drivers/cpuidle/cpuidle.h +++ b/drivers/cpuidle/cpuidle.h @@ -13,6 +13,7 @@ extern struct list_head cpuidle_governors; extern struct list_head cpuidle_detected_devices; extern struct mutex cpuidle_lock; extern spinlock_t cpuidle_driver_lock; +extern int cpuidle_disabled(void); /* idle loop */ extern void cpuidle_install_idle_handler(void); diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c index fd1601e3d125..3f7e3cedd133 100644 --- a/drivers/cpuidle/driver.c +++ b/drivers/cpuidle/driver.c @@ -26,6 +26,9 @@ int cpuidle_register_driver(struct cpuidle_driver *drv) if (!drv) return -EINVAL; + if (cpuidle_disabled()) + return -ENODEV; + spin_lock(&cpuidle_driver_lock); if (cpuidle_curr_driver) { spin_unlock(&cpuidle_driver_lock); diff --git a/drivers/cpuidle/governor.c b/drivers/cpuidle/governor.c index 724c164d31c9..ea2f8e7aa24a 100644 --- a/drivers/cpuidle/governor.c +++ b/drivers/cpuidle/governor.c @@ -81,6 +81,9 @@ int cpuidle_register_governor(struct cpuidle_governor *gov) if (!gov || !gov->select) return -EINVAL; + if (cpuidle_disabled()) + return -ENODEV; + mutex_lock(&cpuidle_lock); if (__cpuidle_find_governor(gov->name) == NULL) { ret = 0; diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 26374b2a55a2..b48967b499da 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -62,9 +62,9 @@ #include <linux/slab.h> static DEFINE_MUTEX(dma_list_mutex); +static DEFINE_IDR(dma_idr); static LIST_HEAD(dma_device_list); static long dmaengine_ref_count; -static struct idr dma_idr; /* --- sysfs implementation --- */ @@ -1050,8 +1050,6 @@ EXPORT_SYMBOL_GPL(dma_run_dependencies); static int __init dma_bus_init(void) { - idr_init(&dma_idr); - mutex_init(&dma_list_mutex); return class_register(&dma_devclass); } arch_initcall(dma_bus_init); diff --git a/drivers/dma/ioat/dma_v3.c b/drivers/dma/ioat/dma_v3.c index d845dc4b7103..f519c93a61e7 100644 --- a/drivers/dma/ioat/dma_v3.c +++ b/drivers/dma/ioat/dma_v3.c @@ -73,10 +73,10 @@ /* provide a lookup table for setting the source address in the base or * extended descriptor of an xor or pq descriptor */ -static const u8 xor_idx_to_desc __read_mostly = 0xd0; -static const u8 xor_idx_to_field[] __read_mostly = { 1, 4, 5, 6, 7, 0, 1, 2 }; -static const u8 pq_idx_to_desc __read_mostly = 0xf8; -static const u8 pq_idx_to_field[] __read_mostly = { 1, 4, 5, 0, 1, 2, 4, 5 }; +static const u8 xor_idx_to_desc = 0xe0; +static const u8 xor_idx_to_field[] = { 1, 4, 5, 6, 7, 0, 1, 2 }; +static const u8 pq_idx_to_desc = 0xf8; +static const u8 pq_idx_to_field[] = { 1, 4, 5, 0, 1, 2, 4, 5 }; static dma_addr_t xor_get_src(struct ioat_raw_descriptor *descs[2], int idx) { diff --git a/drivers/dma/ioat/pci.c b/drivers/dma/ioat/pci.c index fab37d1cf48d..5e3a40f79945 100644 --- a/drivers/dma/ioat/pci.c +++ b/drivers/dma/ioat/pci.c @@ -72,6 +72,17 @@ static struct pci_device_id ioat_pci_tbl[] = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_JSF8) }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_JSF9) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB0) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB1) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB2) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB3) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB4) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB5) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB6) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB7) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB8) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB9) }, + { 0, } }; MODULE_DEVICE_TABLE(pci, ioat_pci_tbl); diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index af1a17d42bd7..c422fead0855 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -41,7 +41,7 @@ config EDAC_DEBUG config EDAC_DECODE_MCE tristate "Decode MCEs in human-readable form (only on AMD for now)" - depends on CPU_SUP_AMD && X86_MCE + depends on CPU_SUP_AMD && X86_MCE_AMD default y ---help--- Enable this option if you want to decode Machine Check Exceptions @@ -173,8 +173,7 @@ config EDAC_I5400 config EDAC_I7CORE tristate "Intel i7 Core (Nehalem) processors" - depends on EDAC_MM_EDAC && PCI && X86 - select EDAC_MCE + depends on EDAC_MM_EDAC && PCI && X86 && X86_MCE_INTEL help Support for error detection and correction the Intel i7 Core (Nehalem) Integrated Memory Controller that exists on diff --git a/drivers/eisa/pci_eisa.c b/drivers/eisa/pci_eisa.c index 30da70d06a6d..cdae207028a7 100644 --- a/drivers/eisa/pci_eisa.c +++ b/drivers/eisa/pci_eisa.c @@ -45,13 +45,13 @@ static int __init pci_eisa_init(struct pci_dev *pdev, return 0; } -static struct pci_device_id __initdata pci_eisa_pci_tbl[] = { +static struct pci_device_id pci_eisa_pci_tbl[] = { { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_BRIDGE_EISA << 8, 0xffff00, 0 }, { 0, } }; -static struct pci_driver __initdata pci_eisa_driver = { +static struct pci_driver __refdata pci_eisa_driver = { .name = "pci_eisa", .id_table = pci_eisa_pci_tbl, .probe = pci_eisa_init, diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index 9d8c892d07c9..9d2668a50872 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -90,7 +90,6 @@ int drm_debugfs_create_files(struct drm_info_list *files, int count, struct drm_device *dev = minor->dev; struct dentry *ent; struct drm_info_node *tmp; - char name[64]; int i, ret; for (i = 0; i < count; i++) { @@ -108,6 +107,9 @@ int drm_debugfs_create_files(struct drm_info_list *files, int count, ent = debugfs_create_file(files[i].name, S_IFREG | S_IRUGO, root, tmp, &drm_debugfs_fops); if (!ent) { + char name[64]; + strncpy(name, root->d_name.name, + min(root->d_name.len, 64U)); DRM_ERROR("Cannot create /sys/kernel/debug/dri/%s/%s\n", name, files[i].name); kfree(tmp); diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 756af4d7ec74..7425e5c9bd75 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -127,6 +127,23 @@ static const u8 edid_header[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }; + /* + * Sanity check the header of the base EDID block. Return 8 if the header + * is perfect, down to 0 if it's totally wrong. + */ +int drm_edid_header_is_valid(const u8 *raw_edid) +{ + int i, score = 0; + + for (i = 0; i < sizeof(edid_header); i++) + if (raw_edid[i] == edid_header[i]) + score++; + + return score; +} +EXPORT_SYMBOL(drm_edid_header_is_valid); + + /* * Sanity check the EDID block (base or extension). Return 0 if the block * doesn't check out, or 1 if it's valid. @@ -139,12 +156,7 @@ drm_edid_block_valid(u8 *raw_edid) struct edid *edid = (struct edid *)raw_edid; if (raw_edid[0] == 0x00) { - int score = 0; - - for (i = 0; i < sizeof(edid_header); i++) - if (raw_edid[i] == edid_header[i]) - score++; - + int score = drm_edid_header_is_valid(raw_edid); if (score == 8) ; else if (score >= 6) { DRM_DEBUG("Fixing EDID header, your hardware may be failing\n"); @@ -1439,6 +1451,8 @@ EXPORT_SYMBOL(drm_detect_monitor_audio); static void drm_add_display_info(struct edid *edid, struct drm_display_info *info) { + u8 *edid_ext; + info->width_mm = edid->width_cm * 10; info->height_mm = edid->height_cm * 10; @@ -1483,6 +1497,13 @@ static void drm_add_display_info(struct edid *edid, info->color_formats = DRM_COLOR_FORMAT_YCRCB444; if (info->color_formats & DRM_EDID_FEATURE_RGB_YCRCB422) info->color_formats = DRM_COLOR_FORMAT_YCRCB422; + + /* Get data from CEA blocks if present */ + edid_ext = drm_find_cea_extension(edid); + if (!edid_ext) + return; + + info->cea_rev = edid_ext[1]; } /** diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 2022a5c966bb..3830e9e478c0 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -291,11 +291,14 @@ static void drm_irq_vgaarb_nokms(void *cookie, bool state) if (!dev->irq_enabled) return; - if (state) - dev->driver->irq_uninstall(dev); - else { - dev->driver->irq_preinstall(dev); - dev->driver->irq_postinstall(dev); + if (state) { + if (dev->driver->irq_uninstall) + dev->driver->irq_uninstall(dev); + } else { + if (dev->driver->irq_preinstall) + dev->driver->irq_preinstall(dev); + if (dev->driver->irq_postinstall) + dev->driver->irq_postinstall(dev); } } @@ -338,7 +341,8 @@ int drm_irq_install(struct drm_device *dev) DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev)); /* Before installing handler */ - dev->driver->irq_preinstall(dev); + if (dev->driver->irq_preinstall) + dev->driver->irq_preinstall(dev); /* Install handler */ if (drm_core_check_feature(dev, DRIVER_IRQ_SHARED)) @@ -363,11 +367,16 @@ int drm_irq_install(struct drm_device *dev) vga_client_register(dev->pdev, (void *)dev, drm_irq_vgaarb_nokms, NULL); /* After installing handler */ - ret = dev->driver->irq_postinstall(dev); + if (dev->driver->irq_postinstall) + ret = dev->driver->irq_postinstall(dev); + if (ret < 0) { mutex_lock(&dev->struct_mutex); dev->irq_enabled = 0; mutex_unlock(&dev->struct_mutex); + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + vga_client_register(dev->pdev, NULL, NULL, NULL); + free_irq(drm_dev_to_irq(dev), dev); } return ret; @@ -413,7 +422,8 @@ int drm_irq_uninstall(struct drm_device *dev) if (!drm_core_check_feature(dev, DRIVER_MODESET)) vga_client_register(dev->pdev, NULL, NULL, NULL); - dev->driver->irq_uninstall(dev); + if (dev->driver->irq_uninstall) + dev->driver->irq_uninstall(dev); free_irq(drm_dev_to_irq(dev), dev); diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index e2662497d50f..a8ab6263e0d7 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1338,6 +1338,155 @@ static const struct file_operations i915_wedged_fops = { .llseek = default_llseek, }; +static int +i915_max_freq_open(struct inode *inode, + struct file *filp) +{ + filp->private_data = inode->i_private; + return 0; +} + +static ssize_t +i915_max_freq_read(struct file *filp, + char __user *ubuf, + size_t max, + loff_t *ppos) +{ + struct drm_device *dev = filp->private_data; + drm_i915_private_t *dev_priv = dev->dev_private; + char buf[80]; + int len; + + len = snprintf(buf, sizeof (buf), + "max freq: %d\n", dev_priv->max_delay * 50); + + if (len > sizeof (buf)) + len = sizeof (buf); + + return simple_read_from_buffer(ubuf, max, ppos, buf, len); +} + +static ssize_t +i915_max_freq_write(struct file *filp, + const char __user *ubuf, + size_t cnt, + loff_t *ppos) +{ + struct drm_device *dev = filp->private_data; + struct drm_i915_private *dev_priv = dev->dev_private; + char buf[20]; + int val = 1; + + if (cnt > 0) { + if (cnt > sizeof (buf) - 1) + return -EINVAL; + + if (copy_from_user(buf, ubuf, cnt)) + return -EFAULT; + buf[cnt] = 0; + + val = simple_strtoul(buf, NULL, 0); + } + + DRM_DEBUG_DRIVER("Manually setting max freq to %d\n", val); + + /* + * Turbo will still be enabled, but won't go above the set value. + */ + dev_priv->max_delay = val / 50; + + gen6_set_rps(dev, val / 50); + + return cnt; +} + +static const struct file_operations i915_max_freq_fops = { + .owner = THIS_MODULE, + .open = i915_max_freq_open, + .read = i915_max_freq_read, + .write = i915_max_freq_write, + .llseek = default_llseek, +}; + +static int +i915_cache_sharing_open(struct inode *inode, + struct file *filp) +{ + filp->private_data = inode->i_private; + return 0; +} + +static ssize_t +i915_cache_sharing_read(struct file *filp, + char __user *ubuf, + size_t max, + loff_t *ppos) +{ + struct drm_device *dev = filp->private_data; + drm_i915_private_t *dev_priv = dev->dev_private; + char buf[80]; + u32 snpcr; + int len; + + mutex_lock(&dev_priv->dev->struct_mutex); + snpcr = I915_READ(GEN6_MBCUNIT_SNPCR); + mutex_unlock(&dev_priv->dev->struct_mutex); + + len = snprintf(buf, sizeof (buf), + "%d\n", (snpcr & GEN6_MBC_SNPCR_MASK) >> + GEN6_MBC_SNPCR_SHIFT); + + if (len > sizeof (buf)) + len = sizeof (buf); + + return simple_read_from_buffer(ubuf, max, ppos, buf, len); +} + +static ssize_t +i915_cache_sharing_write(struct file *filp, + const char __user *ubuf, + size_t cnt, + loff_t *ppos) +{ + struct drm_device *dev = filp->private_data; + struct drm_i915_private *dev_priv = dev->dev_private; + char buf[20]; + u32 snpcr; + int val = 1; + + if (cnt > 0) { + if (cnt > sizeof (buf) - 1) + return -EINVAL; + + if (copy_from_user(buf, ubuf, cnt)) + return -EFAULT; + buf[cnt] = 0; + + val = simple_strtoul(buf, NULL, 0); + } + + if (val < 0 || val > 3) + return -EINVAL; + + DRM_DEBUG_DRIVER("Manually setting uncore sharing to %d\n", val); + + /* Update the cache sharing policy here as well */ + snpcr = I915_READ(GEN6_MBCUNIT_SNPCR); + snpcr &= ~GEN6_MBC_SNPCR_MASK; + snpcr |= (val << GEN6_MBC_SNPCR_SHIFT); + I915_WRITE(GEN6_MBCUNIT_SNPCR, snpcr); + + return cnt; +} + +static const struct file_operations i915_cache_sharing_fops = { + .owner = THIS_MODULE, + .open = i915_cache_sharing_open, + .read = i915_cache_sharing_read, + .write = i915_cache_sharing_write, + .llseek = default_llseek, +}; + /* As the drm_debugfs_init() routines are called before dev->dev_private is * allocated we need to hook into the minor for release. */ static int @@ -1437,6 +1586,36 @@ static int i915_forcewake_create(struct dentry *root, struct drm_minor *minor) return drm_add_fake_info_node(minor, ent, &i915_forcewake_fops); } +static int i915_max_freq_create(struct dentry *root, struct drm_minor *minor) +{ + struct drm_device *dev = minor->dev; + struct dentry *ent; + + ent = debugfs_create_file("i915_max_freq", + S_IRUGO | S_IWUSR, + root, dev, + &i915_max_freq_fops); + if (IS_ERR(ent)) + return PTR_ERR(ent); + + return drm_add_fake_info_node(minor, ent, &i915_max_freq_fops); +} + +static int i915_cache_sharing_create(struct dentry *root, struct drm_minor *minor) +{ + struct drm_device *dev = minor->dev; + struct dentry *ent; + + ent = debugfs_create_file("i915_cache_sharing", + S_IRUGO | S_IWUSR, + root, dev, + &i915_cache_sharing_fops); + if (IS_ERR(ent)) + return PTR_ERR(ent); + + return drm_add_fake_info_node(minor, ent, &i915_cache_sharing_fops); +} + static struct drm_info_list i915_debugfs_list[] = { {"i915_capabilities", i915_capabilities, 0}, {"i915_gem_objects", i915_gem_object_info, 0}, @@ -1490,6 +1669,12 @@ int i915_debugfs_init(struct drm_minor *minor) ret = i915_forcewake_create(minor->debugfs_root, minor); if (ret) return ret; + ret = i915_max_freq_create(minor->debugfs_root, minor); + if (ret) + return ret; + ret = i915_cache_sharing_create(minor->debugfs_root, minor); + if (ret) + return ret; return drm_debugfs_create_files(i915_debugfs_list, I915_DEBUGFS_ENTRIES, @@ -1504,6 +1689,10 @@ void i915_debugfs_cleanup(struct drm_minor *minor) 1, minor); drm_debugfs_remove_files((struct drm_info_list *) &i915_wedged_fops, 1, minor); + drm_debugfs_remove_files((struct drm_info_list *) &i915_max_freq_fops, + 1, minor); + drm_debugfs_remove_files((struct drm_info_list *) &i915_cache_sharing_fops, + 1, minor); } #endif /* CONFIG_DEBUG_FS */ diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 12712824a6d2..8a3942c4f099 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -61,7 +61,6 @@ static void i915_write_hws_pga(struct drm_device *dev) static int i915_init_phys_hws(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; - struct intel_ring_buffer *ring = LP_RING(dev_priv); /* Program Hardware Status Page */ dev_priv->status_page_dmah = @@ -71,10 +70,9 @@ static int i915_init_phys_hws(struct drm_device *dev) DRM_ERROR("Can not allocate hardware status page\n"); return -ENOMEM; } - ring->status_page.page_addr = - (void __force __iomem *)dev_priv->status_page_dmah->vaddr; - memset_io(ring->status_page.page_addr, 0, PAGE_SIZE); + memset_io((void __force __iomem *)dev_priv->status_page_dmah->vaddr, + 0, PAGE_SIZE); i915_write_hws_pga(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6867e193d85e..feb4f164fd1b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -544,6 +544,7 @@ typedef struct drm_i915_private { u32 savePIPEB_LINK_M1; u32 savePIPEB_LINK_N1; u32 saveMCHBAR_RENDER_STANDBY; + u32 savePCH_PORT_HOTPLUG; struct { /** Bridge to intel-gtt-ko */ diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index d1cd8b89f47d..a546a71fb060 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3112,7 +3112,7 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj, if (pipelined != obj->ring) { ret = i915_gem_object_wait_rendering(obj); - if (ret) + if (ret == -ERESTARTSYS) return ret; } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 23d1ae67d279..02f96fd0d52d 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -306,12 +306,15 @@ static void i915_hotplug_work_func(struct work_struct *work) struct drm_mode_config *mode_config = &dev->mode_config; struct intel_encoder *encoder; + mutex_lock(&mode_config->mutex); DRM_DEBUG_KMS("running encoder hotplug functions\n"); list_for_each_entry(encoder, &mode_config->encoder_list, base.head) if (encoder->hot_plug) encoder->hot_plug(encoder); + mutex_unlock(&mode_config->mutex); + /* Just fire off a uevent and let userspace tell us what to do */ drm_helper_hpd_irq_event(dev); } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 02db299f621a..d1331f771e2f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -78,6 +78,14 @@ #define GRDOM_RENDER (1<<2) #define GRDOM_MEDIA (3<<2) +#define GEN6_MBCUNIT_SNPCR 0x900c /* for LLC config */ +#define GEN6_MBC_SNPCR_SHIFT 21 +#define GEN6_MBC_SNPCR_MASK (3<<21) +#define GEN6_MBC_SNPCR_MAX (0<<21) +#define GEN6_MBC_SNPCR_MED (1<<21) +#define GEN6_MBC_SNPCR_LOW (2<<21) +#define GEN6_MBC_SNPCR_MIN (3<<21) /* only 1/16th of the cache is shared */ + #define GEN6_GDRST 0x941c #define GEN6_GRDOM_FULL (1 << 0) #define GEN6_GRDOM_RENDER (1 << 1) @@ -1506,6 +1514,7 @@ #define VIDEO_DIP_SELECT_AVI (0 << 19) #define VIDEO_DIP_SELECT_VENDOR (1 << 19) #define VIDEO_DIP_SELECT_SPD (3 << 19) +#define VIDEO_DIP_SELECT_MASK (3 << 19) #define VIDEO_DIP_FREQ_ONCE (0 << 16) #define VIDEO_DIP_FREQ_VSYNC (1 << 16) #define VIDEO_DIP_FREQ_2VSYNC (2 << 16) @@ -2084,9 +2093,6 @@ #define DP_PIPEB_SELECT (1 << 30) #define DP_PIPE_MASK (1 << 30) -#define DP_PIPE_ENABLED(V, P) \ - (((V) & (DP_PIPE_MASK | DP_PORT_EN)) == ((P) << 30 | DP_PORT_EN)) - /* Link training mode - select a suitable mode for each stage */ #define DP_LINK_TRAIN_PAT_1 (0 << 28) #define DP_LINK_TRAIN_PAT_2 (1 << 28) @@ -3024,6 +3030,20 @@ #define _TRANSA_DP_LINK_M2 0xe0048 #define _TRANSA_DP_LINK_N2 0xe004c +/* Per-transcoder DIP controls */ + +#define _VIDEO_DIP_CTL_A 0xe0200 +#define _VIDEO_DIP_DATA_A 0xe0208 +#define _VIDEO_DIP_GCP_A 0xe0210 + +#define _VIDEO_DIP_CTL_B 0xe1200 +#define _VIDEO_DIP_DATA_B 0xe1208 +#define _VIDEO_DIP_GCP_B 0xe1210 + +#define TVIDEO_DIP_CTL(pipe) _PIPE(pipe, _VIDEO_DIP_CTL_A, _VIDEO_DIP_CTL_B) +#define TVIDEO_DIP_DATA(pipe) _PIPE(pipe, _VIDEO_DIP_DATA_A, _VIDEO_DIP_DATA_B) +#define TVIDEO_DIP_GCP(pipe) _PIPE(pipe, _VIDEO_DIP_GCP_A, _VIDEO_DIP_GCP_B) + #define _TRANS_HTOTAL_B 0xe1000 #define _TRANS_HBLANK_B 0xe1004 #define _TRANS_HSYNC_B 0xe1008 @@ -3076,6 +3096,16 @@ #define TRANS_6BPC (2<<5) #define TRANS_12BPC (3<<5) +#define _TRANSA_CHICKEN2 0xf0064 +#define _TRANSB_CHICKEN2 0xf1064 +#define TRANS_CHICKEN2(pipe) _PIPE(pipe, _TRANSA_CHICKEN2, _TRANSB_CHICKEN2) +#define TRANS_AUTOTRAIN_GEN_STALL_DIS (1<<31) + +#define SOUTH_CHICKEN1 0xc2000 +#define FDIA_PHASE_SYNC_SHIFT_OVR 19 +#define FDIA_PHASE_SYNC_SHIFT_EN 18 +#define FDI_PHASE_SYNC_OVR(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_OVR - ((pipe) * 2))) +#define FDI_PHASE_SYNC_EN(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_EN - ((pipe) * 2))) #define SOUTH_CHICKEN2 0xc2004 #define DPLS_EDP_PPS_FIX_DIS (1<<0) diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 285758603ac8..87677d60d0df 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -812,6 +812,7 @@ int i915_save_state(struct drm_device *dev) dev_priv->saveFDI_RXB_IMR = I915_READ(_FDI_RXB_IMR); dev_priv->saveMCHBAR_RENDER_STANDBY = I915_READ(RSTDBYCTL); + dev_priv->savePCH_PORT_HOTPLUG = I915_READ(PCH_PORT_HOTPLUG); } else { dev_priv->saveIER = I915_READ(IER); dev_priv->saveIMR = I915_READ(IMR); @@ -863,6 +864,7 @@ int i915_restore_state(struct drm_device *dev) I915_WRITE(GTIMR, dev_priv->saveGTIMR); I915_WRITE(_FDI_RXA_IMR, dev_priv->saveFDI_RXA_IMR); I915_WRITE(_FDI_RXB_IMR, dev_priv->saveFDI_RXB_IMR); + I915_WRITE(PCH_PORT_HOTPLUG, dev_priv->savePCH_PORT_HOTPLUG); } else { I915_WRITE(IER, dev_priv->saveIER); I915_WRITE(IMR, dev_priv->saveIMR); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 393a39922e53..35364e68a091 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -980,11 +980,29 @@ static void assert_transcoder_disabled(struct drm_i915_private *dev_priv, pipe_name(pipe)); } +static bool dp_pipe_enabled(struct drm_i915_private *dev_priv, enum pipe pipe, + int reg, u32 port_sel, u32 val) +{ + if ((val & DP_PORT_EN) == 0) + return false; + + if (HAS_PCH_CPT(dev_priv->dev)) { + u32 trans_dp_ctl_reg = TRANS_DP_CTL(pipe); + u32 trans_dp_ctl = I915_READ(trans_dp_ctl_reg); + if ((trans_dp_ctl & TRANS_DP_PORT_SEL_MASK) != port_sel) + return false; + } else { + if ((val & DP_PIPE_MASK) != (pipe << 30)) + return false; + } + return true; +} + static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv, - enum pipe pipe, int reg) + enum pipe pipe, int reg, u32 port_sel) { u32 val = I915_READ(reg); - WARN(DP_PIPE_ENABLED(val, pipe), + WARN(dp_pipe_enabled(dev_priv, pipe, reg, port_sel, val), "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n", reg, pipe_name(pipe)); } @@ -1004,9 +1022,9 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, int reg; u32 val; - assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_B); - assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_C); - assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_D); + assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_B, TRANS_DP_PORT_SEL_B); + assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_C, TRANS_DP_PORT_SEL_C); + assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_D, TRANS_DP_PORT_SEL_D); reg = PCH_ADPA; val = I915_READ(reg); @@ -1276,6 +1294,17 @@ static void intel_disable_pipe(struct drm_i915_private *dev_priv, intel_wait_for_pipe_off(dev_priv->dev, pipe); } +/* + * Plane regs are double buffered, going from enabled->disabled needs a + * trigger in order to latch. The display address reg provides this. + */ +static void intel_flush_display_plane(struct drm_i915_private *dev_priv, + enum plane plane) +{ + I915_WRITE(DSPADDR(plane), I915_READ(DSPADDR(plane))); + I915_WRITE(DSPSURF(plane), I915_READ(DSPSURF(plane))); +} + /** * intel_enable_plane - enable a display plane on a given pipe * @dev_priv: i915 private structure @@ -1299,20 +1328,10 @@ static void intel_enable_plane(struct drm_i915_private *dev_priv, return; I915_WRITE(reg, val | DISPLAY_PLANE_ENABLE); + intel_flush_display_plane(dev_priv, plane); intel_wait_for_vblank(dev_priv->dev, pipe); } -/* - * Plane regs are double buffered, going from enabled->disabled needs a - * trigger in order to latch. The display address reg provides this. - */ -static void intel_flush_display_plane(struct drm_i915_private *dev_priv, - enum plane plane) -{ - u32 reg = DSPADDR(plane); - I915_WRITE(reg, I915_READ(reg)); -} - /** * intel_disable_plane - disable a display plane * @dev_priv: i915 private structure @@ -1338,19 +1357,24 @@ static void intel_disable_plane(struct drm_i915_private *dev_priv, } static void disable_pch_dp(struct drm_i915_private *dev_priv, - enum pipe pipe, int reg) + enum pipe pipe, int reg, u32 port_sel) { u32 val = I915_READ(reg); - if (DP_PIPE_ENABLED(val, pipe)) + if (dp_pipe_enabled(dev_priv, pipe, reg, port_sel, val)) { + DRM_DEBUG_KMS("Disabling pch dp %x on pipe %d\n", reg, pipe); I915_WRITE(reg, val & ~DP_PORT_EN); + } } static void disable_pch_hdmi(struct drm_i915_private *dev_priv, enum pipe pipe, int reg) { u32 val = I915_READ(reg); - if (HDMI_PIPE_ENABLED(val, pipe)) + if (HDMI_PIPE_ENABLED(val, pipe)) { + DRM_DEBUG_KMS("Disabling pch HDMI %x on pipe %d\n", + reg, pipe); I915_WRITE(reg, val & ~PORT_ENABLE); + } } /* Disable any ports connected to this transcoder */ @@ -1362,9 +1386,9 @@ static void intel_disable_pch_ports(struct drm_i915_private *dev_priv, val = I915_READ(PCH_PP_CONTROL); I915_WRITE(PCH_PP_CONTROL, val | PANEL_UNLOCK_REGS); - disable_pch_dp(dev_priv, pipe, PCH_DP_B); - disable_pch_dp(dev_priv, pipe, PCH_DP_C); - disable_pch_dp(dev_priv, pipe, PCH_DP_D); + disable_pch_dp(dev_priv, pipe, PCH_DP_B, TRANS_DP_PORT_SEL_B); + disable_pch_dp(dev_priv, pipe, PCH_DP_C, TRANS_DP_PORT_SEL_C); + disable_pch_dp(dev_priv, pipe, PCH_DP_D, TRANS_DP_PORT_SEL_D); reg = PCH_ADPA; val = I915_READ(reg); @@ -2096,7 +2120,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, /* no fb bound */ if (!crtc->fb) { - DRM_DEBUG_KMS("No FB bound\n"); + DRM_ERROR("No FB bound\n"); return 0; } @@ -2105,6 +2129,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, case 1: break; default: + DRM_ERROR("no plane for crtc\n"); return -EINVAL; } @@ -2114,6 +2139,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, NULL); if (ret != 0) { mutex_unlock(&dev->struct_mutex); + DRM_ERROR("pin & fence failed\n"); return ret; } @@ -2142,6 +2168,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, if (ret) { i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj); mutex_unlock(&dev->struct_mutex); + DRM_ERROR("failed to update base address\n"); return ret; } @@ -2248,6 +2275,18 @@ static void intel_fdi_normal_train(struct drm_crtc *crtc) FDI_FE_ERRC_ENABLE); } +static void cpt_phase_pointer_enable(struct drm_device *dev, int pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 flags = I915_READ(SOUTH_CHICKEN1); + + flags |= FDI_PHASE_SYNC_OVR(pipe); + I915_WRITE(SOUTH_CHICKEN1, flags); /* once to unlock... */ + flags |= FDI_PHASE_SYNC_EN(pipe); + I915_WRITE(SOUTH_CHICKEN1, flags); /* then again to enable */ + POSTING_READ(SOUTH_CHICKEN1); +} + /* The FDI link training functions for ILK/Ibexpeak. */ static void ironlake_fdi_link_train(struct drm_crtc *crtc) { @@ -2398,6 +2437,9 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) POSTING_READ(reg); udelay(150); + if (HAS_PCH_CPT(dev)) + cpt_phase_pointer_enable(dev, pipe); + for (i = 0; i < 4; i++ ) { reg = FDI_TX_CTL(pipe); temp = I915_READ(reg); @@ -2514,6 +2556,9 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc) POSTING_READ(reg); udelay(150); + if (HAS_PCH_CPT(dev)) + cpt_phase_pointer_enable(dev, pipe); + for (i = 0; i < 4; i++ ) { reg = FDI_TX_CTL(pipe); temp = I915_READ(reg); @@ -2623,6 +2668,17 @@ static void ironlake_fdi_pll_enable(struct drm_crtc *crtc) } } +static void cpt_phase_pointer_disable(struct drm_device *dev, int pipe) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 flags = I915_READ(SOUTH_CHICKEN1); + + flags &= ~(FDI_PHASE_SYNC_EN(pipe)); + I915_WRITE(SOUTH_CHICKEN1, flags); /* once to disable... */ + flags &= ~(FDI_PHASE_SYNC_OVR(pipe)); + I915_WRITE(SOUTH_CHICKEN1, flags); /* then again to lock */ + POSTING_READ(SOUTH_CHICKEN1); +} static void ironlake_fdi_disable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -2652,6 +2708,8 @@ static void ironlake_fdi_disable(struct drm_crtc *crtc) I915_WRITE(FDI_RX_CHICKEN(pipe), I915_READ(FDI_RX_CHICKEN(pipe) & ~FDI_RX_PHASE_SYNC_POINTER_EN)); + } else if (HAS_PCH_CPT(dev)) { + cpt_phase_pointer_disable(dev, pipe); } /* still set train pattern 1 */ @@ -2862,14 +2920,18 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) I915_WRITE(PF_WIN_SZ(pipe), dev_priv->pch_pf_size); } + /* + * On ILK+ LUT must be loaded before the pipe is running but with + * clocks enabled + */ + intel_crtc_load_lut(crtc); + intel_enable_pipe(dev_priv, pipe, is_pch_port); intel_enable_plane(dev_priv, plane, pipe); if (is_pch_port) ironlake_pch_enable(crtc); - intel_crtc_load_lut(crtc); - mutex_lock(&dev->struct_mutex); intel_update_fbc(dev); mutex_unlock(&dev->struct_mutex); @@ -4538,7 +4600,9 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc, if (connector->encoder != encoder) continue; - if (connector->display_info.bpc < display_bpc) { + /* Don't use an invalid EDID bpc value */ + if (connector->display_info.bpc && + connector->display_info.bpc < display_bpc) { DRM_DEBUG_DRIVER("clamping display bpc (was %d) to EDID reported max of %d\n", display_bpc, connector->display_info.bpc); display_bpc = connector->display_info.bpc; } @@ -5153,7 +5217,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, temp |= PIPE_12BPC; break; default: - WARN(1, "intel_choose_pipe_bpp returned invalid value\n"); + WARN(1, "intel_choose_pipe_bpp returned invalid value %d\n", + pipe_bpp); temp |= PIPE_8BPC; pipe_bpp = 24; break; @@ -5238,7 +5303,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, } else if (is_sdvo && is_tv) factor = 20; - if (clock.m1 < factor * clock.n) + if (clock.m < factor * clock.n) fp |= FP_CB_TUNE; dpll = 0; @@ -5516,6 +5581,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, drm_vblank_post_modeset(dev, pipe); + intel_crtc->dpms_mode = DRM_MODE_DPMS_ON; + return ret; } @@ -7714,10 +7781,12 @@ static void gen6_init_clock_gating(struct drm_device *dev) ILK_DPARB_CLK_GATE | ILK_DPFD_CLK_GATE); - for_each_pipe(pipe) + for_each_pipe(pipe) { I915_WRITE(DSPCNTR(pipe), I915_READ(DSPCNTR(pipe)) | DISPPLANE_TRICKLE_FEED_DISABLE); + intel_flush_display_plane(dev_priv, pipe); + } } static void ivybridge_init_clock_gating(struct drm_device *dev) @@ -7734,10 +7803,12 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE); - for_each_pipe(pipe) + for_each_pipe(pipe) { I915_WRITE(DSPCNTR(pipe), I915_READ(DSPCNTR(pipe)) | DISPPLANE_TRICKLE_FEED_DISABLE); + intel_flush_display_plane(dev_priv, pipe); + } } static void g4x_init_clock_gating(struct drm_device *dev) @@ -7820,6 +7891,7 @@ static void ibx_init_clock_gating(struct drm_device *dev) static void cpt_init_clock_gating(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + int pipe; /* * On Ibex Peak and Cougar Point, we need to disable clock @@ -7829,6 +7901,9 @@ static void cpt_init_clock_gating(struct drm_device *dev) I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE); I915_WRITE(SOUTH_CHICKEN2, I915_READ(SOUTH_CHICKEN2) | DPLS_EDP_PPS_FIX_DIS); + /* Without this, mode sets may fail silently on FDI */ + for_each_pipe(pipe) + I915_WRITE(TRANS_CHICKEN2(pipe), TRANS_AUTOTRAIN_GEN_STALL_DIS); } static void ironlake_teardown_rc6(struct drm_device *dev) @@ -8178,6 +8253,9 @@ struct intel_quirk intel_quirks[] = { /* Lenovo U160 cannot use SSC on LVDS */ { 0x0046, 0x17aa, 0x3920, quirk_ssc_force_disable }, + + /* Sony Vaio Y cannot use SSC on LVDS */ + { 0x0046, 0x104d, 0x9076, quirk_ssc_force_disable }, }; static void intel_init_quirks(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index f797fb58ba9c..0feae908bb37 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -50,9 +50,10 @@ struct intel_dp { bool has_audio; int force_audio; uint32_t color_range; + int dpms_mode; uint8_t link_bw; uint8_t lane_count; - uint8_t dpcd[4]; + uint8_t dpcd[8]; struct i2c_adapter adapter; struct i2c_algo_dp_aux_data algo; bool is_pch_edp; @@ -316,9 +317,17 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, else precharge = 5; - if (I915_READ(ch_ctl) & DP_AUX_CH_CTL_SEND_BUSY) { - DRM_ERROR("dp_aux_ch not started status 0x%08x\n", - I915_READ(ch_ctl)); + /* Try to wait for any previous AUX channel activity */ + for (try = 0; try < 3; try++) { + status = I915_READ(ch_ctl); + if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0) + break; + msleep(1); + } + + if (try == 3) { + WARN(1, "dp_aux_ch not started status 0x%08x\n", + I915_READ(ch_ctl)); return -EBUSY; } @@ -770,6 +779,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, memset(intel_dp->link_configuration, 0, DP_LINK_CONFIGURATION_SIZE); intel_dp->link_configuration[0] = intel_dp->link_bw; intel_dp->link_configuration[1] = intel_dp->lane_count; + intel_dp->link_configuration[8] = DP_SET_ANSI_8B10B; /* * Check for DPCD version > 1.1 and enhanced framing support @@ -1011,6 +1021,8 @@ static void intel_dp_commit(struct drm_encoder *encoder) if (is_edp(intel_dp)) ironlake_edp_backlight_on(dev); + + intel_dp->dpms_mode = DRM_MODE_DPMS_ON; } static void @@ -1045,6 +1057,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) if (is_edp(intel_dp)) ironlake_edp_backlight_on(dev); } + intel_dp->dpms_mode = mode; } /* @@ -1334,10 +1347,16 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) u32 reg; uint32_t DP = intel_dp->DP; - /* Enable output, wait for it to become active */ - I915_WRITE(intel_dp->output_reg, intel_dp->DP); - POSTING_READ(intel_dp->output_reg); - intel_wait_for_vblank(dev, intel_crtc->pipe); + /* + * On CPT we have to enable the port in training pattern 1, which + * will happen below in intel_dp_set_link_train. Otherwise, enable + * the port and wait for it to become active. + */ + if (!HAS_PCH_CPT(dev)) { + I915_WRITE(intel_dp->output_reg, intel_dp->DP); + POSTING_READ(intel_dp->output_reg); + intel_wait_for_vblank(dev, intel_crtc->pipe); + } /* Write the link configuration data */ intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET, @@ -1370,7 +1389,8 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) reg = DP | DP_LINK_TRAIN_PAT_1; if (!intel_dp_set_link_train(intel_dp, reg, - DP_TRAINING_PATTERN_1)) + DP_TRAINING_PATTERN_1 | + DP_LINK_SCRAMBLING_DISABLE)) break; /* Set training pattern 1 */ @@ -1445,7 +1465,8 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) /* channel eq pattern */ if (!intel_dp_set_link_train(intel_dp, reg, - DP_TRAINING_PATTERN_2)) + DP_TRAINING_PATTERN_2 | + DP_LINK_SCRAMBLING_DISABLE)) break; udelay(400); @@ -1559,6 +1580,18 @@ intel_dp_link_down(struct intel_dp *intel_dp) POSTING_READ(intel_dp->output_reg); } +static bool +intel_dp_get_dpcd(struct intel_dp *intel_dp) +{ + if (intel_dp_aux_native_read_retry(intel_dp, 0x000, intel_dp->dpcd, + sizeof (intel_dp->dpcd)) && + (intel_dp->dpcd[DP_DPCD_REV] != 0)) { + return true; + } + + return false; +} + /* * According to DP spec * 5.1.2: @@ -1571,36 +1604,44 @@ intel_dp_link_down(struct intel_dp *intel_dp) static void intel_dp_check_link_status(struct intel_dp *intel_dp) { - int ret; + if (intel_dp->dpms_mode != DRM_MODE_DPMS_ON) + return; if (!intel_dp->base.base.crtc) return; + /* Try to read receiver status if the link appears to be up */ if (!intel_dp_get_link_status(intel_dp)) { intel_dp_link_down(intel_dp); return; } - /* Try to read receiver status if the link appears to be up */ - ret = intel_dp_aux_native_read(intel_dp, - 0x000, intel_dp->dpcd, - sizeof (intel_dp->dpcd)); - if (ret != sizeof(intel_dp->dpcd)) { + /* Now read the DPCD to see if it's actually running */ + if (!intel_dp_get_dpcd(intel_dp)) { intel_dp_link_down(intel_dp); return; } if (!intel_channel_eq_ok(intel_dp)) { + DRM_DEBUG_KMS("%s: channel EQ not ok, retraining\n", + drm_get_encoder_name(&intel_dp->base.base)); intel_dp_start_link_train(intel_dp); intel_dp_complete_link_train(intel_dp); } } static enum drm_connector_status +intel_dp_detect_dpcd(struct intel_dp *intel_dp) +{ + if (intel_dp_get_dpcd(intel_dp)) + return connector_status_connected; + return connector_status_disconnected; +} + +static enum drm_connector_status ironlake_dp_detect(struct intel_dp *intel_dp) { enum drm_connector_status status; - bool ret; /* Can't disconnect eDP, but you can close the lid... */ if (is_edp(intel_dp)) { @@ -1610,15 +1651,7 @@ ironlake_dp_detect(struct intel_dp *intel_dp) return status; } - status = connector_status_disconnected; - ret = intel_dp_aux_native_read_retry(intel_dp, - 0x000, intel_dp->dpcd, - sizeof (intel_dp->dpcd)); - if (ret && intel_dp->dpcd[DP_DPCD_REV] != 0) - status = connector_status_connected; - DRM_DEBUG_KMS("DPCD: %hx%hx%hx%hx\n", intel_dp->dpcd[0], - intel_dp->dpcd[1], intel_dp->dpcd[2], intel_dp->dpcd[3]); - return status; + return intel_dp_detect_dpcd(intel_dp); } static enum drm_connector_status @@ -1626,7 +1659,6 @@ g4x_dp_detect(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - enum drm_connector_status status; uint32_t temp, bit; switch (intel_dp->output_reg) { @@ -1648,15 +1680,7 @@ g4x_dp_detect(struct intel_dp *intel_dp) if ((temp & bit) == 0) return connector_status_disconnected; - status = connector_status_disconnected; - if (intel_dp_aux_native_read(intel_dp, 0x000, intel_dp->dpcd, - sizeof (intel_dp->dpcd)) == sizeof (intel_dp->dpcd)) - { - if (intel_dp->dpcd[DP_DPCD_REV] != 0) - status = connector_status_connected; - } - - return status; + return intel_dp_detect_dpcd(intel_dp); } /** @@ -1679,6 +1703,12 @@ intel_dp_detect(struct drm_connector *connector, bool force) status = ironlake_dp_detect(intel_dp); else status = g4x_dp_detect(intel_dp); + + DRM_DEBUG_KMS("DPCD: %02hx%02hx%02hx%02hx%02hx%02hx%02hx%02hx\n", + intel_dp->dpcd[0], intel_dp->dpcd[1], intel_dp->dpcd[2], + intel_dp->dpcd[3], intel_dp->dpcd[4], intel_dp->dpcd[5], + intel_dp->dpcd[6], intel_dp->dpcd[7]); + if (status != connector_status_connected) return status; @@ -1924,6 +1954,7 @@ intel_dp_init(struct drm_device *dev, int output_reg) return; intel_dp->output_reg = output_reg; + intel_dp->dpms_mode = -1; intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); if (!intel_connector) { @@ -2000,7 +2031,7 @@ intel_dp_init(struct drm_device *dev, int output_reg) /* Cache some DPCD data in the eDP case */ if (is_edp(intel_dp)) { - int ret; + bool ret; u32 pp_on, pp_div; pp_on = I915_READ(PCH_PP_ON_DELAYS); @@ -2013,11 +2044,9 @@ intel_dp_init(struct drm_device *dev, int output_reg) dev_priv->panel_t12 *= 100; /* t12 in 100ms units */ ironlake_edp_panel_vdd_on(intel_dp); - ret = intel_dp_aux_native_read(intel_dp, DP_DPCD_REV, - intel_dp->dpcd, - sizeof(intel_dp->dpcd)); + ret = intel_dp_get_dpcd(intel_dp); ironlake_edp_panel_vdd_off(intel_dp); - if (ret == sizeof(intel_dp->dpcd)) { + if (ret) { if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) dev_priv->no_aux_handshake = intel_dp->dpcd[DP_MAX_DOWNSPREAD] & diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 6e990f9760ef..7b330e76a435 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -178,10 +178,28 @@ struct intel_crtc { #define to_intel_encoder(x) container_of(x, struct intel_encoder, base) #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base) +#define DIP_HEADER_SIZE 5 + #define DIP_TYPE_AVI 0x82 #define DIP_VERSION_AVI 0x2 #define DIP_LEN_AVI 13 +#define DIP_TYPE_SPD 0x3 +#define DIP_VERSION_SPD 0x1 +#define DIP_LEN_SPD 25 +#define DIP_SPD_UNKNOWN 0 +#define DIP_SPD_DSTB 0x1 +#define DIP_SPD_DVDP 0x2 +#define DIP_SPD_DVHS 0x3 +#define DIP_SPD_HDDVR 0x4 +#define DIP_SPD_DVC 0x5 +#define DIP_SPD_DSC 0x6 +#define DIP_SPD_VCD 0x7 +#define DIP_SPD_GAME 0x8 +#define DIP_SPD_PC 0x9 +#define DIP_SPD_BD 0xa +#define DIP_SPD_SCD 0xb + struct dip_infoframe { uint8_t type; /* HB0 */ uint8_t ver; /* HB1 */ @@ -206,6 +224,11 @@ struct dip_infoframe { uint16_t left_bar_end; uint16_t right_bar_start; } avi; + struct { + uint8_t vn[8]; + uint8_t pd[16]; + uint8_t sdi; + } spd; uint8_t payload[27]; } __attribute__ ((packed)) body; } __attribute__((packed)); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 1ed8e6903915..226ba830f383 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -45,6 +45,8 @@ struct intel_hdmi { bool has_hdmi_sink; bool has_audio; int force_audio; + void (*write_infoframe)(struct drm_encoder *encoder, + struct dip_infoframe *frame); }; static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder) @@ -58,37 +60,70 @@ static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector) struct intel_hdmi, base); } -void intel_dip_infoframe_csum(struct dip_infoframe *avi_if) +void intel_dip_infoframe_csum(struct dip_infoframe *frame) { - uint8_t *data = (uint8_t *)avi_if; + uint8_t *data = (uint8_t *)frame; uint8_t sum = 0; unsigned i; - avi_if->checksum = 0; - avi_if->ecc = 0; + frame->checksum = 0; + frame->ecc = 0; - for (i = 0; i < sizeof(*avi_if); i++) + /* Header isn't part of the checksum */ + for (i = 5; i < frame->len; i++) sum += data[i]; - avi_if->checksum = 0x100 - sum; + frame->checksum = 0x100 - sum; } -static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder) +static u32 intel_infoframe_index(struct dip_infoframe *frame) { - struct dip_infoframe avi_if = { - .type = DIP_TYPE_AVI, - .ver = DIP_VERSION_AVI, - .len = DIP_LEN_AVI, - }; - uint32_t *data = (uint32_t *)&avi_if; + u32 flags = 0; + + switch (frame->type) { + case DIP_TYPE_AVI: + flags |= VIDEO_DIP_SELECT_AVI; + break; + case DIP_TYPE_SPD: + flags |= VIDEO_DIP_SELECT_SPD; + break; + default: + DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); + break; + } + + return flags; +} + +static u32 intel_infoframe_flags(struct dip_infoframe *frame) +{ + u32 flags = 0; + + switch (frame->type) { + case DIP_TYPE_AVI: + flags |= VIDEO_DIP_ENABLE_AVI | VIDEO_DIP_FREQ_VSYNC; + break; + case DIP_TYPE_SPD: + flags |= VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_FREQ_2VSYNC; + break; + default: + DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type); + break; + } + + return flags; +} + +static void i9xx_write_infoframe(struct drm_encoder *encoder, + struct dip_infoframe *frame) +{ + uint32_t *data = (uint32_t *)frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); - u32 port; - unsigned i; + u32 port, flags, val = I915_READ(VIDEO_DIP_CTL); + unsigned i, len = DIP_HEADER_SIZE + frame->len; - if (!intel_hdmi->has_hdmi_sink) - return; /* XXX first guess at handling video port, is this corrent? */ if (intel_hdmi->sdvox_reg == SDVOB) @@ -98,18 +133,87 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder) else return; - I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port | - VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC); + flags = intel_infoframe_index(frame); + + val &= ~VIDEO_DIP_SELECT_MASK; - intel_dip_infoframe_csum(&avi_if); - for (i = 0; i < sizeof(avi_if); i += 4) { + I915_WRITE(VIDEO_DIP_CTL, val | port | flags); + + for (i = 0; i < len; i += 4) { I915_WRITE(VIDEO_DIP_DATA, *data); data++; } - I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | port | - VIDEO_DIP_SELECT_AVI | VIDEO_DIP_FREQ_VSYNC | - VIDEO_DIP_ENABLE_AVI); + flags |= intel_infoframe_flags(frame); + + I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | val | port | flags); +} + +static void ironlake_write_infoframe(struct drm_encoder *encoder, + struct dip_infoframe *frame) +{ + uint32_t *data = (uint32_t *)frame; + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc = encoder->crtc; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int reg = TVIDEO_DIP_CTL(intel_crtc->pipe); + unsigned i, len = DIP_HEADER_SIZE + frame->len; + u32 flags, val = I915_READ(reg); + + intel_wait_for_vblank(dev, intel_crtc->pipe); + + flags = intel_infoframe_index(frame); + + val &= ~VIDEO_DIP_SELECT_MASK; + + I915_WRITE(reg, val | flags); + + for (i = 0; i < len; i += 4) { + I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data); + data++; + } + + flags |= intel_infoframe_flags(frame); + + I915_WRITE(reg, VIDEO_DIP_ENABLE | val | flags); +} +static void intel_set_infoframe(struct drm_encoder *encoder, + struct dip_infoframe *frame) +{ + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); + + if (!intel_hdmi->has_hdmi_sink) + return; + + intel_dip_infoframe_csum(frame); + intel_hdmi->write_infoframe(encoder, frame); +} + +static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder) +{ + struct dip_infoframe avi_if = { + .type = DIP_TYPE_AVI, + .ver = DIP_VERSION_AVI, + .len = DIP_LEN_AVI, + }; + + intel_set_infoframe(encoder, &avi_if); +} + +static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder) +{ + struct dip_infoframe spd_if; + + memset(&spd_if, 0, sizeof(spd_if)); + spd_if.type = DIP_TYPE_SPD; + spd_if.ver = DIP_VERSION_SPD; + spd_if.len = DIP_LEN_SPD; + strcpy(spd_if.body.spd.vn, "Intel"); + strcpy(spd_if.body.spd.pd, "Integrated gfx"); + spd_if.body.spd.sdi = DIP_SPD_PC; + + intel_set_infoframe(encoder, &spd_if); } static void intel_hdmi_mode_set(struct drm_encoder *encoder, @@ -156,6 +260,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, POSTING_READ(intel_hdmi->sdvox_reg); intel_hdmi_set_avi_infoframe(encoder); + intel_hdmi_set_spd_infoframe(encoder); } static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) @@ -433,6 +538,11 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) intel_hdmi->sdvox_reg = sdvox_reg; + if (!HAS_PCH_SPLIT(dev)) + intel_hdmi->write_infoframe = i9xx_write_infoframe; + else + intel_hdmi->write_infoframe = ironlake_write_infoframe; + drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs); intel_hdmi_add_properties(intel_hdmi, connector); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index b28f7bd9f88a..2e8ddfcba40c 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -690,6 +690,14 @@ static const struct dmi_system_id intel_no_lvds[] = { }, { .callback = intel_no_lvds_dmi_callback, + .ident = "Dell OptiPlex FX170", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex FX170"), + }, + }, + { + .callback = intel_no_lvds_dmi_callback, .ident = "AOpen Mini PC", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "AOpen"), diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index a06ff07a4d3b..05f500cd9c24 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -83,11 +83,15 @@ intel_pch_panel_fitting(struct drm_device *dev, u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay; if (scaled_width > scaled_height) { /* pillar */ width = scaled_height / mode->vdisplay; + if (width & 1) + width++; x = (adjusted_mode->hdisplay - width + 1) / 2; y = 0; height = adjusted_mode->vdisplay; } else if (scaled_width < scaled_height) { /* letter */ height = scaled_width / mode->hdisplay; + if (height & 1) + height++; y = (adjusted_mode->vdisplay - height + 1) / 2; x = 0; width = adjusted_mode->hdisplay; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index e9615685a39c..47b9b2777038 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1321,6 +1321,9 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size) ring->get_seqno = pc_render_get_seqno; } + if (!I915_NEED_GFX_HWS(dev)) + ring->status_page.page_addr = dev_priv->status_page_dmah->vaddr; + ring->dev = dev; INIT_LIST_HEAD(&ring->active_list); INIT_LIST_HEAD(&ring->request_list); diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index 3896ef811102..9f363e0c4b60 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile @@ -5,6 +5,7 @@ ccflags-y := -Iinclude/drm hostprogs-y := mkregtable +clean-files := rn50_reg_safe.h r100_reg_safe.h r200_reg_safe.h rv515_reg_safe.h r300_reg_safe.h r420_reg_safe.h rs600_reg_safe.h r600_reg_safe.h evergreen_reg_safe.h cayman_reg_safe.h quiet_cmd_mkregtable = MKREGTABLE $@ cmd_mkregtable = $(obj)/mkregtable $< > $@ diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index ebdb0fdb8348..e88c64417a8a 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -1245,6 +1245,9 @@ struct atom_context *atom_parse(struct card_info *card, void *bios) char name[512]; int i; + if (!ctx) + return NULL; + ctx->card = card; ctx->bios = bios; diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c index 189e86522b5b..a134790903d3 100644 --- a/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/drivers/gpu/drm/radeon/evergreen_cs.c @@ -428,7 +428,7 @@ static inline int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u3 last_reg = ARRAY_SIZE(evergreen_reg_safe_bm); i = (reg >> 7); - if (i > last_reg) { + if (i >= last_reg) { dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx); return -EINVAL; } diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index db8ef1905d5f..cf83aa05a684 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -915,12 +915,11 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx { struct r600_cs_track *track = (struct r600_cs_track *)p->track; struct radeon_cs_reloc *reloc; - u32 last_reg = ARRAY_SIZE(r600_reg_safe_bm); u32 m, i, tmp, *ib; int r; i = (reg >> 7); - if (i > last_reg) { + if (i >= ARRAY_SIZE(r600_reg_safe_bm)) { dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx); return -EINVAL; } diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index a74217cd192f..e0138b674aca 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -2557,6 +2557,7 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev) u16 offset, misc, misc2 = 0; u8 rev, blocks, tmp; int state_index = 0; + struct radeon_i2c_bus_rec i2c_bus; rdev->pm.default_power_state_index = -1; @@ -2575,7 +2576,6 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev) offset = combios_get_table_offset(dev, COMBIOS_OVERDRIVE_INFO_TABLE); if (offset) { u8 thermal_controller = 0, gpio = 0, i2c_addr = 0, clk_bit = 0, data_bit = 0; - struct radeon_i2c_bus_rec i2c_bus; rev = RBIOS8(offset); @@ -2617,6 +2617,25 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev) i2c_new_device(&rdev->pm.i2c_bus->adapter, &info); } } + } else { + /* boards with a thermal chip, but no overdrive table */ + + /* Asus 9600xt has an f75375 on the monid bus */ + if ((dev->pdev->device == 0x4152) && + (dev->pdev->subsystem_vendor == 0x1043) && + (dev->pdev->subsystem_device == 0xc002)) { + i2c_bus = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0); + rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus); + if (rdev->pm.i2c_bus) { + struct i2c_board_info info = { }; + const char *name = "f75375"; + info.addr = 0x28; + strlcpy(info.type, name, sizeof(info.type)); + i2c_new_device(&rdev->pm.i2c_bus->adapter, &info); + DRM_INFO("Possible %s thermal controller at 0x%02x\n", + name, info.addr); + } + } } if (rdev->flags & RADEON_IS_MOBILITY) { diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 9792d4ffdc86..6d6b5f16bc09 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -430,6 +430,45 @@ int radeon_connector_set_property(struct drm_connector *connector, struct drm_pr return 0; } +/* + * Some integrated ATI Radeon chipset implementations (e. g. + * Asus M2A-VM HDMI) may indicate the availability of a DDC, + * even when there's no monitor connected. For these connectors + * following DDC probe extension will be applied: check also for the + * availability of EDID with at least a correct EDID header. Only then, + * DDC is assumed to be available. This prevents drm_get_edid() and + * drm_edid_block_valid() from periodically dumping data and kernel + * errors into the logs and onto the terminal. + */ +static bool radeon_connector_needs_extended_probe(struct radeon_device *dev, + uint32_t supported_device, + int connector_type) +{ + /* Asus M2A-VM HDMI board sends data to i2c bus even, + * if HDMI add-on card is not plugged in or HDMI is disabled in + * BIOS. Valid DDC can only be assumed, if also a valid EDID header + * can be retrieved via i2c bus during DDC probe */ + if ((dev->pdev->device == 0x791e) && + (dev->pdev->subsystem_vendor == 0x1043) && + (dev->pdev->subsystem_device == 0x826d)) { + if ((connector_type == DRM_MODE_CONNECTOR_HDMIA) && + (supported_device == ATOM_DEVICE_DFP2_SUPPORT)) + return true; + } + /* ECS A740GM-M with ATI RADEON 2100 sends data to i2c bus + * for a DVI connector that is not implemented */ + if ((dev->pdev->device == 0x796e) && + (dev->pdev->subsystem_vendor == 0x1019) && + (dev->pdev->subsystem_device == 0x2615)) { + if ((connector_type == DRM_MODE_CONNECTOR_DVID) && + (supported_device == ATOM_DEVICE_DFP2_SUPPORT)) + return true; + } + + /* Default: no EDID header probe required for DDC probing */ + return false; +} + static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder, struct drm_connector *connector) { @@ -661,7 +700,8 @@ radeon_vga_detect(struct drm_connector *connector, bool force) ret = connector_status_disconnected; if (radeon_connector->ddc_bus) - dret = radeon_ddc_probe(radeon_connector); + dret = radeon_ddc_probe(radeon_connector, + radeon_connector->requires_extended_probe); if (dret) { if (radeon_connector->edid) { kfree(radeon_connector->edid); @@ -833,7 +873,8 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) bool dret = false; if (radeon_connector->ddc_bus) - dret = radeon_ddc_probe(radeon_connector); + dret = radeon_ddc_probe(radeon_connector, + radeon_connector->requires_extended_probe); if (dret) { if (radeon_connector->edid) { kfree(radeon_connector->edid); @@ -1251,7 +1292,8 @@ radeon_dp_detect(struct drm_connector *connector, bool force) if (radeon_dp_getdpcd(radeon_connector)) ret = connector_status_connected; } else { - if (radeon_ddc_probe(radeon_connector)) + if (radeon_ddc_probe(radeon_connector, + radeon_connector->requires_extended_probe)) ret = connector_status_connected; } } @@ -1406,6 +1448,9 @@ radeon_add_atom_connector(struct drm_device *dev, radeon_connector->shared_ddc = shared_ddc; radeon_connector->connector_object_id = connector_object_id; radeon_connector->hpd = *hpd; + radeon_connector->requires_extended_probe = + radeon_connector_needs_extended_probe(rdev, supported_device, + connector_type); radeon_connector->router = *router; if (router->ddc_valid || router->cd_valid) { radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info); @@ -1752,6 +1797,9 @@ radeon_add_legacy_connector(struct drm_device *dev, radeon_connector->devices = supported_device; radeon_connector->connector_object_id = connector_object_id; radeon_connector->hpd = *hpd; + radeon_connector->requires_extended_probe = + radeon_connector_needs_extended_probe(rdev, supported_device, + connector_type); switch (connector_type) { case DRM_MODE_CONNECTOR_VGA: drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 7cfaa7e2f3b5..440e6ecccc40 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -704,8 +704,9 @@ int radeon_device_init(struct radeon_device *rdev, rdev->gpu_lockup = false; rdev->accel_working = false; - DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X).\n", - radeon_family_name[rdev->family], pdev->vendor, pdev->device); + DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X 0x%04X:0x%04X).\n", + radeon_family_name[rdev->family], pdev->vendor, pdev->device, + pdev->subsystem_vendor, pdev->subsystem_device); /* mutex initialization are all done here so we * can recall function without having locking issues */ diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 28f4655905bc..1a858944e4f3 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -751,8 +751,17 @@ static int radeon_ddc_dump(struct drm_connector *connector) if (!radeon_connector->ddc_bus) return -1; edid = drm_get_edid(connector, &radeon_connector->ddc_bus->adapter); + /* Log EDID retrieval status here. In particular with regard to + * connectors with requires_extended_probe flag set, that will prevent + * function radeon_dvi_detect() to fetch EDID on this connector, + * as long as there is no valid EDID header found */ if (edid) { + DRM_INFO("Radeon display connector %s: Found valid EDID", + drm_get_connector_name(connector)); kfree(edid); + } else { + DRM_INFO("Radeon display connector %s: No monitor connected or invalid EDID", + drm_get_connector_name(connector)); } return ret; } diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 85f033f19a8a..e71d2ed7fa11 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -50,8 +50,8 @@ * 2.7.0 - fixups for r600 2D tiling support. (no external ABI change), add eg dyn gpr regs * 2.8.0 - pageflip support, r500 US_FORMAT regs. r500 ARGB2101010 colorbuf, r300->r500 CMASK, clock crystal query * 2.9.0 - r600 tiling (s3tc,rgtc) working, SET_PREDICATION packet 3 on r600 + eg, backend query - * 2.10.0 - fusion 2D tiling, initial compute support for the CS checker - * 2.11.0 - backend map + * 2.10.0 - fusion 2D tiling + * 2.11.0 - backend map, initial compute support for the CS checker */ #define KMS_DRIVER_MAJOR 2 #define KMS_DRIVER_MINOR 11 diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index 781196db792f..6c111c1fa3f9 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -32,17 +32,17 @@ * radeon_ddc_probe * */ -bool radeon_ddc_probe(struct radeon_connector *radeon_connector) +bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool requires_extended_probe) { - u8 out_buf[] = { 0x0, 0x0}; - u8 buf[2]; + u8 out = 0x0; + u8 buf[8]; int ret; struct i2c_msg msgs[] = { { .addr = 0x50, .flags = 0, .len = 1, - .buf = out_buf, + .buf = &out, }, { .addr = 0x50, @@ -52,15 +52,31 @@ bool radeon_ddc_probe(struct radeon_connector *radeon_connector) } }; + /* Read 8 bytes from i2c for extended probe of EDID header */ + if (requires_extended_probe) + msgs[1].len = 8; + /* on hw with routers, select right port */ if (radeon_connector->router.ddc_valid) radeon_router_select_ddc_port(radeon_connector); ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2); - if (ret == 2) - return true; - - return false; + if (ret != 2) + /* Couldn't find an accessible DDC on this connector */ + return false; + if (requires_extended_probe) { + /* Probe also for valid EDID header + * EDID header starts with: + * 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00. + * Only the first 6 bytes must be valid as + * drm_edid_block_valid() can fix the last 2 bytes */ + if (drm_edid_header_is_valid(buf) < 6) { + /* Couldn't find an accessible EDID on this + * connector */ + return false; + } + } + return true; } /* bit banging i2c */ diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 6df4e3cec0c2..d09031c03e26 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -438,6 +438,9 @@ struct radeon_connector { struct radeon_i2c_chan *ddc_bus; /* some systems have an hdmi and vga port with a shared ddc line */ bool shared_ddc; + /* for some Radeon chip families we apply an additional EDID header + check as part of the DDC probe */ + bool requires_extended_probe; bool use_digital; /* we need to mind the EDID between detect and get modes due to analog/digital/tvencoder */ @@ -514,7 +517,8 @@ extern void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c, u8 val); extern void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector); extern void radeon_router_select_cd_port(struct radeon_connector *radeon_connector); -extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector); +extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector, + bool requires_extended_probe); extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector); extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector); diff --git a/drivers/ide/cy82c693.c b/drivers/ide/cy82c693.c index 3be60da52123..67cbcfa35122 100644 --- a/drivers/ide/cy82c693.c +++ b/drivers/ide/cy82c693.c @@ -141,6 +141,8 @@ static void cy82c693_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, time_16); pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, time_8); } + if (hwif->index > 0) + pci_dev_put(dev); } static void __devinit init_iops_cy82c693(ide_hwif_t *hwif) diff --git a/drivers/ide/ide_platform.c b/drivers/ide/ide_platform.c index 542603b394e4..962693b10a1c 100644 --- a/drivers/ide/ide_platform.c +++ b/drivers/ide/ide_platform.c @@ -19,6 +19,7 @@ #include <linux/module.h> #include <linux/ata_platform.h> #include <linux/platform_device.h> +#include <linux/interrupt.h> #include <linux/io.h> static void __devinit plat_ide_setup_ports(struct ide_hw *hw, @@ -95,7 +96,10 @@ static int __devinit plat_ide_probe(struct platform_device *pdev) plat_ide_setup_ports(&hw, base, alt_base, pdata, res_irq->start); hw.dev = &pdev->dev; - d.irq_flags = res_irq->flags; + d.irq_flags = res_irq->flags & IRQF_TRIGGER_MASK; + if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE) + d.irq_flags |= IRQF_SHARED; + if (mmio) d.host_flags |= IDE_HFLAG_MMIO; diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index ce281d152275..67df91af8424 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -483,7 +483,7 @@ static int gpio_keys_get_devtree_pdata(struct device *dev, buttons = kzalloc(pdata->nbuttons * (sizeof *buttons), GFP_KERNEL); if (!buttons) - return -ENODEV; + return -ENOMEM; pp = NULL; i = 0; diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index ab0acaf7fe8f..756348a7f93a 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c @@ -754,8 +754,11 @@ fail3: device_remove_file(&client->dev, &dev_attr_disable_kp); fail2: while (--pwm >= 0) - if (lm->pwm[pwm].enabled) + if (lm->pwm[pwm].enabled) { + device_remove_file(lm->pwm[pwm].cdev.dev, + &dev_attr_time); led_classdev_unregister(&lm->pwm[pwm].cdev); + } fail1: input_free_device(idev); kfree(lm); @@ -775,8 +778,10 @@ static int __devexit lm8323_remove(struct i2c_client *client) device_remove_file(&lm->client->dev, &dev_attr_disable_kp); for (i = 0; i < 3; i++) - if (lm->pwm[i].enabled) + if (lm->pwm[i].enabled) { + device_remove_file(lm->pwm[i].cdev.dev, &dev_attr_time); led_classdev_unregister(&lm->pwm[i].cdev); + } kfree(lm); diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index da3828fc2c09..f270447ba951 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c @@ -19,6 +19,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include <linux/kernel.h> #include <linux/module.h> #include <linux/input.h> #include <linux/platform_device.h> @@ -37,7 +38,7 @@ #define KBC_ROW_SCAN_DLY 5 /* KBC uses a 32KHz clock so a cycle = 1/32Khz */ -#define KBC_CYCLE_USEC 32 +#define KBC_CYCLE_MS 32 /* KBC Registers */ @@ -647,7 +648,7 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev) debounce_cnt = min(pdata->debounce_cnt, KBC_MAX_DEBOUNCE_CNT); scan_time_rows = (KBC_ROW_SCAN_TIME + debounce_cnt) * num_rows; kbc->repoll_dly = KBC_ROW_SCAN_DLY + scan_time_rows + pdata->repeat_cnt; - kbc->repoll_dly = ((kbc->repoll_dly * KBC_CYCLE_USEC) + 999) / 1000; + kbc->repoll_dly = DIV_ROUND_UP(kbc->repoll_dly, KBC_CYCLE_MS); input_dev->name = pdev->name; input_dev->id.bustype = BUS_HOST; diff --git a/drivers/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c index c456f63b6bae..783597a9a64a 100644 --- a/drivers/input/misc/kxtj9.c +++ b/drivers/input/misc/kxtj9.c @@ -21,6 +21,7 @@ #include <linux/i2c.h> #include <linux/input.h> #include <linux/interrupt.h> +#include <linux/module.h> #include <linux/slab.h> #include <linux/input/kxtj9.h> #include <linux/input-polldev.h> diff --git a/drivers/input/misc/mma8450.c b/drivers/input/misc/mma8450.c index 20f8f9284f02..6c76cf792991 100644 --- a/drivers/input/misc/mma8450.c +++ b/drivers/input/misc/mma8450.c @@ -24,6 +24,7 @@ #include <linux/delay.h> #include <linux/i2c.h> #include <linux/input-polldev.h> +#include <linux/of_device.h> #define MMA8450_DRV_NAME "mma8450" @@ -229,10 +230,17 @@ static const struct i2c_device_id mma8450_id[] = { }; MODULE_DEVICE_TABLE(i2c, mma8450_id); +static const struct of_device_id mma8450_dt_ids[] = { + { .compatible = "fsl,mma8450", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(i2c, mma8450_dt_ids); + static struct i2c_driver mma8450_driver = { .driver = { .name = MMA8450_DRV_NAME, .owner = THIS_MODULE, + .of_match_table = mma8450_dt_ids, }, .probe = mma8450_probe, .remove = __devexit_p(mma8450_remove), diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c index 95577c15ae56..4d17d9f3320b 100644 --- a/drivers/input/mouse/hgpk.c +++ b/drivers/input/mouse/hgpk.c @@ -32,6 +32,7 @@ #define DEBUG #include <linux/slab.h> #include <linux/input.h> +#include <linux/module.h> #include <linux/serio.h> #include <linux/libps2.h> #include <linux/delay.h> diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index bc3b5187f3a3..131f9d1c921b 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c @@ -249,12 +249,14 @@ static void __ad7879_enable(struct ad7879 *ts) static void __ad7879_disable(struct ad7879 *ts) { + u16 reg = (ts->cmd_crtl2 & ~AD7879_PM(-1)) | + AD7879_PM(AD7879_PM_SHUTDOWN); disable_irq(ts->irq); if (del_timer_sync(&ts->timer)) ad7879_ts_event_release(ts); - ad7879_write(ts, AD7879_REG_CTRL2, AD7879_PM(AD7879_PM_SHUTDOWN)); + ad7879_write(ts, AD7879_REG_CTRL2, reg); } diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c index 5b0dba6d4efa..d724a18b5285 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.c +++ b/drivers/net/bnx2x/bnx2x_cmn.c @@ -1989,14 +1989,20 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode) return -EINVAL; } + /* + * It's important to set the bp->state to the value different from + * BNX2X_STATE_OPEN and only then stop the Tx. Otherwise bnx2x_tx_int() + * may restart the Tx from the NAPI context (see bnx2x_tx_int()). + */ + bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT; + smp_mb(); + /* Stop Tx */ bnx2x_tx_disable(bp); #ifdef BCM_CNIC bnx2x_cnic_notify(bp, CNIC_CTL_STOP_CMD); #endif - bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT; - smp_mb(); bp->rx_mode = BNX2X_RX_MODE_NONE; diff --git a/drivers/net/bnx2x/bnx2x_hsi.h b/drivers/net/bnx2x/bnx2x_hsi.h index 06727f32e505..dc24de40e336 100644 --- a/drivers/net/bnx2x/bnx2x_hsi.h +++ b/drivers/net/bnx2x/bnx2x_hsi.h @@ -1204,6 +1204,8 @@ struct drv_port_mb { #define LINK_STATUS_PFC_ENABLED 0x20000000 + #define LINK_STATUS_PHYSICAL_LINK_FLAG 0x40000000 + u32 port_stx; u32 stat_nig_timer; diff --git a/drivers/net/bnx2x/bnx2x_link.c b/drivers/net/bnx2x/bnx2x_link.c index bcd8f0038628..d45b1555a602 100644 --- a/drivers/net/bnx2x/bnx2x_link.c +++ b/drivers/net/bnx2x/bnx2x_link.c @@ -1546,6 +1546,12 @@ static void bnx2x_umac_enable(struct link_params *params, vars->line_speed); break; } + if (!(vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)) + val |= UMAC_COMMAND_CONFIG_REG_IGNORE_TX_PAUSE; + + if (!(vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)) + val |= UMAC_COMMAND_CONFIG_REG_PAUSE_IGNORE; + REG_WR(bp, umac_base + UMAC_REG_COMMAND_CONFIG, val); udelay(50); @@ -1661,10 +1667,20 @@ static void bnx2x_xmac_disable(struct link_params *params) { u8 port = params->port; struct bnx2x *bp = params->bp; - u32 xmac_base = (port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0; + u32 pfc_ctrl, xmac_base = (port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0; if (REG_RD(bp, MISC_REG_RESET_REG_2) & MISC_REGISTERS_RESET_REG_2_XMAC) { + /* + * Send an indication to change the state in the NIG back to XON + * Clearing this bit enables the next set of this bit to get + * rising edge + */ + pfc_ctrl = REG_RD(bp, xmac_base + XMAC_REG_PFC_CTRL_HI); + REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL_HI, + (pfc_ctrl & ~(1<<1))); + REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL_HI, + (pfc_ctrl | (1<<1))); DP(NETIF_MSG_LINK, "Disable XMAC on port %x\n", port); REG_WR(bp, xmac_base + XMAC_REG_CTRL, 0); usleep_range(1000, 1000); @@ -1729,6 +1745,10 @@ static int bnx2x_emac_enable(struct link_params *params, DP(NETIF_MSG_LINK, "enabling EMAC\n"); + /* Disable BMAC */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); + /* enable emac and not bmac */ REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1); @@ -2583,12 +2603,6 @@ static int bnx2x_bmac1_enable(struct link_params *params, REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS, wb_data, 2); - if (vars->phy_flags & PHY_TX_ERROR_CHECK_FLAG) { - REG_RD_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LSS_STATUS, - wb_data, 2); - if (wb_data[0] > 0) - return -ESRCH; - } return 0; } @@ -2654,16 +2668,6 @@ static int bnx2x_bmac2_enable(struct link_params *params, udelay(30); bnx2x_update_pfc_bmac2(params, vars, is_lb); - if (vars->phy_flags & PHY_TX_ERROR_CHECK_FLAG) { - REG_RD_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_LSS_STAT, - wb_data, 2); - if (wb_data[0] > 0) { - DP(NETIF_MSG_LINK, "Got bad LSS status 0x%x\n", - wb_data[0]); - return -ESRCH; - } - } - return 0; } @@ -2949,7 +2953,9 @@ static int bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy, u32 val; u16 i; int rc = 0; - + if (phy->flags & FLAGS_MDC_MDIO_WA_B0) + bnx2x_bits_en(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_STATUS, + EMAC_MDIO_STATUS_10MB); /* address */ val = ((phy->addr << 21) | (devad << 16) | reg | EMAC_MDIO_COMM_COMMAND_ADDRESS | @@ -3003,6 +3009,9 @@ static int bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy, } } + if (phy->flags & FLAGS_MDC_MDIO_WA_B0) + bnx2x_bits_dis(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_STATUS, + EMAC_MDIO_STATUS_10MB); return rc; } @@ -3012,6 +3021,9 @@ static int bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy, u32 tmp; u8 i; int rc = 0; + if (phy->flags & FLAGS_MDC_MDIO_WA_B0) + bnx2x_bits_en(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_STATUS, + EMAC_MDIO_STATUS_10MB); /* address */ @@ -3065,7 +3077,9 @@ static int bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy, bnx2x_cl45_read(bp, phy, devad, 0xf, &temp_val); } } - + if (phy->flags & FLAGS_MDC_MDIO_WA_B0) + bnx2x_bits_dis(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_STATUS, + EMAC_MDIO_STATUS_10MB); return rc; } @@ -4353,6 +4367,9 @@ void bnx2x_link_status_update(struct link_params *params, vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP); vars->phy_flags = PHY_XGXS_FLAG; + if (vars->link_status & LINK_STATUS_PHYSICAL_LINK_FLAG) + vars->phy_flags |= PHY_PHYSICAL_LINK_FLAG; + if (vars->link_up) { DP(NETIF_MSG_LINK, "phy link up\n"); @@ -4444,6 +4461,8 @@ void bnx2x_link_status_update(struct link_params *params, /* indicate no mac active */ vars->mac_type = MAC_TYPE_NONE; + if (vars->link_status & LINK_STATUS_PHYSICAL_LINK_FLAG) + vars->phy_flags |= PHY_HALF_OPEN_CONN_FLAG; } /* Sync media type */ @@ -5903,20 +5922,30 @@ int bnx2x_set_led(struct link_params *params, tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED); EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE)); - return rc; + /* + * return here without enabling traffic + * LED blink andsetting rate in ON mode. + * In oper mode, enabling LED blink + * and setting rate is needed. + */ + if (mode == LED_MODE_ON) + return rc; } - } else if (SINGLE_MEDIA_DIRECT(params) && - (CHIP_IS_E1x(bp) || - CHIP_IS_E2(bp))) { + } else if (SINGLE_MEDIA_DIRECT(params)) { /* * This is a work-around for HW issue found when link * is up in CL73 */ - REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0); REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1); - } else { + if (CHIP_IS_E1x(bp) || + CHIP_IS_E2(bp) || + (mode == LED_MODE_ON)) + REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0); + else + REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, + hw_led_mode); + } else REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, hw_led_mode); - } REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 + port*4, 0); /* Set blinking rate to ~15.9Hz */ @@ -6160,6 +6189,7 @@ static int bnx2x_update_link_down(struct link_params *params, /* update shared memory */ vars->link_status &= ~(LINK_STATUS_SPEED_AND_DUPLEX_MASK | LINK_STATUS_LINK_UP | + LINK_STATUS_PHYSICAL_LINK_FLAG | LINK_STATUS_AUTO_NEGOTIATE_COMPLETE | LINK_STATUS_RX_FLOW_CONTROL_FLAG_MASK | LINK_STATUS_TX_FLOW_CONTROL_FLAG_MASK | @@ -6197,7 +6227,8 @@ static int bnx2x_update_link_up(struct link_params *params, u8 port = params->port; int rc = 0; - vars->link_status |= LINK_STATUS_LINK_UP; + vars->link_status |= (LINK_STATUS_LINK_UP | + LINK_STATUS_PHYSICAL_LINK_FLAG); vars->phy_flags |= PHY_PHYSICAL_LINK_FLAG; if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) @@ -7998,6 +8029,9 @@ static void bnx2x_warpcore_set_limiting_mode(struct link_params *params, bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE, &val); + /* Restart microcode to re-read the new mode */ + bnx2x_warpcore_reset_lane(bp, phy, 1); + bnx2x_warpcore_reset_lane(bp, phy, 0); } @@ -8116,7 +8150,6 @@ void bnx2x_handle_module_detect_int(struct link_params *params) offsetof(struct shmem_region, dev_info. port_feature_config[params->port]. config)); - bnx2x_set_gpio_int(bp, gpio_num, MISC_REGISTERS_GPIO_INT_OUTPUT_SET, gpio_port); @@ -8125,8 +8158,9 @@ void bnx2x_handle_module_detect_int(struct link_params *params) * Disable transmit for this module */ phy->media_type = ETH_PHY_NOT_PRESENT; - if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == - PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) + if (((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == + PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) || + CHIP_IS_E3(bp)) bnx2x_sfp_set_transmitter(params, phy, 0); } } @@ -8228,9 +8262,6 @@ static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy, u16 cnt, val, tmp1; struct bnx2x *bp = params->bp; - /* SPF+ PHY: Set flag to check for Tx error */ - vars->phy_flags = PHY_TX_ERROR_CHECK_FLAG; - bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port); /* HW reset */ @@ -8414,9 +8445,6 @@ static int bnx2x_8726_config_init(struct bnx2x_phy *phy, struct bnx2x *bp = params->bp; DP(NETIF_MSG_LINK, "Initializing BCM8726\n"); - /* SPF+ PHY: Set flag to check for Tx error */ - vars->phy_flags = PHY_TX_ERROR_CHECK_FLAG; - bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15); bnx2x_wait_reset_complete(bp, phy, params); @@ -8585,9 +8613,6 @@ static int bnx2x_8727_config_init(struct bnx2x_phy *phy, struct bnx2x *bp = params->bp; /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */ - /* SPF+ PHY: Set flag to check for Tx error */ - vars->phy_flags = PHY_TX_ERROR_CHECK_FLAG; - bnx2x_wait_reset_complete(bp, phy, params); rx_alarm_ctrl_val = (1<<2) | (1<<5) ; /* Should be 0x6 to enable XS on Tx side. */ @@ -9243,7 +9268,13 @@ static int bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy, if (phy->req_duplex == DUPLEX_FULL) autoneg_val |= (1<<8); - bnx2x_cl45_write(bp, phy, + /* + * Always write this if this is not 84833. + * For 84833, write it only when it's a forced speed. + */ + if ((phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) || + ((autoneg_val & (1<<12)) == 0)) + bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_MII_CTRL, autoneg_val); @@ -9257,13 +9288,12 @@ static int bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy, bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x3200); - } else if (phy->req_line_speed != SPEED_10 && - phy->req_line_speed != SPEED_100) { + } else bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8481_10GBASE_T_AN_CTRL, 1); - } + /* Save spirom version */ bnx2x_save_848xx_spirom_version(phy, params); @@ -9756,11 +9786,9 @@ static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy, bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, 0x400f, &val16); - /* Put to low power mode on newer FW */ - if ((val16 & 0x303f) > 0x1009) - bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, - MDIO_PMA_REG_CTRL, 0x800); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, 0x800); } } @@ -10191,8 +10219,15 @@ static void bnx2x_54618se_link_reset(struct bnx2x_phy *phy, u32 cfg_pin; u8 port; - /* This works with E3 only, no need to check the chip - before determining the port. */ + /* + * In case of no EPIO routed to reset the GPHY, put it + * in low power mode. + */ + bnx2x_cl22_write(bp, phy, MDIO_PMA_REG_CTRL, 0x800); + /* + * This works with E3 only, no need to check the chip + * before determining the port. + */ port = params->port; cfg_pin = (REG_RD(bp, params->shmem_base + offsetof(struct shmem_region, @@ -10603,7 +10638,8 @@ static struct bnx2x_phy phy_warpcore = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT, .addr = 0xff, .def_md_devad = 0, - .flags = FLAGS_HW_LOCK_REQUIRED, + .flags = (FLAGS_HW_LOCK_REQUIRED | + FLAGS_TX_ERROR_CHECK), .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, @@ -10729,7 +10765,8 @@ static struct bnx2x_phy phy_8706 = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706, .addr = 0xff, .def_md_devad = 0, - .flags = FLAGS_INIT_XGXS_FIRST, + .flags = (FLAGS_INIT_XGXS_FIRST | + FLAGS_TX_ERROR_CHECK), .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, @@ -10760,7 +10797,8 @@ static struct bnx2x_phy phy_8726 = { .addr = 0xff, .def_md_devad = 0, .flags = (FLAGS_HW_LOCK_REQUIRED | - FLAGS_INIT_XGXS_FIRST), + FLAGS_INIT_XGXS_FIRST | + FLAGS_TX_ERROR_CHECK), .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, @@ -10791,7 +10829,8 @@ static struct bnx2x_phy phy_8727 = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, .addr = 0xff, .def_md_devad = 0, - .flags = FLAGS_FAN_FAILURE_DET_REQ, + .flags = (FLAGS_FAN_FAILURE_DET_REQ | + FLAGS_TX_ERROR_CHECK), .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, @@ -11112,6 +11151,8 @@ static int bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port, */ if (CHIP_REV(bp) == CHIP_REV_Ax) phy->flags |= FLAGS_MDC_MDIO_WA; + else + phy->flags |= FLAGS_MDC_MDIO_WA_B0; } else { switch (switch_cfg) { case SWITCH_CFG_1G: @@ -11500,13 +11541,12 @@ void bnx2x_init_xmac_loopback(struct link_params *params, * Set WC to loopback mode since link is required to provide clock * to the XMAC in 20G mode */ - if (vars->line_speed == SPEED_20000) { - bnx2x_set_aer_mmd(params, ¶ms->phy[0]); - bnx2x_warpcore_reset_lane(bp, ¶ms->phy[0], 0); - params->phy[INT_PHY].config_loopback( + bnx2x_set_aer_mmd(params, ¶ms->phy[0]); + bnx2x_warpcore_reset_lane(bp, ¶ms->phy[0], 0); + params->phy[INT_PHY].config_loopback( ¶ms->phy[INT_PHY], params); - } + bnx2x_xmac_enable(params, vars, 1); REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); } @@ -11684,12 +11724,16 @@ int bnx2x_link_reset(struct link_params *params, struct link_vars *vars, bnx2x_set_led(params, vars, LED_MODE_OFF, 0); if (reset_ext_phy) { + bnx2x_set_mdio_clk(bp, params->chip_id, port); for (phy_index = EXT_PHY1; phy_index < params->num_phys; phy_index++) { - if (params->phy[phy_index].link_reset) + if (params->phy[phy_index].link_reset) { + bnx2x_set_aer_mmd(params, + ¶ms->phy[phy_index]); params->phy[phy_index].link_reset( ¶ms->phy[phy_index], params); + } if (params->phy[phy_index].flags & FLAGS_REARM_LATCH_SIGNAL) clear_latch_ind = 1; @@ -12178,10 +12222,6 @@ static void bnx2x_analyze_link_error(struct link_params *params, u8 led_mode; u32 half_open_conn = (vars->phy_flags & PHY_HALF_OPEN_CONN_FLAG) > 0; - /*DP(NETIF_MSG_LINK, "CHECK LINK: %x half_open:%x-> lss:%x\n", - vars->link_up, - half_open_conn, lss_status);*/ - if ((lss_status ^ half_open_conn) == 0) return; @@ -12194,6 +12234,7 @@ static void bnx2x_analyze_link_error(struct link_params *params, * b. Update link_vars->link_up */ if (lss_status) { + DP(NETIF_MSG_LINK, "Remote Fault detected !!!\n"); vars->link_status &= ~LINK_STATUS_LINK_UP; vars->link_up = 0; vars->phy_flags |= PHY_HALF_OPEN_CONN_FLAG; @@ -12203,6 +12244,7 @@ static void bnx2x_analyze_link_error(struct link_params *params, */ led_mode = LED_MODE_OFF; } else { + DP(NETIF_MSG_LINK, "Remote Fault cleared\n"); vars->link_status |= LINK_STATUS_LINK_UP; vars->link_up = 1; vars->phy_flags &= ~PHY_HALF_OPEN_CONN_FLAG; @@ -12219,6 +12261,15 @@ static void bnx2x_analyze_link_error(struct link_params *params, bnx2x_notify_link_changed(bp); } +/****************************************************************************** +* Description: +* This function checks for half opened connection change indication. +* When such change occurs, it calls the bnx2x_analyze_link_error +* to check if Remote Fault is set or cleared. Reception of remote fault +* status message in the MAC indicates that the peer's MAC has detected +* a fault, for example, due to break in the TX side of fiber. +* +******************************************************************************/ static void bnx2x_check_half_open_conn(struct link_params *params, struct link_vars *vars) { @@ -12229,9 +12280,28 @@ static void bnx2x_check_half_open_conn(struct link_params *params, if ((vars->phy_flags & PHY_PHYSICAL_LINK_FLAG) == 0) return; - if (!CHIP_IS_E3(bp) && + if (CHIP_IS_E3(bp) && (REG_RD(bp, MISC_REG_RESET_REG_2) & - (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port))) { + (MISC_REGISTERS_RESET_REG_2_XMAC))) { + /* Check E3 XMAC */ + /* + * Note that link speed cannot be queried here, since it may be + * zero while link is down. In case UMAC is active, LSS will + * simply not be set + */ + mac_base = (params->port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0; + + /* Clear stick bits (Requires rising edge) */ + REG_WR(bp, mac_base + XMAC_REG_CLEAR_RX_LSS_STATUS, 0); + REG_WR(bp, mac_base + XMAC_REG_CLEAR_RX_LSS_STATUS, + XMAC_CLEAR_RX_LSS_STATUS_REG_CLEAR_LOCAL_FAULT_STATUS | + XMAC_CLEAR_RX_LSS_STATUS_REG_CLEAR_REMOTE_FAULT_STATUS); + if (REG_RD(bp, mac_base + XMAC_REG_RX_LSS_STATUS)) + lss_status = 1; + + bnx2x_analyze_link_error(params, vars, lss_status); + } else if (REG_RD(bp, MISC_REG_RESET_REG_2) & + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port)) { /* Check E1X / E2 BMAC */ u32 lss_status_reg; u32 wb_data[2]; @@ -12253,14 +12323,20 @@ static void bnx2x_check_half_open_conn(struct link_params *params, void bnx2x_period_func(struct link_params *params, struct link_vars *vars) { struct bnx2x *bp = params->bp; + u16 phy_idx; if (!params) { - DP(NETIF_MSG_LINK, "Ininitliazed params !\n"); + DP(NETIF_MSG_LINK, "Uninitialized params !\n"); return; } - /* DP(NETIF_MSG_LINK, "Periodic called vars->phy_flags 0x%x speed 0x%x - RESET_REG_2 0x%x\n", vars->phy_flags, vars->line_speed, - REG_RD(bp, MISC_REG_RESET_REG_2)); */ - bnx2x_check_half_open_conn(params, vars); + + for (phy_idx = INT_PHY; phy_idx < MAX_PHYS; phy_idx++) { + if (params->phy[phy_idx].flags & FLAGS_TX_ERROR_CHECK) { + bnx2x_set_aer_mmd(params, ¶ms->phy[phy_idx]); + bnx2x_check_half_open_conn(params, vars); + break; + } + } + if (CHIP_IS_E3(bp)) bnx2x_check_over_curr(params, vars); } diff --git a/drivers/net/bnx2x/bnx2x_link.h b/drivers/net/bnx2x/bnx2x_link.h index 6a7708d5da37..c12db6da213e 100644 --- a/drivers/net/bnx2x/bnx2x_link.h +++ b/drivers/net/bnx2x/bnx2x_link.h @@ -145,6 +145,8 @@ struct bnx2x_phy { #define FLAGS_SFP_NOT_APPROVED (1<<7) #define FLAGS_MDC_MDIO_WA (1<<8) #define FLAGS_DUMMY_READ (1<<9) +#define FLAGS_MDC_MDIO_WA_B0 (1<<10) +#define FLAGS_TX_ERROR_CHECK (1<<12) /* preemphasis values for the rx side */ u16 rx_preemphasis[4]; @@ -276,7 +278,6 @@ struct link_vars { #define PHY_PHYSICAL_LINK_FLAG (1<<2) #define PHY_HALF_OPEN_CONN_FLAG (1<<3) #define PHY_OVER_CURRENT_FLAG (1<<4) -#define PHY_TX_ERROR_CHECK_FLAG (1<<5) u8 mac_type; #define MAC_TYPE_NONE 0 diff --git a/drivers/net/bnx2x/bnx2x_reg.h b/drivers/net/bnx2x/bnx2x_reg.h index 02461fef8751..27b5ecb11830 100644 --- a/drivers/net/bnx2x/bnx2x_reg.h +++ b/drivers/net/bnx2x/bnx2x_reg.h @@ -4771,9 +4771,11 @@ The fields are: [4:0] - tail pointer; 10:5] - Link List size; 15:11] - header pointer. */ #define UCM_REG_XX_TABLE 0xe0300 +#define UMAC_COMMAND_CONFIG_REG_IGNORE_TX_PAUSE (0x1<<28) #define UMAC_COMMAND_CONFIG_REG_LOOP_ENA (0x1<<15) #define UMAC_COMMAND_CONFIG_REG_NO_LGTH_CHECK (0x1<<24) #define UMAC_COMMAND_CONFIG_REG_PAD_EN (0x1<<5) +#define UMAC_COMMAND_CONFIG_REG_PAUSE_IGNORE (0x1<<8) #define UMAC_COMMAND_CONFIG_REG_PROMIS_EN (0x1<<4) #define UMAC_COMMAND_CONFIG_REG_RX_ENA (0x1<<1) #define UMAC_COMMAND_CONFIG_REG_SW_RESET (0x1<<13) @@ -5622,8 +5624,9 @@ #define EMAC_MDIO_COMM_START_BUSY (1L<<29) #define EMAC_MDIO_MODE_AUTO_POLL (1L<<4) #define EMAC_MDIO_MODE_CLAUSE_45 (1L<<31) -#define EMAC_MDIO_MODE_CLOCK_CNT (0x3fL<<16) +#define EMAC_MDIO_MODE_CLOCK_CNT (0x3ffL<<16) #define EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT 16 +#define EMAC_MDIO_STATUS_10MB (1L<<1) #define EMAC_MODE_25G_MODE (1L<<5) #define EMAC_MODE_HALF_DUPLEX (1L<<1) #define EMAC_MODE_PORT_GMII (2L<<2) @@ -5634,6 +5637,7 @@ #define EMAC_REG_EMAC_MAC_MATCH 0x10 #define EMAC_REG_EMAC_MDIO_COMM 0xac #define EMAC_REG_EMAC_MDIO_MODE 0xb4 +#define EMAC_REG_EMAC_MDIO_STATUS 0xb0 #define EMAC_REG_EMAC_MODE 0x0 #define EMAC_REG_EMAC_RX_MODE 0xc8 #define EMAC_REG_EMAC_RX_MTU_SIZE 0x9c diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index c5f0f04219f3..5548d464261a 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -838,6 +838,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) /* Disable all the interrupts */ ew32(IMC, 0xFFFFFFFF); + E1000_WRITE_FLUSH(); msleep(10); /* Test each interrupt */ @@ -856,6 +857,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) adapter->test_icr = 0; ew32(IMC, mask); ew32(ICS, mask); + E1000_WRITE_FLUSH(); msleep(10); if (adapter->test_icr & mask) { @@ -873,6 +875,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) adapter->test_icr = 0; ew32(IMS, mask); ew32(ICS, mask); + E1000_WRITE_FLUSH(); msleep(10); if (!(adapter->test_icr & mask)) { @@ -890,6 +893,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) adapter->test_icr = 0; ew32(IMC, ~mask & 0x00007FFF); ew32(ICS, ~mask & 0x00007FFF); + E1000_WRITE_FLUSH(); msleep(10); if (adapter->test_icr) { @@ -901,6 +905,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) /* Disable all the interrupts */ ew32(IMC, 0xFFFFFFFF); + E1000_WRITE_FLUSH(); msleep(10); /* Unhook test interrupt handler */ @@ -1394,6 +1399,7 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter) if (unlikely(++k == txdr->count)) k = 0; } ew32(TDT, k); + E1000_WRITE_FLUSH(); msleep(200); time = jiffies; /* set the start time for the receive */ good_cnt = 0; diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 1698622af434..8545c7aa93eb 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -446,6 +446,7 @@ s32 e1000_reset_hw(struct e1000_hw *hw) /* Must reset the PHY before resetting the MAC */ if ((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) { ew32(CTRL, (ctrl | E1000_CTRL_PHY_RST)); + E1000_WRITE_FLUSH(); msleep(5); } @@ -3752,6 +3753,7 @@ static s32 e1000_acquire_eeprom(struct e1000_hw *hw) /* Clear SK and CS */ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); ew32(EECD, eecd); + E1000_WRITE_FLUSH(); udelay(1); } @@ -3824,6 +3826,7 @@ static void e1000_release_eeprom(struct e1000_hw *hw) eecd &= ~E1000_EECD_SK; /* Lower SCK */ ew32(EECD, eecd); + E1000_WRITE_FLUSH(); udelay(hw->eeprom.delay_usec); } else if (hw->eeprom.type == e1000_eeprom_microwire) { diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c index c0ecb2d9fdb7..e4f42257c24c 100644 --- a/drivers/net/e1000e/es2lan.c +++ b/drivers/net/e1000e/es2lan.c @@ -1313,6 +1313,7 @@ static s32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN; ew32(KMRNCTRLSTA, kmrnctrlsta); + e1e_flush(); udelay(2); @@ -1347,6 +1348,7 @@ static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & E1000_KMRNCTRLSTA_OFFSET) | data; ew32(KMRNCTRLSTA, kmrnctrlsta); + e1e_flush(); udelay(2); diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index cb1a3623253e..06d88f316dce 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -28,8 +28,8 @@ /* ethtool support for e1000 */ -#include <linux/interrupt.h> #include <linux/netdevice.h> +#include <linux/interrupt.h> #include <linux/ethtool.h> #include <linux/pci.h> #include <linux/slab.h> @@ -964,6 +964,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) /* Disable all the interrupts */ ew32(IMC, 0xFFFFFFFF); + e1e_flush(); usleep_range(10000, 20000); /* Test each interrupt */ @@ -996,6 +997,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) adapter->test_icr = 0; ew32(IMC, mask); ew32(ICS, mask); + e1e_flush(); usleep_range(10000, 20000); if (adapter->test_icr & mask) { @@ -1014,6 +1016,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) adapter->test_icr = 0; ew32(IMS, mask); ew32(ICS, mask); + e1e_flush(); usleep_range(10000, 20000); if (!(adapter->test_icr & mask)) { @@ -1032,6 +1035,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) adapter->test_icr = 0; ew32(IMC, ~mask & 0x00007FFF); ew32(ICS, ~mask & 0x00007FFF); + e1e_flush(); usleep_range(10000, 20000); if (adapter->test_icr) { @@ -1043,6 +1047,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data) /* Disable all the interrupts */ ew32(IMC, 0xFFFFFFFF); + e1e_flush(); usleep_range(10000, 20000); /* Unhook test interrupt handler */ @@ -1276,6 +1281,7 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter) E1000_CTRL_FD); /* Force Duplex to FULL */ ew32(CTRL, ctrl_reg); + e1e_flush(); udelay(500); return 0; @@ -1418,6 +1424,7 @@ static int e1000_set_82571_fiber_loopback(struct e1000_adapter *adapter) */ #define E1000_SERDES_LB_ON 0x410 ew32(SCTL, E1000_SERDES_LB_ON); + e1e_flush(); usleep_range(10000, 20000); return 0; @@ -1513,6 +1520,7 @@ static void e1000_loopback_cleanup(struct e1000_adapter *adapter) hw->phy.media_type == e1000_media_type_internal_serdes) { #define E1000_SERDES_LB_OFF 0x400 ew32(SCTL, E1000_SERDES_LB_OFF); + e1e_flush(); usleep_range(10000, 20000); break; } @@ -1592,6 +1600,7 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter) k = 0; } ew32(TDT, k); + e1e_flush(); msleep(200); time = jiffies; /* set the start time for the receive */ good_cnt = 0; diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index c1752124f3cd..4e36978b8fd8 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -283,6 +283,7 @@ static void e1000_toggle_lanphypc_value_ich8lan(struct e1000_hw *hw) ctrl |= E1000_CTRL_LANPHYPC_OVERRIDE; ctrl &= ~E1000_CTRL_LANPHYPC_VALUE; ew32(CTRL, ctrl); + e1e_flush(); udelay(10); ctrl &= ~E1000_CTRL_LANPHYPC_OVERRIDE; ew32(CTRL, ctrl); @@ -1230,9 +1231,11 @@ s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable) ew32(CTRL, reg); ew32(CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_SPD_BYPS); + e1e_flush(); udelay(20); ew32(CTRL, ctrl_reg); ew32(CTRL_EXT, ctrl_ext); + e1e_flush(); udelay(20); out: @@ -2134,8 +2137,7 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, ret_val = 0; for (i = 0; i < words; i++) { - if ((dev_spec->shadow_ram) && - (dev_spec->shadow_ram[offset+i].modified)) { + if (dev_spec->shadow_ram[offset+i].modified) { data[i] = dev_spec->shadow_ram[offset+i].value; } else { ret_val = e1000_read_flash_word_ich8lan(hw, @@ -3090,6 +3092,7 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) ret_val = e1000_acquire_swflag_ich8lan(hw); e_dbg("Issuing a global reset to ich8lan\n"); ew32(CTRL, (ctrl | E1000_CTRL_RST)); + /* cannot issue a flush here because it hangs the hardware */ msleep(20); if (!ret_val) diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c index 65580b405942..7898a67d6505 100644 --- a/drivers/net/e1000e/lib.c +++ b/drivers/net/e1000e/lib.c @@ -1986,6 +1986,7 @@ static s32 e1000_ready_nvm_eeprom(struct e1000_hw *hw) /* Clear SK and CS */ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); ew32(EECD, eecd); + e1e_flush(); udelay(1); /* diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 4353ad56cf16..ab4be80f7ab5 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -31,12 +31,12 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/init.h> -#include <linux/interrupt.h> #include <linux/pci.h> #include <linux/vmalloc.h> #include <linux/pagemap.h> #include <linux/delay.h> #include <linux/netdevice.h> +#include <linux/interrupt.h> #include <linux/tcp.h> #include <linux/ipv6.h> #include <linux/slab.h> diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c index 2a6ee13285b1..8666476cb9be 100644 --- a/drivers/net/e1000e/phy.c +++ b/drivers/net/e1000e/phy.c @@ -537,6 +537,7 @@ static s32 __e1000_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data, kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN; ew32(KMRNCTRLSTA, kmrnctrlsta); + e1e_flush(); udelay(2); @@ -609,6 +610,7 @@ static s32 __e1000_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data, kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & E1000_KMRNCTRLSTA_OFFSET) | data; ew32(KMRNCTRLSTA, kmrnctrlsta); + e1e_flush(); udelay(2); diff --git a/drivers/net/igb/e1000_nvm.c b/drivers/net/igb/e1000_nvm.c index 7dcd65cede56..40407124e722 100644 --- a/drivers/net/igb/e1000_nvm.c +++ b/drivers/net/igb/e1000_nvm.c @@ -285,6 +285,7 @@ static s32 igb_ready_nvm_eeprom(struct e1000_hw *hw) /* Clear SK and CS */ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); wr32(E1000_EECD, eecd); + wrfl(); udelay(1); timeout = NVM_MAX_RETRY_SPI; diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index ff244ce803ce..414b0225be89 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -1225,6 +1225,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data) /* Disable all the interrupts */ wr32(E1000_IMC, ~0); + wrfl(); msleep(10); /* Define all writable bits for ICS */ @@ -1268,6 +1269,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data) wr32(E1000_IMC, mask); wr32(E1000_ICS, mask); + wrfl(); msleep(10); if (adapter->test_icr & mask) { @@ -1289,6 +1291,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data) wr32(E1000_IMS, mask); wr32(E1000_ICS, mask); + wrfl(); msleep(10); if (!(adapter->test_icr & mask)) { @@ -1310,6 +1313,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data) wr32(E1000_IMC, ~mask); wr32(E1000_ICS, ~mask); + wrfl(); msleep(10); if (adapter->test_icr & mask) { @@ -1321,6 +1325,7 @@ static int igb_intr_test(struct igb_adapter *adapter, u64 *data) /* Disable all the interrupts */ wr32(E1000_IMC, ~0); + wrfl(); msleep(10); /* Unhook test interrupt handler */ diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index dc599059512a..40d4c405fd7e 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -1052,6 +1052,7 @@ msi_only: kfree(adapter->vf_data); adapter->vf_data = NULL; wr32(E1000_IOVCTL, E1000_IOVCTL_REUSE_VFQ); + wrfl(); msleep(100); dev_info(&adapter->pdev->dev, "IOV Disabled\n"); } @@ -2022,7 +2023,7 @@ static int __devinit igb_probe(struct pci_dev *pdev, if (hw->bus.func == 0) hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data); - else if (hw->mac.type == e1000_82580) + else if (hw->mac.type >= e1000_82580) hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A + NVM_82580_LAN_FUNC_OFFSET(hw->bus.func), 1, &eeprom_data); @@ -2198,6 +2199,7 @@ static void __devexit igb_remove(struct pci_dev *pdev) kfree(adapter->vf_data); adapter->vf_data = NULL; wr32(E1000_IOVCTL, E1000_IOVCTL_REUSE_VFQ); + wrfl(); msleep(100); dev_info(&pdev->dev, "IOV Disabled\n"); } diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index 1330c8e932da..40ed066e3ef4 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -1226,6 +1226,7 @@ static void igbvf_configure_tx(struct igbvf_adapter *adapter) /* disable transmits */ txdctl = er32(TXDCTL(0)); ew32(TXDCTL(0), txdctl & ~E1000_TXDCTL_QUEUE_ENABLE); + e1e_flush(); msleep(10); /* Setup the HW Tx Head and Tail descriptor pointers */ @@ -1306,6 +1307,7 @@ static void igbvf_configure_rx(struct igbvf_adapter *adapter) /* disable receives */ rxdctl = er32(RXDCTL(0)); ew32(RXDCTL(0), rxdctl & ~E1000_RXDCTL_QUEUE_ENABLE); + e1e_flush(); msleep(10); rdlen = rx_ring->count * sizeof(union e1000_adv_rx_desc); diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index 954f6e938fb7..8b1c3484d271 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -2405,8 +2405,6 @@ static int __init smsc_superio_lpc(unsigned short cfg_base) * addresses making a subsystem device table necessary. */ #ifdef CONFIG_PCI -#define PCIID_VENDOR_INTEL 0x8086 -#define PCIID_VENDOR_ALI 0x10b9 static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __initdata = { /* * Subsystems needing entries: @@ -2416,7 +2414,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini */ { /* Guessed entry */ - .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */ + .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801DBM LPC bridge */ .device = 0x24cc, .subvendor = 0x103c, .subdevice = 0x08bc, @@ -2429,7 +2427,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini .name = "HP nx5000 family", }, { - .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */ + .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801DBM LPC bridge */ .device = 0x24cc, .subvendor = 0x103c, .subdevice = 0x088c, @@ -2443,7 +2441,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini .name = "HP nc8000 family", }, { - .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */ + .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801DBM LPC bridge */ .device = 0x24cc, .subvendor = 0x103c, .subdevice = 0x0890, @@ -2456,7 +2454,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini .name = "HP nc6000 family", }, { - .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */ + .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801DBM LPC bridge */ .device = 0x24cc, .subvendor = 0x0e11, .subdevice = 0x0860, @@ -2471,7 +2469,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini }, { /* Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge */ - .vendor = PCIID_VENDOR_INTEL, + .vendor = PCI_VENDOR_ID_INTEL, .device = 0x24c0, .subvendor = 0x1179, .subdevice = 0xffff, /* 0xffff is "any" */ @@ -2484,7 +2482,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini .name = "Toshiba laptop with Intel 82801DB/DBL LPC bridge", }, { - .vendor = PCIID_VENDOR_INTEL, /* Intel 82801CAM ISA bridge */ + .vendor = PCI_VENDOR_ID_INTEL, /* Intel 82801CAM ISA bridge */ .device = 0x248c, .subvendor = 0x1179, .subdevice = 0xffff, /* 0xffff is "any" */ @@ -2498,7 +2496,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini }, { /* 82801DBM (ICH4-M) LPC Interface Bridge */ - .vendor = PCIID_VENDOR_INTEL, + .vendor = PCI_VENDOR_ID_INTEL, .device = 0x24cc, .subvendor = 0x1179, .subdevice = 0xffff, /* 0xffff is "any" */ @@ -2512,7 +2510,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini }, { /* ALi M1533/M1535 PCI to ISA Bridge [Aladdin IV/V/V+] */ - .vendor = PCIID_VENDOR_ALI, + .vendor = PCI_VENDOR_ID_AL, .device = 0x1533, .subvendor = 0x1179, .subdevice = 0xffff, /* 0xffff is "any" */ diff --git a/drivers/net/ixgb/ixgb_ee.c b/drivers/net/ixgb/ixgb_ee.c index c982ab9f9005..38b362b67857 100644 --- a/drivers/net/ixgb/ixgb_ee.c +++ b/drivers/net/ixgb/ixgb_ee.c @@ -57,6 +57,7 @@ ixgb_raise_clock(struct ixgb_hw *hw, */ *eecd_reg = *eecd_reg | IXGB_EECD_SK; IXGB_WRITE_REG(hw, EECD, *eecd_reg); + IXGB_WRITE_FLUSH(hw); udelay(50); } @@ -75,6 +76,7 @@ ixgb_lower_clock(struct ixgb_hw *hw, */ *eecd_reg = *eecd_reg & ~IXGB_EECD_SK; IXGB_WRITE_REG(hw, EECD, *eecd_reg); + IXGB_WRITE_FLUSH(hw); udelay(50); } @@ -112,6 +114,7 @@ ixgb_shift_out_bits(struct ixgb_hw *hw, eecd_reg |= IXGB_EECD_DI; IXGB_WRITE_REG(hw, EECD, eecd_reg); + IXGB_WRITE_FLUSH(hw); udelay(50); @@ -206,21 +209,25 @@ ixgb_standby_eeprom(struct ixgb_hw *hw) /* Deselect EEPROM */ eecd_reg &= ~(IXGB_EECD_CS | IXGB_EECD_SK); IXGB_WRITE_REG(hw, EECD, eecd_reg); + IXGB_WRITE_FLUSH(hw); udelay(50); /* Clock high */ eecd_reg |= IXGB_EECD_SK; IXGB_WRITE_REG(hw, EECD, eecd_reg); + IXGB_WRITE_FLUSH(hw); udelay(50); /* Select EEPROM */ eecd_reg |= IXGB_EECD_CS; IXGB_WRITE_REG(hw, EECD, eecd_reg); + IXGB_WRITE_FLUSH(hw); udelay(50); /* Clock low */ eecd_reg &= ~IXGB_EECD_SK; IXGB_WRITE_REG(hw, EECD, eecd_reg); + IXGB_WRITE_FLUSH(hw); udelay(50); } @@ -239,11 +246,13 @@ ixgb_clock_eeprom(struct ixgb_hw *hw) /* Rising edge of clock */ eecd_reg |= IXGB_EECD_SK; IXGB_WRITE_REG(hw, EECD, eecd_reg); + IXGB_WRITE_FLUSH(hw); udelay(50); /* Falling edge of clock */ eecd_reg &= ~IXGB_EECD_SK; IXGB_WRITE_REG(hw, EECD, eecd_reg); + IXGB_WRITE_FLUSH(hw); udelay(50); } diff --git a/drivers/net/ixgb/ixgb_hw.c b/drivers/net/ixgb/ixgb_hw.c index 6cb2e42ff4c1..3d61a9e4faf7 100644 --- a/drivers/net/ixgb/ixgb_hw.c +++ b/drivers/net/ixgb/ixgb_hw.c @@ -149,6 +149,7 @@ ixgb_adapter_stop(struct ixgb_hw *hw) */ IXGB_WRITE_REG(hw, RCTL, IXGB_READ_REG(hw, RCTL) & ~IXGB_RCTL_RXEN); IXGB_WRITE_REG(hw, TCTL, IXGB_READ_REG(hw, TCTL) & ~IXGB_TCTL_TXEN); + IXGB_WRITE_FLUSH(hw); msleep(IXGB_DELAY_BEFORE_RESET); /* Issue a global reset to the MAC. This will reset the chip's @@ -1220,6 +1221,7 @@ ixgb_optics_reset_bcm(struct ixgb_hw *hw) ctrl &= ~IXGB_CTRL0_SDP2; ctrl |= IXGB_CTRL0_SDP3; IXGB_WRITE_REG(hw, CTRL0, ctrl); + IXGB_WRITE_FLUSH(hw); /* SerDes needs extra delay */ msleep(IXGB_SUN_PHY_RESET_DELAY); diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 3b3dd4df4c5c..34f30ec79c2e 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -213,6 +213,7 @@ static s32 ixgbe_init_phy_ops_82599(struct ixgbe_hw *hw) switch (hw->phy.type) { case ixgbe_phy_tn: phy->ops.check_link = &ixgbe_check_phy_link_tnx; + phy->ops.setup_link = &ixgbe_setup_phy_link_tnx; phy->ops.get_firmware_version = &ixgbe_get_phy_firmware_version_tnx; break; diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index 777051f54e53..fc1375f26fe5 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -2632,6 +2632,7 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index) autoc_reg |= IXGBE_AUTOC_AN_RESTART; autoc_reg |= IXGBE_AUTOC_FLU; IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); + IXGBE_WRITE_FLUSH(hw); usleep_range(10000, 20000); } diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index dc649553a0a6..82d4244c6e10 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -1378,6 +1378,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) /* Disable all the interrupts */ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF); + IXGBE_WRITE_FLUSH(&adapter->hw); usleep_range(10000, 20000); /* Test each interrupt */ @@ -1398,6 +1399,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) ~mask & 0x00007FFF); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, ~mask & 0x00007FFF); + IXGBE_WRITE_FLUSH(&adapter->hw); usleep_range(10000, 20000); if (adapter->test_icr & mask) { @@ -1415,6 +1417,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) adapter->test_icr = 0; IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask); + IXGBE_WRITE_FLUSH(&adapter->hw); usleep_range(10000, 20000); if (!(adapter->test_icr &mask)) { @@ -1435,6 +1438,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) ~mask & 0x00007FFF); IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, ~mask & 0x00007FFF); + IXGBE_WRITE_FLUSH(&adapter->hw); usleep_range(10000, 20000); if (adapter->test_icr) { @@ -1446,6 +1450,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data) /* Disable all the interrupts */ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF); + IXGBE_WRITE_FLUSH(&adapter->hw); usleep_range(10000, 20000); /* Unhook test interrupt handler */ diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 1be617545dc9..e86297b32733 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -184,6 +184,7 @@ static inline void ixgbe_disable_sriov(struct ixgbe_adapter *adapter) vmdctl = IXGBE_READ_REG(hw, IXGBE_VT_CTL); vmdctl &= ~IXGBE_VT_CTL_POOL_MASK; IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, vmdctl); + IXGBE_WRITE_FLUSH(hw); /* take a breather then clean up driver data */ msleep(100); @@ -1005,7 +1006,7 @@ static int __ixgbe_notify_dca(struct device *dev, void *data) struct ixgbe_adapter *adapter = dev_get_drvdata(dev); unsigned long event = *(unsigned long *)data; - if (!(adapter->flags & IXGBE_FLAG_DCA_ENABLED)) + if (!(adapter->flags & IXGBE_FLAG_DCA_CAPABLE)) return 0; switch (event) { diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c index 735f686c3b36..f7ca3511b9fe 100644 --- a/drivers/net/ixgbe/ixgbe_phy.c +++ b/drivers/net/ixgbe/ixgbe_phy.c @@ -1585,6 +1585,7 @@ static s32 ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl) *i2cctl |= IXGBE_I2C_CLK_OUT; IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl); + IXGBE_WRITE_FLUSH(hw); /* SCL rise time (1000ns) */ udelay(IXGBE_I2C_T_RISE); @@ -1605,6 +1606,7 @@ static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl) *i2cctl &= ~IXGBE_I2C_CLK_OUT; IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl); + IXGBE_WRITE_FLUSH(hw); /* SCL fall time (300ns) */ udelay(IXGBE_I2C_T_FALL); @@ -1628,6 +1630,7 @@ static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data) *i2cctl &= ~IXGBE_I2C_DATA_OUT; IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl); + IXGBE_WRITE_FLUSH(hw); /* Data rise/fall (1000ns/300ns) and set-up time (250ns) */ udelay(IXGBE_I2C_T_RISE + IXGBE_I2C_T_FALL + IXGBE_I2C_T_SU_DATA); diff --git a/drivers/net/ixgbe/ixgbe_x540.c b/drivers/net/ixgbe/ixgbe_x540.c index bec30ed91adc..2696c78e9f46 100644 --- a/drivers/net/ixgbe/ixgbe_x540.c +++ b/drivers/net/ixgbe/ixgbe_x540.c @@ -162,6 +162,7 @@ mac_reset_top: ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); ctrl_ext |= IXGBE_CTRL_EXT_PFRSTD; IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); + IXGBE_WRITE_FLUSH(hw); msleep(50); diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 0fcdc25699d8..dc4e305a1087 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -322,6 +322,9 @@ static void macb_tx(struct macb *bp) for (i = 0; i < TX_RING_SIZE; i++) bp->tx_ring[i].ctrl = MACB_BIT(TX_USED); + /* Add wrap bit */ + bp->tx_ring[TX_RING_SIZE - 1].ctrl |= MACB_BIT(TX_WRAP); + /* free transmit buffer in upper layer*/ for (tail = bp->tx_tail; tail != head; tail = NEXT_TX(tail)) { struct ring_info *rp = &bp->tx_skb[tail]; diff --git a/drivers/net/mlx4/en_port.c b/drivers/net/mlx4/en_port.c index 5e7109178061..5ada5b469112 100644 --- a/drivers/net/mlx4/en_port.c +++ b/drivers/net/mlx4/en_port.c @@ -128,7 +128,7 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, memset(context, 0, sizeof *context); context->base_qpn = cpu_to_be32(base_qpn); - context->n_mac = 0x7; + context->n_mac = 0x2; context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT | base_qpn); context->mcast = cpu_to_be32(m_promisc << SET_PORT_MC_PROMISC_SHIFT | diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index c94b3426d355..f0ee35df4dd7 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -1117,6 +1117,8 @@ static int mlx4_init_port_info(struct mlx4_dev *dev, int port) info->port = port; mlx4_init_mac_table(dev, &info->mac_table); mlx4_init_vlan_table(dev, &info->vlan_table); + info->base_qpn = dev->caps.reserved_qps_base[MLX4_QP_REGION_ETH_ADDR] + + (port - 1) * (1 << log_num_mac); sprintf(info->dev_name, "mlx4_port%d", port); info->port_attr.attr.name = info->dev_name; diff --git a/drivers/net/mlx4/port.c b/drivers/net/mlx4/port.c index 1f95afda6841..609e0ec14cee 100644 --- a/drivers/net/mlx4/port.c +++ b/drivers/net/mlx4/port.c @@ -258,9 +258,12 @@ void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, int qpn) if (validate_index(dev, table, index)) goto out; - table->entries[index] = 0; - mlx4_set_port_mac_table(dev, port, table->entries); - --table->total; + /* Check whether this address has reference count */ + if (!(--table->refs[index])) { + table->entries[index] = 0; + mlx4_set_port_mac_table(dev, port, table->entries); + --table->total; + } out: mutex_unlock(&table->mutex); } diff --git a/drivers/net/niu.c b/drivers/net/niu.c index cd6c2317e29e..ed47585a6862 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -9201,7 +9201,7 @@ static int __devinit niu_ldg_init(struct niu *np) first_chan = 0; for (i = 0; i < port; i++) - first_chan += parent->rxchan_per_port[port]; + first_chan += parent->rxchan_per_port[i]; num_chan = parent->rxchan_per_port[port]; for (i = first_chan; i < (first_chan + num_chan); i++) { @@ -9217,7 +9217,7 @@ static int __devinit niu_ldg_init(struct niu *np) first_chan = 0; for (i = 0; i < port; i++) - first_chan += parent->txchan_per_port[port]; + first_chan += parent->txchan_per_port[i]; num_chan = parent->txchan_per_port[port]; for (i = first_chan; i < (first_chan + num_chan); i++) { err = niu_ldg_assign_ldn(np, parent, diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 7d9c650f395e..02339b3352e7 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -239,6 +239,7 @@ static DEFINE_PCI_DEVICE_TABLE(rtl8169_pci_tbl) = { { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), 0, 0, RTL_CFG_1 }, { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), 0, 0, RTL_CFG_0 }, { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), 0, 0, RTL_CFG_0 }, + { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4302), 0, 0, RTL_CFG_0 }, { PCI_DEVICE(PCI_VENDOR_ID_AT, 0xc107), 0, 0, RTL_CFG_0 }, { PCI_DEVICE(0x16ec, 0x0116), 0, 0, RTL_CFG_0 }, { PCI_VENDOR_ID_LINKSYS, 0x1032, @@ -1091,6 +1092,21 @@ rtl_w1w0_eri(void __iomem *ioaddr, int addr, u32 mask, u32 p, u32 m, int type) rtl_eri_write(ioaddr, addr, mask, (val & ~m) | p, type); } +struct exgmac_reg { + u16 addr; + u16 mask; + u32 val; +}; + +static void rtl_write_exgmac_batch(void __iomem *ioaddr, + const struct exgmac_reg *r, int len) +{ + while (len-- > 0) { + rtl_eri_write(ioaddr, r->addr, r->mask, r->val, ERIAR_EXGMAC); + r++; + } +} + static u8 rtl8168d_efuse_read(void __iomem *ioaddr, int reg_addr) { u8 value = 0xff; @@ -3116,6 +3132,18 @@ static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr) RTL_W32(MAC0, low); RTL_R32(MAC0); + if (tp->mac_version == RTL_GIGA_MAC_VER_34) { + const struct exgmac_reg e[] = { + { .addr = 0xe0, ERIAR_MASK_1111, .val = low }, + { .addr = 0xe4, ERIAR_MASK_1111, .val = high }, + { .addr = 0xf0, ERIAR_MASK_1111, .val = low << 16 }, + { .addr = 0xf4, ERIAR_MASK_1111, .val = high << 16 | + low >> 16 }, + }; + + rtl_write_exgmac_batch(ioaddr, e, ARRAY_SIZE(e)); + } + RTL_W8(Cfg9346, Cfg9346_Lock); spin_unlock_irq(&tp->lock); diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 8ad7bfbaa3af..3c0f1312b391 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -1825,6 +1825,16 @@ static int sis190_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) generic_mii_ioctl(&tp->mii_if, if_mii(ifr), cmd, NULL); } +static int sis190_mac_addr(struct net_device *dev, void *p) +{ + int rc; + + rc = eth_mac_addr(dev, p); + if (!rc) + sis190_init_rxfilter(dev); + return rc; +} + static const struct net_device_ops sis190_netdev_ops = { .ndo_open = sis190_open, .ndo_stop = sis190_close, @@ -1833,7 +1843,7 @@ static const struct net_device_ops sis190_netdev_ops = { .ndo_tx_timeout = sis190_tx_timeout, .ndo_set_multicast_list = sis190_set_rx_mode, .ndo_change_mtu = eth_change_mtu, - .ndo_set_mac_address = eth_mac_addr, + .ndo_set_mac_address = sis190_mac_addr, .ndo_validate_addr = eth_validate_addr, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = sis190_netpoll, diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index fd622a66ebbf..a03336e086d5 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -53,7 +53,7 @@ #include <linux/usb/usbnet.h> #include <linux/usb/cdc.h> -#define DRIVER_VERSION "01-June-2011" +#define DRIVER_VERSION "04-Aug-2011" /* CDC NCM subclass 3.2.1 */ #define USB_CDC_NCM_NDP16_LENGTH_MIN 0x10 @@ -163,35 +163,8 @@ cdc_ncm_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) usb_make_path(dev->udev, info->bus_info, sizeof(info->bus_info)); } -static int -cdc_ncm_do_request(struct cdc_ncm_ctx *ctx, struct usb_cdc_notification *req, - void *data, u16 flags, u16 *actlen, u16 timeout) -{ - int err; - - err = usb_control_msg(ctx->udev, (req->bmRequestType & USB_DIR_IN) ? - usb_rcvctrlpipe(ctx->udev, 0) : - usb_sndctrlpipe(ctx->udev, 0), - req->bNotificationType, req->bmRequestType, - req->wValue, - req->wIndex, data, - req->wLength, timeout); - - if (err < 0) { - if (actlen) - *actlen = 0; - return err; - } - - if (actlen) - *actlen = err; - - return 0; -} - static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) { - struct usb_cdc_notification req; u32 val; u8 flags; u8 iface_no; @@ -200,14 +173,14 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber; - req.bmRequestType = USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE; - req.bNotificationType = USB_CDC_GET_NTB_PARAMETERS; - req.wValue = 0; - req.wIndex = cpu_to_le16(iface_no); - req.wLength = cpu_to_le16(sizeof(ctx->ncm_parm)); - - err = cdc_ncm_do_request(ctx, &req, &ctx->ncm_parm, 0, NULL, 1000); - if (err) { + err = usb_control_msg(ctx->udev, + usb_rcvctrlpipe(ctx->udev, 0), + USB_CDC_GET_NTB_PARAMETERS, + USB_TYPE_CLASS | USB_DIR_IN + | USB_RECIP_INTERFACE, + 0, iface_no, &ctx->ncm_parm, + sizeof(ctx->ncm_parm), 10000); + if (err < 0) { pr_debug("failed GET_NTB_PARAMETERS\n"); return 1; } @@ -253,31 +226,26 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) /* inform device about NTB input size changes */ if (ctx->rx_max != le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize)) { - req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT | - USB_RECIP_INTERFACE; - req.bNotificationType = USB_CDC_SET_NTB_INPUT_SIZE; - req.wValue = 0; - req.wIndex = cpu_to_le16(iface_no); if (flags & USB_CDC_NCM_NCAP_NTB_INPUT_SIZE) { struct usb_cdc_ncm_ndp_input_size ndp_in_sz; - - req.wLength = 8; - ndp_in_sz.dwNtbInMaxSize = cpu_to_le32(ctx->rx_max); - ndp_in_sz.wNtbInMaxDatagrams = - cpu_to_le16(CDC_NCM_DPT_DATAGRAMS_MAX); - ndp_in_sz.wReserved = 0; - err = cdc_ncm_do_request(ctx, &req, &ndp_in_sz, 0, NULL, - 1000); + err = usb_control_msg(ctx->udev, + usb_sndctrlpipe(ctx->udev, 0), + USB_CDC_SET_NTB_INPUT_SIZE, + USB_TYPE_CLASS | USB_DIR_OUT + | USB_RECIP_INTERFACE, + 0, iface_no, &ndp_in_sz, 8, 1000); } else { __le32 dwNtbInMaxSize = cpu_to_le32(ctx->rx_max); - - req.wLength = 4; - err = cdc_ncm_do_request(ctx, &req, &dwNtbInMaxSize, 0, - NULL, 1000); + err = usb_control_msg(ctx->udev, + usb_sndctrlpipe(ctx->udev, 0), + USB_CDC_SET_NTB_INPUT_SIZE, + USB_TYPE_CLASS | USB_DIR_OUT + | USB_RECIP_INTERFACE, + 0, iface_no, &dwNtbInMaxSize, 4, 1000); } - if (err) + if (err < 0) pr_debug("Setting NTB Input Size failed\n"); } @@ -332,29 +300,24 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) /* set CRC Mode */ if (flags & USB_CDC_NCM_NCAP_CRC_MODE) { - req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT | - USB_RECIP_INTERFACE; - req.bNotificationType = USB_CDC_SET_CRC_MODE; - req.wValue = cpu_to_le16(USB_CDC_NCM_CRC_NOT_APPENDED); - req.wIndex = cpu_to_le16(iface_no); - req.wLength = 0; - - err = cdc_ncm_do_request(ctx, &req, NULL, 0, NULL, 1000); - if (err) + err = usb_control_msg(ctx->udev, usb_sndctrlpipe(ctx->udev, 0), + USB_CDC_SET_CRC_MODE, + USB_TYPE_CLASS | USB_DIR_OUT + | USB_RECIP_INTERFACE, + USB_CDC_NCM_CRC_NOT_APPENDED, + iface_no, NULL, 0, 1000); + if (err < 0) pr_debug("Setting CRC mode off failed\n"); } /* set NTB format, if both formats are supported */ if (ntb_fmt_supported & USB_CDC_NCM_NTH32_SIGN) { - req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT | - USB_RECIP_INTERFACE; - req.bNotificationType = USB_CDC_SET_NTB_FORMAT; - req.wValue = cpu_to_le16(USB_CDC_NCM_NTB16_FORMAT); - req.wIndex = cpu_to_le16(iface_no); - req.wLength = 0; - - err = cdc_ncm_do_request(ctx, &req, NULL, 0, NULL, 1000); - if (err) + err = usb_control_msg(ctx->udev, usb_sndctrlpipe(ctx->udev, 0), + USB_CDC_SET_NTB_FORMAT, USB_TYPE_CLASS + | USB_DIR_OUT | USB_RECIP_INTERFACE, + USB_CDC_NCM_NTB16_FORMAT, + iface_no, NULL, 0, 1000); + if (err < 0) pr_debug("Setting NTB format to 16-bit failed\n"); } @@ -364,17 +327,13 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) if (flags & USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE) { __le16 max_datagram_size; u16 eth_max_sz = le16_to_cpu(ctx->ether_desc->wMaxSegmentSize); - - req.bmRequestType = USB_TYPE_CLASS | USB_DIR_IN | - USB_RECIP_INTERFACE; - req.bNotificationType = USB_CDC_GET_MAX_DATAGRAM_SIZE; - req.wValue = 0; - req.wIndex = cpu_to_le16(iface_no); - req.wLength = cpu_to_le16(2); - - err = cdc_ncm_do_request(ctx, &req, &max_datagram_size, 0, NULL, - 1000); - if (err) { + err = usb_control_msg(ctx->udev, usb_rcvctrlpipe(ctx->udev, 0), + USB_CDC_GET_MAX_DATAGRAM_SIZE, + USB_TYPE_CLASS | USB_DIR_IN + | USB_RECIP_INTERFACE, + 0, iface_no, &max_datagram_size, + 2, 1000); + if (err < 0) { pr_debug("GET_MAX_DATAGRAM_SIZE failed, use size=%u\n", CDC_NCM_MIN_DATAGRAM_SIZE); } else { @@ -395,17 +354,15 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) CDC_NCM_MIN_DATAGRAM_SIZE; /* if value changed, update device */ - req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT | - USB_RECIP_INTERFACE; - req.bNotificationType = USB_CDC_SET_MAX_DATAGRAM_SIZE; - req.wValue = 0; - req.wIndex = cpu_to_le16(iface_no); - req.wLength = 2; - max_datagram_size = cpu_to_le16(ctx->max_datagram_size); - - err = cdc_ncm_do_request(ctx, &req, &max_datagram_size, - 0, NULL, 1000); - if (err) + err = usb_control_msg(ctx->udev, + usb_sndctrlpipe(ctx->udev, 0), + USB_CDC_SET_MAX_DATAGRAM_SIZE, + USB_TYPE_CLASS | USB_DIR_OUT + | USB_RECIP_INTERFACE, + 0, + iface_no, &max_datagram_size, + 2, 1000); + if (err < 0) pr_debug("SET_MAX_DATAGRAM_SIZE failed\n"); } @@ -671,7 +628,7 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb) u32 rem; u32 offset; u32 last_offset; - u16 n = 0; + u16 n = 0, index; u8 ready2send = 0; /* if there is a remaining skb, it gets priority */ @@ -859,8 +816,8 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb) cpu_to_le16(sizeof(ctx->tx_ncm.nth16)); ctx->tx_ncm.nth16.wSequence = cpu_to_le16(ctx->tx_seq); ctx->tx_ncm.nth16.wBlockLength = cpu_to_le16(last_offset); - ctx->tx_ncm.nth16.wNdpIndex = ALIGN(sizeof(struct usb_cdc_ncm_nth16), - ctx->tx_ndp_modulus); + index = ALIGN(sizeof(struct usb_cdc_ncm_nth16), ctx->tx_ndp_modulus); + ctx->tx_ncm.nth16.wNdpIndex = cpu_to_le16(index); memcpy(skb_out->data, &(ctx->tx_ncm.nth16), sizeof(ctx->tx_ncm.nth16)); ctx->tx_seq++; @@ -873,12 +830,11 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb) ctx->tx_ncm.ndp16.wLength = cpu_to_le16(rem); ctx->tx_ncm.ndp16.wNextNdpIndex = 0; /* reserved */ - memcpy(((u8 *)skb_out->data) + ctx->tx_ncm.nth16.wNdpIndex, + memcpy(((u8 *)skb_out->data) + index, &(ctx->tx_ncm.ndp16), sizeof(ctx->tx_ncm.ndp16)); - memcpy(((u8 *)skb_out->data) + ctx->tx_ncm.nth16.wNdpIndex + - sizeof(ctx->tx_ncm.ndp16), + memcpy(((u8 *)skb_out->data) + index + sizeof(ctx->tx_ncm.ndp16), &(ctx->tx_ncm.dpe16), (ctx->tx_curr_frame_num + 1) * sizeof(struct usb_cdc_ncm_dpe16)); diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c index 9ff7c30573b8..44d9d8d56490 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c @@ -309,11 +309,7 @@ static void ar9002_hw_configpcipowersave(struct ath_hw *ah, u8 i; u32 val; - if (ah->is_pciexpress != true) - return; - - /* Do not touch SerDes registers */ - if (ah->config.pcie_powersave_enable == 2) + if (ah->is_pciexpress != true || ah->aspm_enabled != true) return; /* Nothing to do on restore for 11N */ diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 8efdec247c02..ad2bb2bf4e8a 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -519,11 +519,7 @@ static void ar9003_hw_configpcipowersave(struct ath_hw *ah, int restore, int power_off) { - if (ah->is_pciexpress != true) - return; - - /* Do not touch SerDes registers */ - if (ah->config.pcie_powersave_enable == 2) + if (ah->is_pciexpress != true || ah->aspm_enabled != true) return; /* Nothing to do on restore for 11N */ diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 8006ce0c7357..8dcefe74f4c3 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -318,6 +318,14 @@ static void ath9k_hw_disablepcie(struct ath_hw *ah) REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); } +static void ath9k_hw_aspm_init(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + + if (common->bus_ops->aspm_init) + common->bus_ops->aspm_init(common); +} + /* This should work for all families including legacy */ static bool ath9k_hw_chip_test(struct ath_hw *ah) { @@ -378,7 +386,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah) ah->config.additional_swba_backoff = 0; ah->config.ack_6mb = 0x0; ah->config.cwm_ignore_extcca = 0; - ah->config.pcie_powersave_enable = 0; ah->config.pcie_clock_req = 0; ah->config.pcie_waen = 0; ah->config.analog_shiftreg = 1; @@ -598,7 +605,7 @@ static int __ath9k_hw_init(struct ath_hw *ah) if (ah->is_pciexpress) - ath9k_hw_configpcipowersave(ah, 0, 0); + ath9k_hw_aspm_init(ah); else ath9k_hw_disablepcie(ah); diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 6acd0f975ae1..c79889036ec4 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -219,7 +219,6 @@ struct ath9k_ops_config { int additional_swba_backoff; int ack_6mb; u32 cwm_ignore_extcca; - u8 pcie_powersave_enable; bool pcieSerDesWrite; u8 pcie_clock_req; u32 pcie_waen; @@ -673,6 +672,7 @@ struct ath_hw { bool sw_mgmt_crypto; bool is_pciexpress; + bool aspm_enabled; bool is_monitoring; bool need_an_top2_fixup; u16 tx_trig_level; @@ -874,6 +874,7 @@ struct ath_bus_ops { bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data); void (*bt_coex_prep)(struct ath_common *common); void (*extn_synch_en)(struct ath_common *common); + void (*aspm_init)(struct ath_common *common); }; static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index ac5107172f94..aa0ff7e2c922 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -670,8 +670,10 @@ static void ath9k_init_band_txpower(struct ath_softc *sc, int band) static void ath9k_init_txpower_limits(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath9k_channel *curchan = ah->curchan; + ah->txchainmask = common->tx_chainmask; if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) ath9k_init_band_txpower(sc, IEEE80211_BAND_2GHZ); if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 3bad0b2cf9a3..be4ea1329813 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -16,6 +16,7 @@ #include <linux/nl80211.h> #include <linux/pci.h> +#include <linux/pci-aspm.h> #include <linux/ath9k_platform.h> #include "ath9k.h" @@ -115,12 +116,38 @@ static void ath_pci_extn_synch_enable(struct ath_common *common) pci_write_config_byte(pdev, sc->sc_ah->caps.pcie_lcr_offset, lnkctl); } +static void ath_pci_aspm_init(struct ath_common *common) +{ + struct ath_softc *sc = (struct ath_softc *) common->priv; + struct ath_hw *ah = sc->sc_ah; + struct pci_dev *pdev = to_pci_dev(sc->dev); + struct pci_dev *parent; + int pos; + u8 aspm; + + if (!pci_is_pcie(pdev)) + return; + + parent = pdev->bus->self; + if (WARN_ON(!parent)) + return; + + pos = pci_pcie_cap(parent); + pci_read_config_byte(parent, pos + PCI_EXP_LNKCTL, &aspm); + if (aspm & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1)) { + ah->aspm_enabled = true; + /* Initialize PCIe PM and SERDES registers. */ + ath9k_hw_configpcipowersave(ah, 0, 0); + } +} + static const struct ath_bus_ops ath_pci_bus_ops = { .ath_bus_type = ATH_PCI, .read_cachesize = ath_pci_read_cachesize, .eeprom_read = ath_pci_eeprom_read, .bt_coex_prep = ath_pci_bt_coex_prep, .extn_synch_en = ath_pci_extn_synch_enable, + .aspm_init = ath_pci_aspm_init, }; static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/net/wireless/iwlegacy/iwl-3945.c b/drivers/net/wireless/iwlegacy/iwl-3945.c index dab67a12d73b..73fe3cdf796b 100644 --- a/drivers/net/wireless/iwlegacy/iwl-3945.c +++ b/drivers/net/wireless/iwlegacy/iwl-3945.c @@ -1746,7 +1746,11 @@ int iwl3945_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) } memcpy(active_rxon, staging_rxon, sizeof(*active_rxon)); - + /* + * We do not commit tx power settings while channel changing, + * do it now if tx power changed. + */ + iwl_legacy_set_tx_power(priv, priv->tx_power_next, false); return 0; } diff --git a/drivers/net/wireless/iwlegacy/iwl-4965.c b/drivers/net/wireless/iwlegacy/iwl-4965.c index bd4b000733f7..ecdc6e557428 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965.c +++ b/drivers/net/wireless/iwlegacy/iwl-4965.c @@ -1235,7 +1235,12 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *c memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon)); iwl_legacy_print_rx_config_cmd(priv, ctx); - goto set_tx_power; + /* + * We do not commit tx power settings while channel changing, + * do it now if tx power changed. + */ + iwl_legacy_set_tx_power(priv, priv->tx_power_next, false); + return 0; } /* If we are currently associated and the new config requires @@ -1315,7 +1320,6 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *c iwl4965_init_sensitivity(priv); -set_tx_power: /* If we issue a new RXON command which required a tune then we must * send a new TXPOWER command or we won't be able to Tx any frames */ ret = iwl_legacy_set_tx_power(priv, priv->tx_power_next, true); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 3eeb12ebe6e9..c95cefd529dc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -365,6 +365,7 @@ static struct iwl_base_params iwl5000_base_params = { .chain_noise_scale = 1000, .wd_timeout = IWL_LONG_WD_TIMEOUT, .max_event_log_size = 512, + .no_idle_support = true, }; static struct iwl_ht_params iwl5000_ht_params = { .ht_greenfield_support = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 3e6bb734dcb7..02817a438550 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -135,6 +135,7 @@ struct iwl_mod_params { * @temperature_kelvin: temperature report by uCode in kelvin * @max_event_log_size: size of event log buffer size for ucode event logging * @shadow_reg_enable: HW shadhow register bit + * @no_idle_support: do not support idle mode */ struct iwl_base_params { int eeprom_size; @@ -156,6 +157,7 @@ struct iwl_base_params { bool temperature_kelvin; u32 max_event_log_size; const bool shadow_reg_enable; + const bool no_idle_support; }; /* * @advanced_bt_coexist: support advanced bt coexist diff --git a/drivers/net/wireless/iwlwifi/iwl-pci.c b/drivers/net/wireless/iwlwifi/iwl-pci.c index fb7e436b40c7..69d4ec467dca 100644 --- a/drivers/net/wireless/iwlwifi/iwl-pci.c +++ b/drivers/net/wireless/iwlwifi/iwl-pci.c @@ -134,6 +134,7 @@ static void iwl_pci_apm_config(struct iwl_bus *bus) static void iwl_pci_set_drv_data(struct iwl_bus *bus, void *drv_data) { bus->drv_data = drv_data; + pci_set_drvdata(IWL_BUS_GET_PCI_DEV(bus), drv_data); } static void iwl_pci_get_hw_id(struct iwl_bus *bus, char buf[], @@ -454,8 +455,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_write_config_word(pdev, PCI_COMMAND, pci_cmd); } - pci_set_drvdata(pdev, bus); - bus->dev = &pdev->dev; bus->irq = pdev->irq; bus->ops = &pci_ops; @@ -494,11 +493,12 @@ static void iwl_pci_down(struct iwl_bus *bus) static void __devexit iwl_pci_remove(struct pci_dev *pdev) { - struct iwl_bus *bus = pci_get_drvdata(pdev); + struct iwl_priv *priv = pci_get_drvdata(pdev); + void *bus_specific = priv->bus->bus_specific; - iwl_remove(bus->drv_data); + iwl_remove(priv); - iwl_pci_down(bus); + iwl_pci_down(bus_specific); } #ifdef CONFIG_PM @@ -506,20 +506,20 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) static int iwl_pci_suspend(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); - struct iwl_bus *bus = pci_get_drvdata(pdev); + struct iwl_priv *priv = pci_get_drvdata(pdev); /* Before you put code here, think about WoWLAN. You cannot check here * whether WoWLAN is enabled or not, and your code will run even if * WoWLAN is enabled - don't kill the NIC, someone may need it in Sx. */ - return iwl_suspend(bus->drv_data); + return iwl_suspend(priv); } static int iwl_pci_resume(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); - struct iwl_bus *bus = pci_get_drvdata(pdev); + struct iwl_priv *priv = pci_get_drvdata(pdev); /* Before you put code here, think about WoWLAN. You cannot check here * whether WoWLAN is enabled or not, and your code will run even if @@ -532,7 +532,7 @@ static int iwl_pci_resume(struct device *device) */ pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); - return iwl_resume(bus->drv_data); + return iwl_resume(priv); } static SIMPLE_DEV_PM_OPS(iwl_dev_pm_ops, iwl_pci_suspend, iwl_pci_resume); diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 3ec619c6881c..cd64df05f9ed 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -349,7 +349,8 @@ static void iwl_power_build_cmd(struct iwl_priv *priv, if (priv->wowlan) iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, dtimper); - else if (priv->hw->conf.flags & IEEE80211_CONF_IDLE) + else if (!priv->cfg->base_params->no_idle_support && + priv->hw->conf.flags & IEEE80211_CONF_IDLE) iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20); else if (iwl_tt_is_low_power_state(priv)) { /* in thermal throttling low power state */ diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 84ab7d1acb6a..ef67f6786a84 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -703,8 +703,7 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc) /* * Add space for the TXWI in front of the skb. */ - skb_push(entry->skb, TXWI_DESC_SIZE); - memset(entry->skb, 0, TXWI_DESC_SIZE); + memset(skb_push(entry->skb, TXWI_DESC_SIZE), 0, TXWI_DESC_SIZE); /* * Register descriptor details in skb frame descriptor. diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 15cdc7e57fc4..4cdf247a870d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -355,7 +355,8 @@ static inline enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf * return CIPHER_NONE; } -static inline void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry, +static inline void rt2x00crypto_create_tx_descriptor(struct rt2x00_dev *rt2x00dev, + struct sk_buff *skb, struct txentry_desc *txdesc) { } diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 8efab3983528..4ccf23805973 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -113,7 +113,7 @@ void rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * due to possible race conditions in mac80211. */ if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) - goto exit_fail; + goto exit_free_skb; /* * Use the ATIM queue if appropriate and present. @@ -127,7 +127,7 @@ void rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) ERROR(rt2x00dev, "Attempt to send packet over invalid queue %d.\n" "Please file bug report to %s.\n", qid, DRV_PROJECT); - goto exit_fail; + goto exit_free_skb; } /* @@ -159,6 +159,7 @@ void rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) exit_fail: rt2x00queue_pause_queue(queue); + exit_free_skb: dev_kfree_skb_any(skb); } EXPORT_SYMBOL_GPL(rt2x00mac_tx); diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 5efd57833489..56f12358389d 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -1696,15 +1696,17 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, pcipriv->ndis_adapter.devnumber = PCI_SLOT(pdev->devfn); pcipriv->ndis_adapter.funcnumber = PCI_FUNC(pdev->devfn); - /*find bridge info */ - pcipriv->ndis_adapter.pcibridge_vendorid = bridge_pdev->vendor; - for (tmp = 0; tmp < PCI_BRIDGE_VENDOR_MAX; tmp++) { - if (bridge_pdev->vendor == pcibridge_vendors[tmp]) { - pcipriv->ndis_adapter.pcibridge_vendor = tmp; - RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, - ("Pci Bridge Vendor is found index: %d\n", - tmp)); - break; + if (bridge_pdev) { + /*find bridge info if available */ + pcipriv->ndis_adapter.pcibridge_vendorid = bridge_pdev->vendor; + for (tmp = 0; tmp < PCI_BRIDGE_VENDOR_MAX; tmp++) { + if (bridge_pdev->vendor == pcibridge_vendors[tmp]) { + pcipriv->ndis_adapter.pcibridge_vendor = tmp; + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + ("Pci Bridge Vendor is found index:" + " %d\n", tmp)); + break; + } } } diff --git a/drivers/of/base.c b/drivers/of/base.c index fb28b5af733b..3ff22e32b602 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -17,39 +17,14 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ -#include <linux/ctype.h> #include <linux/module.h> #include <linux/of.h> #include <linux/spinlock.h> #include <linux/slab.h> #include <linux/proc_fs.h> -/** - * struct alias_prop - Alias property in 'aliases' node - * @link: List node to link the structure in aliases_lookup list - * @alias: Alias property name - * @np: Pointer to device_node that the alias stands for - * @id: Index value from end of alias name - * @stem: Alias string without the index - * - * The structure represents one alias property of 'aliases' node as - * an entry in aliases_lookup list. - */ -struct alias_prop { - struct list_head link; - const char *alias; - struct device_node *np; - int id; - char stem[0]; -}; - -static LIST_HEAD(aliases_lookup); - struct device_node *allnodes; struct device_node *of_chosen; -struct device_node *of_aliases; - -static DEFINE_MUTEX(of_aliases_mutex); /* use when traversing tree through the allnext, child, sibling, * or parent members of struct device_node. @@ -1013,108 +988,3 @@ out_unlock: } #endif /* defined(CONFIG_OF_DYNAMIC) */ -static void of_alias_add(struct alias_prop *ap, struct device_node *np, - int id, const char *stem, int stem_len) -{ - ap->id = id; - ap->np = np; - strncpy(ap->stem, stem, stem_len); - ap->stem[stem_len] = 0; - list_add_tail(&ap->link, &aliases_lookup); - pr_debug("adding DT alias:%s: stem=%s id=%i node=%s\n", - ap->alias, ap->stem, ap->id, np ? np->full_name : NULL); -} - -/** - * of_alias_scan() - Scan all properties of 'aliases' node - * - * The function scans all the properties of 'aliases' node and populate - * the global lookup table with the properties. It returns the - * number of alias_prop found, or error code in error case. - */ -__init void of_alias_scan(void) -{ - struct property *pp; - - if (!of_aliases) - return; - - for_each_property(pp, of_aliases->properties) { - const char *start = pp->name; - const char *end = start + strlen(start); - struct device_node *np; - struct alias_prop *ap; - int id, len; - - /* Skip those we do not want to proceed */ - if (!strcmp(pp->name, "name") || - !strcmp(pp->name, "phandle") || - !strcmp(pp->name, "linux,phandle")) - continue; - - np = of_find_node_by_path(pp->value); - if (!np) - continue; - - /* walk alias backwards to extract the id and 'stem' string */ - while (isdigit(*(end-1)) && end > start) - end--; - len = end - start; - id = strlen(end) ? simple_strtoul(end, NULL, 10) : -1; - - /* Allocate an alias_prop with enough space for the stem */ - ap = early_init_dt_alloc_memory_arch(sizeof(*ap) + len + 1, 4); - if (!ap) - continue; - ap->alias = start; - of_alias_add(ap, np, id, start, len); - } -} - -/** - * of_alias_get_id() - Get alias id for the given device_node - * @np: Pointer to the given device_node - * @stem: Alias stem of the given device_node - * - * The function travels the lookup table to get alias id for the given - * device_node and alias stem. It returns the alias id if find it. - * If not, dynamically creates one in the lookup table and returns it, - * or returns error code if fail to create. - */ -int of_alias_get_id(struct device_node *np, const char *stem) -{ - struct alias_prop *app; - int id = 0; - bool found = false; - - mutex_lock(&of_aliases_mutex); - list_for_each_entry(app, &aliases_lookup, link) { - if (strcmp(app->stem, stem) != 0) - continue; - - if (np == app->np) { - found = true; - id = app->id; - break; - } - - if (id <= app->id) - id = app->id + 1; - } - - /* If an id is not found, then allocate a new one */ - if (!found) { - app = kzalloc(sizeof(*app) + strlen(stem) + 1, 4); - if (!app) { - id = -ENODEV; - goto out; - } - of_alias_add(app, np, id, stem, strlen(stem)); - } - - out: - mutex_unlock(&of_aliases_mutex); - - return id; -} -EXPORT_SYMBOL_GPL(of_alias_get_id); diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 13d6d3a96b31..65200af29c52 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -707,12 +707,10 @@ void __init unflatten_device_tree(void) __unflatten_device_tree(initial_boot_params, &allnodes, early_init_dt_alloc_memory_arch); - /* Get pointer to "/chosen" and "/aliasas" nodes for use everywhere */ + /* Get pointer to OF "/chosen" node for use everywhere */ of_chosen = of_find_node_by_path("/chosen"); if (of_chosen == NULL) of_chosen = of_find_node_by_path("/chosen@0"); - of_aliases = of_find_node_by_path("/aliases"); - of_alias_scan(); } #endif /* CONFIG_OF_EARLY_FLATTREE */ diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 45e0191c35dd..1e88d4785321 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -769,4 +769,12 @@ config INTEL_OAKTRAIL enable/disable the Camera, WiFi, BT etc. devices. If in doubt, say Y here; it will only load on supported platforms. +config SAMSUNG_Q10 + tristate "Samsung Q10 Extras" + depends on SERIO_I8042 + select BACKLIGHT_CLASS_DEVICE + ---help--- + This driver provides support for backlight control on Samsung Q10 + and related laptops, including Dell Latitude X200. + endif # X86_PLATFORM_DEVICES diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index afc1f832aa67..293a320d9faa 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -44,3 +44,4 @@ obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o obj-$(CONFIG_MXM_WMI) += mxm-wmi.o obj-$(CONFIG_INTEL_MID_POWER_BUTTON) += intel_mid_powerbtn.o obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o +obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index e1c4938b301b..af2bb20cb2fb 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -99,6 +99,7 @@ enum acer_wmi_event_ids { static const struct key_entry acer_wmi_keymap[] = { {KE_KEY, 0x01, {KEY_WLAN} }, /* WiFi */ {KE_KEY, 0x03, {KEY_WLAN} }, /* WiFi */ + {KE_KEY, 0x04, {KEY_WLAN} }, /* WiFi */ {KE_KEY, 0x12, {KEY_BLUETOOTH} }, /* BT */ {KE_KEY, 0x21, {KEY_PROG1} }, /* Backup */ {KE_KEY, 0x22, {KEY_PROG2} }, /* Arcade */ @@ -304,6 +305,10 @@ static struct quirk_entry quirk_fujitsu_amilo_li_1718 = { .wireless = 2, }; +static struct quirk_entry quirk_lenovo_ideapad_s205 = { + .wireless = 3, +}; + /* The Aspire One has a dummy ACPI-WMI interface - disable it */ static struct dmi_system_id __devinitdata acer_blacklist[] = { { @@ -450,6 +455,15 @@ static struct dmi_system_id acer_quirks[] = { }, .driver_data = &quirk_medion_md_98300, }, + { + .callback = dmi_matched, + .ident = "Lenovo Ideapad S205", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "10382LG"), + }, + .driver_data = &quirk_lenovo_ideapad_s205, + }, {} }; @@ -542,6 +556,12 @@ struct wmi_interface *iface) return AE_ERROR; *value = result & 0x1; return AE_OK; + case 3: + err = ec_read(0x78, &result); + if (err) + return AE_ERROR; + *value = result & 0x1; + return AE_OK; default: err = ec_read(0xA, &result); if (err) @@ -1266,8 +1286,13 @@ static void acer_rfkill_update(struct work_struct *ignored) acpi_status status; status = get_u32(&state, ACER_CAP_WIRELESS); - if (ACPI_SUCCESS(status)) - rfkill_set_sw_state(wireless_rfkill, !state); + if (ACPI_SUCCESS(status)) { + if (quirks->wireless == 3) { + rfkill_set_hw_state(wireless_rfkill, !state); + } else { + rfkill_set_sw_state(wireless_rfkill, !state); + } + } if (has_cap(ACER_CAP_BLUETOOTH)) { status = get_u32(&state, ACER_CAP_BLUETOOTH); @@ -1400,6 +1425,9 @@ static ssize_t show_bool_threeg(struct device *dev, { u32 result; \ acpi_status status; + + pr_info("This threeg sysfs will be removed in 2012" + " - used by: %s\n", current->comm); if (wmi_has_guid(WMID_GUID3)) status = wmid3_get_device_status(&result, ACER_WMID3_GDS_THREEG); @@ -1415,8 +1443,10 @@ static ssize_t set_bool_threeg(struct device *dev, { u32 tmp = simple_strtoul(buf, NULL, 10); acpi_status status = set_u32(tmp, ACER_CAP_THREEG); - if (ACPI_FAILURE(status)) - return -EINVAL; + pr_info("This threeg sysfs will be removed in 2012" + " - used by: %s\n", current->comm); + if (ACPI_FAILURE(status)) + return -EINVAL; return count; } static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg, @@ -1425,6 +1455,8 @@ static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg, static ssize_t show_interface(struct device *dev, struct device_attribute *attr, char *buf) { + pr_info("This interface sysfs will be removed in 2012" + " - used by: %s\n", current->comm); switch (interface->type) { case ACER_AMW0: return sprintf(buf, "AMW0\n"); diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c index fca3489218b7..760c6d7624fe 100644 --- a/drivers/platform/x86/acerhdf.c +++ b/drivers/platform/x86/acerhdf.c @@ -182,6 +182,7 @@ static const struct bios_settings_t bios_tbl[] = { {"Acer", "Aspire 1810T", "v1.3308", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1810TZ", "v1.3310", 0x55, 0x58, {0x9e, 0x00} }, {"Acer", "Aspire 1810T", "v1.3310", 0x55, 0x58, {0x9e, 0x00} }, + {"Acer", "Aspire 1810TZ", "v1.3314", 0x55, 0x58, {0x9e, 0x00} }, /* Acer 531 */ {"Acer", "AO531h", "v0.3201", 0x55, 0x58, {0x20, 0x00} }, /* Gateway */ @@ -703,15 +704,15 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Peter Feuerer"); MODULE_DESCRIPTION("Aspire One temperature and fan driver"); MODULE_ALIAS("dmi:*:*Acer*:pnAOA*:"); -MODULE_ALIAS("dmi:*:*Acer*:pnAspire 1410*:"); -MODULE_ALIAS("dmi:*:*Acer*:pnAspire 1810*:"); +MODULE_ALIAS("dmi:*:*Acer*:pnAspire*1410*:"); +MODULE_ALIAS("dmi:*:*Acer*:pnAspire*1810*:"); MODULE_ALIAS("dmi:*:*Acer*:pnAO531*:"); MODULE_ALIAS("dmi:*:*Gateway*:pnAOA*:"); MODULE_ALIAS("dmi:*:*Gateway*:pnLT31*:"); -MODULE_ALIAS("dmi:*:*Packard Bell*:pnAOA*:"); -MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOA*:"); -MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOTMU*:"); -MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOTMA*:"); +MODULE_ALIAS("dmi:*:*Packard*Bell*:pnAOA*:"); +MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOA*:"); +MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOTMU*:"); +MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOTMA*:"); module_init(acerhdf_init); module_exit(acerhdf_exit); diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index d65df92e2acc..fa6d7ec68b26 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -70,11 +70,10 @@ MODULE_LICENSE("GPL"); * WAPF defines the behavior of the Fn+Fx wlan key * The significance of values is yet to be found, but * most of the time: - * 0x0 will do nothing - * 0x1 will allow to control the device with Fn+Fx key. - * 0x4 will send an ACPI event (0x88) while pressing the Fn+Fx key - * 0x5 like 0x1 or 0x4 - * So, if something doesn't work as you want, just try other values =) + * Bit | Bluetooth | WLAN + * 0 | Hardware | Hardware + * 1 | Hardware | Software + * 4 | Software | Software */ static uint wapf = 1; module_param(wapf, uint, 0444); diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 0580d99b0798..b0859d4183e8 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -38,6 +38,24 @@ MODULE_LICENSE("GPL"); MODULE_ALIAS("wmi:"ASUS_NB_WMI_EVENT_GUID); +/* + * WAPF defines the behavior of the Fn+Fx wlan key + * The significance of values is yet to be found, but + * most of the time: + * Bit | Bluetooth | WLAN + * 0 | Hardware | Hardware + * 1 | Hardware | Software + * 4 | Software | Software + */ +static uint wapf; +module_param(wapf, uint, 0444); +MODULE_PARM_DESC(wapf, "WAPF value"); + +static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver) +{ + driver->wapf = wapf; +} + static const struct key_entry asus_nb_wmi_keymap[] = { { KE_KEY, 0x30, { KEY_VOLUMEUP } }, { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, @@ -53,16 +71,16 @@ static const struct key_entry asus_nb_wmi_keymap[] = { { KE_KEY, 0x51, { KEY_WWW } }, { KE_KEY, 0x55, { KEY_CALC } }, { KE_KEY, 0x5C, { KEY_F15 } }, /* Power Gear key */ - { KE_KEY, 0x5D, { KEY_WLAN } }, - { KE_KEY, 0x5E, { KEY_WLAN } }, - { KE_KEY, 0x5F, { KEY_WLAN } }, + { KE_KEY, 0x5D, { KEY_WLAN } }, /* Wireless console Toggle */ + { KE_KEY, 0x5E, { KEY_WLAN } }, /* Wireless console Enable */ + { KE_KEY, 0x5F, { KEY_WLAN } }, /* Wireless console Disable */ { KE_KEY, 0x60, { KEY_SWITCHVIDEOMODE } }, { KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } }, { KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } }, { KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } }, { KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } }, - { KE_KEY, 0x7E, { KEY_BLUETOOTH } }, { KE_KEY, 0x7D, { KEY_BLUETOOTH } }, + { KE_KEY, 0x7E, { KEY_BLUETOOTH } }, { KE_KEY, 0x82, { KEY_CAMERA } }, { KE_KEY, 0x88, { KEY_RFKILL } }, { KE_KEY, 0x8A, { KEY_PROG1 } }, @@ -81,6 +99,7 @@ static struct asus_wmi_driver asus_nb_wmi_driver = { .keymap = asus_nb_wmi_keymap, .input_name = "Asus WMI hotkeys", .input_phys = ASUS_NB_WMI_FILE "/input0", + .quirks = asus_nb_wmi_quirks, }; diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 65b66aa44c78..95cba9ebf6c0 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -44,6 +44,7 @@ #include <linux/debugfs.h> #include <linux/seq_file.h> #include <linux/platform_device.h> +#include <linux/thermal.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> @@ -66,6 +67,8 @@ MODULE_LICENSE("GPL"); #define NOTIFY_BRNUP_MAX 0x1f #define NOTIFY_BRNDOWN_MIN 0x20 #define NOTIFY_BRNDOWN_MAX 0x2e +#define NOTIFY_KBD_BRTUP 0xc4 +#define NOTIFY_KBD_BRTDWN 0xc5 /* WMI Methods */ #define ASUS_WMI_METHODID_SPEC 0x43455053 /* BIOS SPECification */ @@ -93,6 +96,7 @@ MODULE_LICENSE("GPL"); /* Wireless */ #define ASUS_WMI_DEVID_HW_SWITCH 0x00010001 #define ASUS_WMI_DEVID_WIRELESS_LED 0x00010002 +#define ASUS_WMI_DEVID_CWAP 0x00010003 #define ASUS_WMI_DEVID_WLAN 0x00010011 #define ASUS_WMI_DEVID_BLUETOOTH 0x00010013 #define ASUS_WMI_DEVID_GPS 0x00010015 @@ -102,6 +106,12 @@ MODULE_LICENSE("GPL"); /* Leds */ /* 0x000200XX and 0x000400XX */ +#define ASUS_WMI_DEVID_LED1 0x00020011 +#define ASUS_WMI_DEVID_LED2 0x00020012 +#define ASUS_WMI_DEVID_LED3 0x00020013 +#define ASUS_WMI_DEVID_LED4 0x00020014 +#define ASUS_WMI_DEVID_LED5 0x00020015 +#define ASUS_WMI_DEVID_LED6 0x00020016 /* Backlight and Brightness */ #define ASUS_WMI_DEVID_BACKLIGHT 0x00050011 @@ -174,13 +184,18 @@ struct asus_wmi { struct led_classdev tpd_led; int tpd_led_wk; + struct led_classdev kbd_led; + int kbd_led_wk; struct workqueue_struct *led_workqueue; struct work_struct tpd_led_work; + struct work_struct kbd_led_work; struct asus_rfkill wlan; struct asus_rfkill bluetooth; struct asus_rfkill wimax; struct asus_rfkill wwan3g; + struct asus_rfkill gps; + struct asus_rfkill uwb; struct hotplug_slot *hotplug_slot; struct mutex hotplug_lock; @@ -205,6 +220,7 @@ static int asus_wmi_input_init(struct asus_wmi *asus) asus->inputdev->phys = asus->driver->input_phys; asus->inputdev->id.bustype = BUS_HOST; asus->inputdev->dev.parent = &asus->platform_device->dev; + set_bit(EV_REP, asus->inputdev->evbit); err = sparse_keymap_setup(asus->inputdev, asus->driver->keymap, NULL); if (err) @@ -359,30 +375,80 @@ static enum led_brightness tpd_led_get(struct led_classdev *led_cdev) return read_tpd_led_state(asus); } -static int asus_wmi_led_init(struct asus_wmi *asus) +static void kbd_led_update(struct work_struct *work) { - int rv; + int ctrl_param = 0; + struct asus_wmi *asus; - if (read_tpd_led_state(asus) < 0) - return 0; + asus = container_of(work, struct asus_wmi, kbd_led_work); - asus->led_workqueue = create_singlethread_workqueue("led_workqueue"); - if (!asus->led_workqueue) - return -ENOMEM; - INIT_WORK(&asus->tpd_led_work, tpd_led_update); + /* + * bits 0-2: level + * bit 7: light on/off + */ + if (asus->kbd_led_wk > 0) + ctrl_param = 0x80 | (asus->kbd_led_wk & 0x7F); - asus->tpd_led.name = "asus::touchpad"; - asus->tpd_led.brightness_set = tpd_led_set; - asus->tpd_led.brightness_get = tpd_led_get; - asus->tpd_led.max_brightness = 1; + asus_wmi_set_devstate(ASUS_WMI_DEVID_KBD_BACKLIGHT, ctrl_param, NULL); +} - rv = led_classdev_register(&asus->platform_device->dev, &asus->tpd_led); - if (rv) { - destroy_workqueue(asus->led_workqueue); - return rv; +static int kbd_led_read(struct asus_wmi *asus, int *level, int *env) +{ + int retval; + + /* + * bits 0-2: level + * bit 7: light on/off + * bit 8-10: environment (0: dark, 1: normal, 2: light) + * bit 17: status unknown + */ + retval = asus_wmi_get_devstate_bits(asus, ASUS_WMI_DEVID_KBD_BACKLIGHT, + 0xFFFF); + + /* Unknown status is considered as off */ + if (retval == 0x8000) + retval = 0; + + if (retval >= 0) { + if (level) + *level = retval & 0x80 ? retval & 0x7F : 0; + if (env) + *env = (retval >> 8) & 0x7F; + retval = 0; } - return 0; + return retval; +} + +static void kbd_led_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct asus_wmi *asus; + + asus = container_of(led_cdev, struct asus_wmi, kbd_led); + + if (value > asus->kbd_led.max_brightness) + value = asus->kbd_led.max_brightness; + else if (value < 0) + value = 0; + + asus->kbd_led_wk = value; + queue_work(asus->led_workqueue, &asus->kbd_led_work); +} + +static enum led_brightness kbd_led_get(struct led_classdev *led_cdev) +{ + struct asus_wmi *asus; + int retval, value; + + asus = container_of(led_cdev, struct asus_wmi, kbd_led); + + retval = kbd_led_read(asus, &value, NULL); + + if (retval < 0) + return retval; + + return value; } static void asus_wmi_led_exit(struct asus_wmi *asus) @@ -393,6 +459,48 @@ static void asus_wmi_led_exit(struct asus_wmi *asus) destroy_workqueue(asus->led_workqueue); } +static int asus_wmi_led_init(struct asus_wmi *asus) +{ + int rv = 0; + + asus->led_workqueue = create_singlethread_workqueue("led_workqueue"); + if (!asus->led_workqueue) + return -ENOMEM; + + if (read_tpd_led_state(asus) >= 0) { + INIT_WORK(&asus->tpd_led_work, tpd_led_update); + + asus->tpd_led.name = "asus::touchpad"; + asus->tpd_led.brightness_set = tpd_led_set; + asus->tpd_led.brightness_get = tpd_led_get; + asus->tpd_led.max_brightness = 1; + + rv = led_classdev_register(&asus->platform_device->dev, + &asus->tpd_led); + if (rv) + goto error; + } + + if (kbd_led_read(asus, NULL, NULL) >= 0) { + INIT_WORK(&asus->kbd_led_work, kbd_led_update); + + asus->kbd_led.name = "asus::kbd_backlight"; + asus->kbd_led.brightness_set = kbd_led_set; + asus->kbd_led.brightness_get = kbd_led_get; + asus->kbd_led.max_brightness = 3; + + rv = led_classdev_register(&asus->platform_device->dev, + &asus->kbd_led); + } + +error: + if (rv) + asus_wmi_led_exit(asus); + + return rv; +} + + /* * PCI hotplug (for wlan rfkill) */ @@ -729,6 +837,16 @@ static void asus_wmi_rfkill_exit(struct asus_wmi *asus) rfkill_destroy(asus->wwan3g.rfkill); asus->wwan3g.rfkill = NULL; } + if (asus->gps.rfkill) { + rfkill_unregister(asus->gps.rfkill); + rfkill_destroy(asus->gps.rfkill); + asus->gps.rfkill = NULL; + } + if (asus->uwb.rfkill) { + rfkill_unregister(asus->uwb.rfkill); + rfkill_destroy(asus->uwb.rfkill); + asus->uwb.rfkill = NULL; + } } static int asus_wmi_rfkill_init(struct asus_wmi *asus) @@ -763,6 +881,18 @@ static int asus_wmi_rfkill_init(struct asus_wmi *asus) if (result && result != -ENODEV) goto exit; + result = asus_new_rfkill(asus, &asus->gps, "asus-gps", + RFKILL_TYPE_GPS, ASUS_WMI_DEVID_GPS); + + if (result && result != -ENODEV) + goto exit; + + result = asus_new_rfkill(asus, &asus->uwb, "asus-uwb", + RFKILL_TYPE_UWB, ASUS_WMI_DEVID_UWB); + + if (result && result != -ENODEV) + goto exit; + if (!asus->driver->hotplug_wireless) goto exit; @@ -797,8 +927,8 @@ exit: * Hwmon device */ static ssize_t asus_hwmon_pwm1(struct device *dev, - struct device_attribute *attr, - char *buf) + struct device_attribute *attr, + char *buf) { struct asus_wmi *asus = dev_get_drvdata(dev); u32 value; @@ -809,7 +939,7 @@ static ssize_t asus_hwmon_pwm1(struct device *dev, if (err < 0) return err; - value |= 0xFF; + value &= 0xFF; if (value == 1) /* Low Speed */ value = 85; @@ -825,7 +955,26 @@ static ssize_t asus_hwmon_pwm1(struct device *dev, return sprintf(buf, "%d\n", value); } +static ssize_t asus_hwmon_temp1(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct asus_wmi *asus = dev_get_drvdata(dev); + u32 value; + int err; + + err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_THERMAL_CTRL, &value); + + if (err < 0) + return err; + + value = KELVIN_TO_CELSIUS((value & 0xFFFF)) * 1000; + + return sprintf(buf, "%d\n", value); +} + static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO, asus_hwmon_pwm1, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, asus_hwmon_temp1, NULL, 0); static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf) @@ -836,12 +985,13 @@ static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); static struct attribute *hwmon_attributes[] = { &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_name.dev_attr.attr, NULL }; static mode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj, - struct attribute *attr, int idx) + struct attribute *attr, int idx) { struct device *dev = container_of(kobj, struct device, kobj); struct platform_device *pdev = to_platform_device(dev->parent); @@ -852,6 +1002,8 @@ static mode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj, if (attr == &sensor_dev_attr_pwm1.dev_attr.attr) dev_id = ASUS_WMI_DEVID_FAN_CTRL; + else if (attr == &sensor_dev_attr_temp1_input.dev_attr.attr) + dev_id = ASUS_WMI_DEVID_THERMAL_CTRL; if (dev_id != -1) { int err = asus_wmi_get_devstate(asus, dev_id, &value); @@ -869,9 +1021,13 @@ static mode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj, * - reverved bits are non-zero * - sfun and presence bit are not set */ - if (value != ASUS_WMI_UNSUPPORTED_METHOD || value & 0xFFF80000 + if (value == ASUS_WMI_UNSUPPORTED_METHOD || value & 0xFFF80000 || (!asus->sfun && !(value & ASUS_WMI_DSTS_PRESENCE_BIT))) ok = false; + } else if (dev_id == ASUS_WMI_DEVID_THERMAL_CTRL) { + /* If value is zero, something is clearly wrong */ + if (value == 0) + ok = false; } return ok ? attr->mode : 0; @@ -904,6 +1060,7 @@ static int asus_wmi_hwmon_init(struct asus_wmi *asus) pr_err("Could not register asus hwmon device\n"); return PTR_ERR(hwmon); } + dev_set_drvdata(hwmon, asus); asus->hwmon_device = hwmon; result = sysfs_create_group(&hwmon->kobj, &hwmon_attribute_group); if (result) @@ -1060,6 +1217,8 @@ static void asus_wmi_notify(u32 value, void *context) acpi_status status; int code; int orig_code; + unsigned int key_value = 1; + bool autorelease = 1; status = wmi_get_event_data(value, &response); if (status != AE_OK) { @@ -1075,6 +1234,13 @@ static void asus_wmi_notify(u32 value, void *context) code = obj->integer.value; orig_code = code; + if (asus->driver->key_filter) { + asus->driver->key_filter(asus->driver, &code, &key_value, + &autorelease); + if (code == ASUS_WMI_KEY_IGNORE) + goto exit; + } + if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) code = NOTIFY_BRNUP_MIN; else if (code >= NOTIFY_BRNDOWN_MIN && @@ -1084,7 +1250,8 @@ static void asus_wmi_notify(u32 value, void *context) if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) { if (!acpi_video_backlight_support()) asus_wmi_backlight_notify(asus, orig_code); - } else if (!sparse_keymap_report_event(asus->inputdev, code, 1, true)) + } else if (!sparse_keymap_report_event(asus->inputdev, code, + key_value, autorelease)) pr_info("Unknown key %x pressed\n", code); exit: @@ -1164,14 +1331,18 @@ ASUS_WMI_CREATE_DEVICE_ATTR(cardr, 0644, ASUS_WMI_DEVID_CARDREADER); static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - int value; + int value, rv; if (!count || sscanf(buf, "%i", &value) != 1) return -EINVAL; if (value < 0 || value > 2) return -EINVAL; - return asus_wmi_evaluate_method(ASUS_WMI_METHODID_CFVS, value, 0, NULL); + rv = asus_wmi_evaluate_method(ASUS_WMI_METHODID_CFVS, value, 0, NULL); + if (rv < 0) + return rv; + + return count; } static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv); @@ -1234,7 +1405,7 @@ static int asus_wmi_platform_init(struct asus_wmi *asus) /* We don't know yet what to do with this version... */ if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_SPEC, 0, 0x9, &rv)) { - pr_info("BIOS WMI version: %d.%d", rv >> 8, rv & 0xFF); + pr_info("BIOS WMI version: %d.%d", rv >> 16, rv & 0xFF); asus->spec = rv; } @@ -1266,6 +1437,12 @@ static int asus_wmi_platform_init(struct asus_wmi *asus) return -ENODEV; } + /* CWAP allow to define the behavior of the Fn+F2 key, + * this method doesn't seems to be present on Eee PCs */ + if (asus->driver->wapf >= 0) + asus_wmi_set_devstate(ASUS_WMI_DEVID_CWAP, + asus->driver->wapf, NULL); + return asus_wmi_sysfs_init(asus->platform_device); } @@ -1568,6 +1745,14 @@ static int asus_hotk_restore(struct device *device) bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WWAN3G); rfkill_set_sw_state(asus->wwan3g.rfkill, bl); } + if (asus->gps.rfkill) { + bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_GPS); + rfkill_set_sw_state(asus->gps.rfkill, bl); + } + if (asus->uwb.rfkill) { + bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_UWB); + rfkill_set_sw_state(asus->uwb.rfkill, bl); + } return 0; } @@ -1604,7 +1789,7 @@ static int asus_wmi_probe(struct platform_device *pdev) static bool used; -int asus_wmi_register_driver(struct asus_wmi_driver *driver) +int __init_or_module asus_wmi_register_driver(struct asus_wmi_driver *driver) { struct platform_driver *platform_driver; struct platform_device *platform_device; diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h index c044522c8766..8147c10161cc 100644 --- a/drivers/platform/x86/asus-wmi.h +++ b/drivers/platform/x86/asus-wmi.h @@ -29,12 +29,15 @@ #include <linux/platform_device.h> +#define ASUS_WMI_KEY_IGNORE (-1) + struct module; struct key_entry; struct asus_wmi; struct asus_wmi_driver { bool hotplug_wireless; + int wapf; const char *name; struct module *owner; @@ -44,6 +47,10 @@ struct asus_wmi_driver { const struct key_entry *keymap; const char *input_name; const char *input_phys; + /* Returns new code, value, and autorelease values in arguments. + * Return ASUS_WMI_KEY_IGNORE in code if event should be ignored. */ + void (*key_filter) (struct asus_wmi_driver *driver, int *code, + unsigned int *value, bool *autorelease); int (*probe) (struct platform_device *device); void (*quirks) (struct asus_wmi_driver *driver); diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index e39ab1d3ed87..f31fa4efa725 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -612,7 +612,6 @@ static int __init dell_init(void) if (!bufferpage) goto fail_buffer; buffer = page_address(bufferpage); - mutex_init(&buffer_mutex); ret = dell_setup_rfkill(); diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index ce790827e199..fa9a2171cc13 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -54,6 +54,8 @@ MODULE_ALIAS("wmi:"DELL_EVENT_GUID); */ static const struct key_entry dell_wmi_legacy_keymap[] __initconst = { + { KE_IGNORE, 0x003a, { KEY_CAPSLOCK } }, + { KE_KEY, 0xe045, { KEY_PROG1 } }, { KE_KEY, 0xe009, { KEY_EJECTCD } }, @@ -85,6 +87,11 @@ static const struct key_entry dell_wmi_legacy_keymap[] __initconst = { { KE_IGNORE, 0xe013, { KEY_RESERVED } }, { KE_IGNORE, 0xe020, { KEY_MUTE } }, + + /* Shortcut and audio panel keys */ + { KE_IGNORE, 0xe025, { KEY_RESERVED } }, + { KE_IGNORE, 0xe026, { KEY_RESERVED } }, + { KE_IGNORE, 0xe02e, { KEY_VOLUMEDOWN } }, { KE_IGNORE, 0xe030, { KEY_VOLUMEUP } }, { KE_IGNORE, 0xe033, { KEY_KBDILLUMUP } }, @@ -92,6 +99,9 @@ static const struct key_entry dell_wmi_legacy_keymap[] __initconst = { { KE_IGNORE, 0xe03a, { KEY_CAPSLOCK } }, { KE_IGNORE, 0xe045, { KEY_NUMLOCK } }, { KE_IGNORE, 0xe046, { KEY_SCROLLLOCK } }, + { KE_IGNORE, 0xe0f7, { KEY_MUTE } }, + { KE_IGNORE, 0xe0f8, { KEY_VOLUMEDOWN } }, + { KE_IGNORE, 0xe0f9, { KEY_VOLUMEUP } }, { KE_END, 0 } }; diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 4aa867a9b88b..9f6e64302b45 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -56,6 +56,11 @@ MODULE_PARM_DESC(hotplug_wireless, "If your laptop needs that, please report to " "acpi4asus-user@lists.sourceforge.net."); +/* Values for T101MT "Home" key */ +#define HOME_PRESS 0xe4 +#define HOME_HOLD 0xea +#define HOME_RELEASE 0xe5 + static const struct key_entry eeepc_wmi_keymap[] = { /* Sleep already handled via generic ACPI code */ { KE_KEY, 0x30, { KEY_VOLUMEUP } }, @@ -71,6 +76,7 @@ static const struct key_entry eeepc_wmi_keymap[] = { { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } }, { KE_KEY, 0xe0, { KEY_PROG1 } }, /* Task Manager */ { KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */ + { KE_KEY, HOME_PRESS, { KEY_CONFIG } }, /* Home/Express gate key */ { KE_KEY, 0xe8, { KEY_SCREENLOCK } }, { KE_KEY, 0xe9, { KEY_BRIGHTNESS_ZERO } }, { KE_KEY, 0xeb, { KEY_CAMERA_ZOOMOUT } }, @@ -81,6 +87,25 @@ static const struct key_entry eeepc_wmi_keymap[] = { { KE_END, 0}, }; +static void eeepc_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code, + unsigned int *value, bool *autorelease) +{ + switch (*code) { + case HOME_PRESS: + *value = 1; + *autorelease = 0; + break; + case HOME_HOLD: + *code = ASUS_WMI_KEY_IGNORE; + break; + case HOME_RELEASE: + *code = HOME_PRESS; + *value = 0; + *autorelease = 0; + break; + } +} + static acpi_status eeepc_wmi_parse_device(acpi_handle handle, u32 level, void *context, void **retval) { @@ -141,6 +166,7 @@ static void eeepc_dmi_check(struct asus_wmi_driver *driver) static void eeepc_wmi_quirks(struct asus_wmi_driver *driver) { driver->hotplug_wireless = hotplug_wireless; + driver->wapf = -1; eeepc_dmi_check(driver); } @@ -151,6 +177,7 @@ static struct asus_wmi_driver asus_wmi_driver = { .keymap = eeepc_wmi_keymap, .input_name = "Eee PC WMI hotkeys", .input_phys = EEEPC_WMI_FILE "/input0", + .key_filter = eeepc_wmi_key_filter, .probe = eeepc_wmi_probe, .quirks = eeepc_wmi_quirks, }; diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index bfdda33feb26..0c595410e788 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -32,13 +32,22 @@ #include <linux/platform_device.h> #include <linux/input.h> #include <linux/input/sparse-keymap.h> +#include <linux/backlight.h> +#include <linux/fb.h> #define IDEAPAD_RFKILL_DEV_NUM (3) +#define CFG_BT_BIT (16) +#define CFG_3G_BIT (17) +#define CFG_WIFI_BIT (18) +#define CFG_CAMERA_BIT (19) + struct ideapad_private { struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM]; struct platform_device *platform_device; struct input_dev *inputdev; + struct backlight_device *blightdev; + unsigned long cfg; }; static acpi_handle ideapad_handle; @@ -155,7 +164,7 @@ static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data) } /* - * camera power + * sysfs */ static ssize_t show_ideapad_cam(struct device *dev, struct device_attribute *attr, @@ -186,6 +195,44 @@ static ssize_t store_ideapad_cam(struct device *dev, static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam); +static ssize_t show_ideapad_cfg(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ideapad_private *priv = dev_get_drvdata(dev); + + return sprintf(buf, "0x%.8lX\n", priv->cfg); +} + +static DEVICE_ATTR(cfg, 0444, show_ideapad_cfg, NULL); + +static struct attribute *ideapad_attributes[] = { + &dev_attr_camera_power.attr, + &dev_attr_cfg.attr, + NULL +}; + +static mode_t ideapad_is_visible(struct kobject *kobj, + struct attribute *attr, + int idx) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct ideapad_private *priv = dev_get_drvdata(dev); + bool supported; + + if (attr == &dev_attr_camera_power.attr) + supported = test_bit(CFG_CAMERA_BIT, &(priv->cfg)); + else + supported = true; + + return supported ? attr->mode : 0; +} + +static struct attribute_group ideapad_attribute_group = { + .is_visible = ideapad_is_visible, + .attrs = ideapad_attributes +}; + /* * Rfkill */ @@ -197,9 +244,9 @@ struct ideapad_rfk_data { }; const struct ideapad_rfk_data ideapad_rfk_data[] = { - { "ideapad_wlan", 18, 0x15, RFKILL_TYPE_WLAN }, - { "ideapad_bluetooth", 16, 0x17, RFKILL_TYPE_BLUETOOTH }, - { "ideapad_3g", 17, 0x20, RFKILL_TYPE_WWAN }, + { "ideapad_wlan", CFG_WIFI_BIT, 0x15, RFKILL_TYPE_WLAN }, + { "ideapad_bluetooth", CFG_BT_BIT, 0x17, RFKILL_TYPE_BLUETOOTH }, + { "ideapad_3g", CFG_3G_BIT, 0x20, RFKILL_TYPE_WWAN }, }; static int ideapad_rfk_set(void *data, bool blocked) @@ -265,8 +312,7 @@ static int __devinit ideapad_register_rfkill(struct acpi_device *adevice, return 0; } -static void __devexit ideapad_unregister_rfkill(struct acpi_device *adevice, - int dev) +static void ideapad_unregister_rfkill(struct acpi_device *adevice, int dev) { struct ideapad_private *priv = dev_get_drvdata(&adevice->dev); @@ -280,15 +326,6 @@ static void __devexit ideapad_unregister_rfkill(struct acpi_device *adevice, /* * Platform device */ -static struct attribute *ideapad_attributes[] = { - &dev_attr_camera_power.attr, - NULL -}; - -static struct attribute_group ideapad_attribute_group = { - .attrs = ideapad_attributes -}; - static int __devinit ideapad_platform_init(struct ideapad_private *priv) { int result; @@ -369,7 +406,7 @@ err_free_dev: return error; } -static void __devexit ideapad_input_exit(struct ideapad_private *priv) +static void ideapad_input_exit(struct ideapad_private *priv) { sparse_keymap_free(priv->inputdev); input_unregister_device(priv->inputdev); @@ -383,6 +420,98 @@ static void ideapad_input_report(struct ideapad_private *priv, } /* + * backlight + */ +static int ideapad_backlight_get_brightness(struct backlight_device *blightdev) +{ + unsigned long now; + + if (read_ec_data(ideapad_handle, 0x12, &now)) + return -EIO; + return now; +} + +static int ideapad_backlight_update_status(struct backlight_device *blightdev) +{ + if (write_ec_cmd(ideapad_handle, 0x13, blightdev->props.brightness)) + return -EIO; + if (write_ec_cmd(ideapad_handle, 0x33, + blightdev->props.power == FB_BLANK_POWERDOWN ? 0 : 1)) + return -EIO; + + return 0; +} + +static const struct backlight_ops ideapad_backlight_ops = { + .get_brightness = ideapad_backlight_get_brightness, + .update_status = ideapad_backlight_update_status, +}; + +static int ideapad_backlight_init(struct ideapad_private *priv) +{ + struct backlight_device *blightdev; + struct backlight_properties props; + unsigned long max, now, power; + + if (read_ec_data(ideapad_handle, 0x11, &max)) + return -EIO; + if (read_ec_data(ideapad_handle, 0x12, &now)) + return -EIO; + if (read_ec_data(ideapad_handle, 0x18, &power)) + return -EIO; + + memset(&props, 0, sizeof(struct backlight_properties)); + props.max_brightness = max; + props.type = BACKLIGHT_PLATFORM; + blightdev = backlight_device_register("ideapad", + &priv->platform_device->dev, + priv, + &ideapad_backlight_ops, + &props); + if (IS_ERR(blightdev)) { + pr_err("Could not register backlight device\n"); + return PTR_ERR(blightdev); + } + + priv->blightdev = blightdev; + blightdev->props.brightness = now; + blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; + backlight_update_status(blightdev); + + return 0; +} + +static void ideapad_backlight_exit(struct ideapad_private *priv) +{ + if (priv->blightdev) + backlight_device_unregister(priv->blightdev); + priv->blightdev = NULL; +} + +static void ideapad_backlight_notify_power(struct ideapad_private *priv) +{ + unsigned long power; + struct backlight_device *blightdev = priv->blightdev; + + if (read_ec_data(ideapad_handle, 0x18, &power)) + return; + blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; +} + +static void ideapad_backlight_notify_brightness(struct ideapad_private *priv) +{ + unsigned long now; + + /* if we control brightness via acpi video driver */ + if (priv->blightdev == NULL) { + read_ec_data(ideapad_handle, 0x12, &now); + return; + } + + backlight_force_update(priv->blightdev, BACKLIGHT_UPDATE_HOTKEY); +} + +/* * module init/exit */ static const struct acpi_device_id ideapad_device_ids[] = { @@ -393,10 +522,11 @@ MODULE_DEVICE_TABLE(acpi, ideapad_device_ids); static int __devinit ideapad_acpi_add(struct acpi_device *adevice) { - int ret, i, cfg; + int ret, i; + unsigned long cfg; struct ideapad_private *priv; - if (read_method_int(adevice->handle, "_CFG", &cfg)) + if (read_method_int(adevice->handle, "_CFG", (int *)&cfg)) return -ENODEV; priv = kzalloc(sizeof(*priv), GFP_KERNEL); @@ -404,6 +534,7 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice) return -ENOMEM; dev_set_drvdata(&adevice->dev, priv); ideapad_handle = adevice->handle; + priv->cfg = cfg; ret = ideapad_platform_init(priv); if (ret) @@ -414,15 +545,25 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice) goto input_failed; for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) { - if (test_bit(ideapad_rfk_data[i].cfgbit, (unsigned long *)&cfg)) + if (test_bit(ideapad_rfk_data[i].cfgbit, &cfg)) ideapad_register_rfkill(adevice, i); else priv->rfk[i] = NULL; } ideapad_sync_rfk_state(adevice); + if (!acpi_video_backlight_support()) { + ret = ideapad_backlight_init(priv); + if (ret && ret != -ENODEV) + goto backlight_failed; + } + return 0; +backlight_failed: + for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) + ideapad_unregister_rfkill(adevice, i); + ideapad_input_exit(priv); input_failed: ideapad_platform_exit(priv); platform_failed: @@ -435,6 +576,7 @@ static int __devexit ideapad_acpi_remove(struct acpi_device *adevice, int type) struct ideapad_private *priv = dev_get_drvdata(&adevice->dev); int i; + ideapad_backlight_exit(priv); for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) ideapad_unregister_rfkill(adevice, i); ideapad_input_exit(priv); @@ -459,12 +601,19 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event) vpc1 = (vpc2 << 8) | vpc1; for (vpc_bit = 0; vpc_bit < 16; vpc_bit++) { if (test_bit(vpc_bit, &vpc1)) { - if (vpc_bit == 9) + switch (vpc_bit) { + case 9: ideapad_sync_rfk_state(adevice); - else if (vpc_bit == 4) - read_ec_data(handle, 0x12, &vpc2); - else + break; + case 4: + ideapad_backlight_notify_brightness(priv); + break; + case 2: + ideapad_backlight_notify_power(priv); + break; + default: ideapad_input_report(priv, vpc_bit); + } } } } diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c index 5ffe7c398148..809a3ae943c6 100644 --- a/drivers/platform/x86/intel_ips.c +++ b/drivers/platform/x86/intel_ips.c @@ -403,7 +403,7 @@ static void ips_cpu_raise(struct ips_driver *ips) thm_writew(THM_MPCPC, (new_tdp_limit * 10) / 8); - turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDC_OVR_EN; + turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDP_OVR_EN; wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override); turbo_override &= ~TURBO_TDP_MASK; @@ -438,7 +438,7 @@ static void ips_cpu_lower(struct ips_driver *ips) thm_writew(THM_MPCPC, (new_limit * 10) / 8); - turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDC_OVR_EN; + turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDP_OVR_EN; wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override); turbo_override &= ~TURBO_TDP_MASK; diff --git a/drivers/platform/x86/intel_menlow.c b/drivers/platform/x86/intel_menlow.c index 809adea4965f..abddc83e9fd7 100644 --- a/drivers/platform/x86/intel_menlow.c +++ b/drivers/platform/x86/intel_menlow.c @@ -477,6 +477,8 @@ static acpi_status intel_menlow_register_sensor(acpi_handle handle, u32 lvl, return AE_ERROR; } + return AE_OK; + aux1_not_found: if (status == AE_NOT_FOUND) return AE_OK; diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c index 3a578323122b..ccd7b1f83519 100644 --- a/drivers/platform/x86/intel_mid_thermal.c +++ b/drivers/platform/x86/intel_mid_thermal.c @@ -493,20 +493,30 @@ static int mid_thermal_probe(struct platform_device *pdev) /* Register each sensor with the generic thermal framework*/ for (i = 0; i < MSIC_THERMAL_SENSORS; i++) { + struct thermal_device_info *td_info = initialize_sensor(i); + + if (!td_info) { + ret = -ENOMEM; + goto err; + } pinfo->tzd[i] = thermal_zone_device_register(name[i], - 0, initialize_sensor(i), &tzd_ops, 0, 0, 0, 0); - if (IS_ERR(pinfo->tzd[i])) - goto reg_fail; + 0, td_info, &tzd_ops, 0, 0, 0, 0); + if (IS_ERR(pinfo->tzd[i])) { + kfree(td_info); + ret = PTR_ERR(pinfo->tzd[i]); + goto err; + } } pinfo->pdev = pdev; platform_set_drvdata(pdev, pinfo); return 0; -reg_fail: - ret = PTR_ERR(pinfo->tzd[i]); - while (--i >= 0) +err: + while (--i >= 0) { + kfree(pinfo->tzd[i]->devdata); thermal_zone_device_unregister(pinfo->tzd[i]); + } configure_adc(0); kfree(pinfo); return ret; @@ -524,8 +534,10 @@ static int mid_thermal_remove(struct platform_device *pdev) int i; struct platform_info *pinfo = platform_get_drvdata(pdev); - for (i = 0; i < MSIC_THERMAL_SENSORS; i++) + for (i = 0; i < MSIC_THERMAL_SENSORS; i++) { + kfree(pinfo->tzd[i]->devdata); thermal_zone_device_unregister(pinfo->tzd[i]); + } kfree(pinfo); platform_set_drvdata(pdev, NULL); diff --git a/drivers/platform/x86/intel_rar_register.c b/drivers/platform/x86/intel_rar_register.c index bde47e9080cd..c8a6aed45277 100644 --- a/drivers/platform/x86/intel_rar_register.c +++ b/drivers/platform/x86/intel_rar_register.c @@ -637,15 +637,13 @@ end_function: return error; } -const struct pci_device_id rar_pci_id_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(rar_pci_id_tbl) = { { PCI_VDEVICE(INTEL, 0x4110) }, { 0 } }; MODULE_DEVICE_TABLE(pci, rar_pci_id_tbl); -const struct pci_device_id *my_id_table = rar_pci_id_tbl; - /* field for registering driver to PCI device */ static struct pci_driver rar_pci_driver = { .name = "rar_register_driver", diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index 940accbe28d3..c86665369a22 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -725,7 +725,7 @@ static void ipc_remove(struct pci_dev *pdev) intel_scu_devices_destroy(); } -static const struct pci_device_id pci_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(pci_ids) = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080e)}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x082a)}, { 0,} diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c index 3ff629df9f01..f204643c5052 100644 --- a/drivers/platform/x86/msi-laptop.c +++ b/drivers/platform/x86/msi-laptop.c @@ -538,6 +538,15 @@ static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = { }, .callback = dmi_check_cb }, + { + .ident = "MSI U270", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, + "Micro-Star International Co., Ltd."), + DMI_MATCH(DMI_PRODUCT_NAME, "U270 series"), + }, + .callback = dmi_check_cb + }, { } }; @@ -996,3 +1005,4 @@ MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N034:*"); MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N051:*"); MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N014:*"); MODULE_ALIAS("dmi:*:svnMicro-StarInternational*:pnCR620:*"); +MODULE_ALIAS("dmi:*:svnMicro-StarInternational*:pnU270series:*"); diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c index c832e3356cd6..6f40bf202dc7 100644 --- a/drivers/platform/x86/msi-wmi.c +++ b/drivers/platform/x86/msi-wmi.c @@ -272,6 +272,7 @@ static int __init msi_wmi_init(void) err_free_backlight: backlight_device_unregister(backlight); err_free_input: + sparse_keymap_free(msi_wmi_input_dev); input_unregister_device(msi_wmi_input_dev); err_uninstall_notifier: wmi_remove_notify_handler(MSIWMI_EVENT_GUID); diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index d347116d150e..359163011044 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -521,6 +521,16 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = { .callback = dmi_check_cb, }, { + .ident = "N510", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, + "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "N510"), + DMI_MATCH(DMI_BOARD_NAME, "N510"), + }, + .callback = dmi_check_cb, + }, + { .ident = "X125", .matches = { DMI_MATCH(DMI_SYS_VENDOR, @@ -601,6 +611,16 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = { .callback = dmi_check_cb, }, { + .ident = "N150/N210/N220", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, + "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"), + DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"), + }, + .callback = dmi_check_cb, + }, + { .ident = "N150/N210/N220/N230", .matches = { DMI_MATCH(DMI_SYS_VENDOR, diff --git a/drivers/platform/x86/samsung-q10.c b/drivers/platform/x86/samsung-q10.c new file mode 100644 index 000000000000..1e54ae74274c --- /dev/null +++ b/drivers/platform/x86/samsung-q10.c @@ -0,0 +1,196 @@ +/* + * Driver for Samsung Q10 and related laptops: controls the backlight + * + * Copyright (c) 2011 Frederick van der Wyck <fvanderwyck@gmail.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. + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/backlight.h> +#include <linux/i8042.h> +#include <linux/dmi.h> + +#define SAMSUNGQ10_BL_MAX_INTENSITY 255 +#define SAMSUNGQ10_BL_DEFAULT_INTENSITY 185 + +#define SAMSUNGQ10_BL_8042_CMD 0xbe +#define SAMSUNGQ10_BL_8042_DATA { 0x89, 0x91 } + +static int samsungq10_bl_brightness; + +static bool force; +module_param(force, bool, 0); +MODULE_PARM_DESC(force, + "Disable the DMI check and force the driver to be loaded"); + +static int samsungq10_bl_set_intensity(struct backlight_device *bd) +{ + + int brightness = bd->props.brightness; + unsigned char c[3] = SAMSUNGQ10_BL_8042_DATA; + + c[2] = (unsigned char)brightness; + i8042_lock_chip(); + i8042_command(c, (0x30 << 8) | SAMSUNGQ10_BL_8042_CMD); + i8042_unlock_chip(); + samsungq10_bl_brightness = brightness; + + return 0; +} + +static int samsungq10_bl_get_intensity(struct backlight_device *bd) +{ + return samsungq10_bl_brightness; +} + +static const struct backlight_ops samsungq10_bl_ops = { + .get_brightness = samsungq10_bl_get_intensity, + .update_status = samsungq10_bl_set_intensity, +}; + +#ifdef CONFIG_PM_SLEEP +static int samsungq10_suspend(struct device *dev) +{ + return 0; +} + +static int samsungq10_resume(struct device *dev) +{ + + struct backlight_device *bd = dev_get_drvdata(dev); + + samsungq10_bl_set_intensity(bd); + return 0; +} +#else +#define samsungq10_suspend NULL +#define samsungq10_resume NULL +#endif + +static SIMPLE_DEV_PM_OPS(samsungq10_pm_ops, + samsungq10_suspend, samsungq10_resume); + +static int __devinit samsungq10_probe(struct platform_device *pdev) +{ + + struct backlight_properties props; + struct backlight_device *bd; + + memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_PLATFORM; + props.max_brightness = SAMSUNGQ10_BL_MAX_INTENSITY; + bd = backlight_device_register("samsung", &pdev->dev, NULL, + &samsungq10_bl_ops, &props); + if (IS_ERR(bd)) + return PTR_ERR(bd); + + platform_set_drvdata(pdev, bd); + + bd->props.brightness = SAMSUNGQ10_BL_DEFAULT_INTENSITY; + samsungq10_bl_set_intensity(bd); + + return 0; +} + +static int __devexit samsungq10_remove(struct platform_device *pdev) +{ + + struct backlight_device *bd = platform_get_drvdata(pdev); + + bd->props.brightness = SAMSUNGQ10_BL_DEFAULT_INTENSITY; + samsungq10_bl_set_intensity(bd); + + backlight_device_unregister(bd); + + return 0; +} + +static struct platform_driver samsungq10_driver = { + .driver = { + .name = KBUILD_MODNAME, + .owner = THIS_MODULE, + .pm = &samsungq10_pm_ops, + }, + .probe = samsungq10_probe, + .remove = __devexit_p(samsungq10_remove), +}; + +static struct platform_device *samsungq10_device; + +static int __init dmi_check_callback(const struct dmi_system_id *id) +{ + printk(KERN_INFO KBUILD_MODNAME ": found model '%s'\n", id->ident); + return 1; +} + +static struct dmi_system_id __initdata samsungq10_dmi_table[] = { + { + .ident = "Samsung Q10", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Samsung"), + DMI_MATCH(DMI_PRODUCT_NAME, "SQ10"), + }, + .callback = dmi_check_callback, + }, + { + .ident = "Samsung Q20", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG Electronics"), + DMI_MATCH(DMI_PRODUCT_NAME, "SENS Q20"), + }, + .callback = dmi_check_callback, + }, + { + .ident = "Samsung Q25", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG Electronics"), + DMI_MATCH(DMI_PRODUCT_NAME, "NQ25"), + }, + .callback = dmi_check_callback, + }, + { + .ident = "Dell Latitude X200", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "X200"), + }, + .callback = dmi_check_callback, + }, + { }, +}; +MODULE_DEVICE_TABLE(dmi, samsungq10_dmi_table); + +static int __init samsungq10_init(void) +{ + if (!force && !dmi_check_system(samsungq10_dmi_table)) + return -ENODEV; + + samsungq10_device = platform_create_bundle(&samsungq10_driver, + samsungq10_probe, + NULL, 0, NULL, 0); + + if (IS_ERR(samsungq10_device)) + return PTR_ERR(samsungq10_device); + + return 0; +} + +static void __exit samsungq10_exit(void) +{ + platform_device_unregister(samsungq10_device); + platform_driver_unregister(&samsungq10_driver); +} + +module_init(samsungq10_init); +module_exit(samsungq10_exit); + +MODULE_AUTHOR("Frederick van der Wyck <fvanderwyck@gmail.com>"); +MODULE_DESCRIPTION("Samsung Q10 Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 26c5b117df22..7bd829f247eb 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -3186,8 +3186,17 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ /* (assignments unknown, please report if found) */ + KEY_UNKNOWN, KEY_UNKNOWN, + + /* + * The mic mute button only sends 0x1a. It does not + * automatically mute the mic or change the mute light. + */ + KEY_MICMUTE, /* 0x1a: Mic mute (since ?400 or so) */ + + /* (assignments unknown, please report if found) */ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, - KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + KEY_UNKNOWN, }, }; diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 432444af7ee4..a1d3ddba99cc 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -24,6 +24,7 @@ #include <linux/mutex.h> #include <linux/debugfs.h> #include <linux/seq_file.h> +#include <linux/vmalloc.h> #include <asm/ccwdev.h> #include <asm/ebcdic.h> @@ -888,11 +889,11 @@ char *dasd_get_user_string(const char __user *user_buf, size_t user_len) { char *buffer; - buffer = kmalloc(user_len + 1, GFP_KERNEL); + buffer = vmalloc(user_len + 1); if (buffer == NULL) return ERR_PTR(-ENOMEM); if (copy_from_user(buffer, user_buf, user_len) != 0) { - kfree(buffer); + vfree(buffer); return ERR_PTR(-EFAULT); } /* got the string, now strip linefeed. */ @@ -930,7 +931,7 @@ static ssize_t dasd_stats_write(struct file *file, dasd_profile_off(prof); } else rc = -EINVAL; - kfree(buffer); + vfree(buffer); return rc; } @@ -1042,7 +1043,7 @@ static ssize_t dasd_stats_global_write(struct file *file, dasd_global_profile_level = DASD_PROFILE_OFF; } else rc = -EINVAL; - kfree(buffer); + vfree(buffer); return rc; } diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 30fb979d684d..6e835c9fdfcb 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1461,6 +1461,15 @@ dasd_eckd_check_characteristics(struct dasd_device *device) "Read device characteristic failed, rc=%d", rc); goto out_err3; } + + if ((device->features & DASD_FEATURE_USERAW) && + !(private->rdc_data.facilities.RT_in_LR)) { + dev_err(&device->cdev->dev, "The storage server does not " + "support raw-track access\n"); + rc = -EINVAL; + goto out_err3; + } + /* find the valid cylinder size */ if (private->rdc_data.no_cyl == LV_COMPAT_CYL && private->rdc_data.long_no_cyl) diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index 6c3c5364d082..e12989fff4ff 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -312,14 +312,14 @@ static ssize_t dasd_stats_proc_write(struct file *file, pr_info("The statistics have been reset\n"); } else goto out_parse_error; - kfree(buffer); + vfree(buffer); return user_len; out_parse_error: rc = -EINVAL; pr_warning("%s is not a supported value for /proc/dasd/statistics\n", str); out_error: - kfree(buffer); + vfree(buffer); return rc; #else pr_warning("/proc/dasd/statistics: is not activated in this kernel\n"); diff --git a/drivers/s390/char/sclp_async.c b/drivers/s390/char/sclp_async.c index 7ad30e72f868..5f9f929e891c 100644 --- a/drivers/s390/char/sclp_async.c +++ b/drivers/s390/char/sclp_async.c @@ -82,12 +82,9 @@ static int proc_handler_callhome(struct ctl_table *ctl, int write, return -EFAULT; } else { len = *count; - rc = copy_from_user(buf, buffer, sizeof(buf)); - if (rc != 0) - return -EFAULT; - buf[sizeof(buf) - 1] = '\0'; - if (strict_strtoul(buf, 0, &val) != 0) - return -EINVAL; + rc = kstrtoul_from_user(buffer, len, 0, &val); + if (rc) + return rc; if (val != 0 && val != 1) return -EINVAL; callhome_enabled = val; diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 7bc643f3f5ab..e5c966462c5a 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -14,6 +14,8 @@ #include "chsc.h" #define QDIO_BUSY_BIT_PATIENCE (100 << 12) /* 100 microseconds */ +#define QDIO_BUSY_BIT_RETRY_DELAY 10 /* 10 milliseconds */ +#define QDIO_BUSY_BIT_RETRIES 1000 /* = 10s retry time */ #define QDIO_INPUT_THRESHOLD (500 << 12) /* 500 microseconds */ /* diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index f8b03a636e49..0e615cb912d0 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c @@ -188,19 +188,13 @@ static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf, struct qdio_irq *irq_ptr = seq->private; struct qdio_q *q; unsigned long val; - char buf[8]; int ret, i; if (!irq_ptr) return 0; - if (count >= sizeof(buf)) - return -EINVAL; - if (copy_from_user(&buf, ubuf, count)) - return -EFAULT; - buf[count] = 0; - - ret = strict_strtoul(buf, 10, &val); - if (ret < 0) + + ret = kstrtoul_from_user(ubuf, count, 10, &val); + if (ret) return ret; switch (val) { diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index e58169c32474..288c9140290e 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -313,7 +313,7 @@ static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit) unsigned long schid = *((u32 *) &q->irq_ptr->schid); unsigned int fc = QDIO_SIGA_WRITE; u64 start_time = 0; - int cc; + int retries = 0, cc; if (is_qebsm(q)) { schid = q->irq_ptr->sch_token; @@ -325,6 +325,7 @@ again: /* hipersocket busy condition */ if (unlikely(*busy_bit)) { WARN_ON(queue_type(q) != QDIO_IQDIO_QFMT || cc != 2); + retries++; if (!start_time) { start_time = get_clock(); @@ -333,6 +334,11 @@ again: if ((get_clock() - start_time) < QDIO_BUSY_BIT_PATIENCE) goto again; } + if (retries) { + DBF_DEV_EVENT(DBF_WARN, q->irq_ptr, + "%4x cc2 BB1:%1d", SCH_NO(q), q->nr); + DBF_DEV_EVENT(DBF_WARN, q->irq_ptr, "count:%u", retries); + } return cc; } @@ -728,13 +734,14 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q) static int qdio_kick_outbound_q(struct qdio_q *q) { + int retries = 0, cc; unsigned int busy_bit; - int cc; if (!need_siga_out(q)) return 0; DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr); +retry: qperf_inc(q, siga_write); cc = qdio_siga_output(q, &busy_bit); @@ -743,7 +750,11 @@ static int qdio_kick_outbound_q(struct qdio_q *q) break; case 2: if (busy_bit) { - DBF_ERROR("%4x cc2 REP:%1d", SCH_NO(q), q->nr); + while (++retries < QDIO_BUSY_BIT_RETRIES) { + mdelay(QDIO_BUSY_BIT_RETRY_DELAY); + goto retry; + } + DBF_ERROR("%4x cc2 BBC:%1d", SCH_NO(q), q->nr); cc |= QDIO_ERROR_SIGA_BUSY; } else DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w cc2:%1d", q->nr); @@ -753,6 +764,10 @@ static int qdio_kick_outbound_q(struct qdio_q *q) DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc); break; } + if (retries) { + DBF_ERROR("%4x cc2 BB2:%1d", SCH_NO(q), q->nr); + DBF_ERROR("count:%u", retries); + } return cc; } diff --git a/drivers/staging/gma500/gem_glue.c b/drivers/staging/gma500/gem_glue.c index 779ac1a12d24..daac12120653 100644 --- a/drivers/staging/gma500/gem_glue.c +++ b/drivers/staging/gma500/gem_glue.c @@ -20,26 +20,6 @@ #include <drm/drmP.h> #include <drm/drm.h> -/** - * Initialize an already allocated GEM object of the specified size with - * no GEM provided backing store. Instead the caller is responsible for - * backing the object and handling it. - */ -int drm_gem_private_object_init(struct drm_device *dev, - struct drm_gem_object *obj, size_t size) -{ - BUG_ON((size & (PAGE_SIZE - 1)) != 0); - - obj->dev = dev; - obj->filp = NULL; - - kref_init(&obj->refcount); - atomic_set(&obj->handle_count, 0); - obj->size = size; - - return 0; -} - void drm_gem_object_release_wrap(struct drm_gem_object *obj) { /* Remove the list map if one is present */ @@ -51,8 +31,7 @@ void drm_gem_object_release_wrap(struct drm_gem_object *obj) kfree(list->map); list->map = NULL; } - if (obj->filp) - drm_gem_object_release(obj); + drm_gem_object_release(obj); } /** diff --git a/drivers/staging/gma500/gem_glue.h b/drivers/staging/gma500/gem_glue.h index a0f2bc4e4ae7..ce5ce30f74db 100644 --- a/drivers/staging/gma500/gem_glue.h +++ b/drivers/staging/gma500/gem_glue.h @@ -1,4 +1,2 @@ extern void drm_gem_object_release_wrap(struct drm_gem_object *obj); -extern int drm_gem_private_object_init(struct drm_device *dev, - struct drm_gem_object *obj, size_t size); extern int gem_create_mmap_offset(struct drm_gem_object *obj); diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 827db7654594..7e91b3d368cd 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1286,22 +1286,17 @@ static int serial_imx_resume(struct platform_device *dev) static int serial_imx_probe_dt(struct imx_port *sport, struct platform_device *pdev) { + static int portnum = 0; struct device_node *np = pdev->dev.of_node; const struct of_device_id *of_id = of_match_device(imx_uart_dt_ids, &pdev->dev); - int ret; if (!np) return -ENODEV; - ret = of_alias_get_id(np, "serial"); - if (ret < 0) { - pr_err("%s: failed to get alias id, errno %d\n", - __func__, ret); - return -ENODEV; - } else { - sport->port.line = ret; - } + sport->port.line = portnum++; + if (sport->port.line >= UART_NR) + return -EINVAL; if (of_get_property(np, "fsl,uart-has-rtscts", NULL)) sport->have_rtscts = 1; diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index d0a56235c50e..2ec57b2fb278 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1889,7 +1889,7 @@ static int __devinit sci_init_single(struct platform_device *dev, if (p->regtype == SCIx_PROBE_REGTYPE) { ret = sci_probe_regmap(p); - if (unlikely(!ret)) + if (unlikely(ret)) return ret; } diff --git a/drivers/video/savage/savagefb.h b/drivers/video/savage/savagefb.h index 32549d177b19..dcaab9012ca2 100644 --- a/drivers/video/savage/savagefb.h +++ b/drivers/video/savage/savagefb.h @@ -55,7 +55,7 @@ #define S3_SAVAGE3D_SERIES(chip) ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE_MX)) -#define S3_SAVAGE4_SERIES(chip) ((chip>=S3_SAVAGE4) || (chip<=S3_PROSAVAGEDDR)) +#define S3_SAVAGE4_SERIES(chip) ((chip>=S3_SAVAGE4) && (chip<=S3_PROSAVAGEDDR)) #define S3_SAVAGE_MOBILE_SERIES(chip) ((chip==S3_SAVAGE_MX) || (chip==S3_SUPERSAVAGE)) diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index f815283667af..5f7ff8e2fc14 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig @@ -11,7 +11,7 @@ config XEN_BALLOON config XEN_SELFBALLOONING bool "Dynamically self-balloon kernel memory to target" - depends on XEN && XEN_BALLOON && CLEANCACHE && SWAP + depends on XEN && XEN_BALLOON && CLEANCACHE && SWAP && XEN_TMEM default n help Self-ballooning dynamically balloons available kernel memory driven |