7460 lines
244 KiB
Diff
7460 lines
244 KiB
Diff
diff --git a/MAINTAINERS b/MAINTAINERS
|
|
index 8dca9d8..2ccc21c 100644
|
|
--- a/MAINTAINERS
|
|
+++ b/MAINTAINERS
|
|
@@ -897,6 +897,12 @@ W: http://wireless.kernel.org/en/users/Drivers/ar9170
|
|
S: Maintained
|
|
F: drivers/net/wireless/ath/ar9170/
|
|
|
|
+ATK0110 HWMON DRIVER
|
|
+M: Luca Tettamanti <kronos.it@gmail.com>
|
|
+L: lm-sensors@lm-sensors.org
|
|
+S: Maintained
|
|
+F: drivers/hwmon/asus_atk0110.c
|
|
+
|
|
ATI_REMOTE2 DRIVER
|
|
M: Ville Syrjala <syrjala@sci.fi>
|
|
S: Maintained
|
|
diff --git a/arch/alpha/kernel/core_marvel.c b/arch/alpha/kernel/core_marvel.c
|
|
index e302dae..8e059e5 100644
|
|
--- a/arch/alpha/kernel/core_marvel.c
|
|
+++ b/arch/alpha/kernel/core_marvel.c
|
|
@@ -1016,7 +1016,7 @@ marvel_agp_bind_memory(alpha_agp_info *agp, off_t pg_start, struct agp_memory *m
|
|
{
|
|
struct marvel_agp_aperture *aper = agp->aperture.sysdata;
|
|
return iommu_bind(aper->arena, aper->pg_start + pg_start,
|
|
- mem->page_count, mem->memory);
|
|
+ mem->page_count, mem->pages);
|
|
}
|
|
|
|
static int
|
|
diff --git a/arch/alpha/kernel/core_titan.c b/arch/alpha/kernel/core_titan.c
|
|
index 319fcb7..7668649 100644
|
|
--- a/arch/alpha/kernel/core_titan.c
|
|
+++ b/arch/alpha/kernel/core_titan.c
|
|
@@ -680,7 +680,7 @@ titan_agp_bind_memory(alpha_agp_info *agp, off_t pg_start, struct agp_memory *me
|
|
{
|
|
struct titan_agp_aperture *aper = agp->aperture.sysdata;
|
|
return iommu_bind(aper->arena, aper->pg_start + pg_start,
|
|
- mem->page_count, mem->memory);
|
|
+ mem->page_count, mem->pages);
|
|
}
|
|
|
|
static int
|
|
diff --git a/arch/alpha/kernel/pci_impl.h b/arch/alpha/kernel/pci_impl.h
|
|
index 00edd04..85457b2 100644
|
|
--- a/arch/alpha/kernel/pci_impl.h
|
|
+++ b/arch/alpha/kernel/pci_impl.h
|
|
@@ -198,7 +198,7 @@ extern unsigned long size_for_memory(unsigned long max);
|
|
|
|
extern int iommu_reserve(struct pci_iommu_arena *, long, long);
|
|
extern int iommu_release(struct pci_iommu_arena *, long, long);
|
|
-extern int iommu_bind(struct pci_iommu_arena *, long, long, unsigned long *);
|
|
+extern int iommu_bind(struct pci_iommu_arena *, long, long, struct page **);
|
|
extern int iommu_unbind(struct pci_iommu_arena *, long, long);
|
|
|
|
|
|
diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c
|
|
index bfb880a..eadd63b 100644
|
|
--- a/arch/alpha/kernel/pci_iommu.c
|
|
+++ b/arch/alpha/kernel/pci_iommu.c
|
|
@@ -880,7 +880,7 @@ iommu_release(struct pci_iommu_arena *arena, long pg_start, long pg_count)
|
|
|
|
int
|
|
iommu_bind(struct pci_iommu_arena *arena, long pg_start, long pg_count,
|
|
- unsigned long *physaddrs)
|
|
+ struct page **pages)
|
|
{
|
|
unsigned long flags;
|
|
unsigned long *ptes;
|
|
@@ -900,7 +900,7 @@ iommu_bind(struct pci_iommu_arena *arena, long pg_start, long pg_count,
|
|
}
|
|
|
|
for(i = 0, j = pg_start; i < pg_count; i++, j++)
|
|
- ptes[j] = mk_iommu_pte(physaddrs[i]);
|
|
+ ptes[j] = mk_iommu_pte(page_to_phys(pages[i]));
|
|
|
|
spin_unlock_irqrestore(&arena->lock, flags);
|
|
|
|
diff --git a/arch/arm/mach-pxa/sharpsl_pm.c b/arch/arm/mach-pxa/sharpsl_pm.c
|
|
index 2546c06..629e05d 100644
|
|
--- a/arch/arm/mach-pxa/sharpsl_pm.c
|
|
+++ b/arch/arm/mach-pxa/sharpsl_pm.c
|
|
@@ -678,8 +678,8 @@ static int corgi_enter_suspend(unsigned long alarm_time, unsigned int alarm_enab
|
|
dev_dbg(sharpsl_pm.dev, "User triggered wakeup in offline charger.\n");
|
|
}
|
|
|
|
- if ((!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_LOCK)) || (sharpsl_fatal_check() < 0) )
|
|
- {
|
|
+ if ((!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_LOCK)) ||
|
|
+ (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_FATAL))) {
|
|
dev_err(sharpsl_pm.dev, "Fatal condition. Suspend.\n");
|
|
corgi_goto_sleep(alarm_time, alarm_enable, state);
|
|
return 1;
|
|
diff --git a/arch/powerpc/include/asm/pte-common.h b/arch/powerpc/include/asm/pte-common.h
|
|
index a7e210b..0cd2e34 100644
|
|
--- a/arch/powerpc/include/asm/pte-common.h
|
|
+++ b/arch/powerpc/include/asm/pte-common.h
|
|
@@ -176,7 +176,7 @@ extern unsigned long bad_call_to_PMD_PAGE_SIZE(void);
|
|
#define HAVE_PAGE_AGP
|
|
|
|
/* Advertise support for _PAGE_SPECIAL */
|
|
-#ifdef _PAGE_SPECIAL
|
|
+#if _PAGE_SPECIAL != 0
|
|
#define __HAVE_ARCH_PTE_SPECIAL
|
|
#endif
|
|
|
|
diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c
|
|
index 627767d..d8e6725 100644
|
|
--- a/arch/powerpc/mm/pgtable.c
|
|
+++ b/arch/powerpc/mm/pgtable.c
|
|
@@ -30,6 +30,8 @@
|
|
#include <asm/tlbflush.h>
|
|
#include <asm/tlb.h>
|
|
|
|
+#include "mmu_decl.h"
|
|
+
|
|
static DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur);
|
|
static unsigned long pte_freelist_forced_free;
|
|
|
|
@@ -119,7 +121,7 @@ void pte_free_finish(void)
|
|
/*
|
|
* Handle i/d cache flushing, called from set_pte_at() or ptep_set_access_flags()
|
|
*/
|
|
-static pte_t do_dcache_icache_coherency(pte_t pte)
|
|
+static pte_t do_dcache_icache_coherency(pte_t pte, unsigned long addr)
|
|
{
|
|
unsigned long pfn = pte_pfn(pte);
|
|
struct page *page;
|
|
@@ -128,6 +130,17 @@ static pte_t do_dcache_icache_coherency(pte_t pte)
|
|
return pte;
|
|
page = pfn_to_page(pfn);
|
|
|
|
+#ifdef CONFIG_8xx
|
|
+ /* On 8xx, cache control instructions (particularly
|
|
+ * "dcbst" from flush_dcache_icache) fault as write
|
|
+ * operation if there is an unpopulated TLB entry
|
|
+ * for the address in question. To workaround that,
|
|
+ * we invalidate the TLB here, thus avoiding dcbst
|
|
+ * misbehaviour.
|
|
+ */
|
|
+ _tlbil_va(addr, 0 /* 8xx doesn't care about PID */);
|
|
+#endif
|
|
+
|
|
if (!PageReserved(page) && !test_bit(PG_arch_1, &page->flags)) {
|
|
pr_devel("do_dcache_icache_coherency... flushing\n");
|
|
flush_dcache_icache_page(page);
|
|
@@ -198,7 +211,7 @@ void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte
|
|
*/
|
|
pte = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS);
|
|
if (pte_need_exec_flush(pte, 1))
|
|
- pte = do_dcache_icache_coherency(pte);
|
|
+ pte = do_dcache_icache_coherency(pte, addr);
|
|
|
|
/* Perform the setting of the PTE */
|
|
__set_pte_at(mm, addr, ptep, pte, 0);
|
|
@@ -216,7 +229,7 @@ int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address,
|
|
{
|
|
int changed;
|
|
if (!dirty && pte_need_exec_flush(entry, 0))
|
|
- entry = do_dcache_icache_coherency(entry);
|
|
+ entry = do_dcache_icache_coherency(entry, address);
|
|
changed = !pte_same(*(ptep), entry);
|
|
if (changed) {
|
|
if (!(vma->vm_flags & VM_HUGETLB))
|
|
diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h
|
|
index 83c1bc8..456a304 100644
|
|
--- a/arch/x86/include/asm/elf.h
|
|
+++ b/arch/x86/include/asm/elf.h
|
|
@@ -299,6 +299,8 @@ do { \
|
|
|
|
#ifdef CONFIG_X86_32
|
|
|
|
+#define STACK_RND_MASK (0x7ff)
|
|
+
|
|
#define VDSO_HIGH_BASE (__fix_to_virt(FIX_VDSO))
|
|
|
|
#define ARCH_DLINFO ARCH_DLINFO_IA32(vdso_enabled)
|
|
diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h
|
|
index 77a6850..03a0cbd 100644
|
|
--- a/arch/x86/include/asm/uv/uv_hub.h
|
|
+++ b/arch/x86/include/asm/uv/uv_hub.h
|
|
@@ -422,7 +422,7 @@ static inline void uv_hub_send_ipi(int pnode, int apicid, int vector)
|
|
unsigned long val;
|
|
|
|
val = (1UL << UVH_IPI_INT_SEND_SHFT) |
|
|
- ((apicid & 0x3f) << UVH_IPI_INT_APIC_ID_SHFT) |
|
|
+ ((apicid) << UVH_IPI_INT_APIC_ID_SHFT) |
|
|
(vector << UVH_IPI_INT_VECTOR_SHFT);
|
|
uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
|
|
}
|
|
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
|
|
index 2a50ef8..fde0cd3 100644
|
|
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
|
|
+++ b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
|
|
@@ -605,9 +605,10 @@ static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst,
|
|
return 0;
|
|
}
|
|
|
|
-static void invalidate_entry(struct powernow_k8_data *data, unsigned int entry)
|
|
+static void invalidate_entry(struct cpufreq_frequency_table *powernow_table,
|
|
+ unsigned int entry)
|
|
{
|
|
- data->powernow_table[entry].frequency = CPUFREQ_ENTRY_INVALID;
|
|
+ powernow_table[entry].frequency = CPUFREQ_ENTRY_INVALID;
|
|
}
|
|
|
|
static void print_basics(struct powernow_k8_data *data)
|
|
@@ -914,13 +915,13 @@ static int fill_powernow_table_pstate(struct powernow_k8_data *data,
|
|
"bad value %d.\n", i, index);
|
|
printk(KERN_ERR PFX "Please report to BIOS "
|
|
"manufacturer\n");
|
|
- invalidate_entry(data, i);
|
|
+ invalidate_entry(powernow_table, i);
|
|
continue;
|
|
}
|
|
rdmsr(MSR_PSTATE_DEF_BASE + index, lo, hi);
|
|
if (!(hi & HW_PSTATE_VALID_MASK)) {
|
|
dprintk("invalid pstate %d, ignoring\n", index);
|
|
- invalidate_entry(data, i);
|
|
+ invalidate_entry(powernow_table, i);
|
|
continue;
|
|
}
|
|
|
|
@@ -970,7 +971,7 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data,
|
|
/* verify frequency is OK */
|
|
if ((freq > (MAX_FREQ * 1000)) || (freq < (MIN_FREQ * 1000))) {
|
|
dprintk("invalid freq %u kHz, ignoring\n", freq);
|
|
- invalidate_entry(data, i);
|
|
+ invalidate_entry(powernow_table, i);
|
|
continue;
|
|
}
|
|
|
|
@@ -978,7 +979,7 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data,
|
|
* BIOSs are using "off" to indicate invalid */
|
|
if (vid == VID_OFF) {
|
|
dprintk("invalid vid %u, ignoring\n", vid);
|
|
- invalidate_entry(data, i);
|
|
+ invalidate_entry(powernow_table, i);
|
|
continue;
|
|
}
|
|
|
|
@@ -997,7 +998,7 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data,
|
|
|
|
dprintk("double low frequency table entry, "
|
|
"ignoring it.\n");
|
|
- invalidate_entry(data, i);
|
|
+ invalidate_entry(powernow_table, i);
|
|
continue;
|
|
} else
|
|
cntlofreq = i;
|
|
@@ -1009,7 +1010,7 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data,
|
|
(unsigned int)
|
|
(data->acpi_data.states[i].core_frequency
|
|
* 1000));
|
|
- invalidate_entry(data, i);
|
|
+ invalidate_entry(powernow_table, i);
|
|
continue;
|
|
}
|
|
}
|
|
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
|
|
index a5cdb35..4712293 100644
|
|
--- a/arch/x86/kvm/mmu.c
|
|
+++ b/arch/x86/kvm/mmu.c
|
|
@@ -2713,12 +2713,6 @@ static int alloc_mmu_pages(struct kvm_vcpu *vcpu)
|
|
|
|
ASSERT(vcpu);
|
|
|
|
- if (vcpu->kvm->arch.n_requested_mmu_pages)
|
|
- vcpu->kvm->arch.n_free_mmu_pages =
|
|
- vcpu->kvm->arch.n_requested_mmu_pages;
|
|
- else
|
|
- vcpu->kvm->arch.n_free_mmu_pages =
|
|
- vcpu->kvm->arch.n_alloc_mmu_pages;
|
|
/*
|
|
* When emulating 32-bit mode, cr3 is only 32 bits even on x86_64.
|
|
* Therefore we need to allocate shadow page tables in the first
|
|
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
|
|
index b5fa966..6a768ff 100644
|
|
--- a/arch/x86/kvm/vmx.c
|
|
+++ b/arch/x86/kvm/vmx.c
|
|
@@ -1569,7 +1569,6 @@ static void ept_update_paging_mode_cr0(unsigned long *hw_cr0,
|
|
vcpu->arch.cr0 = cr0;
|
|
vmx_set_cr4(vcpu, vcpu->arch.cr4);
|
|
*hw_cr0 |= X86_CR0_PE | X86_CR0_PG;
|
|
- *hw_cr0 &= ~X86_CR0_WP;
|
|
} else if (!is_paging(vcpu)) {
|
|
/* From nonpaging to paging */
|
|
vmcs_write32(CPU_BASED_VM_EXEC_CONTROL,
|
|
@@ -1578,9 +1577,10 @@ static void ept_update_paging_mode_cr0(unsigned long *hw_cr0,
|
|
CPU_BASED_CR3_STORE_EXITING));
|
|
vcpu->arch.cr0 = cr0;
|
|
vmx_set_cr4(vcpu, vcpu->arch.cr4);
|
|
- if (!(vcpu->arch.cr0 & X86_CR0_WP))
|
|
- *hw_cr0 &= ~X86_CR0_WP;
|
|
}
|
|
+
|
|
+ if (!(cr0 & X86_CR0_WP))
|
|
+ *hw_cr0 &= ~X86_CR0_WP;
|
|
}
|
|
|
|
static void ept_update_paging_mode_cr4(unsigned long *hw_cr4,
|
|
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
|
|
index 3d36045..91a077f 100644
|
|
--- a/arch/x86/kvm/x86.c
|
|
+++ b/arch/x86/kvm/x86.c
|
|
@@ -1448,6 +1448,10 @@ static int kvm_dev_ioctl_get_supported_cpuid(struct kvm_cpuid2 *cpuid,
|
|
for (func = 0x80000001; func <= limit && nent < cpuid->nent; ++func)
|
|
do_cpuid_ent(&cpuid_entries[nent], func, 0,
|
|
&nent, cpuid->nent);
|
|
+ r = -E2BIG;
|
|
+ if (nent >= cpuid->nent)
|
|
+ goto out_free;
|
|
+
|
|
r = -EFAULT;
|
|
if (copy_to_user(entries, cpuid_entries,
|
|
nent * sizeof(struct kvm_cpuid_entry2)))
|
|
@@ -3198,6 +3202,9 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu)
|
|
if (!kvm_x86_ops->update_cr8_intercept)
|
|
return;
|
|
|
|
+ if (!vcpu->arch.apic)
|
|
+ return;
|
|
+
|
|
if (!vcpu->arch.apic->vapic_addr)
|
|
max_irr = kvm_lapic_find_highest_irr(vcpu);
|
|
else
|
|
@@ -4118,13 +4125,7 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
|
|
|
|
vcpu->arch.cr2 = sregs->cr2;
|
|
mmu_reset_needed |= vcpu->arch.cr3 != sregs->cr3;
|
|
-
|
|
- down_read(&vcpu->kvm->slots_lock);
|
|
- if (gfn_to_memslot(vcpu->kvm, sregs->cr3 >> PAGE_SHIFT))
|
|
- vcpu->arch.cr3 = sregs->cr3;
|
|
- else
|
|
- set_bit(KVM_REQ_TRIPLE_FAULT, &vcpu->requests);
|
|
- up_read(&vcpu->kvm->slots_lock);
|
|
+ vcpu->arch.cr3 = sregs->cr3;
|
|
|
|
kvm_set_cr8(vcpu, sregs->cr8);
|
|
|
|
diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile
|
|
index eefdeee..0088329 100644
|
|
--- a/arch/x86/mm/Makefile
|
|
+++ b/arch/x86/mm/Makefile
|
|
@@ -1,6 +1,11 @@
|
|
obj-y := init.o init_$(BITS).o fault.o ioremap.o extable.o pageattr.o mmap.o \
|
|
pat.o pgtable.o gup.o
|
|
|
|
+# Make sure __phys_addr has no stackprotector
|
|
+nostackp := $(call cc-option, -fno-stack-protector)
|
|
+CFLAGS_ioremap.o := $(nostackp)
|
|
+CFLAGS_init.o := $(nostackp)
|
|
+
|
|
obj-$(CONFIG_SMP) += tlb.o
|
|
|
|
obj-$(CONFIG_X86_32) += pgtable_32.o iomap_32.o
|
|
diff --git a/arch/x86/mm/mmap.c b/arch/x86/mm/mmap.c
|
|
index 1658296..c8191de 100644
|
|
--- a/arch/x86/mm/mmap.c
|
|
+++ b/arch/x86/mm/mmap.c
|
|
@@ -29,13 +29,26 @@
|
|
#include <linux/random.h>
|
|
#include <linux/limits.h>
|
|
#include <linux/sched.h>
|
|
+#include <asm/elf.h>
|
|
+
|
|
+static unsigned int stack_maxrandom_size(void)
|
|
+{
|
|
+ unsigned int max = 0;
|
|
+ if ((current->flags & PF_RANDOMIZE) &&
|
|
+ !(current->personality & ADDR_NO_RANDOMIZE)) {
|
|
+ max = ((-1U) & STACK_RND_MASK) << PAGE_SHIFT;
|
|
+ }
|
|
+
|
|
+ return max;
|
|
+}
|
|
+
|
|
|
|
/*
|
|
* Top of mmap area (just below the process stack).
|
|
*
|
|
- * Leave an at least ~128 MB hole.
|
|
+ * Leave an at least ~128 MB hole with possible stack randomization.
|
|
*/
|
|
-#define MIN_GAP (128*1024*1024)
|
|
+#define MIN_GAP (128*1024*1024UL + stack_maxrandom_size())
|
|
#define MAX_GAP (TASK_SIZE/6*5)
|
|
|
|
/*
|
|
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
|
|
index e245775..fbb46d6 100644
|
|
--- a/arch/x86/mm/pageattr.c
|
|
+++ b/arch/x86/mm/pageattr.c
|
|
@@ -143,6 +143,7 @@ void clflush_cache_range(void *vaddr, unsigned int size)
|
|
|
|
mb();
|
|
}
|
|
+EXPORT_SYMBOL_GPL(clflush_cache_range);
|
|
|
|
static void __cpa_flush_all(void *arg)
|
|
{
|
|
diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile
|
|
index 7410640..3bb4fc2 100644
|
|
--- a/arch/x86/xen/Makefile
|
|
+++ b/arch/x86/xen/Makefile
|
|
@@ -8,6 +8,7 @@ endif
|
|
# Make sure early boot has no stackprotector
|
|
nostackp := $(call cc-option, -fno-stack-protector)
|
|
CFLAGS_enlighten.o := $(nostackp)
|
|
+CFLAGS_mmu.o := $(nostackp)
|
|
|
|
obj-y := enlighten.o setup.o multicalls.o mmu.o irq.o \
|
|
time.o xen-asm.o xen-asm_$(BITS).o \
|
|
@@ -16,3 +17,4 @@ obj-y := enlighten.o setup.o multicalls.o mmu.o irq.o \
|
|
obj-$(CONFIG_SMP) += smp.o
|
|
obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o
|
|
obj-$(CONFIG_XEN_DEBUG_FS) += debugfs.o
|
|
+
|
|
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
|
|
index eb33aaa..3839a0f 100644
|
|
--- a/arch/x86/xen/enlighten.c
|
|
+++ b/arch/x86/xen/enlighten.c
|
|
@@ -51,6 +51,7 @@
|
|
#include <asm/pgtable.h>
|
|
#include <asm/tlbflush.h>
|
|
#include <asm/reboot.h>
|
|
+#include <asm/stackprotector.h>
|
|
|
|
#include "xen-ops.h"
|
|
#include "mmu.h"
|
|
@@ -330,18 +331,28 @@ static void xen_load_gdt(const struct desc_ptr *dtr)
|
|
unsigned long frames[pages];
|
|
int f;
|
|
|
|
- /* A GDT can be up to 64k in size, which corresponds to 8192
|
|
- 8-byte entries, or 16 4k pages.. */
|
|
+ /*
|
|
+ * A GDT can be up to 64k in size, which corresponds to 8192
|
|
+ * 8-byte entries, or 16 4k pages..
|
|
+ */
|
|
|
|
BUG_ON(size > 65536);
|
|
BUG_ON(va & ~PAGE_MASK);
|
|
|
|
for (f = 0; va < dtr->address + size; va += PAGE_SIZE, f++) {
|
|
int level;
|
|
- pte_t *ptep = lookup_address(va, &level);
|
|
+ pte_t *ptep;
|
|
unsigned long pfn, mfn;
|
|
void *virt;
|
|
|
|
+ /*
|
|
+ * The GDT is per-cpu and is in the percpu data area.
|
|
+ * That can be virtually mapped, so we need to do a
|
|
+ * page-walk to get the underlying MFN for the
|
|
+ * hypercall. The page can also be in the kernel's
|
|
+ * linear range, so we need to RO that mapping too.
|
|
+ */
|
|
+ ptep = lookup_address(va, &level);
|
|
BUG_ON(ptep == NULL);
|
|
|
|
pfn = pte_pfn(*ptep);
|
|
@@ -358,6 +369,44 @@ static void xen_load_gdt(const struct desc_ptr *dtr)
|
|
BUG();
|
|
}
|
|
|
|
+/*
|
|
+ * load_gdt for early boot, when the gdt is only mapped once
|
|
+ */
|
|
+static __init void xen_load_gdt_boot(const struct desc_ptr *dtr)
|
|
+{
|
|
+ unsigned long va = dtr->address;
|
|
+ unsigned int size = dtr->size + 1;
|
|
+ unsigned pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
|
|
+ unsigned long frames[pages];
|
|
+ int f;
|
|
+
|
|
+ /*
|
|
+ * A GDT can be up to 64k in size, which corresponds to 8192
|
|
+ * 8-byte entries, or 16 4k pages..
|
|
+ */
|
|
+
|
|
+ BUG_ON(size > 65536);
|
|
+ BUG_ON(va & ~PAGE_MASK);
|
|
+
|
|
+ for (f = 0; va < dtr->address + size; va += PAGE_SIZE, f++) {
|
|
+ pte_t pte;
|
|
+ unsigned long pfn, mfn;
|
|
+
|
|
+ pfn = virt_to_pfn(va);
|
|
+ mfn = pfn_to_mfn(pfn);
|
|
+
|
|
+ pte = pfn_pte(pfn, PAGE_KERNEL_RO);
|
|
+
|
|
+ if (HYPERVISOR_update_va_mapping((unsigned long)va, pte, 0))
|
|
+ BUG();
|
|
+
|
|
+ frames[f] = mfn;
|
|
+ }
|
|
+
|
|
+ if (HYPERVISOR_set_gdt(frames, size / sizeof(struct desc_struct)))
|
|
+ BUG();
|
|
+}
|
|
+
|
|
static void load_TLS_descriptor(struct thread_struct *t,
|
|
unsigned int cpu, unsigned int i)
|
|
{
|
|
@@ -581,6 +630,29 @@ static void xen_write_gdt_entry(struct desc_struct *dt, int entry,
|
|
preempt_enable();
|
|
}
|
|
|
|
+/*
|
|
+ * Version of write_gdt_entry for use at early boot-time needed to
|
|
+ * update an entry as simply as possible.
|
|
+ */
|
|
+static __init void xen_write_gdt_entry_boot(struct desc_struct *dt, int entry,
|
|
+ const void *desc, int type)
|
|
+{
|
|
+ switch (type) {
|
|
+ case DESC_LDT:
|
|
+ case DESC_TSS:
|
|
+ /* ignore */
|
|
+ break;
|
|
+
|
|
+ default: {
|
|
+ xmaddr_t maddr = virt_to_machine(&dt[entry]);
|
|
+
|
|
+ if (HYPERVISOR_update_descriptor(maddr.maddr, *(u64 *)desc))
|
|
+ dt[entry] = *(struct desc_struct *)desc;
|
|
+ }
|
|
+
|
|
+ }
|
|
+}
|
|
+
|
|
static void xen_load_sp0(struct tss_struct *tss,
|
|
struct thread_struct *thread)
|
|
{
|
|
@@ -965,6 +1037,23 @@ static const struct machine_ops __initdata xen_machine_ops = {
|
|
.emergency_restart = xen_emergency_restart,
|
|
};
|
|
|
|
+/*
|
|
+ * Set up the GDT and segment registers for -fstack-protector. Until
|
|
+ * we do this, we have to be careful not to call any stack-protected
|
|
+ * function, which is most of the kernel.
|
|
+ */
|
|
+static void __init xen_setup_stackprotector(void)
|
|
+{
|
|
+ pv_cpu_ops.write_gdt_entry = xen_write_gdt_entry_boot;
|
|
+ pv_cpu_ops.load_gdt = xen_load_gdt_boot;
|
|
+
|
|
+ setup_stack_canary_segment(0);
|
|
+ switch_to_new_gdt(0);
|
|
+
|
|
+ pv_cpu_ops.write_gdt_entry = xen_write_gdt_entry;
|
|
+ pv_cpu_ops.load_gdt = xen_load_gdt;
|
|
+}
|
|
+
|
|
/* First C function to be called on Xen boot */
|
|
asmlinkage void __init xen_start_kernel(void)
|
|
{
|
|
@@ -983,14 +1072,34 @@ asmlinkage void __init xen_start_kernel(void)
|
|
pv_apic_ops = xen_apic_ops;
|
|
pv_mmu_ops = xen_mmu_ops;
|
|
|
|
-#ifdef CONFIG_X86_64
|
|
/*
|
|
- * Setup percpu state. We only need to do this for 64-bit
|
|
- * because 32-bit already has %fs set properly.
|
|
+ * Set up some pagetable state before starting to set any ptes.
|
|
*/
|
|
- load_percpu_segment(0);
|
|
+
|
|
+ /* Prevent unwanted bits from being set in PTEs. */
|
|
+ __supported_pte_mask &= ~_PAGE_GLOBAL;
|
|
+ if (!xen_initial_domain())
|
|
+ __supported_pte_mask &= ~(_PAGE_PWT | _PAGE_PCD);
|
|
+
|
|
+ __supported_pte_mask |= _PAGE_IOMAP;
|
|
+
|
|
+#ifdef CONFIG_X86_64
|
|
+ /* Work out if we support NX */
|
|
+ check_efer();
|
|
#endif
|
|
|
|
+ xen_setup_features();
|
|
+
|
|
+ /* Get mfn list */
|
|
+ if (!xen_feature(XENFEAT_auto_translated_physmap))
|
|
+ xen_build_dynamic_phys_to_machine();
|
|
+
|
|
+ /*
|
|
+ * Set up kernel GDT and segment registers, mainly so that
|
|
+ * -fstack-protector code can be executed.
|
|
+ */
|
|
+ xen_setup_stackprotector();
|
|
+
|
|
xen_init_irq_ops();
|
|
xen_init_cpuid_mask();
|
|
|
|
@@ -1001,8 +1110,6 @@ asmlinkage void __init xen_start_kernel(void)
|
|
set_xen_basic_apic_ops();
|
|
#endif
|
|
|
|
- xen_setup_features();
|
|
-
|
|
if (xen_feature(XENFEAT_mmu_pt_update_preserve_ad)) {
|
|
pv_mmu_ops.ptep_modify_prot_start = xen_ptep_modify_prot_start;
|
|
pv_mmu_ops.ptep_modify_prot_commit = xen_ptep_modify_prot_commit;
|
|
@@ -1019,22 +1126,8 @@ asmlinkage void __init xen_start_kernel(void)
|
|
|
|
xen_smp_init();
|
|
|
|
- /* Get mfn list */
|
|
- if (!xen_feature(XENFEAT_auto_translated_physmap))
|
|
- xen_build_dynamic_phys_to_machine();
|
|
-
|
|
pgd = (pgd_t *)xen_start_info->pt_base;
|
|
|
|
- /* Prevent unwanted bits from being set in PTEs. */
|
|
- __supported_pte_mask &= ~_PAGE_GLOBAL;
|
|
- if (!xen_initial_domain())
|
|
- __supported_pte_mask &= ~(_PAGE_PWT | _PAGE_PCD);
|
|
-
|
|
-#ifdef CONFIG_X86_64
|
|
- /* Work out if we support NX */
|
|
- check_efer();
|
|
-#endif
|
|
-
|
|
/* Don't do the full vcpu_info placement stuff until we have a
|
|
possible map and a non-dummy shared_info. */
|
|
per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0];
|
|
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
|
|
index 429834e..fe03eee 100644
|
|
--- a/arch/x86/xen/smp.c
|
|
+++ b/arch/x86/xen/smp.c
|
|
@@ -236,6 +236,7 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle)
|
|
ctxt->user_regs.ss = __KERNEL_DS;
|
|
#ifdef CONFIG_X86_32
|
|
ctxt->user_regs.fs = __KERNEL_PERCPU;
|
|
+ ctxt->user_regs.gs = __KERNEL_STACK_CANARY;
|
|
#else
|
|
ctxt->gs_base_kernel = per_cpu_offset(cpu);
|
|
#endif
|
|
diff --git a/arch/x86/xen/spinlock.c b/arch/x86/xen/spinlock.c
|
|
index 5601506..36a5141 100644
|
|
--- a/arch/x86/xen/spinlock.c
|
|
+++ b/arch/x86/xen/spinlock.c
|
|
@@ -187,7 +187,6 @@ static noinline int xen_spin_lock_slow(struct raw_spinlock *lock, bool irq_enabl
|
|
struct xen_spinlock *prev;
|
|
int irq = __get_cpu_var(lock_kicker_irq);
|
|
int ret;
|
|
- unsigned long flags;
|
|
u64 start;
|
|
|
|
/* If kicker interrupts not initialized yet, just spin */
|
|
@@ -199,16 +198,12 @@ static noinline int xen_spin_lock_slow(struct raw_spinlock *lock, bool irq_enabl
|
|
/* announce we're spinning */
|
|
prev = spinning_lock(xl);
|
|
|
|
- flags = __raw_local_save_flags();
|
|
- if (irq_enable) {
|
|
- ADD_STATS(taken_slow_irqenable, 1);
|
|
- raw_local_irq_enable();
|
|
- }
|
|
-
|
|
ADD_STATS(taken_slow, 1);
|
|
ADD_STATS(taken_slow_nested, prev != NULL);
|
|
|
|
do {
|
|
+ unsigned long flags;
|
|
+
|
|
/* clear pending */
|
|
xen_clear_irq_pending(irq);
|
|
|
|
@@ -228,6 +223,12 @@ static noinline int xen_spin_lock_slow(struct raw_spinlock *lock, bool irq_enabl
|
|
goto out;
|
|
}
|
|
|
|
+ flags = __raw_local_save_flags();
|
|
+ if (irq_enable) {
|
|
+ ADD_STATS(taken_slow_irqenable, 1);
|
|
+ raw_local_irq_enable();
|
|
+ }
|
|
+
|
|
/*
|
|
* Block until irq becomes pending. If we're
|
|
* interrupted at this point (after the trylock but
|
|
@@ -238,13 +239,15 @@ static noinline int xen_spin_lock_slow(struct raw_spinlock *lock, bool irq_enabl
|
|
* pending.
|
|
*/
|
|
xen_poll_irq(irq);
|
|
+
|
|
+ raw_local_irq_restore(flags);
|
|
+
|
|
ADD_STATS(taken_slow_spurious, !xen_test_irq_pending(irq));
|
|
} while (!xen_test_irq_pending(irq)); /* check for spurious wakeups */
|
|
|
|
kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
|
|
|
|
out:
|
|
- raw_local_irq_restore(flags);
|
|
unspinning_lock(xl, prev);
|
|
spin_time_accum_blocked(start);
|
|
|
|
@@ -323,8 +326,13 @@ static void xen_spin_unlock(struct raw_spinlock *lock)
|
|
smp_wmb(); /* make sure no writes get moved after unlock */
|
|
xl->lock = 0; /* release lock */
|
|
|
|
- /* make sure unlock happens before kick */
|
|
- barrier();
|
|
+ /*
|
|
+ * Make sure unlock happens before checking for waiting
|
|
+ * spinners. We need a strong barrier to enforce the
|
|
+ * write-read ordering to different memory locations, as the
|
|
+ * CPU makes no implied guarantees about their ordering.
|
|
+ */
|
|
+ mb();
|
|
|
|
if (unlikely(xl->spinners))
|
|
xen_spin_unlock_slow(xl);
|
|
diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c
|
|
index 12158e0..da9d6d2 100644
|
|
--- a/drivers/acpi/pci_slot.c
|
|
+++ b/drivers/acpi/pci_slot.c
|
|
@@ -57,7 +57,7 @@ ACPI_MODULE_NAME("pci_slot");
|
|
MY_NAME , ## arg); \
|
|
} while (0)
|
|
|
|
-#define SLOT_NAME_SIZE 20 /* Inspired by #define in acpiphp.h */
|
|
+#define SLOT_NAME_SIZE 21 /* Inspired by #define in acpiphp.h */
|
|
|
|
struct acpi_pci_slot {
|
|
acpi_handle root_handle; /* handle of the root bridge */
|
|
@@ -149,7 +149,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
|
|
return AE_OK;
|
|
}
|
|
|
|
- snprintf(name, sizeof(name), "%u", (u32)sun);
|
|
+ snprintf(name, sizeof(name), "%llu", sun);
|
|
pci_slot = pci_create_slot(pci_bus, device, name, NULL);
|
|
if (IS_ERR(pci_slot)) {
|
|
err("pci_create_slot returned %ld\n", PTR_ERR(pci_slot));
|
|
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
|
|
index fe3eba5..289c4f8 100644
|
|
--- a/drivers/ata/ahci.c
|
|
+++ b/drivers/ata/ahci.c
|
|
@@ -2861,8 +2861,8 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
if (ahci_asus_m2a_vm_32bit_only(pdev))
|
|
hpriv->flags |= AHCI_HFLAG_32BIT_ONLY;
|
|
|
|
- if (!(hpriv->flags & AHCI_HFLAG_NO_MSI))
|
|
- pci_enable_msi(pdev);
|
|
+ if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
|
|
+ pci_intx(pdev, 1);
|
|
|
|
/* save initial config */
|
|
ahci_save_initial_config(pdev, hpriv);
|
|
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
|
|
index 33a74f1..567f3f7 100644
|
|
--- a/drivers/ata/pata_amd.c
|
|
+++ b/drivers/ata/pata_amd.c
|
|
@@ -307,6 +307,9 @@ static unsigned long nv_mode_filter(struct ata_device *dev,
|
|
limit |= ATA_MASK_PIO;
|
|
if (!(limit & (ATA_MASK_MWDMA | ATA_MASK_UDMA)))
|
|
limit |= ATA_MASK_MWDMA | ATA_MASK_UDMA;
|
|
+ /* PIO4, MWDMA2, UDMA2 should always be supported regardless of
|
|
+ cable detection result */
|
|
+ limit |= ata_pack_xfermask(ATA_PIO4, ATA_MWDMA2, ATA_UDMA2);
|
|
|
|
ata_port_printk(ap, KERN_DEBUG, "nv_mode_filter: 0x%lx&0x%lx->0x%lx, "
|
|
"BIOS=0x%lx (0x%x) ACPI=0x%lx%s\n",
|
|
diff --git a/drivers/base/base.h b/drivers/base/base.h
|
|
index b528145..1e52c12 100644
|
|
--- a/drivers/base/base.h
|
|
+++ b/drivers/base/base.h
|
|
@@ -104,7 +104,7 @@ extern int system_bus_init(void);
|
|
extern int cpu_dev_init(void);
|
|
|
|
extern int bus_add_device(struct device *dev);
|
|
-extern void bus_attach_device(struct device *dev);
|
|
+extern void bus_probe_device(struct device *dev);
|
|
extern void bus_remove_device(struct device *dev);
|
|
|
|
extern int bus_add_driver(struct device_driver *drv);
|
|
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
|
|
index 4b04a15..973bf2a 100644
|
|
--- a/drivers/base/bus.c
|
|
+++ b/drivers/base/bus.c
|
|
@@ -459,8 +459,9 @@ static inline void remove_deprecated_bus_links(struct device *dev) { }
|
|
* bus_add_device - add device to bus
|
|
* @dev: device being added
|
|
*
|
|
+ * - Add device's bus attributes.
|
|
+ * - Create links to device's bus.
|
|
* - Add the device to its bus's list of devices.
|
|
- * - Create link to device's bus.
|
|
*/
|
|
int bus_add_device(struct device *dev)
|
|
{
|
|
@@ -483,6 +484,7 @@ int bus_add_device(struct device *dev)
|
|
error = make_deprecated_bus_links(dev);
|
|
if (error)
|
|
goto out_deprecated;
|
|
+ klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);
|
|
}
|
|
return 0;
|
|
|
|
@@ -498,24 +500,19 @@ out_put:
|
|
}
|
|
|
|
/**
|
|
- * bus_attach_device - add device to bus
|
|
- * @dev: device tried to attach to a driver
|
|
+ * bus_probe_device - probe drivers for a new device
|
|
+ * @dev: device to probe
|
|
*
|
|
- * - Add device to bus's list of devices.
|
|
- * - Try to attach to driver.
|
|
+ * - Automatically probe for a driver if the bus allows it.
|
|
*/
|
|
-void bus_attach_device(struct device *dev)
|
|
+void bus_probe_device(struct device *dev)
|
|
{
|
|
struct bus_type *bus = dev->bus;
|
|
- int ret = 0;
|
|
+ int ret;
|
|
|
|
- if (bus) {
|
|
- if (bus->p->drivers_autoprobe)
|
|
- ret = device_attach(dev);
|
|
+ if (bus && bus->p->drivers_autoprobe) {
|
|
+ ret = device_attach(dev);
|
|
WARN_ON(ret < 0);
|
|
- if (ret >= 0)
|
|
- klist_add_tail(&dev->p->knode_bus,
|
|
- &bus->p->klist_devices);
|
|
}
|
|
}
|
|
|
|
diff --git a/drivers/base/core.c b/drivers/base/core.c
|
|
index 7ecb193..c34774d 100644
|
|
--- a/drivers/base/core.c
|
|
+++ b/drivers/base/core.c
|
|
@@ -945,7 +945,7 @@ int device_add(struct device *dev)
|
|
BUS_NOTIFY_ADD_DEVICE, dev);
|
|
|
|
kobject_uevent(&dev->kobj, KOBJ_ADD);
|
|
- bus_attach_device(dev);
|
|
+ bus_probe_device(dev);
|
|
if (parent)
|
|
klist_add_tail(&dev->p->knode_parent,
|
|
&parent->p->klist_children);
|
|
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
|
|
index dee0f1f..6cf88b6 100644
|
|
--- a/drivers/char/agp/intel-agp.c
|
|
+++ b/drivers/char/agp/intel-agp.c
|
|
@@ -679,23 +679,39 @@ static void intel_i830_setup_flush(void)
|
|
if (!intel_private.i8xx_page)
|
|
return;
|
|
|
|
- /* make page uncached */
|
|
- map_page_into_agp(intel_private.i8xx_page);
|
|
-
|
|
intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page);
|
|
if (!intel_private.i8xx_flush_page)
|
|
intel_i830_fini_flush();
|
|
}
|
|
|
|
+static void
|
|
+do_wbinvd(void *null)
|
|
+{
|
|
+ wbinvd();
|
|
+}
|
|
+
|
|
+/* The chipset_flush interface needs to get data that has already been
|
|
+ * flushed out of the CPU all the way out to main memory, because the GPU
|
|
+ * doesn't snoop those buffers.
|
|
+ *
|
|
+ * The 8xx series doesn't have the same lovely interface for flushing the
|
|
+ * chipset write buffers that the later chips do. According to the 865
|
|
+ * specs, it's 64 octwords, or 1KB. So, to get those previous things in
|
|
+ * that buffer out, we just fill 1KB and clflush it out, on the assumption
|
|
+ * that it'll push whatever was in there out. It appears to work.
|
|
+ */
|
|
static void intel_i830_chipset_flush(struct agp_bridge_data *bridge)
|
|
{
|
|
unsigned int *pg = intel_private.i8xx_flush_page;
|
|
- int i;
|
|
|
|
- for (i = 0; i < 256; i += 2)
|
|
- *(pg + i) = i;
|
|
+ memset(pg, 0, 1024);
|
|
|
|
- wmb();
|
|
+ if (cpu_has_clflush) {
|
|
+ clflush_cache_range(pg, 1024);
|
|
+ } else {
|
|
+ if (on_each_cpu(do_wbinvd, NULL, 1) != 0)
|
|
+ printk(KERN_ERR "Timed out waiting for cache flush.\n");
|
|
+ }
|
|
}
|
|
|
|
/* The intel i830 automatically initializes the agp aperture during POST.
|
|
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
|
|
index b33d668..53761ce 100644
|
|
--- a/drivers/char/pty.c
|
|
+++ b/drivers/char/pty.c
|
|
@@ -120,8 +120,10 @@ static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c)
|
|
/* Stuff the data into the input queue of the other end */
|
|
c = tty_insert_flip_string(to, buf, c);
|
|
/* And shovel */
|
|
- tty_flip_buffer_push(to);
|
|
- tty_wakeup(tty);
|
|
+ if (c) {
|
|
+ tty_flip_buffer_push(to);
|
|
+ tty_wakeup(tty);
|
|
+ }
|
|
}
|
|
return c;
|
|
}
|
|
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
|
|
index a3afa0c..9fc9517 100644
|
|
--- a/drivers/char/tty_io.c
|
|
+++ b/drivers/char/tty_io.c
|
|
@@ -1184,6 +1184,7 @@ int tty_init_termios(struct tty_struct *tty)
|
|
tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
|
|
return 0;
|
|
}
|
|
+EXPORT_SYMBOL_GPL(tty_init_termios);
|
|
|
|
/**
|
|
* tty_driver_install_tty() - install a tty entry in the driver
|
|
diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c
|
|
index 9769b11..549bd0f 100644
|
|
--- a/drivers/char/tty_port.c
|
|
+++ b/drivers/char/tty_port.c
|
|
@@ -96,6 +96,14 @@ void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
|
|
}
|
|
EXPORT_SYMBOL(tty_port_tty_set);
|
|
|
|
+static void tty_port_shutdown(struct tty_port *port)
|
|
+{
|
|
+ if (port->ops->shutdown &&
|
|
+ test_and_clear_bit(ASYNC_INITIALIZED, &port->flags))
|
|
+ port->ops->shutdown(port);
|
|
+
|
|
+}
|
|
+
|
|
/**
|
|
* tty_port_hangup - hangup helper
|
|
* @port: tty port
|
|
@@ -116,6 +124,7 @@ void tty_port_hangup(struct tty_port *port)
|
|
port->tty = NULL;
|
|
spin_unlock_irqrestore(&port->lock, flags);
|
|
wake_up_interruptible(&port->open_wait);
|
|
+ tty_port_shutdown(port);
|
|
}
|
|
EXPORT_SYMBOL(tty_port_hangup);
|
|
|
|
@@ -296,15 +305,17 @@ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct f
|
|
|
|
if (port->count) {
|
|
spin_unlock_irqrestore(&port->lock, flags);
|
|
+ if (port->ops->drop)
|
|
+ port->ops->drop(port);
|
|
return 0;
|
|
}
|
|
- port->flags |= ASYNC_CLOSING;
|
|
+ set_bit(ASYNC_CLOSING, &port->flags);
|
|
tty->closing = 1;
|
|
spin_unlock_irqrestore(&port->lock, flags);
|
|
/* Don't block on a stalled port, just pull the chain */
|
|
if (tty->flow_stopped)
|
|
tty_driver_flush_buffer(tty);
|
|
- if (port->flags & ASYNC_INITIALIZED &&
|
|
+ if (test_bit(ASYNCB_INITIALIZED, &port->flags) &&
|
|
port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
|
|
tty_wait_until_sent(tty, port->closing_wait);
|
|
if (port->drain_delay) {
|
|
@@ -318,6 +329,9 @@ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct f
|
|
timeout = 2 * HZ;
|
|
schedule_timeout_interruptible(timeout);
|
|
}
|
|
+ /* Don't call port->drop for the last reference. Callers will want
|
|
+ to drop the last active reference in ->shutdown() or the tty
|
|
+ shutdown path */
|
|
return 1;
|
|
}
|
|
EXPORT_SYMBOL(tty_port_close_start);
|
|
@@ -348,3 +362,14 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
|
|
spin_unlock_irqrestore(&port->lock, flags);
|
|
}
|
|
EXPORT_SYMBOL(tty_port_close_end);
|
|
+
|
|
+void tty_port_close(struct tty_port *port, struct tty_struct *tty,
|
|
+ struct file *filp)
|
|
+{
|
|
+ if (tty_port_close_start(port, tty, filp) == 0)
|
|
+ return;
|
|
+ tty_port_shutdown(port);
|
|
+ tty_port_close_end(port, tty);
|
|
+ tty_port_tty_set(port, NULL);
|
|
+}
|
|
+EXPORT_SYMBOL(tty_port_close);
|
|
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
|
|
index fc4b68a..c078d99 100644
|
|
--- a/drivers/gpu/drm/i915/i915_drv.c
|
|
+++ b/drivers/gpu/drm/i915/i915_drv.c
|
|
@@ -94,8 +94,6 @@ static int i915_resume(struct drm_device *dev)
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
int ret = 0;
|
|
|
|
- pci_set_power_state(dev->pdev, PCI_D0);
|
|
- pci_restore_state(dev->pdev);
|
|
if (pci_enable_device(dev->pdev))
|
|
return -1;
|
|
pci_set_master(dev->pdev);
|
|
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
|
|
index 80e5ba4..2b7aeee 100644
|
|
--- a/drivers/gpu/drm/i915/i915_gem.c
|
|
+++ b/drivers/gpu/drm/i915/i915_gem.c
|
|
@@ -1151,27 +1151,21 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|
mutex_lock(&dev->struct_mutex);
|
|
if (!obj_priv->gtt_space) {
|
|
ret = i915_gem_object_bind_to_gtt(obj, obj_priv->gtt_alignment);
|
|
- if (ret) {
|
|
- mutex_unlock(&dev->struct_mutex);
|
|
- return VM_FAULT_SIGBUS;
|
|
- }
|
|
-
|
|
- ret = i915_gem_object_set_to_gtt_domain(obj, write);
|
|
- if (ret) {
|
|
- mutex_unlock(&dev->struct_mutex);
|
|
- return VM_FAULT_SIGBUS;
|
|
- }
|
|
+ if (ret)
|
|
+ goto unlock;
|
|
|
|
list_add_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
|
|
+
|
|
+ ret = i915_gem_object_set_to_gtt_domain(obj, write);
|
|
+ if (ret)
|
|
+ goto unlock;
|
|
}
|
|
|
|
/* Need a new fence register? */
|
|
if (obj_priv->tiling_mode != I915_TILING_NONE) {
|
|
ret = i915_gem_object_get_fence_reg(obj);
|
|
- if (ret) {
|
|
- mutex_unlock(&dev->struct_mutex);
|
|
- return VM_FAULT_SIGBUS;
|
|
- }
|
|
+ if (ret)
|
|
+ goto unlock;
|
|
}
|
|
|
|
pfn = ((dev->agp->base + obj_priv->gtt_offset) >> PAGE_SHIFT) +
|
|
@@ -1179,18 +1173,18 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|
|
|
/* Finally, remap it using the new GTT offset */
|
|
ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn);
|
|
-
|
|
+unlock:
|
|
mutex_unlock(&dev->struct_mutex);
|
|
|
|
switch (ret) {
|
|
+ case 0:
|
|
+ case -ERESTARTSYS:
|
|
+ return VM_FAULT_NOPAGE;
|
|
case -ENOMEM:
|
|
case -EAGAIN:
|
|
return VM_FAULT_OOM;
|
|
- case -EFAULT:
|
|
- case -EINVAL:
|
|
- return VM_FAULT_SIGBUS;
|
|
default:
|
|
- return VM_FAULT_NOPAGE;
|
|
+ return VM_FAULT_SIGBUS;
|
|
}
|
|
}
|
|
|
|
@@ -2506,16 +2500,6 @@ i915_gem_clflush_object(struct drm_gem_object *obj)
|
|
if (obj_priv->pages == NULL)
|
|
return;
|
|
|
|
- /* XXX: The 865 in particular appears to be weird in how it handles
|
|
- * cache flushing. We haven't figured it out, but the
|
|
- * clflush+agp_chipset_flush doesn't appear to successfully get the
|
|
- * data visible to the PGU, while wbinvd + agp_chipset_flush does.
|
|
- */
|
|
- if (IS_I865G(obj->dev)) {
|
|
- wbinvd();
|
|
- return;
|
|
- }
|
|
-
|
|
drm_clflush_pages(obj_priv->pages, obj->size / PAGE_SIZE);
|
|
}
|
|
|
|
@@ -3007,6 +2991,16 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
|
|
return -EINVAL;
|
|
}
|
|
|
|
+ if (reloc->delta >= target_obj->size) {
|
|
+ DRM_ERROR("Relocation beyond target object bounds: "
|
|
+ "obj %p target %d delta %d size %d.\n",
|
|
+ obj, reloc->target_handle,
|
|
+ (int) reloc->delta, (int) target_obj->size);
|
|
+ drm_gem_object_unreference(target_obj);
|
|
+ i915_gem_object_unpin(obj);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
if (reloc->write_domain & I915_GEM_DOMAIN_CPU ||
|
|
reloc->read_domains & I915_GEM_DOMAIN_CPU) {
|
|
DRM_ERROR("reloc with read/write CPU domains: "
|
|
@@ -3837,7 +3831,8 @@ void i915_gem_free_object(struct drm_gem_object *obj)
|
|
|
|
i915_gem_object_unbind(obj);
|
|
|
|
- i915_gem_free_mmap_offset(obj);
|
|
+ if (obj_priv->mmap_offset)
|
|
+ i915_gem_free_mmap_offset(obj);
|
|
|
|
kfree(obj_priv->page_cpu_valid);
|
|
kfree(obj_priv->bit_17);
|
|
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
|
|
index a2d527b..e774a4a 100644
|
|
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
|
|
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
|
|
@@ -234,7 +234,13 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
|
|
uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
|
|
bool need_disable;
|
|
|
|
- if (!IS_I9XX(dev)) {
|
|
+ if (IS_IGDNG(dev)) {
|
|
+ /* On IGDNG whatever DRAM config, GPU always do
|
|
+ * same swizzling setup.
|
|
+ */
|
|
+ swizzle_x = I915_BIT_6_SWIZZLE_9_10;
|
|
+ swizzle_y = I915_BIT_6_SWIZZLE_9;
|
|
+ } else if (!IS_I9XX(dev)) {
|
|
/* As far as we know, the 865 doesn't have these bit 6
|
|
* swizzling issues.
|
|
*/
|
|
@@ -317,13 +323,6 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
|
|
}
|
|
}
|
|
|
|
- /* FIXME: check with memory config on IGDNG */
|
|
- if (IS_IGDNG(dev)) {
|
|
- DRM_ERROR("disable tiling on IGDNG...\n");
|
|
- swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
|
|
- swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
|
|
- }
|
|
-
|
|
dev_priv->mm.bit_6_swizzle_x = swizzle_x;
|
|
dev_priv->mm.bit_6_swizzle_y = swizzle_y;
|
|
}
|
|
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
|
|
index 2955083..106a1ae 100644
|
|
--- a/drivers/gpu/drm/i915/i915_reg.h
|
|
+++ b/drivers/gpu/drm/i915/i915_reg.h
|
|
@@ -1733,6 +1733,7 @@
|
|
#define DISPPLANE_NO_LINE_DOUBLE 0
|
|
#define DISPPLANE_STEREO_POLARITY_FIRST 0
|
|
#define DISPPLANE_STEREO_POLARITY_SECOND (1<<18)
|
|
+#define DISPPLANE_TRICKLE_FEED_DISABLE (1<<14) /* IGDNG */
|
|
#define DISPPLANE_TILED (1<<10)
|
|
#define DSPAADDR 0x70184
|
|
#define DSPASTRIDE 0x70188
|
|
@@ -1867,6 +1868,8 @@
|
|
#define PF_ENABLE (1<<31)
|
|
#define PFA_WIN_SZ 0x68074
|
|
#define PFB_WIN_SZ 0x68874
|
|
+#define PFA_WIN_POS 0x68070
|
|
+#define PFB_WIN_POS 0x68870
|
|
|
|
/* legacy palette */
|
|
#define LGC_PALETTE_A 0x4a000
|
|
@@ -1913,6 +1916,9 @@
|
|
#define GTIIR 0x44018
|
|
#define GTIER 0x4401c
|
|
|
|
+#define DISP_ARB_CTL 0x45000
|
|
+#define DISP_TILE_SURFACE_SWIZZLING (1<<13)
|
|
+
|
|
/* PCH */
|
|
|
|
/* south display engine interrupt */
|
|
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
|
|
index f806fcc..698a0ed 100644
|
|
--- a/drivers/gpu/drm/i915/intel_bios.c
|
|
+++ b/drivers/gpu/drm/i915/intel_bios.c
|
|
@@ -217,6 +217,9 @@ parse_general_features(struct drm_i915_private *dev_priv,
|
|
if (IS_I85X(dev_priv->dev))
|
|
dev_priv->lvds_ssc_freq =
|
|
general->ssc_freq ? 66 : 48;
|
|
+ else if (IS_IGDNG(dev_priv->dev))
|
|
+ dev_priv->lvds_ssc_freq =
|
|
+ general->ssc_freq ? 100 : 120;
|
|
else
|
|
dev_priv->lvds_ssc_freq =
|
|
general->ssc_freq ? 100 : 96;
|
|
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
|
|
index 590f81c..5ae4c1a 100644
|
|
--- a/drivers/gpu/drm/i915/intel_crt.c
|
|
+++ b/drivers/gpu/drm/i915/intel_crt.c
|
|
@@ -151,13 +151,10 @@ static bool intel_igdng_crt_detect_hotplug(struct drm_connector *connector)
|
|
{
|
|
struct drm_device *dev = connector->dev;
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
- u32 adpa, temp;
|
|
+ u32 adpa;
|
|
bool ret;
|
|
|
|
- temp = adpa = I915_READ(PCH_ADPA);
|
|
-
|
|
- adpa &= ~ADPA_DAC_ENABLE;
|
|
- I915_WRITE(PCH_ADPA, adpa);
|
|
+ adpa = I915_READ(PCH_ADPA);
|
|
|
|
adpa &= ~ADPA_CRT_HOTPLUG_MASK;
|
|
|
|
@@ -184,8 +181,6 @@ static bool intel_igdng_crt_detect_hotplug(struct drm_connector *connector)
|
|
else
|
|
ret = false;
|
|
|
|
- /* restore origin register */
|
|
- I915_WRITE(PCH_ADPA, temp);
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
|
|
index 748ed50..8b5af29 100644
|
|
--- a/drivers/gpu/drm/i915/intel_display.c
|
|
+++ b/drivers/gpu/drm/i915/intel_display.c
|
|
@@ -818,7 +818,7 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
|
refclk, best_clock);
|
|
|
|
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
|
|
- if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
|
|
+ if ((I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) ==
|
|
LVDS_CLKB_POWER_UP)
|
|
clock.p2 = limit->p2.p2_fast;
|
|
else
|
|
@@ -1008,6 +1008,10 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
|
|
dspcntr &= ~DISPPLANE_TILED;
|
|
}
|
|
|
|
+ if (IS_IGDNG(dev))
|
|
+ /* must disable */
|
|
+ dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
|
|
+
|
|
I915_WRITE(dspcntr_reg, dspcntr);
|
|
|
|
Start = obj_priv->gtt_offset;
|
|
@@ -1154,6 +1158,7 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
|
|
int transconf_reg = (pipe == 0) ? TRANSACONF : TRANSBCONF;
|
|
int pf_ctl_reg = (pipe == 0) ? PFA_CTL_1 : PFB_CTL_1;
|
|
int pf_win_size = (pipe == 0) ? PFA_WIN_SZ : PFB_WIN_SZ;
|
|
+ int pf_win_pos = (pipe == 0) ? PFA_WIN_POS : PFB_WIN_POS;
|
|
int cpu_htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
|
|
int cpu_hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
|
|
int cpu_hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
|
|
@@ -1205,6 +1210,19 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
|
|
}
|
|
}
|
|
|
|
+ /* Enable panel fitting for LVDS */
|
|
+ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
|
|
+ temp = I915_READ(pf_ctl_reg);
|
|
+ I915_WRITE(pf_ctl_reg, temp | PF_ENABLE);
|
|
+
|
|
+ /* currently full aspect */
|
|
+ I915_WRITE(pf_win_pos, 0);
|
|
+
|
|
+ I915_WRITE(pf_win_size,
|
|
+ (dev_priv->panel_fixed_mode->hdisplay << 16) |
|
|
+ (dev_priv->panel_fixed_mode->vdisplay));
|
|
+ }
|
|
+
|
|
/* Enable CPU pipe */
|
|
temp = I915_READ(pipeconf_reg);
|
|
if ((temp & PIPEACONF_ENABLE) == 0) {
|
|
@@ -1858,7 +1876,14 @@ static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
|
|
{
|
|
long entries_required, wm_size;
|
|
|
|
- entries_required = (clock_in_khz * pixel_size * latency_ns) / 1000000;
|
|
+ /*
|
|
+ * Note: we need to make sure we don't overflow for various clock &
|
|
+ * latency values.
|
|
+ * clocks go from a few thousand to several hundred thousand.
|
|
+ * latency is usually a few thousand
|
|
+ */
|
|
+ entries_required = ((clock_in_khz / 1000) * pixel_size * latency_ns) /
|
|
+ 1000;
|
|
entries_required /= wm->cacheline_size;
|
|
|
|
DRM_DEBUG("FIFO entries required for mode: %d\n", entries_required);
|
|
@@ -2616,6 +2641,12 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
|
|
|
|
intel_wait_for_vblank(dev);
|
|
|
|
+ if (IS_IGDNG(dev)) {
|
|
+ /* enable address swizzle for tiling buffer */
|
|
+ temp = I915_READ(DISP_ARB_CTL);
|
|
+ I915_WRITE(DISP_ARB_CTL, temp | DISP_TILE_SURFACE_SWIZZLING);
|
|
+ }
|
|
+
|
|
I915_WRITE(dspcntr_reg, dspcntr);
|
|
|
|
/* Flush the plane changes */
|
|
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
|
|
index 8df02ef..b7d091b 100644
|
|
--- a/drivers/gpu/drm/i915/intel_lvds.c
|
|
+++ b/drivers/gpu/drm/i915/intel_lvds.c
|
|
@@ -305,6 +305,10 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
|
|
goto out;
|
|
}
|
|
|
|
+ /* full screen scale for now */
|
|
+ if (IS_IGDNG(dev))
|
|
+ goto out;
|
|
+
|
|
/* 965+ wants fuzzy fitting */
|
|
if (IS_I965G(dev))
|
|
pfit_control |= (intel_crtc->pipe << PFIT_PIPE_SHIFT) |
|
|
@@ -332,8 +336,10 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
|
|
* to register description and PRM.
|
|
* Change the value here to see the borders for debugging
|
|
*/
|
|
- I915_WRITE(BCLRPAT_A, 0);
|
|
- I915_WRITE(BCLRPAT_B, 0);
|
|
+ if (!IS_IGDNG(dev)) {
|
|
+ I915_WRITE(BCLRPAT_A, 0);
|
|
+ I915_WRITE(BCLRPAT_B, 0);
|
|
+ }
|
|
|
|
switch (lvds_priv->fitting_mode) {
|
|
case DRM_MODE_SCALE_NO_SCALE:
|
|
@@ -582,7 +588,6 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
|
|
* settings.
|
|
*/
|
|
|
|
- /* No panel fitting yet, fixme */
|
|
if (IS_IGDNG(dev))
|
|
return;
|
|
|
|
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
|
|
index d3b74ba..66dc1a5 100644
|
|
--- a/drivers/gpu/drm/i915/intel_sdvo.c
|
|
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
|
|
@@ -114,6 +114,9 @@ struct intel_sdvo_priv {
|
|
/* DDC bus used by this SDVO output */
|
|
uint8_t ddc_bus;
|
|
|
|
+ /* Mac mini hack -- use the same DDC as the analog connector */
|
|
+ struct i2c_adapter *analog_ddc_bus;
|
|
+
|
|
int save_sdvo_mult;
|
|
u16 save_active_outputs;
|
|
struct intel_sdvo_dtd save_input_dtd_1, save_input_dtd_2;
|
|
@@ -1478,6 +1481,36 @@ intel_sdvo_multifunc_encoder(struct intel_output *intel_output)
|
|
return (caps > 1);
|
|
}
|
|
|
|
+static struct drm_connector *
|
|
+intel_find_analog_connector(struct drm_device *dev)
|
|
+{
|
|
+ struct drm_connector *connector;
|
|
+ struct intel_output *intel_output;
|
|
+
|
|
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
|
+ intel_output = to_intel_output(connector);
|
|
+ if (intel_output->type == INTEL_OUTPUT_ANALOG)
|
|
+ return connector;
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static int
|
|
+intel_analog_is_connected(struct drm_device *dev)
|
|
+{
|
|
+ struct drm_connector *analog_connector;
|
|
+ analog_connector = intel_find_analog_connector(dev);
|
|
+
|
|
+ if (!analog_connector)
|
|
+ return false;
|
|
+
|
|
+ if (analog_connector->funcs->detect(analog_connector) ==
|
|
+ connector_status_disconnected)
|
|
+ return false;
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
enum drm_connector_status
|
|
intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response)
|
|
{
|
|
@@ -1488,6 +1521,15 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response)
|
|
|
|
edid = drm_get_edid(&intel_output->base,
|
|
intel_output->ddc_bus);
|
|
+
|
|
+ /* when there is no edid and no monitor is connected with VGA
|
|
+ * port, try to use the CRT ddc to read the EDID for DVI-connector
|
|
+ */
|
|
+ if (edid == NULL &&
|
|
+ sdvo_priv->analog_ddc_bus &&
|
|
+ !intel_analog_is_connected(intel_output->base.dev))
|
|
+ edid = drm_get_edid(&intel_output->base,
|
|
+ sdvo_priv->analog_ddc_bus);
|
|
if (edid != NULL) {
|
|
/* Don't report the output as connected if it's a DVI-I
|
|
* connector with a non-digital EDID coming out.
|
|
@@ -1540,31 +1582,32 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect
|
|
static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
|
|
{
|
|
struct intel_output *intel_output = to_intel_output(connector);
|
|
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
|
|
+ int num_modes;
|
|
|
|
/* set the bus switch and get the modes */
|
|
- intel_ddc_get_modes(intel_output);
|
|
+ num_modes = intel_ddc_get_modes(intel_output);
|
|
|
|
-#if 0
|
|
- struct drm_device *dev = encoder->dev;
|
|
- struct drm_i915_private *dev_priv = dev->dev_private;
|
|
- /* Mac mini hack. On this device, I get DDC through the analog, which
|
|
- * load-detects as disconnected. I fail to DDC through the SDVO DDC,
|
|
- * but it does load-detect as connected. So, just steal the DDC bits
|
|
- * from analog when we fail at finding it the right way.
|
|
+ /*
|
|
+ * Mac mini hack. On this device, the DVI-I connector shares one DDC
|
|
+ * link between analog and digital outputs. So, if the regular SDVO
|
|
+ * DDC fails, check to see if the analog output is disconnected, in
|
|
+ * which case we'll look there for the digital DDC data.
|
|
*/
|
|
- crt = xf86_config->output[0];
|
|
- intel_output = crt->driver_private;
|
|
- if (intel_output->type == I830_OUTPUT_ANALOG &&
|
|
- crt->funcs->detect(crt) == XF86OutputStatusDisconnected) {
|
|
- I830I2CInit(pScrn, &intel_output->pDDCBus, GPIOA, "CRTDDC_A");
|
|
- edid_mon = xf86OutputGetEDID(crt, intel_output->pDDCBus);
|
|
- xf86DestroyI2CBusRec(intel_output->pDDCBus, true, true);
|
|
- }
|
|
- if (edid_mon) {
|
|
- xf86OutputSetEDID(output, edid_mon);
|
|
- modes = xf86OutputGetEDIDModes(output);
|
|
+ if (num_modes == 0 &&
|
|
+ sdvo_priv->analog_ddc_bus &&
|
|
+ !intel_analog_is_connected(intel_output->base.dev)) {
|
|
+ struct i2c_adapter *digital_ddc_bus;
|
|
+
|
|
+ /* Switch to the analog ddc bus and try that
|
|
+ */
|
|
+ digital_ddc_bus = intel_output->ddc_bus;
|
|
+ intel_output->ddc_bus = sdvo_priv->analog_ddc_bus;
|
|
+
|
|
+ (void) intel_ddc_get_modes(intel_output);
|
|
+
|
|
+ intel_output->ddc_bus = digital_ddc_bus;
|
|
}
|
|
-#endif
|
|
}
|
|
|
|
/**
|
|
@@ -1748,6 +1791,8 @@ static void intel_sdvo_destroy(struct drm_connector *connector)
|
|
intel_i2c_destroy(intel_output->i2c_bus);
|
|
if (intel_output->ddc_bus)
|
|
intel_i2c_destroy(intel_output->ddc_bus);
|
|
+ if (sdvo_priv->analog_ddc_bus)
|
|
+ intel_i2c_destroy(sdvo_priv->analog_ddc_bus);
|
|
|
|
if (sdvo_priv->sdvo_lvds_fixed_mode != NULL)
|
|
drm_mode_destroy(connector->dev,
|
|
@@ -2074,10 +2119,15 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
|
|
}
|
|
|
|
/* setup the DDC bus. */
|
|
- if (output_device == SDVOB)
|
|
+ if (output_device == SDVOB) {
|
|
intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS");
|
|
- else
|
|
+ sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA,
|
|
+ "SDVOB/VGA DDC BUS");
|
|
+ } else {
|
|
intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS");
|
|
+ sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA,
|
|
+ "SDVOC/VGA DDC BUS");
|
|
+ }
|
|
|
|
if (intel_output->ddc_bus == NULL)
|
|
goto err_i2c;
|
|
@@ -2143,6 +2193,8 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
|
|
return true;
|
|
|
|
err_i2c:
|
|
+ if (sdvo_priv->analog_ddc_bus != NULL)
|
|
+ intel_i2c_destroy(sdvo_priv->analog_ddc_bus);
|
|
if (intel_output->ddc_bus != NULL)
|
|
intel_i2c_destroy(intel_output->ddc_bus);
|
|
if (intel_output->i2c_bus != NULL)
|
|
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
|
|
index 5eb10c2..047844d 100644
|
|
--- a/drivers/hid/hid-core.c
|
|
+++ b/drivers/hid/hid-core.c
|
|
@@ -1319,7 +1319,6 @@ static const struct hid_device_id hid_blacklist[] = {
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
|
|
{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
|
|
|
|
- { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c) },
|
|
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) },
|
|
{ }
|
|
};
|
|
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c
|
|
index 8ff7e35..f33ac27 100644
|
|
--- a/drivers/isdn/gigaset/interface.c
|
|
+++ b/drivers/isdn/gigaset/interface.c
|
|
@@ -408,33 +408,28 @@ static int if_write_room(struct tty_struct *tty)
|
|
return retval;
|
|
}
|
|
|
|
-/* FIXME: This function does not have error returns */
|
|
-
|
|
static int if_chars_in_buffer(struct tty_struct *tty)
|
|
{
|
|
struct cardstate *cs;
|
|
- int retval = -ENODEV;
|
|
+ int retval = 0;
|
|
|
|
cs = (struct cardstate *) tty->driver_data;
|
|
if (!cs) {
|
|
pr_err("%s: no cardstate\n", __func__);
|
|
- return -ENODEV;
|
|
+ return 0;
|
|
}
|
|
|
|
gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__);
|
|
|
|
- if (mutex_lock_interruptible(&cs->mutex))
|
|
- return -ERESTARTSYS; // FIXME -EINTR?
|
|
+ mutex_lock(&cs->mutex);
|
|
|
|
- if (!cs->connected) {
|
|
+ if (!cs->connected)
|
|
gig_dbg(DEBUG_IF, "not connected");
|
|
- retval = -ENODEV;
|
|
- } else if (!cs->open_count)
|
|
+ else if (!cs->open_count)
|
|
dev_warn(cs->dev, "%s: device not opened\n", __func__);
|
|
- else if (cs->mstate != MS_LOCKED) {
|
|
+ else if (cs->mstate != MS_LOCKED)
|
|
dev_warn(cs->dev, "can't write to unlocked device\n");
|
|
- retval = -EBUSY;
|
|
- } else
|
|
+ else
|
|
retval = cs->ops->chars_in_buffer(cs);
|
|
|
|
mutex_unlock(&cs->mutex);
|
|
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
|
|
index 1c2e544..ffe9306 100644
|
|
--- a/drivers/media/video/em28xx/em28xx-cards.c
|
|
+++ b/drivers/media/video/em28xx/em28xx-cards.c
|
|
@@ -2170,8 +2170,6 @@ static int em28xx_hint_board(struct em28xx *dev)
|
|
/* ----------------------------------------------------------------------- */
|
|
void em28xx_register_i2c_ir(struct em28xx *dev)
|
|
{
|
|
- struct i2c_board_info info;
|
|
- struct IR_i2c_init_data init_data;
|
|
const unsigned short addr_list[] = {
|
|
0x30, 0x47, I2C_CLIENT_END
|
|
};
|
|
@@ -2179,9 +2177,9 @@ void em28xx_register_i2c_ir(struct em28xx *dev)
|
|
if (disable_ir)
|
|
return;
|
|
|
|
- memset(&info, 0, sizeof(struct i2c_board_info));
|
|
- memset(&init_data, 0, sizeof(struct IR_i2c_init_data));
|
|
- strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
|
|
+ memset(&dev->info, 0, sizeof(&dev->info));
|
|
+ memset(&dev->init_data, 0, sizeof(dev->init_data));
|
|
+ strlcpy(dev->info.type, "ir_video", I2C_NAME_SIZE);
|
|
|
|
/* detect & configure */
|
|
switch (dev->model) {
|
|
@@ -2191,19 +2189,19 @@ void em28xx_register_i2c_ir(struct em28xx *dev)
|
|
break;
|
|
case (EM2800_BOARD_TERRATEC_CINERGY_200):
|
|
case (EM2820_BOARD_TERRATEC_CINERGY_250):
|
|
- init_data.ir_codes = ir_codes_em_terratec;
|
|
- init_data.get_key = em28xx_get_key_terratec;
|
|
- init_data.name = "i2c IR (EM28XX Terratec)";
|
|
+ dev->init_data.ir_codes = ir_codes_em_terratec;
|
|
+ dev->init_data.get_key = em28xx_get_key_terratec;
|
|
+ dev->init_data.name = "i2c IR (EM28XX Terratec)";
|
|
break;
|
|
case (EM2820_BOARD_PINNACLE_USB_2):
|
|
- init_data.ir_codes = ir_codes_pinnacle_grey;
|
|
- init_data.get_key = em28xx_get_key_pinnacle_usb_grey;
|
|
- init_data.name = "i2c IR (EM28XX Pinnacle PCTV)";
|
|
+ dev->init_data.ir_codes = ir_codes_pinnacle_grey;
|
|
+ dev->init_data.get_key = em28xx_get_key_pinnacle_usb_grey;
|
|
+ dev->init_data.name = "i2c IR (EM28XX Pinnacle PCTV)";
|
|
break;
|
|
case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2):
|
|
- init_data.ir_codes = ir_codes_hauppauge_new;
|
|
- init_data.get_key = em28xx_get_key_em_haup;
|
|
- init_data.name = "i2c IR (EM2840 Hauppauge)";
|
|
+ dev->init_data.ir_codes = ir_codes_hauppauge_new;
|
|
+ dev->init_data.get_key = em28xx_get_key_em_haup;
|
|
+ dev->init_data.name = "i2c IR (EM2840 Hauppauge)";
|
|
break;
|
|
case (EM2820_BOARD_MSI_VOX_USB_2):
|
|
break;
|
|
@@ -2215,9 +2213,9 @@ void em28xx_register_i2c_ir(struct em28xx *dev)
|
|
break;
|
|
}
|
|
|
|
- if (init_data.name)
|
|
- info.platform_data = &init_data;
|
|
- i2c_new_probed_device(&dev->i2c_adap, &info, addr_list);
|
|
+ if (dev->init_data.name)
|
|
+ dev->info.platform_data = &dev->init_data;
|
|
+ i2c_new_probed_device(&dev->i2c_adap, &dev->info, addr_list);
|
|
}
|
|
|
|
void em28xx_card_setup(struct em28xx *dev)
|
|
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
|
|
index a2add61..cb2a70a 100644
|
|
--- a/drivers/media/video/em28xx/em28xx.h
|
|
+++ b/drivers/media/video/em28xx/em28xx.h
|
|
@@ -595,6 +595,10 @@ struct em28xx {
|
|
struct delayed_work sbutton_query_work;
|
|
|
|
struct em28xx_dvb *dvb;
|
|
+
|
|
+ /* I2C keyboard data */
|
|
+ struct i2c_board_info info;
|
|
+ struct IR_i2c_init_data init_data;
|
|
};
|
|
|
|
struct em28xx_ops {
|
|
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
|
|
index 6e219c2..69e48ce 100644
|
|
--- a/drivers/media/video/saa7134/saa7134-input.c
|
|
+++ b/drivers/media/video/saa7134/saa7134-input.c
|
|
@@ -684,8 +684,6 @@ void saa7134_input_fini(struct saa7134_dev *dev)
|
|
|
|
void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
|
|
{
|
|
- struct i2c_board_info info;
|
|
- struct IR_i2c_init_data init_data;
|
|
const unsigned short addr_list[] = {
|
|
0x7a, 0x47, 0x71, 0x2d,
|
|
I2C_CLIENT_END
|
|
@@ -705,32 +703,32 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
|
|
return;
|
|
}
|
|
|
|
- memset(&info, 0, sizeof(struct i2c_board_info));
|
|
- memset(&init_data, 0, sizeof(struct IR_i2c_init_data));
|
|
- strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
|
|
+ memset(&dev->info, 0, sizeof(dev->info));
|
|
+ memset(&dev->init_data, 0, sizeof(dev->init_data));
|
|
+ strlcpy(dev->info.type, "ir_video", I2C_NAME_SIZE);
|
|
|
|
switch (dev->board) {
|
|
case SAA7134_BOARD_PINNACLE_PCTV_110i:
|
|
case SAA7134_BOARD_PINNACLE_PCTV_310i:
|
|
- init_data.name = "Pinnacle PCTV";
|
|
+ dev->init_data.name = "Pinnacle PCTV";
|
|
if (pinnacle_remote == 0) {
|
|
- init_data.get_key = get_key_pinnacle_color;
|
|
- init_data.ir_codes = ir_codes_pinnacle_color;
|
|
+ dev->init_data.get_key = get_key_pinnacle_color;
|
|
+ dev->init_data.ir_codes = ir_codes_pinnacle_color;
|
|
} else {
|
|
- init_data.get_key = get_key_pinnacle_grey;
|
|
- init_data.ir_codes = ir_codes_pinnacle_grey;
|
|
+ dev->init_data.get_key = get_key_pinnacle_grey;
|
|
+ dev->init_data.ir_codes = ir_codes_pinnacle_grey;
|
|
}
|
|
break;
|
|
case SAA7134_BOARD_UPMOST_PURPLE_TV:
|
|
- init_data.name = "Purple TV";
|
|
- init_data.get_key = get_key_purpletv;
|
|
- init_data.ir_codes = ir_codes_purpletv;
|
|
+ dev->init_data.name = "Purple TV";
|
|
+ dev->init_data.get_key = get_key_purpletv;
|
|
+ dev->init_data.ir_codes = ir_codes_purpletv;
|
|
break;
|
|
case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS:
|
|
- init_data.name = "MSI TV@nywhere Plus";
|
|
- init_data.get_key = get_key_msi_tvanywhere_plus;
|
|
- init_data.ir_codes = ir_codes_msi_tvanywhere_plus;
|
|
- info.addr = 0x30;
|
|
+ dev->init_data.name = "MSI TV@nywhere Plus";
|
|
+ dev->init_data.get_key = get_key_msi_tvanywhere_plus;
|
|
+ dev->init_data.ir_codes = ir_codes_msi_tvanywhere_plus;
|
|
+ dev->info.addr = 0x30;
|
|
/* MSI TV@nywhere Plus controller doesn't seem to
|
|
respond to probes unless we read something from
|
|
an existing device. Weird...
|
|
@@ -741,9 +739,9 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
|
|
(1 == rc) ? "yes" : "no");
|
|
break;
|
|
case SAA7134_BOARD_HAUPPAUGE_HVR1110:
|
|
- init_data.name = "HVR 1110";
|
|
- init_data.get_key = get_key_hvr1110;
|
|
- init_data.ir_codes = ir_codes_hauppauge_new;
|
|
+ dev->init_data.name = "HVR 1110";
|
|
+ dev->init_data.get_key = get_key_hvr1110;
|
|
+ dev->init_data.ir_codes = ir_codes_hauppauge_new;
|
|
break;
|
|
case SAA7134_BOARD_BEHOLD_607FM_MK3:
|
|
case SAA7134_BOARD_BEHOLD_607FM_MK5:
|
|
@@ -757,26 +755,26 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
|
|
case SAA7134_BOARD_BEHOLD_M63:
|
|
case SAA7134_BOARD_BEHOLD_M6_EXTRA:
|
|
case SAA7134_BOARD_BEHOLD_H6:
|
|
- init_data.name = "BeholdTV";
|
|
- init_data.get_key = get_key_beholdm6xx;
|
|
- init_data.ir_codes = ir_codes_behold;
|
|
+ dev->init_data.name = "BeholdTV";
|
|
+ dev->init_data.get_key = get_key_beholdm6xx;
|
|
+ dev->init_data.ir_codes = ir_codes_behold;
|
|
break;
|
|
case SAA7134_BOARD_AVERMEDIA_CARDBUS_501:
|
|
case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
|
|
- info.addr = 0x40;
|
|
+ dev->info.addr = 0x40;
|
|
break;
|
|
}
|
|
|
|
- if (init_data.name)
|
|
- info.platform_data = &init_data;
|
|
+ if (dev->init_data.name)
|
|
+ dev->info.platform_data = &dev->init_data;
|
|
/* No need to probe if address is known */
|
|
- if (info.addr) {
|
|
- i2c_new_device(&dev->i2c_adap, &info);
|
|
+ if (dev->info.addr) {
|
|
+ i2c_new_device(&dev->i2c_adap, &dev->info);
|
|
return;
|
|
}
|
|
|
|
/* Address not known, fallback to probing */
|
|
- i2c_new_probed_device(&dev->i2c_adap, &info, addr_list);
|
|
+ i2c_new_probed_device(&dev->i2c_adap, &dev->info, addr_list);
|
|
}
|
|
|
|
static int saa7134_rc5_irq(struct saa7134_dev *dev)
|
|
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
|
|
index fb564f1..4d85f5c 100644
|
|
--- a/drivers/media/video/saa7134/saa7134.h
|
|
+++ b/drivers/media/video/saa7134/saa7134.h
|
|
@@ -584,6 +584,10 @@ struct saa7134_dev {
|
|
int nosignal;
|
|
unsigned int insuspend;
|
|
|
|
+ /* I2C keyboard data */
|
|
+ struct i2c_board_info info;
|
|
+ struct IR_i2c_init_data init_data;
|
|
+
|
|
/* SAA7134_MPEG_* */
|
|
struct saa7134_ts ts;
|
|
struct saa7134_dmaqueue ts_q;
|
|
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
|
|
index 5d0ba4f..9ad7bb4 100644
|
|
--- a/drivers/message/fusion/mptbase.c
|
|
+++ b/drivers/message/fusion/mptbase.c
|
|
@@ -1015,9 +1015,9 @@ mpt_add_sge_64bit(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
|
|
{
|
|
SGESimple64_t *pSge = (SGESimple64_t *) pAddr;
|
|
pSge->Address.Low = cpu_to_le32
|
|
- (lower_32_bits((unsigned long)(dma_addr)));
|
|
+ (lower_32_bits(dma_addr));
|
|
pSge->Address.High = cpu_to_le32
|
|
- (upper_32_bits((unsigned long)dma_addr));
|
|
+ (upper_32_bits(dma_addr));
|
|
pSge->FlagsLength = cpu_to_le32
|
|
((flagslength | MPT_SGE_FLAGS_64_BIT_ADDRESSING));
|
|
}
|
|
@@ -1038,8 +1038,8 @@ mpt_add_sge_64bit_1078(void *pAddr, u32 flagslength, dma_addr_t dma_addr)
|
|
u32 tmp;
|
|
|
|
pSge->Address.Low = cpu_to_le32
|
|
- (lower_32_bits((unsigned long)(dma_addr)));
|
|
- tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
|
|
+ (lower_32_bits(dma_addr));
|
|
+ tmp = (u32)(upper_32_bits(dma_addr));
|
|
|
|
/*
|
|
* 1078 errata workaround for the 36GB limitation
|
|
@@ -1101,7 +1101,7 @@ mpt_add_chain_64bit(void *pAddr, u8 next, u16 length, dma_addr_t dma_addr)
|
|
pChain->NextChainOffset = next;
|
|
|
|
pChain->Address.Low = cpu_to_le32(tmp);
|
|
- tmp = (u32)(upper_32_bits((unsigned long)dma_addr));
|
|
+ tmp = (u32)(upper_32_bits(dma_addr));
|
|
pChain->Address.High = cpu_to_le32(tmp);
|
|
}
|
|
|
|
diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c
|
|
index 13e7d7b..dd8b6b3 100644
|
|
--- a/drivers/mfd/ab3100-core.c
|
|
+++ b/drivers/mfd/ab3100-core.c
|
|
@@ -643,7 +643,7 @@ struct ab3100_init_setting {
|
|
u8 setting;
|
|
};
|
|
|
|
-static const struct ab3100_init_setting __initdata
|
|
+static const struct ab3100_init_setting __initconst
|
|
ab3100_init_settings[] = {
|
|
{
|
|
.abreg = AB3100_MCA,
|
|
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
|
|
index 06084db..72f2df1 100644
|
|
--- a/drivers/mmc/core/mmc.c
|
|
+++ b/drivers/mmc/core/mmc.c
|
|
@@ -180,11 +180,11 @@ static int mmc_read_ext_csd(struct mmc_card *card)
|
|
|
|
err = mmc_send_ext_csd(card, ext_csd);
|
|
if (err) {
|
|
- /*
|
|
- * We all hosts that cannot perform the command
|
|
- * to fail more gracefully
|
|
- */
|
|
- if (err != -EINVAL)
|
|
+ /* If the host or the card can't do the switch,
|
|
+ * fail more gracefully. */
|
|
+ if ((err != -EINVAL)
|
|
+ && (err != -ENOSYS)
|
|
+ && (err != -EFAULT))
|
|
goto out;
|
|
|
|
/*
|
|
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
|
|
index cd81c39..65c32bf 100644
|
|
--- a/drivers/mmc/core/sd.c
|
|
+++ b/drivers/mmc/core/sd.c
|
|
@@ -210,11 +210,11 @@ static int mmc_read_switch(struct mmc_card *card)
|
|
|
|
err = mmc_sd_switch(card, 0, 0, 1, status);
|
|
if (err) {
|
|
- /*
|
|
- * We all hosts that cannot perform the command
|
|
- * to fail more gracefully
|
|
- */
|
|
- if (err != -EINVAL)
|
|
+ /* If the host or the card can't do the switch,
|
|
+ * fail more gracefully. */
|
|
+ if ((err != -EINVAL)
|
|
+ && (err != -ENOSYS)
|
|
+ && (err != -EFAULT))
|
|
goto out;
|
|
|
|
printk(KERN_WARNING "%s: problem reading switch "
|
|
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
|
|
index 61ea833..94bb61e 100644
|
|
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
|
|
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
|
|
@@ -282,16 +282,6 @@ static void fixup_s29gl032n_sectors(struct mtd_info *mtd, void *param)
|
|
}
|
|
}
|
|
|
|
-static void fixup_M29W128G_write_buffer(struct mtd_info *mtd, void *param)
|
|
-{
|
|
- struct map_info *map = mtd->priv;
|
|
- struct cfi_private *cfi = map->fldrv_priv;
|
|
- if (cfi->cfiq->BufWriteTimeoutTyp) {
|
|
- pr_warning("Don't use write buffer on ST flash M29W128G\n");
|
|
- cfi->cfiq->BufWriteTimeoutTyp = 0;
|
|
- }
|
|
-}
|
|
-
|
|
static struct cfi_fixup cfi_fixup_table[] = {
|
|
{ CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL },
|
|
#ifdef AMD_BOOTLOC_BUG
|
|
@@ -308,7 +298,6 @@ static struct cfi_fixup cfi_fixup_table[] = {
|
|
{ CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors, NULL, },
|
|
{ CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors, NULL, },
|
|
{ CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors, NULL, },
|
|
- { CFI_MFR_ST, 0x227E, fixup_M29W128G_write_buffer, NULL, },
|
|
#if !FORCE_WORD_WRITE
|
|
{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, },
|
|
#endif
|
|
diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c
|
|
index 34d40e2..c5a84fd 100644
|
|
--- a/drivers/mtd/chips/cfi_util.c
|
|
+++ b/drivers/mtd/chips/cfi_util.c
|
|
@@ -81,6 +81,10 @@ void __xipram cfi_qry_mode_off(uint32_t base, struct map_info *map,
|
|
{
|
|
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
|
|
cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
|
|
+ /* M29W128G flashes require an additional reset command
|
|
+ when exit qry mode */
|
|
+ if ((cfi->mfr == CFI_MFR_ST) && (cfi->id == 0x227E || cfi->id == 0x7E))
|
|
+ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
|
|
}
|
|
EXPORT_SYMBOL_GPL(cfi_qry_mode_off);
|
|
|
|
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
|
|
index 89bf85a..40b5658 100644
|
|
--- a/drivers/mtd/nand/ndfc.c
|
|
+++ b/drivers/mtd/nand/ndfc.c
|
|
@@ -102,8 +102,8 @@ static int ndfc_calculate_ecc(struct mtd_info *mtd,
|
|
wmb();
|
|
ecc = in_be32(ndfc->ndfcbase + NDFC_ECC);
|
|
/* The NDFC uses Smart Media (SMC) bytes order */
|
|
- ecc_code[0] = p[2];
|
|
- ecc_code[1] = p[1];
|
|
+ ecc_code[0] = p[1];
|
|
+ ecc_code[1] = p[2];
|
|
ecc_code[2] = p[3];
|
|
|
|
return 0;
|
|
diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
|
|
index 3e164f0..62d6a78 100644
|
|
--- a/drivers/mtd/ofpart.c
|
|
+++ b/drivers/mtd/ofpart.c
|
|
@@ -46,21 +46,12 @@ int __devinit of_mtd_parse_partitions(struct device *dev,
|
|
const u32 *reg;
|
|
int len;
|
|
|
|
- /* check if this is a partition node */
|
|
- partname = of_get_property(pp, "name", &len);
|
|
- if (strcmp(partname, "partition") != 0) {
|
|
+ reg = of_get_property(pp, "reg", &len);
|
|
+ if (!reg) {
|
|
nr_parts--;
|
|
continue;
|
|
}
|
|
|
|
- reg = of_get_property(pp, "reg", &len);
|
|
- if (!reg || (len != 2 * sizeof(u32))) {
|
|
- of_node_put(pp);
|
|
- dev_err(dev, "Invalid 'reg' on %s\n", node->full_name);
|
|
- kfree(*pparts);
|
|
- *pparts = NULL;
|
|
- return -EINVAL;
|
|
- }
|
|
(*pparts)[i].offset = reg[0];
|
|
(*pparts)[i].size = reg[1];
|
|
|
|
@@ -75,6 +66,14 @@ int __devinit of_mtd_parse_partitions(struct device *dev,
|
|
i++;
|
|
}
|
|
|
|
+ if (!i) {
|
|
+ of_node_put(pp);
|
|
+ dev_err(dev, "No valid partition found on %s\n", node->full_name);
|
|
+ kfree(*pparts);
|
|
+ *pparts = NULL;
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
return nr_parts;
|
|
}
|
|
EXPORT_SYMBOL(of_mtd_parse_partitions);
|
|
diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c
|
|
index a10c1d7..460bb88 100644
|
|
--- a/drivers/net/can/vcan.c
|
|
+++ b/drivers/net/can/vcan.c
|
|
@@ -80,7 +80,7 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
|
|
skb->dev = dev;
|
|
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
|
|
- netif_rx(skb);
|
|
+ netif_rx_ni(skb);
|
|
}
|
|
|
|
static int vcan_tx(struct sk_buff *skb, struct net_device *dev)
|
|
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
|
|
index 1f9ec29..65a43c8 100644
|
|
--- a/drivers/net/usb/kaweth.c
|
|
+++ b/drivers/net/usb/kaweth.c
|
|
@@ -263,6 +263,7 @@ static int kaweth_control(struct kaweth_device *kaweth,
|
|
int timeout)
|
|
{
|
|
struct usb_ctrlrequest *dr;
|
|
+ int retval;
|
|
|
|
dbg("kaweth_control()");
|
|
|
|
@@ -278,18 +279,21 @@ static int kaweth_control(struct kaweth_device *kaweth,
|
|
return -ENOMEM;
|
|
}
|
|
|
|
- dr->bRequestType= requesttype;
|
|
+ dr->bRequestType = requesttype;
|
|
dr->bRequest = request;
|
|
dr->wValue = cpu_to_le16(value);
|
|
dr->wIndex = cpu_to_le16(index);
|
|
dr->wLength = cpu_to_le16(size);
|
|
|
|
- return kaweth_internal_control_msg(kaweth->dev,
|
|
- pipe,
|
|
- dr,
|
|
- data,
|
|
- size,
|
|
- timeout);
|
|
+ retval = kaweth_internal_control_msg(kaweth->dev,
|
|
+ pipe,
|
|
+ dr,
|
|
+ data,
|
|
+ size,
|
|
+ timeout);
|
|
+
|
|
+ kfree(dr);
|
|
+ return retval;
|
|
}
|
|
|
|
/****************************************************************
|
|
diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c
|
|
index 007eb85..1084ca6 100644
|
|
--- a/drivers/net/wireless/ath/ar9170/usb.c
|
|
+++ b/drivers/net/wireless/ath/ar9170/usb.c
|
|
@@ -64,6 +64,8 @@ static struct usb_device_id ar9170_usb_ids[] = {
|
|
{ USB_DEVICE(0x0cf3, 0x9170) },
|
|
/* Atheros TG121N */
|
|
{ USB_DEVICE(0x0cf3, 0x1001) },
|
|
+ /* TP-Link TL-WN821N v2 */
|
|
+ { USB_DEVICE(0x0cf3, 0x1002) },
|
|
/* Cace Airpcap NX */
|
|
{ USB_DEVICE(0xcace, 0x0300) },
|
|
/* D-Link DWA 160A */
|
|
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
|
|
index 6358233..778baf7 100644
|
|
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
|
|
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
|
|
@@ -1164,6 +1164,7 @@ extern void ath5k_unregister_leds(struct ath5k_softc *sc);
|
|
|
|
/* Reset Functions */
|
|
extern int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial);
|
|
+extern int ath5k_hw_on_hold(struct ath5k_hw *ah);
|
|
extern int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, struct ieee80211_channel *channel, bool change_channel);
|
|
/* Power management functions */
|
|
extern int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration);
|
|
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
|
|
index c41ef58..605b8f6 100644
|
|
--- a/drivers/net/wireless/ath/ath5k/attach.c
|
|
+++ b/drivers/net/wireless/ath/ath5k/attach.c
|
|
@@ -145,7 +145,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
|
|
goto err_free;
|
|
|
|
/* Bring device out of sleep and reset it's units */
|
|
- ret = ath5k_hw_nic_wakeup(ah, CHANNEL_B, true);
|
|
+ ret = ath5k_hw_nic_wakeup(ah, 0, true);
|
|
if (ret)
|
|
goto err_free;
|
|
|
|
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
|
|
index ba6d225..753f50e 100644
|
|
--- a/drivers/net/wireless/ath/ath5k/base.c
|
|
+++ b/drivers/net/wireless/ath/ath5k/base.c
|
|
@@ -666,7 +666,6 @@ ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state)
|
|
|
|
ath5k_led_off(sc);
|
|
|
|
- free_irq(pdev->irq, sc);
|
|
pci_save_state(pdev);
|
|
pci_disable_device(pdev);
|
|
pci_set_power_state(pdev, PCI_D3hot);
|
|
@@ -694,18 +693,8 @@ ath5k_pci_resume(struct pci_dev *pdev)
|
|
*/
|
|
pci_write_config_byte(pdev, 0x41, 0);
|
|
|
|
- err = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
|
|
- if (err) {
|
|
- ATH5K_ERR(sc, "request_irq failed\n");
|
|
- goto err_no_irq;
|
|
- }
|
|
-
|
|
ath5k_led_enable(sc);
|
|
return 0;
|
|
-
|
|
-err_no_irq:
|
|
- pci_disable_device(pdev);
|
|
- return err;
|
|
}
|
|
#endif /* CONFIG_PM */
|
|
|
|
@@ -2445,27 +2434,29 @@ ath5k_stop_hw(struct ath5k_softc *sc)
|
|
ret = ath5k_stop_locked(sc);
|
|
if (ret == 0 && !test_bit(ATH_STAT_INVALID, sc->status)) {
|
|
/*
|
|
- * Set the chip in full sleep mode. Note that we are
|
|
- * careful to do this only when bringing the interface
|
|
- * completely to a stop. When the chip is in this state
|
|
- * it must be carefully woken up or references to
|
|
- * registers in the PCI clock domain may freeze the bus
|
|
- * (and system). This varies by chip and is mostly an
|
|
- * issue with newer parts that go to sleep more quickly.
|
|
- */
|
|
- if (sc->ah->ah_mac_srev >= 0x78) {
|
|
- /*
|
|
- * XXX
|
|
- * don't put newer MAC revisions > 7.8 to sleep because
|
|
- * of the above mentioned problems
|
|
- */
|
|
- ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mac version > 7.8, "
|
|
- "not putting device to sleep\n");
|
|
- } else {
|
|
- ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
|
|
- "putting device to full sleep\n");
|
|
- ath5k_hw_set_power(sc->ah, AR5K_PM_FULL_SLEEP, true, 0);
|
|
- }
|
|
+ * Don't set the card in full sleep mode!
|
|
+ *
|
|
+ * a) When the device is in this state it must be carefully
|
|
+ * woken up or references to registers in the PCI clock
|
|
+ * domain may freeze the bus (and system). This varies
|
|
+ * by chip and is mostly an issue with newer parts
|
|
+ * (madwifi sources mentioned srev >= 0x78) that go to
|
|
+ * sleep more quickly.
|
|
+ *
|
|
+ * b) On older chips full sleep results a weird behaviour
|
|
+ * during wakeup. I tested various cards with srev < 0x78
|
|
+ * and they don't wake up after module reload, a second
|
|
+ * module reload is needed to bring the card up again.
|
|
+ *
|
|
+ * Until we figure out what's going on don't enable
|
|
+ * full chip reset on any chip (this is what Legacy HAL
|
|
+ * and Sam's HAL do anyway). Instead Perform a full reset
|
|
+ * on the device (same as initial state after attach) and
|
|
+ * leave it idle (keep MAC/BB on warm reset) */
|
|
+ ret = ath5k_hw_on_hold(sc->ah);
|
|
+
|
|
+ ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
|
|
+ "putting device to sleep\n");
|
|
}
|
|
ath5k_txbuf_free(sc, sc->bbuf);
|
|
|
|
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
|
|
index bd0a97a..4980621 100644
|
|
--- a/drivers/net/wireless/ath/ath5k/reset.c
|
|
+++ b/drivers/net/wireless/ath/ath5k/reset.c
|
|
@@ -258,29 +258,35 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
|
|
if (!set_chip)
|
|
goto commit;
|
|
|
|
- /* Preserve sleep duration */
|
|
data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL);
|
|
+
|
|
+ /* If card is down we 'll get 0xffff... so we
|
|
+ * need to clean this up before we write the register
|
|
+ */
|
|
if (data & 0xffc00000)
|
|
data = 0;
|
|
else
|
|
- data = data & 0xfffcffff;
|
|
+ /* Preserve sleep duration etc */
|
|
+ data = data & ~AR5K_SLEEP_CTL_SLE;
|
|
|
|
- ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);
|
|
+ ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE,
|
|
+ AR5K_SLEEP_CTL);
|
|
udelay(15);
|
|
|
|
- for (i = 50; i > 0; i--) {
|
|
+ for (i = 200; i > 0; i--) {
|
|
/* Check if the chip did wake up */
|
|
if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) &
|
|
AR5K_PCICFG_SPWR_DN) == 0)
|
|
break;
|
|
|
|
/* Wait a bit and retry */
|
|
- udelay(200);
|
|
- ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);
|
|
+ udelay(50);
|
|
+ ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE,
|
|
+ AR5K_SLEEP_CTL);
|
|
}
|
|
|
|
/* Fail if the chip didn't wake up */
|
|
- if (i <= 0)
|
|
+ if (i == 0)
|
|
return -EIO;
|
|
|
|
break;
|
|
@@ -297,6 +303,64 @@ commit:
|
|
}
|
|
|
|
/*
|
|
+ * Put device on hold
|
|
+ *
|
|
+ * Put MAC and Baseband on warm reset and
|
|
+ * keep that state (don't clean sleep control
|
|
+ * register). After this MAC and Baseband are
|
|
+ * disabled and a full reset is needed to come
|
|
+ * back. This way we save as much power as possible
|
|
+ * without puting the card on full sleep.
|
|
+ */
|
|
+int ath5k_hw_on_hold(struct ath5k_hw *ah)
|
|
+{
|
|
+ struct pci_dev *pdev = ah->ah_sc->pdev;
|
|
+ u32 bus_flags;
|
|
+ int ret;
|
|
+
|
|
+ /* Make sure device is awake */
|
|
+ ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
|
|
+ if (ret) {
|
|
+ ATH5K_ERR(ah->ah_sc, "failed to wakeup the MAC Chip\n");
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Put chipset on warm reset...
|
|
+ *
|
|
+ * Note: puting PCI core on warm reset on PCI-E cards
|
|
+ * results card to hang and always return 0xffff... so
|
|
+ * we ingore that flag for PCI-E cards. On PCI cards
|
|
+ * this flag gets cleared after 64 PCI clocks.
|
|
+ */
|
|
+ bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
|
|
+
|
|
+ if (ah->ah_version == AR5K_AR5210) {
|
|
+ ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
|
|
+ AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
|
|
+ AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
|
|
+ mdelay(2);
|
|
+ } else {
|
|
+ ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
|
|
+ AR5K_RESET_CTL_BASEBAND | bus_flags);
|
|
+ }
|
|
+
|
|
+ if (ret) {
|
|
+ ATH5K_ERR(ah->ah_sc, "failed to put device on warm reset\n");
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ /* ...wakeup again!*/
|
|
+ ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
|
|
+ if (ret) {
|
|
+ ATH5K_ERR(ah->ah_sc, "failed to put device on hold\n");
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/*
|
|
* Bring up MAC + PHY Chips and program PLL
|
|
* TODO: Half/Quarter rate support
|
|
*/
|
|
@@ -319,6 +383,50 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
|
|
return ret;
|
|
}
|
|
|
|
+ /*
|
|
+ * Put chipset on warm reset...
|
|
+ *
|
|
+ * Note: puting PCI core on warm reset on PCI-E cards
|
|
+ * results card to hang and always return 0xffff... so
|
|
+ * we ingore that flag for PCI-E cards. On PCI cards
|
|
+ * this flag gets cleared after 64 PCI clocks.
|
|
+ */
|
|
+ bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
|
|
+
|
|
+ if (ah->ah_version == AR5K_AR5210) {
|
|
+ ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
|
|
+ AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
|
|
+ AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
|
|
+ mdelay(2);
|
|
+ } else {
|
|
+ ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
|
|
+ AR5K_RESET_CTL_BASEBAND | bus_flags);
|
|
+ }
|
|
+
|
|
+ if (ret) {
|
|
+ ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n");
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ /* ...wakeup again!...*/
|
|
+ ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
|
|
+ if (ret) {
|
|
+ ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n");
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ /* ...clear reset control register and pull device out of
|
|
+ * warm reset */
|
|
+ if (ath5k_hw_nic_reset(ah, 0)) {
|
|
+ ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n");
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ /* On initialization skip PLL programming since we don't have
|
|
+ * a channel / mode set yet */
|
|
+ if (initial)
|
|
+ return 0;
|
|
+
|
|
if (ah->ah_version != AR5K_AR5210) {
|
|
/*
|
|
* Get channel mode flags
|
|
@@ -384,39 +492,6 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
|
|
AR5K_PHY_TURBO);
|
|
}
|
|
|
|
- /* reseting PCI on PCI-E cards results card to hang
|
|
- * and always return 0xffff... so we ingore that flag
|
|
- * for PCI-E cards */
|
|
- bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
|
|
-
|
|
- /* Reset chipset */
|
|
- if (ah->ah_version == AR5K_AR5210) {
|
|
- ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
|
|
- AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
|
|
- AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
|
|
- mdelay(2);
|
|
- } else {
|
|
- ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
|
|
- AR5K_RESET_CTL_BASEBAND | bus_flags);
|
|
- }
|
|
- if (ret) {
|
|
- ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n");
|
|
- return -EIO;
|
|
- }
|
|
-
|
|
- /* ...wakeup again!*/
|
|
- ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
|
|
- if (ret) {
|
|
- ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n");
|
|
- return ret;
|
|
- }
|
|
-
|
|
- /* ...final warm reset */
|
|
- if (ath5k_hw_nic_reset(ah, 0)) {
|
|
- ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n");
|
|
- return -EIO;
|
|
- }
|
|
-
|
|
if (ah->ah_version != AR5K_AR5210) {
|
|
|
|
/* ...update PLL if needed */
|
|
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
|
|
index 7da52f1..d83d430 100644
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
|
|
@@ -46,7 +46,7 @@
|
|
#include "iwl-5000-hw.h"
|
|
|
|
/* Highest firmware API version supported */
|
|
-#define IWL1000_UCODE_API_MAX 2
|
|
+#define IWL1000_UCODE_API_MAX 3
|
|
|
|
/* Lowest firmware API version supported */
|
|
#define IWL1000_UCODE_API_MIN 1
|
|
@@ -62,12 +62,14 @@ struct iwl_cfg iwl1000_bgn_cfg = {
|
|
.ucode_api_min = IWL1000_UCODE_API_MIN,
|
|
.sku = IWL_SKU_G|IWL_SKU_N,
|
|
.ops = &iwl5000_ops,
|
|
- .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
|
|
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
|
|
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
|
|
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
|
|
.mod_params = &iwl50_mod_params,
|
|
.valid_tx_ant = ANT_A,
|
|
.valid_rx_ant = ANT_AB,
|
|
.need_pll_cfg = true,
|
|
+ .max_ll_items = OTP_MAX_LL_ITEMS_1000,
|
|
+ .shadow_ram_support = false,
|
|
};
|
|
|
|
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
|
|
index 46288e7..b73ab6c 100644
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
|
|
@@ -2784,11 +2784,50 @@ static int iwl3945_load_bsm(struct iwl_priv *priv)
|
|
return 0;
|
|
}
|
|
|
|
+#define IWL3945_UCODE_GET(item) \
|
|
+static u32 iwl3945_ucode_get_##item(const struct iwl_ucode_header *ucode,\
|
|
+ u32 api_ver) \
|
|
+{ \
|
|
+ return le32_to_cpu(ucode->u.v1.item); \
|
|
+}
|
|
+
|
|
+static u32 iwl3945_ucode_get_header_size(u32 api_ver)
|
|
+{
|
|
+ return UCODE_HEADER_SIZE(1);
|
|
+}
|
|
+static u32 iwl3945_ucode_get_build(const struct iwl_ucode_header *ucode,
|
|
+ u32 api_ver)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+static u8 *iwl3945_ucode_get_data(const struct iwl_ucode_header *ucode,
|
|
+ u32 api_ver)
|
|
+{
|
|
+ return (u8 *) ucode->u.v1.data;
|
|
+}
|
|
+
|
|
+IWL3945_UCODE_GET(inst_size);
|
|
+IWL3945_UCODE_GET(data_size);
|
|
+IWL3945_UCODE_GET(init_size);
|
|
+IWL3945_UCODE_GET(init_data_size);
|
|
+IWL3945_UCODE_GET(boot_size);
|
|
+
|
|
static struct iwl_hcmd_ops iwl3945_hcmd = {
|
|
.rxon_assoc = iwl3945_send_rxon_assoc,
|
|
.commit_rxon = iwl3945_commit_rxon,
|
|
};
|
|
|
|
+static struct iwl_ucode_ops iwl3945_ucode = {
|
|
+ .get_header_size = iwl3945_ucode_get_header_size,
|
|
+ .get_build = iwl3945_ucode_get_build,
|
|
+ .get_inst_size = iwl3945_ucode_get_inst_size,
|
|
+ .get_data_size = iwl3945_ucode_get_data_size,
|
|
+ .get_init_size = iwl3945_ucode_get_init_size,
|
|
+ .get_init_data_size = iwl3945_ucode_get_init_data_size,
|
|
+ .get_boot_size = iwl3945_ucode_get_boot_size,
|
|
+ .get_data = iwl3945_ucode_get_data,
|
|
+};
|
|
+
|
|
static struct iwl_lib_ops iwl3945_lib = {
|
|
.txq_attach_buf_to_tfd = iwl3945_hw_txq_attach_buf_to_tfd,
|
|
.txq_free_tfd = iwl3945_hw_txq_free_tfd,
|
|
@@ -2829,6 +2868,7 @@ static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
|
|
};
|
|
|
|
static struct iwl_ops iwl3945_ops = {
|
|
+ .ucode = &iwl3945_ucode,
|
|
.lib = &iwl3945_lib,
|
|
.hcmd = &iwl3945_hcmd,
|
|
.utils = &iwl3945_hcmd_utils,
|
|
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
|
|
index 8f3d4bc..157ee15 100644
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
|
|
@@ -2221,12 +2221,50 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv)
|
|
cancel_work_sync(&priv->txpower_work);
|
|
}
|
|
|
|
+#define IWL4965_UCODE_GET(item) \
|
|
+static u32 iwl4965_ucode_get_##item(const struct iwl_ucode_header *ucode,\
|
|
+ u32 api_ver) \
|
|
+{ \
|
|
+ return le32_to_cpu(ucode->u.v1.item); \
|
|
+}
|
|
+
|
|
+static u32 iwl4965_ucode_get_header_size(u32 api_ver)
|
|
+{
|
|
+ return UCODE_HEADER_SIZE(1);
|
|
+}
|
|
+static u32 iwl4965_ucode_get_build(const struct iwl_ucode_header *ucode,
|
|
+ u32 api_ver)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+static u8 *iwl4965_ucode_get_data(const struct iwl_ucode_header *ucode,
|
|
+ u32 api_ver)
|
|
+{
|
|
+ return (u8 *) ucode->u.v1.data;
|
|
+}
|
|
+
|
|
+IWL4965_UCODE_GET(inst_size);
|
|
+IWL4965_UCODE_GET(data_size);
|
|
+IWL4965_UCODE_GET(init_size);
|
|
+IWL4965_UCODE_GET(init_data_size);
|
|
+IWL4965_UCODE_GET(boot_size);
|
|
+
|
|
static struct iwl_hcmd_ops iwl4965_hcmd = {
|
|
.rxon_assoc = iwl4965_send_rxon_assoc,
|
|
.commit_rxon = iwl_commit_rxon,
|
|
.set_rxon_chain = iwl_set_rxon_chain,
|
|
};
|
|
|
|
+static struct iwl_ucode_ops iwl4965_ucode = {
|
|
+ .get_header_size = iwl4965_ucode_get_header_size,
|
|
+ .get_build = iwl4965_ucode_get_build,
|
|
+ .get_inst_size = iwl4965_ucode_get_inst_size,
|
|
+ .get_data_size = iwl4965_ucode_get_data_size,
|
|
+ .get_init_size = iwl4965_ucode_get_init_size,
|
|
+ .get_init_data_size = iwl4965_ucode_get_init_data_size,
|
|
+ .get_boot_size = iwl4965_ucode_get_boot_size,
|
|
+ .get_data = iwl4965_ucode_get_data,
|
|
+};
|
|
static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
|
|
.get_hcmd_size = iwl4965_get_hcmd_size,
|
|
.build_addsta_hcmd = iwl4965_build_addsta_hcmd,
|
|
@@ -2287,6 +2325,7 @@ static struct iwl_lib_ops iwl4965_lib = {
|
|
};
|
|
|
|
static struct iwl_ops iwl4965_ops = {
|
|
+ .ucode = &iwl4965_ucode,
|
|
.lib = &iwl4965_lib,
|
|
.hcmd = &iwl4965_hcmd,
|
|
.utils = &iwl4965_hcmd_utils,
|
|
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
|
|
index b3c648c..a9ea3b5 100644
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
|
|
@@ -239,6 +239,13 @@ static void iwl5000_nic_config(struct iwl_priv *priv)
|
|
APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
|
|
~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
|
|
|
|
+ if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_1000) {
|
|
+ /* Setting digital SVR for 1000 card to 1.32V */
|
|
+ iwl_set_bits_mask_prph(priv, APMG_DIGITAL_SVR_REG,
|
|
+ APMG_SVR_DIGITAL_VOLTAGE_1_32,
|
|
+ ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK);
|
|
+ }
|
|
+
|
|
spin_unlock_irqrestore(&priv->lock, flags);
|
|
}
|
|
|
|
@@ -1426,6 +1433,44 @@ int iwl5000_calc_rssi(struct iwl_priv *priv,
|
|
return max_rssi - agc - IWL49_RSSI_OFFSET;
|
|
}
|
|
|
|
+#define IWL5000_UCODE_GET(item) \
|
|
+static u32 iwl5000_ucode_get_##item(const struct iwl_ucode_header *ucode,\
|
|
+ u32 api_ver) \
|
|
+{ \
|
|
+ if (api_ver <= 2) \
|
|
+ return le32_to_cpu(ucode->u.v1.item); \
|
|
+ return le32_to_cpu(ucode->u.v2.item); \
|
|
+}
|
|
+
|
|
+static u32 iwl5000_ucode_get_header_size(u32 api_ver)
|
|
+{
|
|
+ if (api_ver <= 2)
|
|
+ return UCODE_HEADER_SIZE(1);
|
|
+ return UCODE_HEADER_SIZE(2);
|
|
+}
|
|
+
|
|
+static u32 iwl5000_ucode_get_build(const struct iwl_ucode_header *ucode,
|
|
+ u32 api_ver)
|
|
+{
|
|
+ if (api_ver <= 2)
|
|
+ return 0;
|
|
+ return le32_to_cpu(ucode->u.v2.build);
|
|
+}
|
|
+
|
|
+static u8 *iwl5000_ucode_get_data(const struct iwl_ucode_header *ucode,
|
|
+ u32 api_ver)
|
|
+{
|
|
+ if (api_ver <= 2)
|
|
+ return (u8 *) ucode->u.v1.data;
|
|
+ return (u8 *) ucode->u.v2.data;
|
|
+}
|
|
+
|
|
+IWL5000_UCODE_GET(inst_size);
|
|
+IWL5000_UCODE_GET(data_size);
|
|
+IWL5000_UCODE_GET(init_size);
|
|
+IWL5000_UCODE_GET(init_data_size);
|
|
+IWL5000_UCODE_GET(boot_size);
|
|
+
|
|
struct iwl_hcmd_ops iwl5000_hcmd = {
|
|
.rxon_assoc = iwl5000_send_rxon_assoc,
|
|
.commit_rxon = iwl_commit_rxon,
|
|
@@ -1441,6 +1486,17 @@ struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
|
|
.calc_rssi = iwl5000_calc_rssi,
|
|
};
|
|
|
|
+struct iwl_ucode_ops iwl5000_ucode = {
|
|
+ .get_header_size = iwl5000_ucode_get_header_size,
|
|
+ .get_build = iwl5000_ucode_get_build,
|
|
+ .get_inst_size = iwl5000_ucode_get_inst_size,
|
|
+ .get_data_size = iwl5000_ucode_get_data_size,
|
|
+ .get_init_size = iwl5000_ucode_get_init_size,
|
|
+ .get_init_data_size = iwl5000_ucode_get_init_data_size,
|
|
+ .get_boot_size = iwl5000_ucode_get_boot_size,
|
|
+ .get_data = iwl5000_ucode_get_data,
|
|
+};
|
|
+
|
|
struct iwl_lib_ops iwl5000_lib = {
|
|
.set_hw_params = iwl5000_hw_set_hw_params,
|
|
.txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
|
|
@@ -1542,12 +1598,14 @@ static struct iwl_lib_ops iwl5150_lib = {
|
|
};
|
|
|
|
struct iwl_ops iwl5000_ops = {
|
|
+ .ucode = &iwl5000_ucode,
|
|
.lib = &iwl5000_lib,
|
|
.hcmd = &iwl5000_hcmd,
|
|
.utils = &iwl5000_hcmd_utils,
|
|
};
|
|
|
|
static struct iwl_ops iwl5150_ops = {
|
|
+ .ucode = &iwl5000_ucode,
|
|
.lib = &iwl5150_lib,
|
|
.hcmd = &iwl5000_hcmd,
|
|
.utils = &iwl5000_hcmd_utils,
|
|
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
|
|
index bd438d8..e4a405f 100644
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
|
|
@@ -46,8 +46,8 @@
|
|
#include "iwl-5000-hw.h"
|
|
|
|
/* Highest firmware API version supported */
|
|
-#define IWL6000_UCODE_API_MAX 2
|
|
-#define IWL6050_UCODE_API_MAX 2
|
|
+#define IWL6000_UCODE_API_MAX 3
|
|
+#define IWL6050_UCODE_API_MAX 3
|
|
|
|
/* Lowest firmware API version supported */
|
|
#define IWL6000_UCODE_API_MIN 1
|
|
@@ -69,6 +69,7 @@ static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = {
|
|
};
|
|
|
|
static struct iwl_ops iwl6000_ops = {
|
|
+ .ucode = &iwl5000_ucode,
|
|
.lib = &iwl5000_lib,
|
|
.hcmd = &iwl5000_hcmd,
|
|
.utils = &iwl6000_hcmd_utils,
|
|
@@ -81,13 +82,15 @@ struct iwl_cfg iwl6000_2ag_cfg = {
|
|
.ucode_api_min = IWL6000_UCODE_API_MIN,
|
|
.sku = IWL_SKU_A|IWL_SKU_G,
|
|
.ops = &iwl6000_ops,
|
|
- .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
|
|
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
|
|
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
|
|
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
|
|
.mod_params = &iwl50_mod_params,
|
|
.valid_tx_ant = ANT_BC,
|
|
.valid_rx_ant = ANT_BC,
|
|
.need_pll_cfg = false,
|
|
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
|
|
+ .shadow_ram_support = true,
|
|
};
|
|
|
|
struct iwl_cfg iwl6000_2agn_cfg = {
|
|
@@ -97,13 +100,15 @@ struct iwl_cfg iwl6000_2agn_cfg = {
|
|
.ucode_api_min = IWL6000_UCODE_API_MIN,
|
|
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
|
|
.ops = &iwl6000_ops,
|
|
- .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
|
|
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
|
|
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
|
|
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
|
|
.mod_params = &iwl50_mod_params,
|
|
.valid_tx_ant = ANT_AB,
|
|
.valid_rx_ant = ANT_AB,
|
|
.need_pll_cfg = false,
|
|
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
|
|
+ .shadow_ram_support = true,
|
|
};
|
|
|
|
struct iwl_cfg iwl6050_2agn_cfg = {
|
|
@@ -113,13 +118,15 @@ struct iwl_cfg iwl6050_2agn_cfg = {
|
|
.ucode_api_min = IWL6050_UCODE_API_MIN,
|
|
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
|
|
.ops = &iwl6000_ops,
|
|
- .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
|
|
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
|
|
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
|
|
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
|
|
.mod_params = &iwl50_mod_params,
|
|
.valid_tx_ant = ANT_AB,
|
|
.valid_rx_ant = ANT_AB,
|
|
.need_pll_cfg = false,
|
|
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
|
|
+ .shadow_ram_support = true,
|
|
};
|
|
|
|
struct iwl_cfg iwl6000_3agn_cfg = {
|
|
@@ -129,13 +136,15 @@ struct iwl_cfg iwl6000_3agn_cfg = {
|
|
.ucode_api_min = IWL6000_UCODE_API_MIN,
|
|
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
|
|
.ops = &iwl6000_ops,
|
|
- .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
|
|
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
|
|
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
|
|
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
|
|
.mod_params = &iwl50_mod_params,
|
|
.valid_tx_ant = ANT_ABC,
|
|
.valid_rx_ant = ANT_ABC,
|
|
.need_pll_cfg = false,
|
|
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
|
|
+ .shadow_ram_support = true,
|
|
};
|
|
|
|
struct iwl_cfg iwl6050_3agn_cfg = {
|
|
@@ -145,13 +154,15 @@ struct iwl_cfg iwl6050_3agn_cfg = {
|
|
.ucode_api_min = IWL6050_UCODE_API_MIN,
|
|
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
|
|
.ops = &iwl6000_ops,
|
|
- .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
|
|
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
|
|
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
|
|
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
|
|
.mod_params = &iwl50_mod_params,
|
|
.valid_tx_ant = ANT_ABC,
|
|
.valid_rx_ant = ANT_ABC,
|
|
.need_pll_cfg = false,
|
|
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
|
|
+ .shadow_ram_support = true,
|
|
};
|
|
|
|
MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
|
|
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
|
|
index 355f50e..2a577ae 100644
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
|
|
@@ -1348,7 +1348,7 @@ static void iwl_nic_start(struct iwl_priv *priv)
|
|
*/
|
|
static int iwl_read_ucode(struct iwl_priv *priv)
|
|
{
|
|
- struct iwl_ucode *ucode;
|
|
+ struct iwl_ucode_header *ucode;
|
|
int ret = -EINVAL, index;
|
|
const struct firmware *ucode_raw;
|
|
const char *name_pre = priv->cfg->fw_name_pre;
|
|
@@ -1357,7 +1357,8 @@ static int iwl_read_ucode(struct iwl_priv *priv)
|
|
char buf[25];
|
|
u8 *src;
|
|
size_t len;
|
|
- u32 api_ver, inst_size, data_size, init_size, init_data_size, boot_size;
|
|
+ u32 api_ver, build;
|
|
+ u32 inst_size, data_size, init_size, init_data_size, boot_size;
|
|
|
|
/* Ask kernel firmware_class module to get the boot firmware off disk.
|
|
* request_firmware() is synchronous, file is in memory on return. */
|
|
@@ -1387,23 +1388,26 @@ static int iwl_read_ucode(struct iwl_priv *priv)
|
|
if (ret < 0)
|
|
goto error;
|
|
|
|
- /* Make sure that we got at least our header! */
|
|
- if (ucode_raw->size < sizeof(*ucode)) {
|
|
+ /* Make sure that we got at least the v1 header! */
|
|
+ if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) {
|
|
IWL_ERR(priv, "File size way too small!\n");
|
|
ret = -EINVAL;
|
|
goto err_release;
|
|
}
|
|
|
|
/* Data from ucode file: header followed by uCode images */
|
|
- ucode = (void *)ucode_raw->data;
|
|
+ ucode = (struct iwl_ucode_header *)ucode_raw->data;
|
|
|
|
priv->ucode_ver = le32_to_cpu(ucode->ver);
|
|
api_ver = IWL_UCODE_API(priv->ucode_ver);
|
|
- inst_size = le32_to_cpu(ucode->inst_size);
|
|
- data_size = le32_to_cpu(ucode->data_size);
|
|
- init_size = le32_to_cpu(ucode->init_size);
|
|
- init_data_size = le32_to_cpu(ucode->init_data_size);
|
|
- boot_size = le32_to_cpu(ucode->boot_size);
|
|
+ build = priv->cfg->ops->ucode->get_build(ucode, api_ver);
|
|
+ inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver);
|
|
+ data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver);
|
|
+ init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver);
|
|
+ init_data_size =
|
|
+ priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver);
|
|
+ boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver);
|
|
+ src = priv->cfg->ops->ucode->get_data(ucode, api_ver);
|
|
|
|
/* api_ver should match the api version forming part of the
|
|
* firmware filename ... but we don't check for that and only rely
|
|
@@ -1429,6 +1433,9 @@ static int iwl_read_ucode(struct iwl_priv *priv)
|
|
IWL_UCODE_API(priv->ucode_ver),
|
|
IWL_UCODE_SERIAL(priv->ucode_ver));
|
|
|
|
+ if (build)
|
|
+ IWL_DEBUG_INFO(priv, "Build %u\n", build);
|
|
+
|
|
IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n",
|
|
priv->ucode_ver);
|
|
IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %u\n",
|
|
@@ -1443,12 +1450,14 @@ static int iwl_read_ucode(struct iwl_priv *priv)
|
|
boot_size);
|
|
|
|
/* Verify size of file vs. image size info in file's header */
|
|
- if (ucode_raw->size < sizeof(*ucode) +
|
|
+ if (ucode_raw->size !=
|
|
+ priv->cfg->ops->ucode->get_header_size(api_ver) +
|
|
inst_size + data_size + init_size +
|
|
init_data_size + boot_size) {
|
|
|
|
- IWL_DEBUG_INFO(priv, "uCode file size %d too small\n",
|
|
- (int)ucode_raw->size);
|
|
+ IWL_DEBUG_INFO(priv,
|
|
+ "uCode file size %d does not match expected size\n",
|
|
+ (int)ucode_raw->size);
|
|
ret = -EINVAL;
|
|
goto err_release;
|
|
}
|
|
@@ -1528,42 +1537,42 @@ static int iwl_read_ucode(struct iwl_priv *priv)
|
|
/* Copy images into buffers for card's bus-master reads ... */
|
|
|
|
/* Runtime instructions (first block of data in file) */
|
|
- src = &ucode->data[0];
|
|
- len = priv->ucode_code.len;
|
|
+ len = inst_size;
|
|
IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n", len);
|
|
memcpy(priv->ucode_code.v_addr, src, len);
|
|
+ src += len;
|
|
+
|
|
IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
|
|
priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
|
|
|
|
/* Runtime data (2nd block)
|
|
* NOTE: Copy into backup buffer will be done in iwl_up() */
|
|
- src = &ucode->data[inst_size];
|
|
- len = priv->ucode_data.len;
|
|
+ len = data_size;
|
|
IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", len);
|
|
memcpy(priv->ucode_data.v_addr, src, len);
|
|
memcpy(priv->ucode_data_backup.v_addr, src, len);
|
|
+ src += len;
|
|
|
|
/* Initialization instructions (3rd block) */
|
|
if (init_size) {
|
|
- src = &ucode->data[inst_size + data_size];
|
|
- len = priv->ucode_init.len;
|
|
+ len = init_size;
|
|
IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %Zd\n",
|
|
len);
|
|
memcpy(priv->ucode_init.v_addr, src, len);
|
|
+ src += len;
|
|
}
|
|
|
|
/* Initialization data (4th block) */
|
|
if (init_data_size) {
|
|
- src = &ucode->data[inst_size + data_size + init_size];
|
|
- len = priv->ucode_init_data.len;
|
|
+ len = init_data_size;
|
|
IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %Zd\n",
|
|
len);
|
|
memcpy(priv->ucode_init_data.v_addr, src, len);
|
|
+ src += len;
|
|
}
|
|
|
|
/* Bootstrap instructions (5th block) */
|
|
- src = &ucode->data[inst_size + data_size + init_size + init_data_size];
|
|
- len = priv->ucode_boot.len;
|
|
+ len = boot_size;
|
|
IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", len);
|
|
memcpy(priv->ucode_boot.v_addr, src, len);
|
|
|
|
@@ -2206,7 +2215,7 @@ static void iwl_mac_stop(struct ieee80211_hw *hw)
|
|
|
|
priv->is_open = 0;
|
|
|
|
- if (iwl_is_ready_rf(priv)) {
|
|
+ if (iwl_is_ready_rf(priv) || test_bit(STATUS_SCAN_HW, &priv->status)) {
|
|
/* stop mac, cancel any scan request and clear
|
|
* RXON_FILTER_ASSOC_MSK BIT
|
|
*/
|
|
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
|
|
index dabf663..1e51891 100644
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
|
|
@@ -116,6 +116,17 @@ struct iwl_temp_ops {
|
|
void (*set_ct_kill)(struct iwl_priv *priv);
|
|
};
|
|
|
|
+struct iwl_ucode_ops {
|
|
+ u32 (*get_header_size)(u32);
|
|
+ u32 (*get_build)(const struct iwl_ucode_header *, u32);
|
|
+ u32 (*get_inst_size)(const struct iwl_ucode_header *, u32);
|
|
+ u32 (*get_data_size)(const struct iwl_ucode_header *, u32);
|
|
+ u32 (*get_init_size)(const struct iwl_ucode_header *, u32);
|
|
+ u32 (*get_init_data_size)(const struct iwl_ucode_header *, u32);
|
|
+ u32 (*get_boot_size)(const struct iwl_ucode_header *, u32);
|
|
+ u8 * (*get_data)(const struct iwl_ucode_header *, u32);
|
|
+};
|
|
+
|
|
struct iwl_lib_ops {
|
|
/* set hw dependent parameters */
|
|
int (*set_hw_params)(struct iwl_priv *priv);
|
|
@@ -171,6 +182,7 @@ struct iwl_lib_ops {
|
|
};
|
|
|
|
struct iwl_ops {
|
|
+ const struct iwl_ucode_ops *ucode;
|
|
const struct iwl_lib_ops *lib;
|
|
const struct iwl_hcmd_ops *hcmd;
|
|
const struct iwl_hcmd_utils_ops *utils;
|
|
@@ -195,6 +207,8 @@ struct iwl_mod_params {
|
|
* filename is constructed as fw_name_pre<api>.ucode.
|
|
* @ucode_api_max: Highest version of uCode API supported by driver.
|
|
* @ucode_api_min: Lowest version of uCode API supported by driver.
|
|
+ * @max_ll_items: max number of OTP blocks
|
|
+ * @shadow_ram_support: shadow support for OTP memory
|
|
*
|
|
* We enable the driver to be backward compatible wrt API version. The
|
|
* driver specifies which APIs it supports (with @ucode_api_max being the
|
|
@@ -231,6 +245,8 @@ struct iwl_cfg {
|
|
u8 valid_rx_ant;
|
|
bool need_pll_cfg;
|
|
bool use_isr_legacy;
|
|
+ const u16 max_ll_items;
|
|
+ const bool shadow_ram_support;
|
|
};
|
|
|
|
/***************************
|
|
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
|
|
index 650e20a..e8c8607 100644
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
|
|
@@ -66,6 +66,7 @@ extern struct iwl_cfg iwl1000_bgn_cfg;
|
|
/* shared structures from iwl-5000.c */
|
|
extern struct iwl_mod_params iwl50_mod_params;
|
|
extern struct iwl_ops iwl5000_ops;
|
|
+extern struct iwl_ucode_ops iwl5000_ucode;
|
|
extern struct iwl_lib_ops iwl5000_lib;
|
|
extern struct iwl_hcmd_ops iwl5000_hcmd;
|
|
extern struct iwl_hcmd_utils_ops iwl5000_hcmd_utils;
|
|
@@ -525,15 +526,29 @@ struct fw_desc {
|
|
};
|
|
|
|
/* uCode file layout */
|
|
-struct iwl_ucode {
|
|
- __le32 ver; /* major/minor/API/serial */
|
|
- __le32 inst_size; /* bytes of runtime instructions */
|
|
- __le32 data_size; /* bytes of runtime data */
|
|
- __le32 init_size; /* bytes of initialization instructions */
|
|
- __le32 init_data_size; /* bytes of initialization data */
|
|
- __le32 boot_size; /* bytes of bootstrap instructions */
|
|
- u8 data[0]; /* data in same order as "size" elements */
|
|
+struct iwl_ucode_header {
|
|
+ __le32 ver; /* major/minor/API/serial */
|
|
+ union {
|
|
+ struct {
|
|
+ __le32 inst_size; /* bytes of runtime code */
|
|
+ __le32 data_size; /* bytes of runtime data */
|
|
+ __le32 init_size; /* bytes of init code */
|
|
+ __le32 init_data_size; /* bytes of init data */
|
|
+ __le32 boot_size; /* bytes of bootstrap code */
|
|
+ u8 data[0]; /* in same order as sizes */
|
|
+ } v1;
|
|
+ struct {
|
|
+ __le32 build; /* build number */
|
|
+ __le32 inst_size; /* bytes of runtime code */
|
|
+ __le32 data_size; /* bytes of runtime data */
|
|
+ __le32 init_size; /* bytes of init code */
|
|
+ __le32 init_data_size; /* bytes of init data */
|
|
+ __le32 boot_size; /* bytes of bootstrap code */
|
|
+ u8 data[0]; /* in same order as sizes */
|
|
+ } v2;
|
|
+ } u;
|
|
};
|
|
+#define UCODE_HEADER_SIZE(ver) ((ver) == 1 ? 24 : 28)
|
|
|
|
struct iwl4965_ibss_seq {
|
|
u8 mac[ETH_ALEN];
|
|
@@ -820,6 +835,18 @@ enum iwl_nvm_type {
|
|
NVM_DEVICE_TYPE_OTP,
|
|
};
|
|
|
|
+/*
|
|
+ * Two types of OTP memory access modes
|
|
+ * IWL_OTP_ACCESS_ABSOLUTE - absolute address mode,
|
|
+ * based on physical memory addressing
|
|
+ * IWL_OTP_ACCESS_RELATIVE - relative address mode,
|
|
+ * based on logical memory addressing
|
|
+ */
|
|
+enum iwl_access_mode {
|
|
+ IWL_OTP_ACCESS_ABSOLUTE,
|
|
+ IWL_OTP_ACCESS_RELATIVE,
|
|
+};
|
|
+
|
|
/* interrupt statistics */
|
|
struct isr_statistics {
|
|
u32 hw;
|
|
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
|
|
index 7d7554a..e8c0e82 100644
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
|
|
@@ -152,6 +152,19 @@ int iwlcore_eeprom_verify_signature(struct iwl_priv *priv)
|
|
}
|
|
EXPORT_SYMBOL(iwlcore_eeprom_verify_signature);
|
|
|
|
+static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode)
|
|
+{
|
|
+ u32 otpgp;
|
|
+
|
|
+ otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
|
|
+ if (mode == IWL_OTP_ACCESS_ABSOLUTE)
|
|
+ iwl_clear_bit(priv, CSR_OTP_GP_REG,
|
|
+ CSR_OTP_GP_REG_OTP_ACCESS_MODE);
|
|
+ else
|
|
+ iwl_set_bit(priv, CSR_OTP_GP_REG,
|
|
+ CSR_OTP_GP_REG_OTP_ACCESS_MODE);
|
|
+}
|
|
+
|
|
static int iwlcore_get_nvm_type(struct iwl_priv *priv)
|
|
{
|
|
u32 otpgp;
|
|
@@ -249,6 +262,124 @@ static int iwl_init_otp_access(struct iwl_priv *priv)
|
|
return ret;
|
|
}
|
|
|
|
+static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, u16 *eeprom_data)
|
|
+{
|
|
+ int ret = 0;
|
|
+ u32 r;
|
|
+ u32 otpgp;
|
|
+
|
|
+ _iwl_write32(priv, CSR_EEPROM_REG,
|
|
+ CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
|
|
+ ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG,
|
|
+ CSR_EEPROM_REG_READ_VALID_MSK,
|
|
+ IWL_EEPROM_ACCESS_TIMEOUT);
|
|
+ if (ret < 0) {
|
|
+ IWL_ERR(priv, "Time out reading OTP[%d]\n", addr);
|
|
+ return ret;
|
|
+ }
|
|
+ r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
|
|
+ /* check for ECC errors: */
|
|
+ otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
|
|
+ if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) {
|
|
+ /* stop in this case */
|
|
+ /* set the uncorrectable OTP ECC bit for acknowledgement */
|
|
+ iwl_set_bit(priv, CSR_OTP_GP_REG,
|
|
+ CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
|
|
+ IWL_ERR(priv, "Uncorrectable OTP ECC error, abort OTP read\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) {
|
|
+ /* continue in this case */
|
|
+ /* set the correctable OTP ECC bit for acknowledgement */
|
|
+ iwl_set_bit(priv, CSR_OTP_GP_REG,
|
|
+ CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK);
|
|
+ IWL_ERR(priv, "Correctable OTP ECC error, continue read\n");
|
|
+ }
|
|
+ *eeprom_data = le16_to_cpu((__force __le16)(r >> 16));
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * iwl_is_otp_empty: check for empty OTP
|
|
+ */
|
|
+static bool iwl_is_otp_empty(struct iwl_priv *priv)
|
|
+{
|
|
+ u16 next_link_addr = 0, link_value;
|
|
+ bool is_empty = false;
|
|
+
|
|
+ /* locate the beginning of OTP link list */
|
|
+ if (!iwl_read_otp_word(priv, next_link_addr, &link_value)) {
|
|
+ if (!link_value) {
|
|
+ IWL_ERR(priv, "OTP is empty\n");
|
|
+ is_empty = true;
|
|
+ }
|
|
+ } else {
|
|
+ IWL_ERR(priv, "Unable to read first block of OTP list.\n");
|
|
+ is_empty = true;
|
|
+ }
|
|
+
|
|
+ return is_empty;
|
|
+}
|
|
+
|
|
+
|
|
+/*
|
|
+ * iwl_find_otp_image: find EEPROM image in OTP
|
|
+ * finding the OTP block that contains the EEPROM image.
|
|
+ * the last valid block on the link list (the block _before_ the last block)
|
|
+ * is the block we should read and used to configure the device.
|
|
+ * If all the available OTP blocks are full, the last block will be the block
|
|
+ * we should read and used to configure the device.
|
|
+ * only perform this operation if shadow RAM is disabled
|
|
+ */
|
|
+static int iwl_find_otp_image(struct iwl_priv *priv,
|
|
+ u16 *validblockaddr)
|
|
+{
|
|
+ u16 next_link_addr = 0, link_value = 0, valid_addr;
|
|
+ int ret = 0;
|
|
+ int usedblocks = 0;
|
|
+
|
|
+ /* set addressing mode to absolute to traverse the link list */
|
|
+ iwl_set_otp_access(priv, IWL_OTP_ACCESS_ABSOLUTE);
|
|
+
|
|
+ /* checking for empty OTP or error */
|
|
+ if (iwl_is_otp_empty(priv))
|
|
+ return -EINVAL;
|
|
+
|
|
+ /*
|
|
+ * start traverse link list
|
|
+ * until reach the max number of OTP blocks
|
|
+ * different devices have different number of OTP blocks
|
|
+ */
|
|
+ do {
|
|
+ /* save current valid block address
|
|
+ * check for more block on the link list
|
|
+ */
|
|
+ valid_addr = next_link_addr;
|
|
+ next_link_addr = link_value;
|
|
+ IWL_DEBUG_INFO(priv, "OTP blocks %d addr 0x%x\n",
|
|
+ usedblocks, next_link_addr);
|
|
+ if (iwl_read_otp_word(priv, next_link_addr, &link_value))
|
|
+ return -EINVAL;
|
|
+ if (!link_value) {
|
|
+ /*
|
|
+ * reach the end of link list,
|
|
+ * set address point to the starting address
|
|
+ * of the image
|
|
+ */
|
|
+ goto done;
|
|
+ }
|
|
+ /* more in the link list, continue */
|
|
+ usedblocks++;
|
|
+ } while (usedblocks < priv->cfg->max_ll_items);
|
|
+ /* OTP full, use last block */
|
|
+ IWL_DEBUG_INFO(priv, "OTP is full, use last block\n");
|
|
+done:
|
|
+ *validblockaddr = valid_addr;
|
|
+ /* skip first 2 bytes (link list pointer) */
|
|
+ *validblockaddr += 2;
|
|
+ return ret;
|
|
+}
|
|
+
|
|
/**
|
|
* iwl_eeprom_init - read EEPROM contents
|
|
*
|
|
@@ -263,14 +394,13 @@ int iwl_eeprom_init(struct iwl_priv *priv)
|
|
int sz;
|
|
int ret;
|
|
u16 addr;
|
|
- u32 otpgp;
|
|
+ u16 validblockaddr = 0;
|
|
+ u16 cache_addr = 0;
|
|
|
|
priv->nvm_device_type = iwlcore_get_nvm_type(priv);
|
|
|
|
/* allocate eeprom */
|
|
- if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
|
|
- priv->cfg->eeprom_size =
|
|
- OTP_BLOCK_SIZE * OTP_LOWER_BLOCKS_TOTAL;
|
|
+ IWL_DEBUG_INFO(priv, "NVM size = %d\n", priv->cfg->eeprom_size);
|
|
sz = priv->cfg->eeprom_size;
|
|
priv->eeprom = kzalloc(sz, GFP_KERNEL);
|
|
if (!priv->eeprom) {
|
|
@@ -298,46 +428,31 @@ int iwl_eeprom_init(struct iwl_priv *priv)
|
|
if (ret) {
|
|
IWL_ERR(priv, "Failed to initialize OTP access.\n");
|
|
ret = -ENOENT;
|
|
- goto err;
|
|
+ goto done;
|
|
}
|
|
_iwl_write32(priv, CSR_EEPROM_GP,
|
|
iwl_read32(priv, CSR_EEPROM_GP) &
|
|
~CSR_EEPROM_GP_IF_OWNER_MSK);
|
|
- /* clear */
|
|
- _iwl_write32(priv, CSR_OTP_GP_REG,
|
|
- iwl_read32(priv, CSR_OTP_GP_REG) |
|
|
+
|
|
+ iwl_set_bit(priv, CSR_OTP_GP_REG,
|
|
CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK |
|
|
CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
|
|
-
|
|
- for (addr = 0; addr < sz; addr += sizeof(u16)) {
|
|
- u32 r;
|
|
-
|
|
- _iwl_write32(priv, CSR_EEPROM_REG,
|
|
- CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
|
|
-
|
|
- ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG,
|
|
- CSR_EEPROM_REG_READ_VALID_MSK,
|
|
- IWL_EEPROM_ACCESS_TIMEOUT);
|
|
- if (ret < 0) {
|
|
- IWL_ERR(priv, "Time out reading OTP[%d]\n", addr);
|
|
+ /* traversing the linked list if no shadow ram supported */
|
|
+ if (!priv->cfg->shadow_ram_support) {
|
|
+ if (iwl_find_otp_image(priv, &validblockaddr)) {
|
|
+ ret = -ENOENT;
|
|
goto done;
|
|
}
|
|
- r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
|
|
- /* check for ECC errors: */
|
|
- otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
|
|
- if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) {
|
|
- /* stop in this case */
|
|
- IWL_ERR(priv, "Uncorrectable OTP ECC error, Abort OTP read\n");
|
|
+ }
|
|
+ for (addr = validblockaddr; addr < validblockaddr + sz;
|
|
+ addr += sizeof(u16)) {
|
|
+ u16 eeprom_data;
|
|
+
|
|
+ ret = iwl_read_otp_word(priv, addr, &eeprom_data);
|
|
+ if (ret)
|
|
goto done;
|
|
- }
|
|
- if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) {
|
|
- /* continue in this case */
|
|
- _iwl_write32(priv, CSR_OTP_GP_REG,
|
|
- iwl_read32(priv, CSR_OTP_GP_REG) |
|
|
- CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK);
|
|
- IWL_ERR(priv, "Correctable OTP ECC error, continue read\n");
|
|
- }
|
|
- e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
|
|
+ e[cache_addr / 2] = eeprom_data;
|
|
+ cache_addr += sizeof(u16);
|
|
}
|
|
} else {
|
|
/* eeprom is an array of 16bit values */
|
|
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
|
|
index 195b4ef..7899885 100644
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
|
|
@@ -180,8 +180,14 @@ struct iwl_eeprom_channel {
|
|
#define EEPROM_5050_EEPROM_VERSION (0x21E)
|
|
|
|
/* OTP */
|
|
-#define OTP_LOWER_BLOCKS_TOTAL (3)
|
|
-#define OTP_BLOCK_SIZE (0x400)
|
|
+/* lower blocks contain EEPROM image and calibration data */
|
|
+#define OTP_LOW_IMAGE_SIZE (2 * 512 * sizeof(u16)) /* 2 KB */
|
|
+/* high blocks contain PAPD data */
|
|
+#define OTP_HIGH_IMAGE_SIZE_6x00 (6 * 512 * sizeof(u16)) /* 6 KB */
|
|
+#define OTP_HIGH_IMAGE_SIZE_1000 (0x200 * sizeof(u16)) /* 1024 bytes */
|
|
+#define OTP_MAX_LL_ITEMS_1000 (3) /* OTP blocks for 1000 */
|
|
+#define OTP_MAX_LL_ITEMS_6x00 (4) /* OTP blocks for 6x00 */
|
|
+#define OTP_MAX_LL_ITEMS_6x50 (7) /* OTP blocks for 6x50 */
|
|
|
|
/* 2.4 GHz */
|
|
extern const u8 iwl_eeprom_band_1[14];
|
|
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
|
|
index 3b9cac3..d393e8f 100644
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
|
|
@@ -80,6 +80,8 @@
|
|
#define APMG_RFKILL_REG (APMG_BASE + 0x0014)
|
|
#define APMG_RTC_INT_STT_REG (APMG_BASE + 0x001c)
|
|
#define APMG_RTC_INT_MSK_REG (APMG_BASE + 0x0020)
|
|
+#define APMG_DIGITAL_SVR_REG (APMG_BASE + 0x0058)
|
|
+#define APMG_ANALOG_SVR_REG (APMG_BASE + 0x006C)
|
|
|
|
#define APMG_CLK_VAL_DMA_CLK_RQT (0x00000200)
|
|
#define APMG_CLK_VAL_BSM_CLK_RQT (0x00000800)
|
|
@@ -91,7 +93,8 @@
|
|
#define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000)
|
|
#define APMG_PS_CTRL_VAL_PWR_SRC_MAX (0x01000000) /* 3945 only */
|
|
#define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x02000000)
|
|
-
|
|
+#define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK (0x000001E0) /* bit 8:5 */
|
|
+#define APMG_SVR_DIGITAL_VOLTAGE_1_32 (0x00000060)
|
|
|
|
#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800)
|
|
|
|
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
|
|
index e26875d..474fd49 100644
|
|
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
|
|
@@ -799,7 +799,8 @@ void iwl_bg_abort_scan(struct work_struct *work)
|
|
{
|
|
struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan);
|
|
|
|
- if (!iwl_is_ready(priv))
|
|
+ if (!test_bit(STATUS_READY, &priv->status) ||
|
|
+ !test_bit(STATUS_GEO_CONFIGURED, &priv->status))
|
|
return;
|
|
|
|
mutex_lock(&priv->mutex);
|
|
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
|
|
index 5238433..054d6c7 100644
|
|
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
|
|
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
|
|
@@ -2111,7 +2111,7 @@ static void iwl3945_nic_start(struct iwl_priv *priv)
|
|
*/
|
|
static int iwl3945_read_ucode(struct iwl_priv *priv)
|
|
{
|
|
- struct iwl_ucode *ucode;
|
|
+ const struct iwl_ucode_header *ucode;
|
|
int ret = -EINVAL, index;
|
|
const struct firmware *ucode_raw;
|
|
/* firmware file name contains uCode/driver compatibility version */
|
|
@@ -2152,22 +2152,24 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
|
|
goto error;
|
|
|
|
/* Make sure that we got at least our header! */
|
|
- if (ucode_raw->size < sizeof(*ucode)) {
|
|
+ if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) {
|
|
IWL_ERR(priv, "File size way too small!\n");
|
|
ret = -EINVAL;
|
|
goto err_release;
|
|
}
|
|
|
|
/* Data from ucode file: header followed by uCode images */
|
|
- ucode = (void *)ucode_raw->data;
|
|
+ ucode = (struct iwl_ucode_header *)ucode_raw->data;
|
|
|
|
priv->ucode_ver = le32_to_cpu(ucode->ver);
|
|
api_ver = IWL_UCODE_API(priv->ucode_ver);
|
|
- inst_size = le32_to_cpu(ucode->inst_size);
|
|
- data_size = le32_to_cpu(ucode->data_size);
|
|
- init_size = le32_to_cpu(ucode->init_size);
|
|
- init_data_size = le32_to_cpu(ucode->init_data_size);
|
|
- boot_size = le32_to_cpu(ucode->boot_size);
|
|
+ inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver);
|
|
+ data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver);
|
|
+ init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver);
|
|
+ init_data_size =
|
|
+ priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver);
|
|
+ boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver);
|
|
+ src = priv->cfg->ops->ucode->get_data(ucode, api_ver);
|
|
|
|
/* api_ver should match the api version forming part of the
|
|
* firmware filename ... but we don't check for that and only rely
|
|
@@ -2208,12 +2210,13 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
|
|
|
|
|
|
/* Verify size of file vs. image size info in file's header */
|
|
- if (ucode_raw->size < sizeof(*ucode) +
|
|
+ if (ucode_raw->size != priv->cfg->ops->ucode->get_header_size(api_ver) +
|
|
inst_size + data_size + init_size +
|
|
init_data_size + boot_size) {
|
|
|
|
- IWL_DEBUG_INFO(priv, "uCode file size %zd too small\n",
|
|
- ucode_raw->size);
|
|
+ IWL_DEBUG_INFO(priv,
|
|
+ "uCode file size %zd does not match expected size\n",
|
|
+ ucode_raw->size);
|
|
ret = -EINVAL;
|
|
goto err_release;
|
|
}
|
|
@@ -2296,44 +2299,44 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
|
|
/* Copy images into buffers for card's bus-master reads ... */
|
|
|
|
/* Runtime instructions (first block of data in file) */
|
|
- src = &ucode->data[0];
|
|
- len = priv->ucode_code.len;
|
|
+ len = inst_size;
|
|
IWL_DEBUG_INFO(priv,
|
|
"Copying (but not loading) uCode instr len %zd\n", len);
|
|
memcpy(priv->ucode_code.v_addr, src, len);
|
|
+ src += len;
|
|
+
|
|
IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
|
|
priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
|
|
|
|
/* Runtime data (2nd block)
|
|
* NOTE: Copy into backup buffer will be done in iwl3945_up() */
|
|
- src = &ucode->data[inst_size];
|
|
- len = priv->ucode_data.len;
|
|
+ len = data_size;
|
|
IWL_DEBUG_INFO(priv,
|
|
"Copying (but not loading) uCode data len %zd\n", len);
|
|
memcpy(priv->ucode_data.v_addr, src, len);
|
|
memcpy(priv->ucode_data_backup.v_addr, src, len);
|
|
+ src += len;
|
|
|
|
/* Initialization instructions (3rd block) */
|
|
if (init_size) {
|
|
- src = &ucode->data[inst_size + data_size];
|
|
- len = priv->ucode_init.len;
|
|
+ len = init_size;
|
|
IWL_DEBUG_INFO(priv,
|
|
"Copying (but not loading) init instr len %zd\n", len);
|
|
memcpy(priv->ucode_init.v_addr, src, len);
|
|
+ src += len;
|
|
}
|
|
|
|
/* Initialization data (4th block) */
|
|
if (init_data_size) {
|
|
- src = &ucode->data[inst_size + data_size + init_size];
|
|
- len = priv->ucode_init_data.len;
|
|
+ len = init_data_size;
|
|
IWL_DEBUG_INFO(priv,
|
|
"Copying (but not loading) init data len %zd\n", len);
|
|
memcpy(priv->ucode_init_data.v_addr, src, len);
|
|
+ src += len;
|
|
}
|
|
|
|
/* Bootstrap instructions (5th block) */
|
|
- src = &ucode->data[inst_size + data_size + init_size + init_data_size];
|
|
- len = priv->ucode_boot.len;
|
|
+ len = boot_size;
|
|
IWL_DEBUG_INFO(priv,
|
|
"Copying (but not loading) boot instr len %zd\n", len);
|
|
memcpy(priv->ucode_boot.v_addr, src, len);
|
|
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
|
|
index 0e877a1..6e1b889 100644
|
|
--- a/drivers/net/wireless/p54/p54usb.c
|
|
+++ b/drivers/net/wireless/p54/p54usb.c
|
|
@@ -66,6 +66,7 @@ static struct usb_device_id p54u_table[] __devinitdata = {
|
|
{USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/
|
|
{USB_DEVICE(0x0cde, 0x0006)}, /* Medion MD40900 */
|
|
{USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */
|
|
+ {USB_DEVICE(0x0cde, 0x0015)}, /* Zcomax XG-705A */
|
|
{USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */
|
|
{USB_DEVICE(0x124a, 0x4025)}, /* IOGear GWU513 (GW3887IK chip) */
|
|
{USB_DEVICE(0x1260, 0xee22)}, /* SMC 2862W-G version 2 */
|
|
diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c
|
|
index 9e1140f..e1dcced 100644
|
|
--- a/drivers/pcmcia/at91_cf.c
|
|
+++ b/drivers/pcmcia/at91_cf.c
|
|
@@ -363,7 +363,7 @@ static int at91_cf_suspend(struct platform_device *pdev, pm_message_t mesg)
|
|
struct at91_cf_socket *cf = platform_get_drvdata(pdev);
|
|
struct at91_cf_data *board = cf->board;
|
|
|
|
- pcmcia_socket_dev_suspend(&pdev->dev, mesg);
|
|
+ pcmcia_socket_dev_suspend(&pdev->dev);
|
|
if (device_may_wakeup(&pdev->dev)) {
|
|
enable_irq_wake(board->det_pin);
|
|
if (board->irq_pin)
|
|
diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c
|
|
index 9001334..0208870 100644
|
|
--- a/drivers/pcmcia/au1000_generic.c
|
|
+++ b/drivers/pcmcia/au1000_generic.c
|
|
@@ -515,7 +515,7 @@ static int au1x00_drv_pcmcia_probe(struct platform_device *dev)
|
|
static int au1x00_drv_pcmcia_suspend(struct platform_device *dev,
|
|
pm_message_t state)
|
|
{
|
|
- return pcmcia_socket_dev_suspend(&dev->dev, state);
|
|
+ return pcmcia_socket_dev_suspend(&dev->dev);
|
|
}
|
|
|
|
static int au1x00_drv_pcmcia_resume(struct platform_device *dev)
|
|
diff --git a/drivers/pcmcia/bfin_cf_pcmcia.c b/drivers/pcmcia/bfin_cf_pcmcia.c
|
|
index b59d411..300b368 100644
|
|
--- a/drivers/pcmcia/bfin_cf_pcmcia.c
|
|
+++ b/drivers/pcmcia/bfin_cf_pcmcia.c
|
|
@@ -302,7 +302,7 @@ static int __devexit bfin_cf_remove(struct platform_device *pdev)
|
|
|
|
static int bfin_cf_suspend(struct platform_device *pdev, pm_message_t mesg)
|
|
{
|
|
- return pcmcia_socket_dev_suspend(&pdev->dev, mesg);
|
|
+ return pcmcia_socket_dev_suspend(&pdev->dev);
|
|
}
|
|
|
|
static int bfin_cf_resume(struct platform_device *pdev)
|
|
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
|
|
index 0660ad1..934d4be 100644
|
|
--- a/drivers/pcmcia/cs.c
|
|
+++ b/drivers/pcmcia/cs.c
|
|
@@ -101,7 +101,7 @@ EXPORT_SYMBOL(pcmcia_socket_list_rwsem);
|
|
static int socket_resume(struct pcmcia_socket *skt);
|
|
static int socket_suspend(struct pcmcia_socket *skt);
|
|
|
|
-int pcmcia_socket_dev_suspend(struct device *dev, pm_message_t state)
|
|
+int pcmcia_socket_dev_suspend(struct device *dev)
|
|
{
|
|
struct pcmcia_socket *socket;
|
|
|
|
diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c
|
|
index 46561fa..a04f21c 100644
|
|
--- a/drivers/pcmcia/i82092.c
|
|
+++ b/drivers/pcmcia/i82092.c
|
|
@@ -42,7 +42,7 @@ MODULE_DEVICE_TABLE(pci, i82092aa_pci_ids);
|
|
#ifdef CONFIG_PM
|
|
static int i82092aa_socket_suspend (struct pci_dev *dev, pm_message_t state)
|
|
{
|
|
- return pcmcia_socket_dev_suspend(&dev->dev, state);
|
|
+ return pcmcia_socket_dev_suspend(&dev->dev);
|
|
}
|
|
|
|
static int i82092aa_socket_resume (struct pci_dev *dev)
|
|
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
|
|
index 40d4953..b906abe 100644
|
|
--- a/drivers/pcmcia/i82365.c
|
|
+++ b/drivers/pcmcia/i82365.c
|
|
@@ -1241,7 +1241,7 @@ static int pcic_init(struct pcmcia_socket *s)
|
|
static int i82365_drv_pcmcia_suspend(struct platform_device *dev,
|
|
pm_message_t state)
|
|
{
|
|
- return pcmcia_socket_dev_suspend(&dev->dev, state);
|
|
+ return pcmcia_socket_dev_suspend(&dev->dev);
|
|
}
|
|
|
|
static int i82365_drv_pcmcia_resume(struct platform_device *dev)
|
|
diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c
|
|
index 62b4ecc..d1d89c4 100644
|
|
--- a/drivers/pcmcia/m32r_cfc.c
|
|
+++ b/drivers/pcmcia/m32r_cfc.c
|
|
@@ -699,7 +699,7 @@ static struct pccard_operations pcc_operations = {
|
|
static int cfc_drv_pcmcia_suspend(struct platform_device *dev,
|
|
pm_message_t state)
|
|
{
|
|
- return pcmcia_socket_dev_suspend(&dev->dev, state);
|
|
+ return pcmcia_socket_dev_suspend(&dev->dev);
|
|
}
|
|
|
|
static int cfc_drv_pcmcia_resume(struct platform_device *dev)
|
|
diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c
|
|
index 12034b4..a065583 100644
|
|
--- a/drivers/pcmcia/m32r_pcc.c
|
|
+++ b/drivers/pcmcia/m32r_pcc.c
|
|
@@ -675,7 +675,7 @@ static struct pccard_operations pcc_operations = {
|
|
static int pcc_drv_pcmcia_suspend(struct platform_device *dev,
|
|
pm_message_t state)
|
|
{
|
|
- return pcmcia_socket_dev_suspend(&dev->dev, state);
|
|
+ return pcmcia_socket_dev_suspend(&dev->dev);
|
|
}
|
|
|
|
static int pcc_drv_pcmcia_resume(struct platform_device *dev)
|
|
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
|
|
index d1ad096..c69f2c4 100644
|
|
--- a/drivers/pcmcia/m8xx_pcmcia.c
|
|
+++ b/drivers/pcmcia/m8xx_pcmcia.c
|
|
@@ -1296,7 +1296,7 @@ static int m8xx_remove(struct of_device *ofdev)
|
|
#ifdef CONFIG_PM
|
|
static int m8xx_suspend(struct platform_device *pdev, pm_message_t state)
|
|
{
|
|
- return pcmcia_socket_dev_suspend(&pdev->dev, state);
|
|
+ return pcmcia_socket_dev_suspend(&pdev->dev);
|
|
}
|
|
|
|
static int m8xx_resume(struct platform_device *pdev)
|
|
diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c
|
|
index f373639..68570bc 100644
|
|
--- a/drivers/pcmcia/omap_cf.c
|
|
+++ b/drivers/pcmcia/omap_cf.c
|
|
@@ -334,7 +334,7 @@ static int __exit omap_cf_remove(struct platform_device *pdev)
|
|
|
|
static int omap_cf_suspend(struct platform_device *pdev, pm_message_t mesg)
|
|
{
|
|
- return pcmcia_socket_dev_suspend(&pdev->dev, mesg);
|
|
+ return pcmcia_socket_dev_suspend(&pdev->dev);
|
|
}
|
|
|
|
static int omap_cf_resume(struct platform_device *pdev)
|
|
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c
|
|
index 8bed1da..1c39d34 100644
|
|
--- a/drivers/pcmcia/pd6729.c
|
|
+++ b/drivers/pcmcia/pd6729.c
|
|
@@ -758,7 +758,7 @@ static void __devexit pd6729_pci_remove(struct pci_dev *dev)
|
|
#ifdef CONFIG_PM
|
|
static int pd6729_socket_suspend(struct pci_dev *dev, pm_message_t state)
|
|
{
|
|
- return pcmcia_socket_dev_suspend(&dev->dev, state);
|
|
+ return pcmcia_socket_dev_suspend(&dev->dev);
|
|
}
|
|
|
|
static int pd6729_socket_resume(struct pci_dev *dev)
|
|
diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c
|
|
index c49a726..86ad876 100644
|
|
--- a/drivers/pcmcia/pxa2xx_base.c
|
|
+++ b/drivers/pcmcia/pxa2xx_base.c
|
|
@@ -302,7 +302,7 @@ static int pxa2xx_drv_pcmcia_remove(struct platform_device *dev)
|
|
|
|
static int pxa2xx_drv_pcmcia_suspend(struct platform_device *dev, pm_message_t state)
|
|
{
|
|
- return pcmcia_socket_dev_suspend(&dev->dev, state);
|
|
+ return pcmcia_socket_dev_suspend(&dev->dev);
|
|
}
|
|
|
|
static int pxa2xx_drv_pcmcia_resume(struct platform_device *dev)
|
|
diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c
|
|
index d8da5ac..2d0e997 100644
|
|
--- a/drivers/pcmcia/sa1100_generic.c
|
|
+++ b/drivers/pcmcia/sa1100_generic.c
|
|
@@ -89,7 +89,7 @@ static int sa11x0_drv_pcmcia_remove(struct platform_device *dev)
|
|
static int sa11x0_drv_pcmcia_suspend(struct platform_device *dev,
|
|
pm_message_t state)
|
|
{
|
|
- return pcmcia_socket_dev_suspend(&dev->dev, state);
|
|
+ return pcmcia_socket_dev_suspend(&dev->dev);
|
|
}
|
|
|
|
static int sa11x0_drv_pcmcia_resume(struct platform_device *dev)
|
|
diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c
|
|
index 401052a..4be4e17 100644
|
|
--- a/drivers/pcmcia/sa1111_generic.c
|
|
+++ b/drivers/pcmcia/sa1111_generic.c
|
|
@@ -159,7 +159,7 @@ static int __devexit pcmcia_remove(struct sa1111_dev *dev)
|
|
|
|
static int pcmcia_suspend(struct sa1111_dev *dev, pm_message_t state)
|
|
{
|
|
- return pcmcia_socket_dev_suspend(&dev->dev, state);
|
|
+ return pcmcia_socket_dev_suspend(&dev->dev);
|
|
}
|
|
|
|
static int pcmcia_resume(struct sa1111_dev *dev)
|
|
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
|
|
index 8eb0423..582413f 100644
|
|
--- a/drivers/pcmcia/tcic.c
|
|
+++ b/drivers/pcmcia/tcic.c
|
|
@@ -366,7 +366,7 @@ static int __init get_tcic_id(void)
|
|
static int tcic_drv_pcmcia_suspend(struct platform_device *dev,
|
|
pm_message_t state)
|
|
{
|
|
- return pcmcia_socket_dev_suspend(&dev->dev, state);
|
|
+ return pcmcia_socket_dev_suspend(&dev->dev);
|
|
}
|
|
|
|
static int tcic_drv_pcmcia_resume(struct platform_device *dev)
|
|
diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c
|
|
index d4ad50d..c9fcbdc 100644
|
|
--- a/drivers/pcmcia/vrc4171_card.c
|
|
+++ b/drivers/pcmcia/vrc4171_card.c
|
|
@@ -707,7 +707,7 @@ __setup("vrc4171_card=", vrc4171_card_setup);
|
|
static int vrc4171_card_suspend(struct platform_device *dev,
|
|
pm_message_t state)
|
|
{
|
|
- return pcmcia_socket_dev_suspend(&dev->dev, state);
|
|
+ return pcmcia_socket_dev_suspend(&dev->dev);
|
|
}
|
|
|
|
static int vrc4171_card_resume(struct platform_device *dev)
|
|
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
|
|
index 3ecd7c9..f728a45 100644
|
|
--- a/drivers/pcmcia/yenta_socket.c
|
|
+++ b/drivers/pcmcia/yenta_socket.c
|
|
@@ -1225,60 +1225,71 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i
|
|
}
|
|
|
|
#ifdef CONFIG_PM
|
|
-static int yenta_dev_suspend (struct pci_dev *dev, pm_message_t state)
|
|
+static int yenta_dev_suspend_noirq(struct device *dev)
|
|
{
|
|
- struct yenta_socket *socket = pci_get_drvdata(dev);
|
|
+ struct pci_dev *pdev = to_pci_dev(dev);
|
|
+ struct yenta_socket *socket = pci_get_drvdata(pdev);
|
|
int ret;
|
|
|
|
- ret = pcmcia_socket_dev_suspend(&dev->dev, state);
|
|
+ ret = pcmcia_socket_dev_suspend(dev);
|
|
|
|
- if (socket) {
|
|
- if (socket->type && socket->type->save_state)
|
|
- socket->type->save_state(socket);
|
|
+ if (!socket)
|
|
+ return ret;
|
|
|
|
- /* FIXME: pci_save_state needs to have a better interface */
|
|
- pci_save_state(dev);
|
|
- pci_read_config_dword(dev, 16*4, &socket->saved_state[0]);
|
|
- pci_read_config_dword(dev, 17*4, &socket->saved_state[1]);
|
|
- pci_disable_device(dev);
|
|
+ if (socket->type && socket->type->save_state)
|
|
+ socket->type->save_state(socket);
|
|
|
|
- /*
|
|
- * Some laptops (IBM T22) do not like us putting the Cardbus
|
|
- * bridge into D3. At a guess, some other laptop will
|
|
- * probably require this, so leave it commented out for now.
|
|
- */
|
|
- /* pci_set_power_state(dev, 3); */
|
|
- }
|
|
+ pci_save_state(pdev);
|
|
+ pci_read_config_dword(pdev, 16*4, &socket->saved_state[0]);
|
|
+ pci_read_config_dword(pdev, 17*4, &socket->saved_state[1]);
|
|
+ pci_disable_device(pdev);
|
|
+
|
|
+ /*
|
|
+ * Some laptops (IBM T22) do not like us putting the Cardbus
|
|
+ * bridge into D3. At a guess, some other laptop will
|
|
+ * probably require this, so leave it commented out for now.
|
|
+ */
|
|
+ /* pci_set_power_state(dev, 3); */
|
|
|
|
return ret;
|
|
}
|
|
|
|
-
|
|
-static int yenta_dev_resume (struct pci_dev *dev)
|
|
+static int yenta_dev_resume_noirq(struct device *dev)
|
|
{
|
|
- struct yenta_socket *socket = pci_get_drvdata(dev);
|
|
+ struct pci_dev *pdev = to_pci_dev(dev);
|
|
+ struct yenta_socket *socket = pci_get_drvdata(pdev);
|
|
+ int ret;
|
|
|
|
- if (socket) {
|
|
- int rc;
|
|
+ if (!socket)
|
|
+ return 0;
|
|
|
|
- pci_set_power_state(dev, 0);
|
|
- /* FIXME: pci_restore_state needs to have a better interface */
|
|
- pci_restore_state(dev);
|
|
- pci_write_config_dword(dev, 16*4, socket->saved_state[0]);
|
|
- pci_write_config_dword(dev, 17*4, socket->saved_state[1]);
|
|
+ pci_write_config_dword(pdev, 16*4, socket->saved_state[0]);
|
|
+ pci_write_config_dword(pdev, 17*4, socket->saved_state[1]);
|
|
|
|
- rc = pci_enable_device(dev);
|
|
- if (rc)
|
|
- return rc;
|
|
+ ret = pci_enable_device(pdev);
|
|
+ if (ret)
|
|
+ return ret;
|
|
|
|
- pci_set_master(dev);
|
|
+ pci_set_master(pdev);
|
|
|
|
- if (socket->type && socket->type->restore_state)
|
|
- socket->type->restore_state(socket);
|
|
- }
|
|
+ if (socket->type && socket->type->restore_state)
|
|
+ socket->type->restore_state(socket);
|
|
|
|
- return pcmcia_socket_dev_resume(&dev->dev);
|
|
+ return pcmcia_socket_dev_resume(dev);
|
|
}
|
|
+
|
|
+static struct dev_pm_ops yenta_pm_ops = {
|
|
+ .suspend_noirq = yenta_dev_suspend_noirq,
|
|
+ .resume_noirq = yenta_dev_resume_noirq,
|
|
+ .freeze_noirq = yenta_dev_suspend_noirq,
|
|
+ .thaw_noirq = yenta_dev_resume_noirq,
|
|
+ .poweroff_noirq = yenta_dev_suspend_noirq,
|
|
+ .restore_noirq = yenta_dev_resume_noirq,
|
|
+};
|
|
+
|
|
+#define YENTA_PM_OPS (¥ta_pm_ops)
|
|
+#else
|
|
+#define YENTA_PM_OPS NULL
|
|
#endif
|
|
|
|
#define CB_ID(vend,dev,type) \
|
|
@@ -1376,10 +1387,7 @@ static struct pci_driver yenta_cardbus_driver = {
|
|
.id_table = yenta_table,
|
|
.probe = yenta_probe,
|
|
.remove = __devexit_p(yenta_close),
|
|
-#ifdef CONFIG_PM
|
|
- .suspend = yenta_dev_suspend,
|
|
- .resume = yenta_dev_resume,
|
|
-#endif
|
|
+ .driver.pm = YENTA_PM_OPS,
|
|
};
|
|
|
|
|
|
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
|
|
index dafaa4a..a234a9d 100644
|
|
--- a/drivers/platform/x86/sony-laptop.c
|
|
+++ b/drivers/platform/x86/sony-laptop.c
|
|
@@ -1081,6 +1081,8 @@ static int sony_nc_setup_rfkill(struct acpi_device *device,
|
|
struct rfkill *rfk;
|
|
enum rfkill_type type;
|
|
const char *name;
|
|
+ int result;
|
|
+ bool hwblock;
|
|
|
|
switch (nc_type) {
|
|
case SONY_WIFI:
|
|
@@ -1108,6 +1110,10 @@ static int sony_nc_setup_rfkill(struct acpi_device *device,
|
|
if (!rfk)
|
|
return -ENOMEM;
|
|
|
|
+ sony_call_snc_handle(0x124, 0x200, &result);
|
|
+ hwblock = !(result & 0x1);
|
|
+ rfkill_set_hw_state(rfk, hwblock);
|
|
+
|
|
err = rfkill_register(rfk);
|
|
if (err) {
|
|
rfkill_destroy(rfk);
|
|
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
|
|
index e856008..d287283 100644
|
|
--- a/drivers/platform/x86/thinkpad_acpi.c
|
|
+++ b/drivers/platform/x86/thinkpad_acpi.c
|
|
@@ -5655,16 +5655,16 @@ static const struct tpacpi_quirk brightness_quirk_table[] __initconst = {
|
|
/* Models with ATI GPUs known to require ECNVRAM mode */
|
|
TPACPI_Q_IBM('1', 'Y', TPACPI_BRGHT_Q_EC), /* T43/p ATI */
|
|
|
|
- /* Models with ATI GPUs (waiting confirmation) */
|
|
- TPACPI_Q_IBM('1', 'R', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
|
|
+ /* Models with ATI GPUs that can use ECNVRAM */
|
|
+ TPACPI_Q_IBM('1', 'R', TPACPI_BRGHT_Q_EC),
|
|
TPACPI_Q_IBM('1', 'Q', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
|
|
TPACPI_Q_IBM('7', '6', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
|
|
TPACPI_Q_IBM('7', '8', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC),
|
|
|
|
- /* Models with Intel Extreme Graphics 2 (waiting confirmation) */
|
|
+ /* Models with Intel Extreme Graphics 2 */
|
|
+ TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_NOEC),
|
|
TPACPI_Q_IBM('1', 'V', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC),
|
|
TPACPI_Q_IBM('1', 'W', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC),
|
|
- TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC),
|
|
|
|
/* Models with Intel GMA900 */
|
|
TPACPI_Q_IBM('7', '0', TPACPI_BRGHT_Q_NOEC), /* T43, R52 */
|
|
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
|
|
index b4a7650..4fff4e5 100644
|
|
--- a/drivers/serial/bfin_5xx.c
|
|
+++ b/drivers/serial/bfin_5xx.c
|
|
@@ -42,6 +42,10 @@
|
|
# undef CONFIG_EARLY_PRINTK
|
|
#endif
|
|
|
|
+#ifdef CONFIG_SERIAL_BFIN_MODULE
|
|
+# undef CONFIG_EARLY_PRINTK
|
|
+#endif
|
|
+
|
|
/* UART name and device definitions */
|
|
#define BFIN_SERIAL_NAME "ttyBF"
|
|
#define BFIN_SERIAL_MAJOR 204
|
|
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
|
|
index 79c9c5f..6ecb51b 100644
|
|
--- a/drivers/serial/serial_cs.c
|
|
+++ b/drivers/serial/serial_cs.c
|
|
@@ -884,6 +884,7 @@ static struct pcmcia_device_id serial_ids[] = {
|
|
PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0xa555, "SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- pre update */
|
|
PCMCIA_DEVICE_CIS_MANF_CARD(0x013f, 0xa555, "SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- post update */
|
|
PCMCIA_DEVICE_CIS_PROD_ID12("MultiTech", "PCMCIA 56K DataFax", 0x842047ee, 0xc2efcf03, "MT5634ZLX.cis"),
|
|
+ PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-2", 0x96913a85, 0x27ab5437, "COMpad2.cis"),
|
|
PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-4", 0x96913a85, 0xcec8f102, "COMpad4.cis"),
|
|
PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "COMpad2.cis"),
|
|
PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "RS-COM-2P.cis"),
|
|
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
|
|
index 2bfc41e..e3861b2 100644
|
|
--- a/drivers/usb/class/cdc-acm.c
|
|
+++ b/drivers/usb/class/cdc-acm.c
|
|
@@ -59,6 +59,7 @@
|
|
#include <linux/init.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/tty.h>
|
|
+#include <linux/serial.h>
|
|
#include <linux/tty_driver.h>
|
|
#include <linux/tty_flip.h>
|
|
#include <linux/module.h>
|
|
@@ -609,6 +610,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
|
|
acm->throttle = 0;
|
|
|
|
tasklet_schedule(&acm->urb_task);
|
|
+ set_bit(ASYNCB_INITIALIZED, &acm->port.flags);
|
|
rv = tty_port_block_til_ready(&acm->port, tty, filp);
|
|
done:
|
|
mutex_unlock(&acm->mutex);
|
|
@@ -858,10 +860,7 @@ static void acm_tty_set_termios(struct tty_struct *tty,
|
|
if (!ACM_READY(acm))
|
|
return;
|
|
|
|
- /* FIXME: Needs to support the tty_baud interface */
|
|
- /* FIXME: Broken on sparc */
|
|
- newline.dwDTERate = cpu_to_le32p(acm_tty_speed +
|
|
- (termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));
|
|
+ newline.dwDTERate = cpu_to_le32(tty_get_baud_rate(tty));
|
|
newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;
|
|
newline.bParityType = termios->c_cflag & PARENB ?
|
|
(termios->c_cflag & PARODD ? 1 : 2) +
|
|
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
|
|
index ba589d4..a9c3399 100644
|
|
--- a/drivers/usb/class/cdc-wdm.c
|
|
+++ b/drivers/usb/class/cdc-wdm.c
|
|
@@ -313,8 +313,13 @@ static ssize_t wdm_write
|
|
r = usb_autopm_get_interface(desc->intf);
|
|
if (r < 0)
|
|
goto outnp;
|
|
- r = wait_event_interruptible(desc->wait, !test_bit(WDM_IN_USE,
|
|
- &desc->flags));
|
|
+
|
|
+ if (!file->f_flags && O_NONBLOCK)
|
|
+ r = wait_event_interruptible(desc->wait, !test_bit(WDM_IN_USE,
|
|
+ &desc->flags));
|
|
+ else
|
|
+ if (test_bit(WDM_IN_USE, &desc->flags))
|
|
+ r = -EAGAIN;
|
|
if (r < 0)
|
|
goto out;
|
|
|
|
@@ -377,7 +382,7 @@ outnl:
|
|
static ssize_t wdm_read
|
|
(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
|
|
{
|
|
- int rv, cntr;
|
|
+ int rv, cntr = 0;
|
|
int i = 0;
|
|
struct wdm_device *desc = file->private_data;
|
|
|
|
@@ -389,10 +394,23 @@ static ssize_t wdm_read
|
|
if (desc->length == 0) {
|
|
desc->read = 0;
|
|
retry:
|
|
+ if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
|
|
+ rv = -ENODEV;
|
|
+ goto err;
|
|
+ }
|
|
i++;
|
|
- rv = wait_event_interruptible(desc->wait,
|
|
- test_bit(WDM_READ, &desc->flags));
|
|
+ if (file->f_flags & O_NONBLOCK) {
|
|
+ if (!test_bit(WDM_READ, &desc->flags)) {
|
|
+ rv = cntr ? cntr : -EAGAIN;
|
|
+ goto err;
|
|
+ }
|
|
+ rv = 0;
|
|
+ } else {
|
|
+ rv = wait_event_interruptible(desc->wait,
|
|
+ test_bit(WDM_READ, &desc->flags));
|
|
+ }
|
|
|
|
+ /* may have happened while we slept */
|
|
if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
|
|
rv = -ENODEV;
|
|
goto err;
|
|
@@ -448,7 +466,7 @@ retry:
|
|
|
|
err:
|
|
mutex_unlock(&desc->rlock);
|
|
- if (rv < 0)
|
|
+ if (rv < 0 && rv != -EAGAIN)
|
|
dev_err(&desc->intf->dev, "wdm_read: exit error\n");
|
|
return rv;
|
|
}
|
|
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
|
|
index b09a527..21b3719 100644
|
|
--- a/drivers/usb/class/usbtmc.c
|
|
+++ b/drivers/usb/class/usbtmc.c
|
|
@@ -367,13 +367,13 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
|
|
{
|
|
struct usbtmc_device_data *data;
|
|
struct device *dev;
|
|
- unsigned long int n_characters;
|
|
+ u32 n_characters;
|
|
u8 *buffer;
|
|
int actual;
|
|
- int done;
|
|
- int remaining;
|
|
+ size_t done;
|
|
+ size_t remaining;
|
|
int retval;
|
|
- int this_part;
|
|
+ size_t this_part;
|
|
|
|
/* Get pointer to private data structure */
|
|
data = filp->private_data;
|
|
@@ -455,6 +455,18 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
|
|
(buffer[6] << 16) +
|
|
(buffer[7] << 24);
|
|
|
|
+ /* Ensure the instrument doesn't lie about it */
|
|
+ if(n_characters > actual - 12) {
|
|
+ dev_err(dev, "Device lies about message size: %zu > %zu\n", n_characters, actual - 12);
|
|
+ n_characters = actual - 12;
|
|
+ }
|
|
+
|
|
+ /* Ensure the instrument doesn't send more back than requested */
|
|
+ if(n_characters > this_part) {
|
|
+ dev_err(dev, "Device returns more than requested: %zu > %zu\n", done + n_characters, done + this_part);
|
|
+ n_characters = this_part;
|
|
+ }
|
|
+
|
|
/* Copy buffer to user space */
|
|
if (copy_to_user(buf + done, &buffer[12], n_characters)) {
|
|
/* There must have been an addressing problem */
|
|
@@ -465,6 +477,8 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
|
|
done += n_characters;
|
|
if (n_characters < USBTMC_SIZE_IOBUFFER)
|
|
remaining = 0;
|
|
+ else
|
|
+ remaining -= n_characters;
|
|
}
|
|
|
|
/* Update file position value */
|
|
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
|
|
index a16c538..0d3af6a 100644
|
|
--- a/drivers/usb/core/config.c
|
|
+++ b/drivers/usb/core/config.c
|
|
@@ -105,7 +105,7 @@ static int usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
|
|
ep->ss_ep_comp->extralen = i;
|
|
buffer += i;
|
|
size -= i;
|
|
- retval = buffer - buffer_start + i;
|
|
+ retval = buffer - buffer_start;
|
|
if (num_skipped > 0)
|
|
dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
|
|
num_skipped, plural(num_skipped),
|
|
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
|
|
index a949259..5b22a4d 100644
|
|
--- a/drivers/usb/host/sl811-hcd.c
|
|
+++ b/drivers/usb/host/sl811-hcd.c
|
|
@@ -719,8 +719,12 @@ retry:
|
|
/* port status seems weird until after reset, so
|
|
* force the reset and make khubd clean up later.
|
|
*/
|
|
- sl811->port1 |= (1 << USB_PORT_FEAT_C_CONNECTION)
|
|
- | (1 << USB_PORT_FEAT_CONNECTION);
|
|
+ if (sl811->stat_insrmv & 1)
|
|
+ sl811->port1 |= 1 << USB_PORT_FEAT_CONNECTION;
|
|
+ else
|
|
+ sl811->port1 &= ~(1 << USB_PORT_FEAT_CONNECTION);
|
|
+
|
|
+ sl811->port1 |= 1 << USB_PORT_FEAT_C_CONNECTION;
|
|
|
|
} else if (irqstat & SL11H_INTMASK_RD) {
|
|
if (sl811->port1 & (1 << USB_PORT_FEAT_SUSPEND)) {
|
|
diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c
|
|
index 705e343..33128d5 100644
|
|
--- a/drivers/usb/host/xhci-dbg.c
|
|
+++ b/drivers/usb/host/xhci-dbg.c
|
|
@@ -413,7 +413,8 @@ void xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx)
|
|
int i;
|
|
|
|
struct xhci_slot_ctx *slot_ctx = xhci_get_slot_ctx(xhci, ctx);
|
|
- dma_addr_t dma = ctx->dma + ((unsigned long)slot_ctx - (unsigned long)ctx);
|
|
+ dma_addr_t dma = ctx->dma +
|
|
+ ((unsigned long)slot_ctx - (unsigned long)ctx->bytes);
|
|
int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params);
|
|
|
|
xhci_dbg(xhci, "Slot Context:\n");
|
|
@@ -459,7 +460,7 @@ void xhci_dbg_ep_ctx(struct xhci_hcd *xhci,
|
|
for (i = 0; i < last_ep_ctx; ++i) {
|
|
struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, ctx, i);
|
|
dma_addr_t dma = ctx->dma +
|
|
- ((unsigned long)ep_ctx - (unsigned long)ctx);
|
|
+ ((unsigned long)ep_ctx - (unsigned long)ctx->bytes);
|
|
|
|
xhci_dbg(xhci, "Endpoint %02d Context:\n", i);
|
|
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info\n",
|
|
diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
|
|
index 816c39c..e478a63 100644
|
|
--- a/drivers/usb/host/xhci-hcd.c
|
|
+++ b/drivers/usb/host/xhci-hcd.c
|
|
@@ -22,12 +22,18 @@
|
|
|
|
#include <linux/irq.h>
|
|
#include <linux/module.h>
|
|
+#include <linux/moduleparam.h>
|
|
|
|
#include "xhci.h"
|
|
|
|
#define DRIVER_AUTHOR "Sarah Sharp"
|
|
#define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver"
|
|
|
|
+/* Some 0.95 hardware can't handle the chain bit on a Link TRB being cleared */
|
|
+static int link_quirk;
|
|
+module_param(link_quirk, int, S_IRUGO | S_IWUSR);
|
|
+MODULE_PARM_DESC(link_quirk, "Don't clear the chain bit on a link TRB");
|
|
+
|
|
/* TODO: copied from ehci-hcd.c - can this be refactored? */
|
|
/*
|
|
* handshake - spin reading hc until handshake completes or fails
|
|
@@ -214,6 +220,12 @@ int xhci_init(struct usb_hcd *hcd)
|
|
|
|
xhci_dbg(xhci, "xhci_init\n");
|
|
spin_lock_init(&xhci->lock);
|
|
+ if (link_quirk) {
|
|
+ xhci_dbg(xhci, "QUIRK: Not clearing Link TRB chain bits.\n");
|
|
+ xhci->quirks |= XHCI_LINK_TRB_QUIRK;
|
|
+ } else {
|
|
+ xhci_dbg(xhci, "xHCI doesn't need link TRB QUIRK\n");
|
|
+ }
|
|
retval = xhci_mem_init(xhci, GFP_KERNEL);
|
|
xhci_dbg(xhci, "Finished xhci_init\n");
|
|
|
|
@@ -555,13 +567,22 @@ unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc)
|
|
return 1 << (xhci_get_endpoint_index(desc) + 1);
|
|
}
|
|
|
|
+/* Find the flag for this endpoint (for use in the control context). Use the
|
|
+ * endpoint index to create a bitmask. The slot context is bit 0, endpoint 0 is
|
|
+ * bit 1, etc.
|
|
+ */
|
|
+unsigned int xhci_get_endpoint_flag_from_index(unsigned int ep_index)
|
|
+{
|
|
+ return 1 << (ep_index + 1);
|
|
+}
|
|
+
|
|
/* Compute the last valid endpoint context index. Basically, this is the
|
|
* endpoint index plus one. For slot contexts with more than valid endpoint,
|
|
* we find the most significant bit set in the added contexts flags.
|
|
* e.g. ep 1 IN (with epnum 0x81) => added_ctxs = 0b1000
|
|
* fls(0b1000) = 4, but the endpoint context index is 3, so subtract one.
|
|
*/
|
|
-static inline unsigned int xhci_last_valid_endpoint(u32 added_ctxs)
|
|
+unsigned int xhci_last_valid_endpoint(u32 added_ctxs)
|
|
{
|
|
return fls(added_ctxs) - 1;
|
|
}
|
|
@@ -589,6 +610,70 @@ int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev,
|
|
return 1;
|
|
}
|
|
|
|
+static int xhci_configure_endpoint(struct xhci_hcd *xhci,
|
|
+ struct usb_device *udev, struct xhci_virt_device *virt_dev,
|
|
+ bool ctx_change);
|
|
+
|
|
+/*
|
|
+ * Full speed devices may have a max packet size greater than 8 bytes, but the
|
|
+ * USB core doesn't know that until it reads the first 8 bytes of the
|
|
+ * descriptor. If the usb_device's max packet size changes after that point,
|
|
+ * we need to issue an evaluate context command and wait on it.
|
|
+ */
|
|
+static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,
|
|
+ unsigned int ep_index, struct urb *urb)
|
|
+{
|
|
+ struct xhci_container_ctx *in_ctx;
|
|
+ struct xhci_container_ctx *out_ctx;
|
|
+ struct xhci_input_control_ctx *ctrl_ctx;
|
|
+ struct xhci_ep_ctx *ep_ctx;
|
|
+ int max_packet_size;
|
|
+ int hw_max_packet_size;
|
|
+ int ret = 0;
|
|
+
|
|
+ out_ctx = xhci->devs[slot_id]->out_ctx;
|
|
+ ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index);
|
|
+ hw_max_packet_size = MAX_PACKET_DECODED(ep_ctx->ep_info2);
|
|
+ max_packet_size = urb->dev->ep0.desc.wMaxPacketSize;
|
|
+ if (hw_max_packet_size != max_packet_size) {
|
|
+ xhci_dbg(xhci, "Max Packet Size for ep 0 changed.\n");
|
|
+ xhci_dbg(xhci, "Max packet size in usb_device = %d\n",
|
|
+ max_packet_size);
|
|
+ xhci_dbg(xhci, "Max packet size in xHCI HW = %d\n",
|
|
+ hw_max_packet_size);
|
|
+ xhci_dbg(xhci, "Issuing evaluate context command.\n");
|
|
+
|
|
+ /* Set up the modified control endpoint 0 */
|
|
+ xhci_endpoint_copy(xhci, xhci->devs[slot_id], ep_index);
|
|
+ in_ctx = xhci->devs[slot_id]->in_ctx;
|
|
+ ep_ctx = xhci_get_ep_ctx(xhci, in_ctx, ep_index);
|
|
+ ep_ctx->ep_info2 &= ~MAX_PACKET_MASK;
|
|
+ ep_ctx->ep_info2 |= MAX_PACKET(max_packet_size);
|
|
+
|
|
+ /* Set up the input context flags for the command */
|
|
+ /* FIXME: This won't work if a non-default control endpoint
|
|
+ * changes max packet sizes.
|
|
+ */
|
|
+ ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
|
|
+ ctrl_ctx->add_flags = EP0_FLAG;
|
|
+ ctrl_ctx->drop_flags = 0;
|
|
+
|
|
+ xhci_dbg(xhci, "Slot %d input context\n", slot_id);
|
|
+ xhci_dbg_ctx(xhci, in_ctx, ep_index);
|
|
+ xhci_dbg(xhci, "Slot %d output context\n", slot_id);
|
|
+ xhci_dbg_ctx(xhci, out_ctx, ep_index);
|
|
+
|
|
+ ret = xhci_configure_endpoint(xhci, urb->dev,
|
|
+ xhci->devs[slot_id], true);
|
|
+
|
|
+ /* Clean up the input context for later use by bandwidth
|
|
+ * functions.
|
|
+ */
|
|
+ ctrl_ctx->add_flags = SLOT_FLAG;
|
|
+ }
|
|
+ return ret;
|
|
+}
|
|
+
|
|
/*
|
|
* non-error returns are a promise to giveback() the urb later
|
|
* we drop ownership so next owner (or urb unlink) can get it
|
|
@@ -600,13 +685,13 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
|
|
int ret = 0;
|
|
unsigned int slot_id, ep_index;
|
|
|
|
+
|
|
if (!urb || xhci_check_args(hcd, urb->dev, urb->ep, true, __func__) <= 0)
|
|
return -EINVAL;
|
|
|
|
slot_id = urb->dev->slot_id;
|
|
ep_index = xhci_get_endpoint_index(&urb->ep->desc);
|
|
|
|
- spin_lock_irqsave(&xhci->lock, flags);
|
|
if (!xhci->devs || !xhci->devs[slot_id]) {
|
|
if (!in_interrupt())
|
|
dev_warn(&urb->dev->dev, "WARN: urb submitted for dev with no Slot ID\n");
|
|
@@ -619,19 +704,38 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
|
|
ret = -ESHUTDOWN;
|
|
goto exit;
|
|
}
|
|
- if (usb_endpoint_xfer_control(&urb->ep->desc))
|
|
+ if (usb_endpoint_xfer_control(&urb->ep->desc)) {
|
|
+ /* Check to see if the max packet size for the default control
|
|
+ * endpoint changed during FS device enumeration
|
|
+ */
|
|
+ if (urb->dev->speed == USB_SPEED_FULL) {
|
|
+ ret = xhci_check_maxpacket(xhci, slot_id,
|
|
+ ep_index, urb);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
/* We have a spinlock and interrupts disabled, so we must pass
|
|
* atomic context to this function, which may allocate memory.
|
|
*/
|
|
+ spin_lock_irqsave(&xhci->lock, flags);
|
|
ret = xhci_queue_ctrl_tx(xhci, GFP_ATOMIC, urb,
|
|
slot_id, ep_index);
|
|
- else if (usb_endpoint_xfer_bulk(&urb->ep->desc))
|
|
+ spin_unlock_irqrestore(&xhci->lock, flags);
|
|
+ } else if (usb_endpoint_xfer_bulk(&urb->ep->desc)) {
|
|
+ spin_lock_irqsave(&xhci->lock, flags);
|
|
ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb,
|
|
slot_id, ep_index);
|
|
- else
|
|
+ spin_unlock_irqrestore(&xhci->lock, flags);
|
|
+ } else if (usb_endpoint_xfer_int(&urb->ep->desc)) {
|
|
+ spin_lock_irqsave(&xhci->lock, flags);
|
|
+ ret = xhci_queue_intr_tx(xhci, GFP_ATOMIC, urb,
|
|
+ slot_id, ep_index);
|
|
+ spin_unlock_irqrestore(&xhci->lock, flags);
|
|
+ } else {
|
|
ret = -EINVAL;
|
|
+ }
|
|
exit:
|
|
- spin_unlock_irqrestore(&xhci->lock, flags);
|
|
return ret;
|
|
}
|
|
|
|
@@ -930,6 +1034,122 @@ static void xhci_zero_in_ctx(struct xhci_hcd *xhci, struct xhci_virt_device *vir
|
|
}
|
|
}
|
|
|
|
+static int xhci_configure_endpoint_result(struct xhci_hcd *xhci,
|
|
+ struct usb_device *udev, struct xhci_virt_device *virt_dev)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ switch (virt_dev->cmd_status) {
|
|
+ case COMP_ENOMEM:
|
|
+ dev_warn(&udev->dev, "Not enough host controller resources "
|
|
+ "for new device state.\n");
|
|
+ ret = -ENOMEM;
|
|
+ /* FIXME: can we allocate more resources for the HC? */
|
|
+ break;
|
|
+ case COMP_BW_ERR:
|
|
+ dev_warn(&udev->dev, "Not enough bandwidth "
|
|
+ "for new device state.\n");
|
|
+ ret = -ENOSPC;
|
|
+ /* FIXME: can we go back to the old state? */
|
|
+ break;
|
|
+ case COMP_TRB_ERR:
|
|
+ /* the HCD set up something wrong */
|
|
+ dev_warn(&udev->dev, "ERROR: Endpoint drop flag = 0, "
|
|
+ "add flag = 1, "
|
|
+ "and endpoint is not disabled.\n");
|
|
+ ret = -EINVAL;
|
|
+ break;
|
|
+ case COMP_SUCCESS:
|
|
+ dev_dbg(&udev->dev, "Successful Endpoint Configure command\n");
|
|
+ ret = 0;
|
|
+ break;
|
|
+ default:
|
|
+ xhci_err(xhci, "ERROR: unexpected command completion "
|
|
+ "code 0x%x.\n", virt_dev->cmd_status);
|
|
+ ret = -EINVAL;
|
|
+ break;
|
|
+ }
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int xhci_evaluate_context_result(struct xhci_hcd *xhci,
|
|
+ struct usb_device *udev, struct xhci_virt_device *virt_dev)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ switch (virt_dev->cmd_status) {
|
|
+ case COMP_EINVAL:
|
|
+ dev_warn(&udev->dev, "WARN: xHCI driver setup invalid evaluate "
|
|
+ "context command.\n");
|
|
+ ret = -EINVAL;
|
|
+ break;
|
|
+ case COMP_EBADSLT:
|
|
+ dev_warn(&udev->dev, "WARN: slot not enabled for"
|
|
+ "evaluate context command.\n");
|
|
+ case COMP_CTX_STATE:
|
|
+ dev_warn(&udev->dev, "WARN: invalid context state for "
|
|
+ "evaluate context command.\n");
|
|
+ xhci_dbg_ctx(xhci, virt_dev->out_ctx, 1);
|
|
+ ret = -EINVAL;
|
|
+ break;
|
|
+ case COMP_SUCCESS:
|
|
+ dev_dbg(&udev->dev, "Successful evaluate context command\n");
|
|
+ ret = 0;
|
|
+ break;
|
|
+ default:
|
|
+ xhci_err(xhci, "ERROR: unexpected command completion "
|
|
+ "code 0x%x.\n", virt_dev->cmd_status);
|
|
+ ret = -EINVAL;
|
|
+ break;
|
|
+ }
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/* Issue a configure endpoint command or evaluate context command
|
|
+ * and wait for it to finish.
|
|
+ */
|
|
+static int xhci_configure_endpoint(struct xhci_hcd *xhci,
|
|
+ struct usb_device *udev, struct xhci_virt_device *virt_dev,
|
|
+ bool ctx_change)
|
|
+{
|
|
+ int ret;
|
|
+ int timeleft;
|
|
+ unsigned long flags;
|
|
+
|
|
+ spin_lock_irqsave(&xhci->lock, flags);
|
|
+ if (!ctx_change)
|
|
+ ret = xhci_queue_configure_endpoint(xhci, virt_dev->in_ctx->dma,
|
|
+ udev->slot_id);
|
|
+ else
|
|
+ ret = xhci_queue_evaluate_context(xhci, virt_dev->in_ctx->dma,
|
|
+ udev->slot_id);
|
|
+ if (ret < 0) {
|
|
+ spin_unlock_irqrestore(&xhci->lock, flags);
|
|
+ xhci_dbg(xhci, "FIXME allocate a new ring segment\n");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ xhci_ring_cmd_db(xhci);
|
|
+ spin_unlock_irqrestore(&xhci->lock, flags);
|
|
+
|
|
+ /* Wait for the configure endpoint command to complete */
|
|
+ timeleft = wait_for_completion_interruptible_timeout(
|
|
+ &virt_dev->cmd_completion,
|
|
+ USB_CTRL_SET_TIMEOUT);
|
|
+ if (timeleft <= 0) {
|
|
+ xhci_warn(xhci, "%s while waiting for %s command\n",
|
|
+ timeleft == 0 ? "Timeout" : "Signal",
|
|
+ ctx_change == 0 ?
|
|
+ "configure endpoint" :
|
|
+ "evaluate context");
|
|
+ /* FIXME cancel the configure endpoint command */
|
|
+ return -ETIME;
|
|
+ }
|
|
+
|
|
+ if (!ctx_change)
|
|
+ return xhci_configure_endpoint_result(xhci, udev, virt_dev);
|
|
+ return xhci_evaluate_context_result(xhci, udev, virt_dev);
|
|
+}
|
|
+
|
|
/* Called after one or more calls to xhci_add_endpoint() or
|
|
* xhci_drop_endpoint(). If this call fails, the USB core is expected
|
|
* to call xhci_reset_bandwidth().
|
|
@@ -944,8 +1164,6 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
|
|
{
|
|
int i;
|
|
int ret = 0;
|
|
- int timeleft;
|
|
- unsigned long flags;
|
|
struct xhci_hcd *xhci;
|
|
struct xhci_virt_device *virt_dev;
|
|
struct xhci_input_control_ctx *ctrl_ctx;
|
|
@@ -975,56 +1193,7 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
|
|
xhci_dbg_ctx(xhci, virt_dev->in_ctx,
|
|
LAST_CTX_TO_EP_NUM(slot_ctx->dev_info));
|
|
|
|
- spin_lock_irqsave(&xhci->lock, flags);
|
|
- ret = xhci_queue_configure_endpoint(xhci, virt_dev->in_ctx->dma,
|
|
- udev->slot_id);
|
|
- if (ret < 0) {
|
|
- spin_unlock_irqrestore(&xhci->lock, flags);
|
|
- xhci_dbg(xhci, "FIXME allocate a new ring segment\n");
|
|
- return -ENOMEM;
|
|
- }
|
|
- xhci_ring_cmd_db(xhci);
|
|
- spin_unlock_irqrestore(&xhci->lock, flags);
|
|
-
|
|
- /* Wait for the configure endpoint command to complete */
|
|
- timeleft = wait_for_completion_interruptible_timeout(
|
|
- &virt_dev->cmd_completion,
|
|
- USB_CTRL_SET_TIMEOUT);
|
|
- if (timeleft <= 0) {
|
|
- xhci_warn(xhci, "%s while waiting for configure endpoint command\n",
|
|
- timeleft == 0 ? "Timeout" : "Signal");
|
|
- /* FIXME cancel the configure endpoint command */
|
|
- return -ETIME;
|
|
- }
|
|
-
|
|
- switch (virt_dev->cmd_status) {
|
|
- case COMP_ENOMEM:
|
|
- dev_warn(&udev->dev, "Not enough host controller resources "
|
|
- "for new device state.\n");
|
|
- ret = -ENOMEM;
|
|
- /* FIXME: can we allocate more resources for the HC? */
|
|
- break;
|
|
- case COMP_BW_ERR:
|
|
- dev_warn(&udev->dev, "Not enough bandwidth "
|
|
- "for new device state.\n");
|
|
- ret = -ENOSPC;
|
|
- /* FIXME: can we go back to the old state? */
|
|
- break;
|
|
- case COMP_TRB_ERR:
|
|
- /* the HCD set up something wrong */
|
|
- dev_warn(&udev->dev, "ERROR: Endpoint drop flag = 0, add flag = 1, "
|
|
- "and endpoint is not disabled.\n");
|
|
- ret = -EINVAL;
|
|
- break;
|
|
- case COMP_SUCCESS:
|
|
- dev_dbg(&udev->dev, "Successful Endpoint Configure command\n");
|
|
- break;
|
|
- default:
|
|
- xhci_err(xhci, "ERROR: unexpected command completion "
|
|
- "code 0x%x.\n", virt_dev->cmd_status);
|
|
- ret = -EINVAL;
|
|
- break;
|
|
- }
|
|
+ ret = xhci_configure_endpoint(xhci, udev, virt_dev, false);
|
|
if (ret) {
|
|
/* Callee should call reset_bandwidth() */
|
|
return ret;
|
|
@@ -1075,6 +1244,75 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
|
|
xhci_zero_in_ctx(xhci, virt_dev);
|
|
}
|
|
|
|
+void xhci_setup_input_ctx_for_quirk(struct xhci_hcd *xhci,
|
|
+ unsigned int slot_id, unsigned int ep_index,
|
|
+ struct xhci_dequeue_state *deq_state)
|
|
+{
|
|
+ struct xhci_container_ctx *in_ctx;
|
|
+ struct xhci_input_control_ctx *ctrl_ctx;
|
|
+ struct xhci_ep_ctx *ep_ctx;
|
|
+ u32 added_ctxs;
|
|
+ dma_addr_t addr;
|
|
+
|
|
+ xhci_endpoint_copy(xhci, xhci->devs[slot_id], ep_index);
|
|
+ in_ctx = xhci->devs[slot_id]->in_ctx;
|
|
+ ep_ctx = xhci_get_ep_ctx(xhci, in_ctx, ep_index);
|
|
+ addr = xhci_trb_virt_to_dma(deq_state->new_deq_seg,
|
|
+ deq_state->new_deq_ptr);
|
|
+ if (addr == 0) {
|
|
+ xhci_warn(xhci, "WARN Cannot submit config ep after "
|
|
+ "reset ep command\n");
|
|
+ xhci_warn(xhci, "WARN deq seg = %p, deq ptr = %p\n",
|
|
+ deq_state->new_deq_seg,
|
|
+ deq_state->new_deq_ptr);
|
|
+ return;
|
|
+ }
|
|
+ ep_ctx->deq = addr | deq_state->new_cycle_state;
|
|
+
|
|
+ xhci_slot_copy(xhci, xhci->devs[slot_id]);
|
|
+
|
|
+ ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
|
|
+ added_ctxs = xhci_get_endpoint_flag_from_index(ep_index);
|
|
+ ctrl_ctx->add_flags = added_ctxs | SLOT_FLAG;
|
|
+ ctrl_ctx->drop_flags = added_ctxs;
|
|
+
|
|
+ xhci_dbg(xhci, "Slot ID %d Input Context:\n", slot_id);
|
|
+ xhci_dbg_ctx(xhci, in_ctx, ep_index);
|
|
+}
|
|
+
|
|
+void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,
|
|
+ struct usb_device *udev,
|
|
+ unsigned int ep_index, struct xhci_ring *ep_ring)
|
|
+{
|
|
+ struct xhci_dequeue_state deq_state;
|
|
+
|
|
+ xhci_dbg(xhci, "Cleaning up stalled endpoint ring\n");
|
|
+ /* We need to move the HW's dequeue pointer past this TD,
|
|
+ * or it will attempt to resend it on the next doorbell ring.
|
|
+ */
|
|
+ xhci_find_new_dequeue_state(xhci, udev->slot_id,
|
|
+ ep_index, ep_ring->stopped_td,
|
|
+ &deq_state);
|
|
+
|
|
+ /* HW with the reset endpoint quirk will use the saved dequeue state to
|
|
+ * issue a configure endpoint command later.
|
|
+ */
|
|
+ if (!(xhci->quirks & XHCI_RESET_EP_QUIRK)) {
|
|
+ xhci_dbg(xhci, "Queueing new dequeue state\n");
|
|
+ xhci_queue_new_dequeue_state(xhci, ep_ring,
|
|
+ udev->slot_id,
|
|
+ ep_index, &deq_state);
|
|
+ } else {
|
|
+ /* Better hope no one uses the input context between now and the
|
|
+ * reset endpoint completion!
|
|
+ */
|
|
+ xhci_dbg(xhci, "Setting up input context for "
|
|
+ "configure endpoint command\n");
|
|
+ xhci_setup_input_ctx_for_quirk(xhci, udev->slot_id,
|
|
+ ep_index, &deq_state);
|
|
+ }
|
|
+}
|
|
+
|
|
/* Deal with stalled endpoints. The core should have sent the control message
|
|
* to clear the halt condition. However, we need to make the xHCI hardware
|
|
* reset its sequence number, since a device will expect a sequence number of
|
|
@@ -1089,7 +1327,6 @@ void xhci_endpoint_reset(struct usb_hcd *hcd,
|
|
unsigned int ep_index;
|
|
unsigned long flags;
|
|
int ret;
|
|
- struct xhci_dequeue_state deq_state;
|
|
struct xhci_ring *ep_ring;
|
|
|
|
xhci = hcd_to_xhci(hcd);
|
|
@@ -1106,6 +1343,10 @@ void xhci_endpoint_reset(struct usb_hcd *hcd,
|
|
ep->desc.bEndpointAddress);
|
|
return;
|
|
}
|
|
+ if (usb_endpoint_xfer_control(&ep->desc)) {
|
|
+ xhci_dbg(xhci, "Control endpoint stall already handled.\n");
|
|
+ return;
|
|
+ }
|
|
|
|
xhci_dbg(xhci, "Queueing reset endpoint command\n");
|
|
spin_lock_irqsave(&xhci->lock, flags);
|
|
@@ -1116,16 +1357,7 @@ void xhci_endpoint_reset(struct usb_hcd *hcd,
|
|
* command. Better hope that last command worked!
|
|
*/
|
|
if (!ret) {
|
|
- xhci_dbg(xhci, "Cleaning up stalled endpoint ring\n");
|
|
- /* We need to move the HW's dequeue pointer past this TD,
|
|
- * or it will attempt to resend it on the next doorbell ring.
|
|
- */
|
|
- xhci_find_new_dequeue_state(xhci, udev->slot_id,
|
|
- ep_index, ep_ring->stopped_td, &deq_state);
|
|
- xhci_dbg(xhci, "Queueing new dequeue state\n");
|
|
- xhci_queue_new_dequeue_state(xhci, ep_ring,
|
|
- udev->slot_id,
|
|
- ep_index, &deq_state);
|
|
+ xhci_cleanup_stalled_ring(xhci, udev, ep_index, ep_ring);
|
|
kfree(ep_ring->stopped_td);
|
|
xhci_ring_cmd_db(xhci);
|
|
}
|
|
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
|
|
index e6b9a1c..55920b3 100644
|
|
--- a/drivers/usb/host/xhci-mem.c
|
|
+++ b/drivers/usb/host/xhci-mem.c
|
|
@@ -94,6 +94,9 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,
|
|
val = prev->trbs[TRBS_PER_SEGMENT-1].link.control;
|
|
val &= ~TRB_TYPE_BITMASK;
|
|
val |= TRB_TYPE(TRB_LINK);
|
|
+ /* Always set the chain bit with 0.95 hardware */
|
|
+ if (xhci_link_trb_quirk(xhci))
|
|
+ val |= TRB_CHAIN;
|
|
prev->trbs[TRBS_PER_SEGMENT-1].link.control = val;
|
|
}
|
|
xhci_dbg(xhci, "Linking segment 0x%llx to segment 0x%llx (DMA)\n",
|
|
@@ -398,15 +401,28 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
|
|
/* Step 5 */
|
|
ep0_ctx->ep_info2 = EP_TYPE(CTRL_EP);
|
|
/*
|
|
- * See section 4.3 bullet 6:
|
|
- * The default Max Packet size for ep0 is "8 bytes for a USB2
|
|
- * LS/FS/HS device or 512 bytes for a USB3 SS device"
|
|
* XXX: Not sure about wireless USB devices.
|
|
*/
|
|
- if (udev->speed == USB_SPEED_SUPER)
|
|
+ switch (udev->speed) {
|
|
+ case USB_SPEED_SUPER:
|
|
ep0_ctx->ep_info2 |= MAX_PACKET(512);
|
|
- else
|
|
+ break;
|
|
+ case USB_SPEED_HIGH:
|
|
+ /* USB core guesses at a 64-byte max packet first for FS devices */
|
|
+ case USB_SPEED_FULL:
|
|
+ ep0_ctx->ep_info2 |= MAX_PACKET(64);
|
|
+ break;
|
|
+ case USB_SPEED_LOW:
|
|
ep0_ctx->ep_info2 |= MAX_PACKET(8);
|
|
+ break;
|
|
+ case USB_SPEED_VARIABLE:
|
|
+ xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n");
|
|
+ return -EINVAL;
|
|
+ break;
|
|
+ default:
|
|
+ /* New speed? */
|
|
+ BUG();
|
|
+ }
|
|
/* EP 0 can handle "burst" sizes of 1, so Max Burst Size field is 0 */
|
|
ep0_ctx->ep_info2 |= MAX_BURST(0);
|
|
ep0_ctx->ep_info2 |= ERROR_COUNT(3);
|
|
@@ -598,6 +614,44 @@ void xhci_endpoint_zero(struct xhci_hcd *xhci,
|
|
*/
|
|
}
|
|
|
|
+/* Copy output xhci_ep_ctx to the input xhci_ep_ctx copy.
|
|
+ * Useful when you want to change one particular aspect of the endpoint and then
|
|
+ * issue a configure endpoint command.
|
|
+ */
|
|
+void xhci_endpoint_copy(struct xhci_hcd *xhci,
|
|
+ struct xhci_virt_device *vdev, unsigned int ep_index)
|
|
+{
|
|
+ struct xhci_ep_ctx *out_ep_ctx;
|
|
+ struct xhci_ep_ctx *in_ep_ctx;
|
|
+
|
|
+ out_ep_ctx = xhci_get_ep_ctx(xhci, vdev->out_ctx, ep_index);
|
|
+ in_ep_ctx = xhci_get_ep_ctx(xhci, vdev->in_ctx, ep_index);
|
|
+
|
|
+ in_ep_ctx->ep_info = out_ep_ctx->ep_info;
|
|
+ in_ep_ctx->ep_info2 = out_ep_ctx->ep_info2;
|
|
+ in_ep_ctx->deq = out_ep_ctx->deq;
|
|
+ in_ep_ctx->tx_info = out_ep_ctx->tx_info;
|
|
+}
|
|
+
|
|
+/* Copy output xhci_slot_ctx to the input xhci_slot_ctx.
|
|
+ * Useful when you want to change one particular aspect of the endpoint and then
|
|
+ * issue a configure endpoint command. Only the context entries field matters,
|
|
+ * but we'll copy the whole thing anyway.
|
|
+ */
|
|
+void xhci_slot_copy(struct xhci_hcd *xhci, struct xhci_virt_device *vdev)
|
|
+{
|
|
+ struct xhci_slot_ctx *in_slot_ctx;
|
|
+ struct xhci_slot_ctx *out_slot_ctx;
|
|
+
|
|
+ in_slot_ctx = xhci_get_slot_ctx(xhci, vdev->in_ctx);
|
|
+ out_slot_ctx = xhci_get_slot_ctx(xhci, vdev->out_ctx);
|
|
+
|
|
+ in_slot_ctx->dev_info = out_slot_ctx->dev_info;
|
|
+ in_slot_ctx->dev_info2 = out_slot_ctx->dev_info2;
|
|
+ in_slot_ctx->tt_info = out_slot_ctx->tt_info;
|
|
+ in_slot_ctx->dev_state = out_slot_ctx->dev_state;
|
|
+}
|
|
+
|
|
/* Set up the scratchpad buffer array and scratchpad buffers, if needed. */
|
|
static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
|
|
{
|
|
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
|
|
index 592fe7e..8fb308d 100644
|
|
--- a/drivers/usb/host/xhci-pci.c
|
|
+++ b/drivers/usb/host/xhci-pci.c
|
|
@@ -24,6 +24,10 @@
|
|
|
|
#include "xhci.h"
|
|
|
|
+/* Device for a quirk */
|
|
+#define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73
|
|
+#define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000
|
|
+
|
|
static const char hcd_name[] = "xhci_hcd";
|
|
|
|
/* called after powerup, by probe or system-pm "wakeup" */
|
|
@@ -62,6 +66,15 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
|
|
xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
|
|
xhci_print_registers(xhci);
|
|
|
|
+ /* Look for vendor-specific quirks */
|
|
+ if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC &&
|
|
+ pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK &&
|
|
+ pdev->revision == 0x0) {
|
|
+ xhci->quirks |= XHCI_RESET_EP_QUIRK;
|
|
+ xhci_dbg(xhci, "QUIRK: Fresco Logic xHC needs configure"
|
|
+ " endpoint cmd after reset endpoint\n");
|
|
+ }
|
|
+
|
|
/* Make sure the HC is halted. */
|
|
retval = xhci_halt(xhci);
|
|
if (retval)
|
|
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
|
|
index aa88a06..ff5e6bc 100644
|
|
--- a/drivers/usb/host/xhci-ring.c
|
|
+++ b/drivers/usb/host/xhci-ring.c
|
|
@@ -172,8 +172,9 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer
|
|
* have their chain bit cleared (so that each Link TRB is a separate TD).
|
|
*
|
|
* Section 6.4.4.1 of the 0.95 spec says link TRBs cannot have the chain bit
|
|
- * set, but other sections talk about dealing with the chain bit set.
|
|
- * Assume section 6.4.4.1 is wrong, and the chain bit can be set in a Link TRB.
|
|
+ * set, but other sections talk about dealing with the chain bit set. This was
|
|
+ * fixed in the 0.96 specification errata, but we have to assume that all 0.95
|
|
+ * xHCI hardware can't handle the chain bit being cleared on a link TRB.
|
|
*/
|
|
static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer)
|
|
{
|
|
@@ -191,8 +192,14 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer
|
|
while (last_trb(xhci, ring, ring->enq_seg, next)) {
|
|
if (!consumer) {
|
|
if (ring != xhci->event_ring) {
|
|
- next->link.control &= ~TRB_CHAIN;
|
|
- next->link.control |= chain;
|
|
+ /* If we're not dealing with 0.95 hardware,
|
|
+ * carry over the chain bit of the previous TRB
|
|
+ * (which may mean the chain bit is cleared).
|
|
+ */
|
|
+ if (!xhci_link_trb_quirk(xhci)) {
|
|
+ next->link.control &= ~TRB_CHAIN;
|
|
+ next->link.control |= chain;
|
|
+ }
|
|
/* Give this link TRB to the hardware */
|
|
wmb();
|
|
if (next->link.control & TRB_CYCLE)
|
|
@@ -462,7 +469,6 @@ void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,
|
|
* ring running.
|
|
*/
|
|
ep_ring->state |= SET_DEQ_PENDING;
|
|
- xhci_ring_cmd_db(xhci);
|
|
}
|
|
|
|
/*
|
|
@@ -531,6 +537,7 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
|
|
if (deq_state.new_deq_ptr && deq_state.new_deq_seg) {
|
|
xhci_queue_new_dequeue_state(xhci, ep_ring,
|
|
slot_id, ep_index, &deq_state);
|
|
+ xhci_ring_cmd_db(xhci);
|
|
} else {
|
|
/* Otherwise just ring the doorbell to restart the ring */
|
|
ring_ep_doorbell(xhci, slot_id, ep_index);
|
|
@@ -644,18 +651,31 @@ static void handle_reset_ep_completion(struct xhci_hcd *xhci,
|
|
{
|
|
int slot_id;
|
|
unsigned int ep_index;
|
|
+ struct xhci_ring *ep_ring;
|
|
|
|
slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]);
|
|
ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]);
|
|
+ ep_ring = xhci->devs[slot_id]->ep_rings[ep_index];
|
|
/* This command will only fail if the endpoint wasn't halted,
|
|
* but we don't care.
|
|
*/
|
|
xhci_dbg(xhci, "Ignoring reset ep completion code of %u\n",
|
|
(unsigned int) GET_COMP_CODE(event->status));
|
|
|
|
- /* Clear our internal halted state and restart the ring */
|
|
- xhci->devs[slot_id]->ep_rings[ep_index]->state &= ~EP_HALTED;
|
|
- ring_ep_doorbell(xhci, slot_id, ep_index);
|
|
+ /* HW with the reset endpoint quirk needs to have a configure endpoint
|
|
+ * command complete before the endpoint can be used. Queue that here
|
|
+ * because the HW can't handle two commands being queued in a row.
|
|
+ */
|
|
+ if (xhci->quirks & XHCI_RESET_EP_QUIRK) {
|
|
+ xhci_dbg(xhci, "Queueing configure endpoint command\n");
|
|
+ xhci_queue_configure_endpoint(xhci,
|
|
+ xhci->devs[slot_id]->in_ctx->dma, slot_id);
|
|
+ xhci_ring_cmd_db(xhci);
|
|
+ } else {
|
|
+ /* Clear our internal halted state and restart the ring */
|
|
+ ep_ring->state &= ~EP_HALTED;
|
|
+ ring_ep_doorbell(xhci, slot_id, ep_index);
|
|
+ }
|
|
}
|
|
|
|
static void handle_cmd_completion(struct xhci_hcd *xhci,
|
|
@@ -664,6 +684,10 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
|
|
int slot_id = TRB_TO_SLOT_ID(event->flags);
|
|
u64 cmd_dma;
|
|
dma_addr_t cmd_dequeue_dma;
|
|
+ struct xhci_input_control_ctx *ctrl_ctx;
|
|
+ unsigned int ep_index;
|
|
+ struct xhci_ring *ep_ring;
|
|
+ unsigned int ep_state;
|
|
|
|
cmd_dma = event->cmd_trb;
|
|
cmd_dequeue_dma = xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg,
|
|
@@ -691,6 +715,41 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
|
|
xhci_free_virt_device(xhci, slot_id);
|
|
break;
|
|
case TRB_TYPE(TRB_CONFIG_EP):
|
|
+ /*
|
|
+ * Configure endpoint commands can come from the USB core
|
|
+ * configuration or alt setting changes, or because the HW
|
|
+ * needed an extra configure endpoint command after a reset
|
|
+ * endpoint command. In the latter case, the xHCI driver is
|
|
+ * not waiting on the configure endpoint command.
|
|
+ */
|
|
+ ctrl_ctx = xhci_get_input_control_ctx(xhci,
|
|
+ xhci->devs[slot_id]->in_ctx);
|
|
+ /* Input ctx add_flags are the endpoint index plus one */
|
|
+ ep_index = xhci_last_valid_endpoint(ctrl_ctx->add_flags) - 1;
|
|
+ ep_ring = xhci->devs[slot_id]->ep_rings[ep_index];
|
|
+ if (!ep_ring) {
|
|
+ /* This must have been an initial configure endpoint */
|
|
+ xhci->devs[slot_id]->cmd_status =
|
|
+ GET_COMP_CODE(event->status);
|
|
+ complete(&xhci->devs[slot_id]->cmd_completion);
|
|
+ break;
|
|
+ }
|
|
+ ep_state = ep_ring->state;
|
|
+ xhci_dbg(xhci, "Completed config ep cmd - last ep index = %d, "
|
|
+ "state = %d\n", ep_index, ep_state);
|
|
+ if (xhci->quirks & XHCI_RESET_EP_QUIRK &&
|
|
+ ep_state & EP_HALTED) {
|
|
+ /* Clear our internal halted state and restart ring */
|
|
+ xhci->devs[slot_id]->ep_rings[ep_index]->state &=
|
|
+ ~EP_HALTED;
|
|
+ ring_ep_doorbell(xhci, slot_id, ep_index);
|
|
+ } else {
|
|
+ xhci->devs[slot_id]->cmd_status =
|
|
+ GET_COMP_CODE(event->status);
|
|
+ complete(&xhci->devs[slot_id]->cmd_completion);
|
|
+ }
|
|
+ break;
|
|
+ case TRB_TYPE(TRB_EVAL_CONTEXT):
|
|
xhci->devs[slot_id]->cmd_status = GET_COMP_CODE(event->status);
|
|
complete(&xhci->devs[slot_id]->cmd_completion);
|
|
break;
|
|
@@ -806,6 +865,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|
{
|
|
struct xhci_virt_device *xdev;
|
|
struct xhci_ring *ep_ring;
|
|
+ unsigned int slot_id;
|
|
int ep_index;
|
|
struct xhci_td *td = 0;
|
|
dma_addr_t event_dma;
|
|
@@ -814,9 +874,11 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|
struct urb *urb = 0;
|
|
int status = -EINPROGRESS;
|
|
struct xhci_ep_ctx *ep_ctx;
|
|
+ u32 trb_comp_code;
|
|
|
|
xhci_dbg(xhci, "In %s\n", __func__);
|
|
- xdev = xhci->devs[TRB_TO_SLOT_ID(event->flags)];
|
|
+ slot_id = TRB_TO_SLOT_ID(event->flags);
|
|
+ xdev = xhci->devs[slot_id];
|
|
if (!xdev) {
|
|
xhci_err(xhci, "ERROR Transfer event pointed to bad slot\n");
|
|
return -ENODEV;
|
|
@@ -870,7 +932,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|
(unsigned int) event->flags);
|
|
|
|
/* Look for common error cases */
|
|
- switch (GET_COMP_CODE(event->transfer_len)) {
|
|
+ trb_comp_code = GET_COMP_CODE(event->transfer_len);
|
|
+ switch (trb_comp_code) {
|
|
/* Skip codes that require special handling depending on
|
|
* transfer type
|
|
*/
|
|
@@ -913,7 +976,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|
/* Was this a control transfer? */
|
|
if (usb_endpoint_xfer_control(&td->urb->ep->desc)) {
|
|
xhci_debug_trb(xhci, xhci->event_ring->dequeue);
|
|
- switch (GET_COMP_CODE(event->transfer_len)) {
|
|
+ switch (trb_comp_code) {
|
|
case COMP_SUCCESS:
|
|
if (event_trb == ep_ring->dequeue) {
|
|
xhci_warn(xhci, "WARN: Success on ctrl setup TRB without IOC set??\n");
|
|
@@ -928,8 +991,39 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|
break;
|
|
case COMP_SHORT_TX:
|
|
xhci_warn(xhci, "WARN: short transfer on control ep\n");
|
|
- status = -EREMOTEIO;
|
|
+ if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
|
|
+ status = -EREMOTEIO;
|
|
+ else
|
|
+ status = 0;
|
|
break;
|
|
+ case COMP_BABBLE:
|
|
+ /* The 0.96 spec says a babbling control endpoint
|
|
+ * is not halted. The 0.96 spec says it is. Some HW
|
|
+ * claims to be 0.95 compliant, but it halts the control
|
|
+ * endpoint anyway. Check if a babble halted the
|
|
+ * endpoint.
|
|
+ */
|
|
+ if (ep_ctx->ep_info != EP_STATE_HALTED)
|
|
+ break;
|
|
+ /* else fall through */
|
|
+ case COMP_STALL:
|
|
+ /* Did we transfer part of the data (middle) phase? */
|
|
+ if (event_trb != ep_ring->dequeue &&
|
|
+ event_trb != td->last_trb)
|
|
+ td->urb->actual_length =
|
|
+ td->urb->transfer_buffer_length
|
|
+ - TRB_LEN(event->transfer_len);
|
|
+ else
|
|
+ td->urb->actual_length = 0;
|
|
+
|
|
+ ep_ring->stopped_td = td;
|
|
+ ep_ring->stopped_trb = event_trb;
|
|
+ xhci_queue_reset_ep(xhci, slot_id, ep_index);
|
|
+ xhci_cleanup_stalled_ring(xhci,
|
|
+ td->urb->dev,
|
|
+ ep_index, ep_ring);
|
|
+ xhci_ring_cmd_db(xhci);
|
|
+ goto td_cleanup;
|
|
default:
|
|
/* Others already handled above */
|
|
break;
|
|
@@ -943,7 +1037,10 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|
if (event_trb == td->last_trb) {
|
|
if (td->urb->actual_length != 0) {
|
|
/* Don't overwrite a previously set error code */
|
|
- if (status == -EINPROGRESS || status == 0)
|
|
+ if ((status == -EINPROGRESS ||
|
|
+ status == 0) &&
|
|
+ (td->urb->transfer_flags
|
|
+ & URB_SHORT_NOT_OK))
|
|
/* Did we already see a short data stage? */
|
|
status = -EREMOTEIO;
|
|
} else {
|
|
@@ -952,7 +1049,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|
}
|
|
} else {
|
|
/* Maybe the event was for the data stage? */
|
|
- if (GET_COMP_CODE(event->transfer_len) != COMP_STOP_INVAL) {
|
|
+ if (trb_comp_code != COMP_STOP_INVAL) {
|
|
/* We didn't stop on a link TRB in the middle */
|
|
td->urb->actual_length =
|
|
td->urb->transfer_buffer_length -
|
|
@@ -964,7 +1061,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|
}
|
|
}
|
|
} else {
|
|
- switch (GET_COMP_CODE(event->transfer_len)) {
|
|
+ switch (trb_comp_code) {
|
|
case COMP_SUCCESS:
|
|
/* Double check that the HW transferred everything. */
|
|
if (event_trb != td->last_trb) {
|
|
@@ -975,7 +1072,12 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|
else
|
|
status = 0;
|
|
} else {
|
|
- xhci_dbg(xhci, "Successful bulk transfer!\n");
|
|
+ if (usb_endpoint_xfer_bulk(&td->urb->ep->desc))
|
|
+ xhci_dbg(xhci, "Successful bulk "
|
|
+ "transfer!\n");
|
|
+ else
|
|
+ xhci_dbg(xhci, "Successful interrupt "
|
|
+ "transfer!\n");
|
|
status = 0;
|
|
}
|
|
break;
|
|
@@ -1001,11 +1103,17 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|
td->urb->actual_length =
|
|
td->urb->transfer_buffer_length -
|
|
TRB_LEN(event->transfer_len);
|
|
- if (td->urb->actual_length < 0) {
|
|
+ if (td->urb->transfer_buffer_length <
|
|
+ td->urb->actual_length) {
|
|
xhci_warn(xhci, "HC gave bad length "
|
|
"of %d bytes left\n",
|
|
TRB_LEN(event->transfer_len));
|
|
td->urb->actual_length = 0;
|
|
+ if (td->urb->transfer_flags &
|
|
+ URB_SHORT_NOT_OK)
|
|
+ status = -EREMOTEIO;
|
|
+ else
|
|
+ status = 0;
|
|
}
|
|
/* Don't overwrite a previously set error code */
|
|
if (status == -EINPROGRESS) {
|
|
@@ -1041,14 +1149,14 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|
/* If the ring didn't stop on a Link or No-op TRB, add
|
|
* in the actual bytes transferred from the Normal TRB
|
|
*/
|
|
- if (GET_COMP_CODE(event->transfer_len) != COMP_STOP_INVAL)
|
|
+ if (trb_comp_code != COMP_STOP_INVAL)
|
|
td->urb->actual_length +=
|
|
TRB_LEN(cur_trb->generic.field[2]) -
|
|
TRB_LEN(event->transfer_len);
|
|
}
|
|
}
|
|
- if (GET_COMP_CODE(event->transfer_len) == COMP_STOP_INVAL ||
|
|
- GET_COMP_CODE(event->transfer_len) == COMP_STOP) {
|
|
+ if (trb_comp_code == COMP_STOP_INVAL ||
|
|
+ trb_comp_code == COMP_STOP) {
|
|
/* The Endpoint Stop Command completion will take care of any
|
|
* stopped TDs. A stopped TD may be restarted, so don't update
|
|
* the ring dequeue pointer or take this TD off any lists yet.
|
|
@@ -1056,7 +1164,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|
ep_ring->stopped_td = td;
|
|
ep_ring->stopped_trb = event_trb;
|
|
} else {
|
|
- if (GET_COMP_CODE(event->transfer_len) == COMP_STALL) {
|
|
+ if (trb_comp_code == COMP_STALL ||
|
|
+ trb_comp_code == COMP_BABBLE) {
|
|
/* The transfer is completed from the driver's
|
|
* perspective, but we need to issue a set dequeue
|
|
* command for this stalled endpoint to move the dequeue
|
|
@@ -1072,16 +1181,41 @@ static int handle_tx_event(struct xhci_hcd *xhci,
|
|
inc_deq(xhci, ep_ring, false);
|
|
}
|
|
|
|
+td_cleanup:
|
|
/* Clean up the endpoint's TD list */
|
|
urb = td->urb;
|
|
+ /* Do one last check of the actual transfer length.
|
|
+ * If the host controller said we transferred more data than
|
|
+ * the buffer length, urb->actual_length will be a very big
|
|
+ * number (since it's unsigned). Play it safe and say we didn't
|
|
+ * transfer anything.
|
|
+ */
|
|
+ if (urb->actual_length > urb->transfer_buffer_length) {
|
|
+ xhci_warn(xhci, "URB transfer length is wrong, "
|
|
+ "xHC issue? req. len = %u, "
|
|
+ "act. len = %u\n",
|
|
+ urb->transfer_buffer_length,
|
|
+ urb->actual_length);
|
|
+ urb->actual_length = 0;
|
|
+ if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
|
|
+ status = -EREMOTEIO;
|
|
+ else
|
|
+ status = 0;
|
|
+ }
|
|
list_del(&td->td_list);
|
|
/* Was this TD slated to be cancelled but completed anyway? */
|
|
if (!list_empty(&td->cancelled_td_list)) {
|
|
list_del(&td->cancelled_td_list);
|
|
ep_ring->cancels_pending--;
|
|
}
|
|
- /* Leave the TD around for the reset endpoint function to use */
|
|
- if (GET_COMP_CODE(event->transfer_len) != COMP_STALL) {
|
|
+ /* Leave the TD around for the reset endpoint function to use
|
|
+ * (but only if it's not a control endpoint, since we already
|
|
+ * queued the Set TR dequeue pointer command for stalled
|
|
+ * control endpoints).
|
|
+ */
|
|
+ if (usb_endpoint_xfer_control(&urb->ep->desc) ||
|
|
+ (trb_comp_code != COMP_STALL &&
|
|
+ trb_comp_code != COMP_BABBLE)) {
|
|
kfree(td);
|
|
}
|
|
urb->hcpriv = NULL;
|
|
@@ -1094,7 +1228,7 @@ cleanup:
|
|
if (urb) {
|
|
usb_hcd_unlink_urb_from_ep(xhci_to_hcd(xhci), urb);
|
|
xhci_dbg(xhci, "Giveback URB %p, len = %d, status = %d\n",
|
|
- urb, td->urb->actual_length, status);
|
|
+ urb, urb->actual_length, status);
|
|
spin_unlock(&xhci->lock);
|
|
usb_hcd_giveback_urb(xhci_to_hcd(xhci), urb, status);
|
|
spin_lock(&xhci->lock);
|
|
@@ -1335,6 +1469,47 @@ static void giveback_first_trb(struct xhci_hcd *xhci, int slot_id,
|
|
ring_ep_doorbell(xhci, slot_id, ep_index);
|
|
}
|
|
|
|
+/*
|
|
+ * xHCI uses normal TRBs for both bulk and interrupt. When the interrupt
|
|
+ * endpoint is to be serviced, the xHC will consume (at most) one TD. A TD
|
|
+ * (comprised of sg list entries) can take several service intervals to
|
|
+ * transmit.
|
|
+ */
|
|
+int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|
+ struct urb *urb, int slot_id, unsigned int ep_index)
|
|
+{
|
|
+ struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci,
|
|
+ xhci->devs[slot_id]->out_ctx, ep_index);
|
|
+ int xhci_interval;
|
|
+ int ep_interval;
|
|
+
|
|
+ xhci_interval = EP_INTERVAL_TO_UFRAMES(ep_ctx->ep_info);
|
|
+ ep_interval = urb->interval;
|
|
+ /* Convert to microframes */
|
|
+ if (urb->dev->speed == USB_SPEED_LOW ||
|
|
+ urb->dev->speed == USB_SPEED_FULL)
|
|
+ ep_interval *= 8;
|
|
+ /* FIXME change this to a warning and a suggestion to use the new API
|
|
+ * to set the polling interval (once the API is added).
|
|
+ */
|
|
+ if (xhci_interval != ep_interval) {
|
|
+ if (!printk_ratelimit())
|
|
+ dev_dbg(&urb->dev->dev, "Driver uses different interval"
|
|
+ " (%d microframe%s) than xHCI "
|
|
+ "(%d microframe%s)\n",
|
|
+ ep_interval,
|
|
+ ep_interval == 1 ? "" : "s",
|
|
+ xhci_interval,
|
|
+ xhci_interval == 1 ? "" : "s");
|
|
+ urb->interval = xhci_interval;
|
|
+ /* Convert back to frames for LS/FS devices */
|
|
+ if (urb->dev->speed == USB_SPEED_LOW ||
|
|
+ urb->dev->speed == USB_SPEED_FULL)
|
|
+ urb->interval /= 8;
|
|
+ }
|
|
+ return xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index);
|
|
+}
|
|
+
|
|
static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|
struct urb *urb, int slot_id, unsigned int ep_index)
|
|
{
|
|
@@ -1733,6 +1908,15 @@ int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
|
|
TRB_TYPE(TRB_CONFIG_EP) | SLOT_ID_FOR_TRB(slot_id));
|
|
}
|
|
|
|
+/* Queue an evaluate context command TRB */
|
|
+int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
|
|
+ u32 slot_id)
|
|
+{
|
|
+ return queue_command(xhci, lower_32_bits(in_ctx_ptr),
|
|
+ upper_32_bits(in_ctx_ptr), 0,
|
|
+ TRB_TYPE(TRB_EVAL_CONTEXT) | SLOT_ID_FOR_TRB(slot_id));
|
|
+}
|
|
+
|
|
int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id,
|
|
unsigned int ep_index)
|
|
{
|
|
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
|
|
index d31d322..8085841 100644
|
|
--- a/drivers/usb/host/xhci.h
|
|
+++ b/drivers/usb/host/xhci.h
|
|
@@ -581,6 +581,7 @@ struct xhci_ep_ctx {
|
|
/* bit 15 is Linear Stream Array */
|
|
/* Interval - period between requests to an endpoint - 125u increments. */
|
|
#define EP_INTERVAL(p) ((p & 0xff) << 16)
|
|
+#define EP_INTERVAL_TO_UFRAMES(p) (1 << (((p) >> 16) & 0xff))
|
|
|
|
/* ep_info2 bitmasks */
|
|
/*
|
|
@@ -589,6 +590,7 @@ struct xhci_ep_ctx {
|
|
*/
|
|
#define FORCE_EVENT (0x1)
|
|
#define ERROR_COUNT(p) (((p) & 0x3) << 1)
|
|
+#define CTX_TO_EP_TYPE(p) (((p) >> 3) & 0x7)
|
|
#define EP_TYPE(p) ((p) << 3)
|
|
#define ISOC_OUT_EP 1
|
|
#define BULK_OUT_EP 2
|
|
@@ -601,6 +603,8 @@ struct xhci_ep_ctx {
|
|
/* bit 7 is Host Initiate Disable - for disabling stream selection */
|
|
#define MAX_BURST(p) (((p)&0xff) << 8)
|
|
#define MAX_PACKET(p) (((p)&0xffff) << 16)
|
|
+#define MAX_PACKET_MASK (0xffff << 16)
|
|
+#define MAX_PACKET_DECODED(p) (((p) >> 16) & 0xffff)
|
|
|
|
|
|
/**
|
|
@@ -926,6 +930,12 @@ struct xhci_td {
|
|
union xhci_trb *last_trb;
|
|
};
|
|
|
|
+struct xhci_dequeue_state {
|
|
+ struct xhci_segment *new_deq_seg;
|
|
+ union xhci_trb *new_deq_ptr;
|
|
+ int new_cycle_state;
|
|
+};
|
|
+
|
|
struct xhci_ring {
|
|
struct xhci_segment *first_seg;
|
|
union xhci_trb *enqueue;
|
|
@@ -952,12 +962,6 @@ struct xhci_ring {
|
|
u32 cycle_state;
|
|
};
|
|
|
|
-struct xhci_dequeue_state {
|
|
- struct xhci_segment *new_deq_seg;
|
|
- union xhci_trb *new_deq_ptr;
|
|
- int new_cycle_state;
|
|
-};
|
|
-
|
|
struct xhci_erst_entry {
|
|
/* 64-bit event ring segment address */
|
|
u64 seg_addr;
|
|
@@ -1058,6 +1062,9 @@ struct xhci_hcd {
|
|
int noops_submitted;
|
|
int noops_handled;
|
|
int error_bitmask;
|
|
+ unsigned int quirks;
|
|
+#define XHCI_LINK_TRB_QUIRK (1 << 0)
|
|
+#define XHCI_RESET_EP_QUIRK (1 << 1)
|
|
};
|
|
|
|
/* For testing purposes */
|
|
@@ -1136,6 +1143,13 @@ static inline void xhci_write_64(struct xhci_hcd *xhci,
|
|
writel(val_hi, ptr + 1);
|
|
}
|
|
|
|
+static inline int xhci_link_trb_quirk(struct xhci_hcd *xhci)
|
|
+{
|
|
+ u32 temp = xhci_readl(xhci, &xhci->cap_regs->hc_capbase);
|
|
+ return ((HC_VERSION(temp) == 0x95) &&
|
|
+ (xhci->quirks & XHCI_LINK_TRB_QUIRK));
|
|
+}
|
|
+
|
|
/* xHCI debugging */
|
|
void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int set_num);
|
|
void xhci_print_registers(struct xhci_hcd *xhci);
|
|
@@ -1158,7 +1172,12 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, struct usb_device
|
|
int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *udev);
|
|
unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc);
|
|
unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc);
|
|
+unsigned int xhci_get_endpoint_flag_from_index(unsigned int ep_index);
|
|
+unsigned int xhci_last_valid_endpoint(u32 added_ctxs);
|
|
void xhci_endpoint_zero(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, struct usb_host_endpoint *ep);
|
|
+void xhci_endpoint_copy(struct xhci_hcd *xhci,
|
|
+ struct xhci_virt_device *vdev, unsigned int ep_index);
|
|
+void xhci_slot_copy(struct xhci_hcd *xhci, struct xhci_virt_device *vdev);
|
|
int xhci_endpoint_init(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev,
|
|
struct usb_device *udev, struct usb_host_endpoint *ep,
|
|
gfp_t mem_flags);
|
|
@@ -1205,8 +1224,12 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,
|
|
int slot_id, unsigned int ep_index);
|
|
int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,
|
|
int slot_id, unsigned int ep_index);
|
|
+int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,
|
|
+ int slot_id, unsigned int ep_index);
|
|
int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
|
|
u32 slot_id);
|
|
+int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
|
|
+ u32 slot_id);
|
|
int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id,
|
|
unsigned int ep_index);
|
|
void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
|
|
@@ -1215,6 +1238,12 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
|
|
void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,
|
|
struct xhci_ring *ep_ring, unsigned int slot_id,
|
|
unsigned int ep_index, struct xhci_dequeue_state *deq_state);
|
|
+void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,
|
|
+ struct usb_device *udev,
|
|
+ unsigned int ep_index, struct xhci_ring *ep_ring);
|
|
+void xhci_queue_config_ep_quirk(struct xhci_hcd *xhci,
|
|
+ unsigned int slot_id, unsigned int ep_index,
|
|
+ struct xhci_dequeue_state *deq_state);
|
|
|
|
/* xHCI roothub code */
|
|
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
|
|
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
|
|
index aec6188..1a50beb 100644
|
|
--- a/drivers/usb/serial/ark3116.c
|
|
+++ b/drivers/usb/serial/ark3116.c
|
|
@@ -35,11 +35,6 @@ static struct usb_device_id id_table [] = {
|
|
};
|
|
MODULE_DEVICE_TABLE(usb, id_table);
|
|
|
|
-struct ark3116_private {
|
|
- spinlock_t lock;
|
|
- u8 termios_initialized;
|
|
-};
|
|
-
|
|
static inline void ARK3116_SND(struct usb_serial *serial, int seq,
|
|
__u8 request, __u8 requesttype,
|
|
__u16 value, __u16 index)
|
|
@@ -82,22 +77,11 @@ static inline void ARK3116_RCV_QUIET(struct usb_serial *serial,
|
|
static int ark3116_attach(struct usb_serial *serial)
|
|
{
|
|
char *buf;
|
|
- struct ark3116_private *priv;
|
|
- int i;
|
|
-
|
|
- for (i = 0; i < serial->num_ports; ++i) {
|
|
- priv = kzalloc(sizeof(struct ark3116_private), GFP_KERNEL);
|
|
- if (!priv)
|
|
- goto cleanup;
|
|
- spin_lock_init(&priv->lock);
|
|
-
|
|
- usb_set_serial_port_data(serial->port[i], priv);
|
|
- }
|
|
|
|
buf = kmalloc(1, GFP_KERNEL);
|
|
if (!buf) {
|
|
dbg("error kmalloc -> out of mem?");
|
|
- goto cleanup;
|
|
+ return -ENOMEM;
|
|
}
|
|
|
|
/* 3 */
|
|
@@ -149,13 +133,16 @@ static int ark3116_attach(struct usb_serial *serial)
|
|
|
|
kfree(buf);
|
|
return 0;
|
|
+}
|
|
|
|
-cleanup:
|
|
- for (--i; i >= 0; --i) {
|
|
- kfree(usb_get_serial_port_data(serial->port[i]));
|
|
- usb_set_serial_port_data(serial->port[i], NULL);
|
|
- }
|
|
- return -ENOMEM;
|
|
+static void ark3116_init_termios(struct tty_struct *tty)
|
|
+{
|
|
+ struct ktermios *termios = tty->termios;
|
|
+ *termios = tty_std_termios;
|
|
+ termios->c_cflag = B9600 | CS8
|
|
+ | CREAD | HUPCL | CLOCAL;
|
|
+ termios->c_ispeed = 9600;
|
|
+ termios->c_ospeed = 9600;
|
|
}
|
|
|
|
static void ark3116_set_termios(struct tty_struct *tty,
|
|
@@ -163,10 +150,8 @@ static void ark3116_set_termios(struct tty_struct *tty,
|
|
struct ktermios *old_termios)
|
|
{
|
|
struct usb_serial *serial = port->serial;
|
|
- struct ark3116_private *priv = usb_get_serial_port_data(port);
|
|
struct ktermios *termios = tty->termios;
|
|
unsigned int cflag = termios->c_cflag;
|
|
- unsigned long flags;
|
|
int baud;
|
|
int ark3116_baud;
|
|
char *buf;
|
|
@@ -176,16 +161,6 @@ static void ark3116_set_termios(struct tty_struct *tty,
|
|
|
|
dbg("%s - port %d", __func__, port->number);
|
|
|
|
- spin_lock_irqsave(&priv->lock, flags);
|
|
- if (!priv->termios_initialized) {
|
|
- *termios = tty_std_termios;
|
|
- termios->c_cflag = B9600 | CS8
|
|
- | CREAD | HUPCL | CLOCAL;
|
|
- termios->c_ispeed = 9600;
|
|
- termios->c_ospeed = 9600;
|
|
- priv->termios_initialized = 1;
|
|
- }
|
|
- spin_unlock_irqrestore(&priv->lock, flags);
|
|
|
|
cflag = termios->c_cflag;
|
|
termios->c_cflag &= ~(CMSPAR|CRTSCTS);
|
|
@@ -455,6 +430,7 @@ static struct usb_serial_driver ark3116_device = {
|
|
.num_ports = 1,
|
|
.attach = ark3116_attach,
|
|
.set_termios = ark3116_set_termios,
|
|
+ .init_termios = ark3116_init_termios,
|
|
.ioctl = ark3116_ioctl,
|
|
.tiocmget = ark3116_tiocmget,
|
|
.open = ark3116_open,
|
|
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
|
|
index 0e4f2e4..3e49b2e 100644
|
|
--- a/drivers/usb/serial/console.c
|
|
+++ b/drivers/usb/serial/console.c
|
|
@@ -16,6 +16,7 @@
|
|
#include <linux/slab.h>
|
|
#include <linux/tty.h>
|
|
#include <linux/console.h>
|
|
+#include <linux/serial.h>
|
|
#include <linux/usb.h>
|
|
#include <linux/usb/serial.h>
|
|
|
|
@@ -63,7 +64,7 @@ static int usb_console_setup(struct console *co, char *options)
|
|
char *s;
|
|
struct usb_serial *serial;
|
|
struct usb_serial_port *port;
|
|
- int retval = 0;
|
|
+ int retval;
|
|
struct tty_struct *tty = NULL;
|
|
struct ktermios *termios = NULL, dummy;
|
|
|
|
@@ -116,13 +117,17 @@ static int usb_console_setup(struct console *co, char *options)
|
|
return -ENODEV;
|
|
}
|
|
|
|
- port = serial->port[0];
|
|
+ retval = usb_autopm_get_interface(serial->interface);
|
|
+ if (retval)
|
|
+ goto error_get_interface;
|
|
+
|
|
+ port = serial->port[co->index - serial->minor];
|
|
tty_port_tty_set(&port->port, NULL);
|
|
|
|
info->port = port;
|
|
|
|
++port->port.count;
|
|
- if (port->port.count == 1) {
|
|
+ if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) {
|
|
if (serial->type->set_termios) {
|
|
/*
|
|
* allocate a fake tty so the driver can initialize
|
|
@@ -168,6 +173,7 @@ static int usb_console_setup(struct console *co, char *options)
|
|
kfree(termios);
|
|
kfree(tty);
|
|
}
|
|
+ set_bit(ASYNCB_INITIALIZED, &port->port.flags);
|
|
}
|
|
/* Now that any required fake tty operations are completed restore
|
|
* the tty port count */
|
|
@@ -175,18 +181,22 @@ static int usb_console_setup(struct console *co, char *options)
|
|
/* The console is special in terms of closing the device so
|
|
* indicate this port is now acting as a system console. */
|
|
port->console = 1;
|
|
- retval = 0;
|
|
|
|
-out:
|
|
+ mutex_unlock(&serial->disc_mutex);
|
|
return retval;
|
|
-free_termios:
|
|
+
|
|
+ free_termios:
|
|
kfree(termios);
|
|
tty_port_tty_set(&port->port, NULL);
|
|
-free_tty:
|
|
+ free_tty:
|
|
kfree(tty);
|
|
-reset_open_count:
|
|
+ reset_open_count:
|
|
port->port.count = 0;
|
|
- goto out;
|
|
+ usb_autopm_put_interface(serial->interface);
|
|
+ error_get_interface:
|
|
+ usb_serial_put(serial);
|
|
+ mutex_unlock(&serial->disc_mutex);
|
|
+ return retval;
|
|
}
|
|
|
|
static void usb_console_write(struct console *co,
|
|
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
|
|
index 985cbcf..b5275c4 100644
|
|
--- a/drivers/usb/serial/cp210x.c
|
|
+++ b/drivers/usb/serial/cp210x.c
|
|
@@ -399,12 +399,6 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port,
|
|
|
|
/* Configure the termios structure */
|
|
cp210x_get_termios(tty, port);
|
|
-
|
|
- /* Set the DTR and RTS pins low */
|
|
- cp210x_tiocmset_port(tty ? (struct usb_serial_port *) tty->driver_data
|
|
- : port,
|
|
- NULL, TIOCM_DTR | TIOCM_RTS, 0);
|
|
-
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
|
|
index 59adfe1..27b5a27 100644
|
|
--- a/drivers/usb/serial/cypress_m8.c
|
|
+++ b/drivers/usb/serial/cypress_m8.c
|
|
@@ -659,15 +659,7 @@ static int cypress_open(struct tty_struct *tty,
|
|
spin_unlock_irqrestore(&priv->lock, flags);
|
|
|
|
/* Set termios */
|
|
- result = cypress_write(tty, port, NULL, 0);
|
|
-
|
|
- if (result) {
|
|
- dev_err(&port->dev,
|
|
- "%s - failed setting the control lines - error %d\n",
|
|
- __func__, result);
|
|
- return result;
|
|
- } else
|
|
- dbg("%s - success setting the control lines", __func__);
|
|
+ cypress_send(port);
|
|
|
|
if (tty)
|
|
cypress_set_termios(tty, port, &priv->tmp_termios);
|
|
@@ -1005,6 +997,8 @@ static void cypress_set_termios(struct tty_struct *tty,
|
|
dbg("%s - port %d", __func__, port->number);
|
|
|
|
spin_lock_irqsave(&priv->lock, flags);
|
|
+ /* We can't clean this one up as we don't know the device type
|
|
+ early enough */
|
|
if (!priv->termios_initialized) {
|
|
if (priv->chiptype == CT_EARTHMATE) {
|
|
*(tty->termios) = tty_std_termios;
|
|
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
|
|
index 80cb347..3433f9d 100644
|
|
--- a/drivers/usb/serial/empeg.c
|
|
+++ b/drivers/usb/serial/empeg.c
|
|
@@ -90,8 +90,7 @@ static int empeg_chars_in_buffer(struct tty_struct *tty);
|
|
static void empeg_throttle(struct tty_struct *tty);
|
|
static void empeg_unthrottle(struct tty_struct *tty);
|
|
static int empeg_startup(struct usb_serial *serial);
|
|
-static void empeg_set_termios(struct tty_struct *tty,
|
|
- struct usb_serial_port *port, struct ktermios *old_termios);
|
|
+static void empeg_init_termios(struct tty_struct *tty);
|
|
static void empeg_write_bulk_callback(struct urb *urb);
|
|
static void empeg_read_bulk_callback(struct urb *urb);
|
|
|
|
@@ -123,7 +122,7 @@ static struct usb_serial_driver empeg_device = {
|
|
.throttle = empeg_throttle,
|
|
.unthrottle = empeg_unthrottle,
|
|
.attach = empeg_startup,
|
|
- .set_termios = empeg_set_termios,
|
|
+ .init_termios = empeg_init_termios,
|
|
.write = empeg_write,
|
|
.write_room = empeg_write_room,
|
|
.chars_in_buffer = empeg_chars_in_buffer,
|
|
@@ -150,9 +149,6 @@ static int empeg_open(struct tty_struct *tty, struct usb_serial_port *port,
|
|
|
|
dbg("%s - port %d", __func__, port->number);
|
|
|
|
- /* Force default termio settings */
|
|
- empeg_set_termios(tty, port, NULL) ;
|
|
-
|
|
bytes_in = 0;
|
|
bytes_out = 0;
|
|
|
|
@@ -425,11 +421,9 @@ static int empeg_startup(struct usb_serial *serial)
|
|
}
|
|
|
|
|
|
-static void empeg_set_termios(struct tty_struct *tty,
|
|
- struct usb_serial_port *port, struct ktermios *old_termios)
|
|
+static void empeg_init_termios(struct tty_struct *tty)
|
|
{
|
|
struct ktermios *termios = tty->termios;
|
|
- dbg("%s - port %d", __func__, port->number);
|
|
|
|
/*
|
|
* The empeg-car player wants these particular tty settings.
|
|
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
|
|
index 8fec5d4..0cc78f9 100644
|
|
--- a/drivers/usb/serial/ftdi_sio.c
|
|
+++ b/drivers/usb/serial/ftdi_sio.c
|
|
@@ -176,6 +176,9 @@ static struct usb_device_id id_table_combined [] = {
|
|
{ USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) },
|
|
{ USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
|
|
{ USB_DEVICE(FTDI_VID, FTDI_OPENDCC_PID) },
|
|
+ { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_SNIFFER_PID) },
|
|
+ { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_THROTTLE_PID) },
|
|
+ { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GATEWAY_PID) },
|
|
{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) },
|
|
{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) },
|
|
{ USB_DEVICE(FTDI_VID, FTDI_SPROG_II) },
|
|
@@ -694,6 +697,8 @@ static struct usb_device_id id_table_combined [] = {
|
|
{ USB_DEVICE(DE_VID, WHT_PID) },
|
|
{ USB_DEVICE(ADI_VID, ADI_GNICE_PID),
|
|
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
|
|
+ { USB_DEVICE(ADI_VID, ADI_GNICEPLUS_PID),
|
|
+ .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
|
|
{ USB_DEVICE(JETI_VID, JETI_SPC1201_PID) },
|
|
{ USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID),
|
|
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
|
|
@@ -702,6 +707,8 @@ static struct usb_device_id id_table_combined [] = {
|
|
{ USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) },
|
|
{ USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID),
|
|
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
|
|
+ { USB_DEVICE(FTDI_VID, HAMEG_HO820_PID) },
|
|
+ { USB_DEVICE(FTDI_VID, HAMEG_HO870_PID) },
|
|
{ }, /* Optional parameter entry */
|
|
{ } /* Terminating entry */
|
|
};
|
|
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
|
|
index 8c92b88..6f31e0d 100644
|
|
--- a/drivers/usb/serial/ftdi_sio.h
|
|
+++ b/drivers/usb/serial/ftdi_sio.h
|
|
@@ -81,6 +81,9 @@
|
|
|
|
/* OpenDCC (www.opendcc.de) product id */
|
|
#define FTDI_OPENDCC_PID 0xBFD8
|
|
+#define FTDI_OPENDCC_SNIFFER_PID 0xBFD9
|
|
+#define FTDI_OPENDCC_THROTTLE_PID 0xBFDA
|
|
+#define FTDI_OPENDCC_GATEWAY_PID 0xBFDB
|
|
|
|
/* Sprog II (Andrew Crosland's SprogII DCC interface) */
|
|
#define FTDI_SPROG_II 0xF0C8
|
|
@@ -930,6 +933,7 @@
|
|
*/
|
|
#define ADI_VID 0x0456
|
|
#define ADI_GNICE_PID 0xF000
|
|
+#define ADI_GNICEPLUS_PID 0xF001
|
|
|
|
/*
|
|
* JETI SPECTROMETER SPECBOS 1201
|
|
@@ -968,6 +972,12 @@
|
|
#define MARVELL_OPENRD_PID 0x9e90
|
|
|
|
/*
|
|
+ * Hameg HO820 and HO870 interface (using VID 0x0403)
|
|
+ */
|
|
+#define HAMEG_HO820_PID 0xed74
|
|
+#define HAMEG_HO870_PID 0xed71
|
|
+
|
|
+/*
|
|
* BmRequestType: 1100 0000b
|
|
* bRequest: FTDI_E2_READ
|
|
* wValue: 0
|
|
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
|
|
index 96873a7..af6df6c 100644
|
|
--- a/drivers/usb/serial/iuu_phoenix.c
|
|
+++ b/drivers/usb/serial/iuu_phoenix.c
|
|
@@ -71,7 +71,6 @@ struct iuu_private {
|
|
spinlock_t lock; /* store irq state */
|
|
wait_queue_head_t delta_msr_wait;
|
|
u8 line_status;
|
|
- u8 termios_initialized;
|
|
int tiostatus; /* store IUART SIGNAL for tiocmget call */
|
|
u8 reset; /* if 1 reset is needed */
|
|
int poll; /* number of poll */
|
|
@@ -1018,6 +1017,18 @@ static void iuu_close(struct usb_serial_port *port)
|
|
}
|
|
}
|
|
|
|
+static void iuu_init_termios(struct tty_struct *tty)
|
|
+{
|
|
+ *(tty->termios) = tty_std_termios;
|
|
+ tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600
|
|
+ | TIOCM_CTS | CSTOPB | PARENB;
|
|
+ tty->termios->c_ispeed = 9600;
|
|
+ tty->termios->c_ospeed = 9600;
|
|
+ tty->termios->c_lflag = 0;
|
|
+ tty->termios->c_oflag = 0;
|
|
+ tty->termios->c_iflag = 0;
|
|
+}
|
|
+
|
|
static int iuu_open(struct tty_struct *tty,
|
|
struct usb_serial_port *port, struct file *filp)
|
|
{
|
|
@@ -1025,7 +1036,6 @@ static int iuu_open(struct tty_struct *tty,
|
|
u8 *buf;
|
|
int result;
|
|
u32 actual;
|
|
- unsigned long flags;
|
|
struct iuu_private *priv = usb_get_serial_port_data(port);
|
|
|
|
dbg("%s - port %d", __func__, port->number);
|
|
@@ -1064,21 +1074,7 @@ static int iuu_open(struct tty_struct *tty,
|
|
port->bulk_in_buffer, 512,
|
|
NULL, NULL);
|
|
|
|
- /* set the termios structure */
|
|
- spin_lock_irqsave(&priv->lock, flags);
|
|
- if (tty && !priv->termios_initialized) {
|
|
- *(tty->termios) = tty_std_termios;
|
|
- tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600
|
|
- | TIOCM_CTS | CSTOPB | PARENB;
|
|
- tty->termios->c_ispeed = 9600;
|
|
- tty->termios->c_ospeed = 9600;
|
|
- tty->termios->c_lflag = 0;
|
|
- tty->termios->c_oflag = 0;
|
|
- tty->termios->c_iflag = 0;
|
|
- priv->termios_initialized = 1;
|
|
- priv->poll = 0;
|
|
- }
|
|
- spin_unlock_irqrestore(&priv->lock, flags);
|
|
+ priv->poll = 0;
|
|
|
|
/* initialize writebuf */
|
|
#define FISH(a, b, c, d) do { \
|
|
@@ -1201,6 +1197,7 @@ static struct usb_serial_driver iuu_device = {
|
|
.tiocmget = iuu_tiocmget,
|
|
.tiocmset = iuu_tiocmset,
|
|
.set_termios = iuu_set_termios,
|
|
+ .init_termios = iuu_init_termios,
|
|
.attach = iuu_startup,
|
|
.release = iuu_release,
|
|
};
|
|
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
|
|
index 6db0e56..46d47d1 100644
|
|
--- a/drivers/usb/serial/kobil_sct.c
|
|
+++ b/drivers/usb/serial/kobil_sct.c
|
|
@@ -85,7 +85,7 @@ static void kobil_read_int_callback(struct urb *urb);
|
|
static void kobil_write_callback(struct urb *purb);
|
|
static void kobil_set_termios(struct tty_struct *tty,
|
|
struct usb_serial_port *port, struct ktermios *old);
|
|
-
|
|
+static void kobil_init_termios(struct tty_struct *tty);
|
|
|
|
static struct usb_device_id id_table [] = {
|
|
{ USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_B_PRODUCT_ID) },
|
|
@@ -120,6 +120,7 @@ static struct usb_serial_driver kobil_device = {
|
|
.release = kobil_release,
|
|
.ioctl = kobil_ioctl,
|
|
.set_termios = kobil_set_termios,
|
|
+ .init_termios = kobil_init_termios,
|
|
.tiocmget = kobil_tiocmget,
|
|
.tiocmset = kobil_tiocmset,
|
|
.open = kobil_open,
|
|
@@ -210,6 +211,15 @@ static void kobil_release(struct usb_serial *serial)
|
|
kfree(usb_get_serial_port_data(serial->port[i]));
|
|
}
|
|
|
|
+static void kobil_init_termios(struct tty_struct *tty)
|
|
+{
|
|
+ /* Default to echo off and other sane device settings */
|
|
+ tty->termios->c_lflag = 0;
|
|
+ tty->termios->c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE);
|
|
+ tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;
|
|
+ /* do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) */
|
|
+ tty->termios->c_oflag &= ~ONLCR;
|
|
+}
|
|
|
|
static int kobil_open(struct tty_struct *tty,
|
|
struct usb_serial_port *port, struct file *filp)
|
|
@@ -226,16 +236,6 @@ static int kobil_open(struct tty_struct *tty,
|
|
/* someone sets the dev to 0 if the close method has been called */
|
|
port->interrupt_in_urb->dev = port->serial->dev;
|
|
|
|
- if (tty) {
|
|
-
|
|
- /* Default to echo off and other sane device settings */
|
|
- tty->termios->c_lflag = 0;
|
|
- tty->termios->c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN |
|
|
- XCASE);
|
|
- tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;
|
|
- /* do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) */
|
|
- tty->termios->c_oflag &= ~ONLCR;
|
|
- }
|
|
/* allocate memory for transfer buffer */
|
|
transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
|
|
if (!transfer_buffer)
|
|
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
|
|
index c784ddb..0101548 100644
|
|
--- a/drivers/usb/serial/option.c
|
|
+++ b/drivers/usb/serial/option.c
|
|
@@ -292,6 +292,7 @@ static int option_resume(struct usb_serial *serial);
|
|
|
|
#define TELIT_VENDOR_ID 0x1bc7
|
|
#define TELIT_PRODUCT_UC864E 0x1003
|
|
+#define TELIT_PRODUCT_UC864G 0x1004
|
|
|
|
/* ZTE PRODUCTS */
|
|
#define ZTE_VENDOR_ID 0x19d2
|
|
@@ -300,6 +301,7 @@ static int option_resume(struct usb_serial *serial);
|
|
#define ZTE_PRODUCT_MF626 0x0031
|
|
#define ZTE_PRODUCT_CDMA_TECH 0xfffe
|
|
#define ZTE_PRODUCT_AC8710 0xfff1
|
|
+#define ZTE_PRODUCT_AC2726 0xfff5
|
|
|
|
#define BENQ_VENDOR_ID 0x04a5
|
|
#define BENQ_PRODUCT_H10 0x4068
|
|
@@ -503,6 +505,7 @@ static struct usb_device_id option_ids[] = {
|
|
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */
|
|
{ USB_DEVICE(MAXON_VENDOR_ID, 0x6280) }, /* BP3-USB & BP3-EXT HSDPA */
|
|
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) },
|
|
+ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864G) },
|
|
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */
|
|
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff) },
|
|
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0003, 0xff, 0xff, 0xff) },
|
|
@@ -572,6 +575,7 @@ static struct usb_device_id option_ids[] = {
|
|
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0073, 0xff, 0xff, 0xff) },
|
|
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH, 0xff, 0xff, 0xff) },
|
|
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710, 0xff, 0xff, 0xff) },
|
|
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2726, 0xff, 0xff, 0xff) },
|
|
{ USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) },
|
|
{ USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) },
|
|
{ USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4512) },
|
|
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
|
|
index 3cece27..ef34cff 100644
|
|
--- a/drivers/usb/serial/oti6858.c
|
|
+++ b/drivers/usb/serial/oti6858.c
|
|
@@ -146,6 +146,7 @@ static int oti6858_open(struct tty_struct *tty,
|
|
static void oti6858_close(struct usb_serial_port *port);
|
|
static void oti6858_set_termios(struct tty_struct *tty,
|
|
struct usb_serial_port *port, struct ktermios *old);
|
|
+static void oti6858_init_termios(struct tty_struct *tty);
|
|
static int oti6858_ioctl(struct tty_struct *tty, struct file *file,
|
|
unsigned int cmd, unsigned long arg);
|
|
static void oti6858_read_int_callback(struct urb *urb);
|
|
@@ -186,6 +187,7 @@ static struct usb_serial_driver oti6858_device = {
|
|
.write = oti6858_write,
|
|
.ioctl = oti6858_ioctl,
|
|
.set_termios = oti6858_set_termios,
|
|
+ .init_termios = oti6858_init_termios,
|
|
.tiocmget = oti6858_tiocmget,
|
|
.tiocmset = oti6858_tiocmset,
|
|
.read_bulk_callback = oti6858_read_bulk_callback,
|
|
@@ -206,7 +208,6 @@ struct oti6858_private {
|
|
struct {
|
|
u8 read_urb_in_use;
|
|
u8 write_urb_in_use;
|
|
- u8 termios_initialized;
|
|
} flags;
|
|
struct delayed_work delayed_write_work;
|
|
|
|
@@ -447,6 +448,14 @@ static int oti6858_chars_in_buffer(struct tty_struct *tty)
|
|
return chars;
|
|
}
|
|
|
|
+static void oti6858_init_termios(struct tty_struct *tty)
|
|
+{
|
|
+ *(tty->termios) = tty_std_termios;
|
|
+ tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL;
|
|
+ tty->termios->c_ispeed = 38400;
|
|
+ tty->termios->c_ospeed = 38400;
|
|
+}
|
|
+
|
|
static void oti6858_set_termios(struct tty_struct *tty,
|
|
struct usb_serial_port *port, struct ktermios *old_termios)
|
|
{
|
|
@@ -464,16 +473,6 @@ static void oti6858_set_termios(struct tty_struct *tty,
|
|
return;
|
|
}
|
|
|
|
- spin_lock_irqsave(&priv->lock, flags);
|
|
- if (!priv->flags.termios_initialized) {
|
|
- *(tty->termios) = tty_std_termios;
|
|
- tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL;
|
|
- tty->termios->c_ispeed = 38400;
|
|
- tty->termios->c_ospeed = 38400;
|
|
- priv->flags.termios_initialized = 1;
|
|
- }
|
|
- spin_unlock_irqrestore(&priv->lock, flags);
|
|
-
|
|
cflag = tty->termios->c_cflag;
|
|
|
|
spin_lock_irqsave(&priv->lock, flags);
|
|
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
|
|
index 3e86815..124d5ae 100644
|
|
--- a/drivers/usb/serial/pl2303.c
|
|
+++ b/drivers/usb/serial/pl2303.c
|
|
@@ -96,6 +96,7 @@ static struct usb_device_id id_table [] = {
|
|
{ USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
|
|
{ USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
|
|
{ USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
|
|
+ { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },
|
|
{ } /* Terminating entry */
|
|
};
|
|
|
|
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
|
|
index ee9505e..d640dc9 100644
|
|
--- a/drivers/usb/serial/pl2303.h
|
|
+++ b/drivers/usb/serial/pl2303.h
|
|
@@ -130,3 +130,7 @@
|
|
/* Sony, USB data cable for CMD-Jxx mobile phones */
|
|
#define SONY_VENDOR_ID 0x054c
|
|
#define SONY_QN3USB_PRODUCT_ID 0x0437
|
|
+
|
|
+/* Sanwa KB-USB2 multimeter cable (ID: 11ad:0001) */
|
|
+#define SANWA_VENDOR_ID 0x11ad
|
|
+#define SANWA_PRODUCT_ID 0x0001
|
|
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
|
|
index 3c249d8..993a6d5 100644
|
|
--- a/drivers/usb/serial/spcp8x5.c
|
|
+++ b/drivers/usb/serial/spcp8x5.c
|
|
@@ -299,7 +299,6 @@ struct spcp8x5_private {
|
|
wait_queue_head_t delta_msr_wait;
|
|
u8 line_control;
|
|
u8 line_status;
|
|
- u8 termios_initialized;
|
|
};
|
|
|
|
/* desc : when device plug in,this function would be called.
|
|
@@ -498,6 +497,15 @@ static void spcp8x5_close(struct usb_serial_port *port)
|
|
dev_dbg(&port->dev, "usb_unlink_urb(read_urb) = %d\n", result);
|
|
}
|
|
|
|
+static void spcp8x5_init_termios(struct tty_struct *tty)
|
|
+{
|
|
+ /* for the 1st time call this function */
|
|
+ *(tty->termios) = tty_std_termios;
|
|
+ tty->termios->c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
|
|
+ tty->termios->c_ispeed = 115200;
|
|
+ tty->termios->c_ospeed = 115200;
|
|
+}
|
|
+
|
|
/* set the serial param for transfer. we should check if we really need to
|
|
* transfer. if we set flow control we should do this too. */
|
|
static void spcp8x5_set_termios(struct tty_struct *tty,
|
|
@@ -514,16 +522,6 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
|
|
int i;
|
|
u8 control;
|
|
|
|
- /* for the 1st time call this function */
|
|
- spin_lock_irqsave(&priv->lock, flags);
|
|
- if (!priv->termios_initialized) {
|
|
- *(tty->termios) = tty_std_termios;
|
|
- tty->termios->c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
|
|
- tty->termios->c_ispeed = 115200;
|
|
- tty->termios->c_ospeed = 115200;
|
|
- priv->termios_initialized = 1;
|
|
- }
|
|
- spin_unlock_irqrestore(&priv->lock, flags);
|
|
|
|
/* check that they really want us to change something */
|
|
if (!tty_termios_hw_change(tty->termios, old_termios))
|
|
@@ -1011,6 +1009,7 @@ static struct usb_serial_driver spcp8x5_device = {
|
|
.carrier_raised = spcp8x5_carrier_raised,
|
|
.write = spcp8x5_write,
|
|
.set_termios = spcp8x5_set_termios,
|
|
+ .init_termios = spcp8x5_init_termios,
|
|
.ioctl = spcp8x5_ioctl,
|
|
.tiocmget = spcp8x5_tiocmget,
|
|
.tiocmset = spcp8x5_tiocmset,
|
|
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
|
|
index 99188c9..a0702db 100644
|
|
--- a/drivers/usb/serial/usb-serial.c
|
|
+++ b/drivers/usb/serial/usb-serial.c
|
|
@@ -43,8 +43,6 @@
|
|
#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/"
|
|
#define DRIVER_DESC "USB Serial Driver core"
|
|
|
|
-static void port_free(struct usb_serial_port *port);
|
|
-
|
|
/* Driver structure we register with the USB core */
|
|
static struct usb_driver usb_serial_driver = {
|
|
.name = "usbserial",
|
|
@@ -68,6 +66,11 @@ static struct usb_serial *serial_table[SERIAL_TTY_MINORS];
|
|
static DEFINE_MUTEX(table_lock);
|
|
static LIST_HEAD(usb_serial_driver_list);
|
|
|
|
+/*
|
|
+ * Look up the serial structure. If it is found and it hasn't been
|
|
+ * disconnected, return with its disc_mutex held and its refcount
|
|
+ * incremented. Otherwise return NULL.
|
|
+ */
|
|
struct usb_serial *usb_serial_get_by_index(unsigned index)
|
|
{
|
|
struct usb_serial *serial;
|
|
@@ -75,8 +78,15 @@ struct usb_serial *usb_serial_get_by_index(unsigned index)
|
|
mutex_lock(&table_lock);
|
|
serial = serial_table[index];
|
|
|
|
- if (serial)
|
|
- kref_get(&serial->kref);
|
|
+ if (serial) {
|
|
+ mutex_lock(&serial->disc_mutex);
|
|
+ if (serial->disconnected) {
|
|
+ mutex_unlock(&serial->disc_mutex);
|
|
+ serial = NULL;
|
|
+ } else {
|
|
+ kref_get(&serial->kref);
|
|
+ }
|
|
+ }
|
|
mutex_unlock(&table_lock);
|
|
return serial;
|
|
}
|
|
@@ -125,8 +135,10 @@ static void return_serial(struct usb_serial *serial)
|
|
|
|
dbg("%s", __func__);
|
|
|
|
+ mutex_lock(&table_lock);
|
|
for (i = 0; i < serial->num_ports; ++i)
|
|
serial_table[serial->minor + i] = NULL;
|
|
+ mutex_unlock(&table_lock);
|
|
}
|
|
|
|
static void destroy_serial(struct kref *kref)
|
|
@@ -145,161 +157,157 @@ static void destroy_serial(struct kref *kref)
|
|
|
|
serial->type->release(serial);
|
|
|
|
- for (i = 0; i < serial->num_ports; ++i) {
|
|
+ /* Now that nothing is using the ports, they can be freed */
|
|
+ for (i = 0; i < serial->num_port_pointers; ++i) {
|
|
port = serial->port[i];
|
|
- if (port)
|
|
+ if (port) {
|
|
+ port->serial = NULL;
|
|
put_device(&port->dev);
|
|
- }
|
|
-
|
|
- /* If this is a "fake" port, we have to clean it up here, as it will
|
|
- * not get cleaned up in port_release() as it was never registered with
|
|
- * the driver core */
|
|
- if (serial->num_ports < serial->num_port_pointers) {
|
|
- for (i = serial->num_ports;
|
|
- i < serial->num_port_pointers; ++i) {
|
|
- port = serial->port[i];
|
|
- if (port)
|
|
- port_free(port);
|
|
}
|
|
}
|
|
|
|
usb_put_dev(serial->dev);
|
|
-
|
|
- /* free up any memory that we allocated */
|
|
kfree(serial);
|
|
}
|
|
|
|
void usb_serial_put(struct usb_serial *serial)
|
|
{
|
|
- mutex_lock(&table_lock);
|
|
kref_put(&serial->kref, destroy_serial);
|
|
- mutex_unlock(&table_lock);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Driver tty interface functions
|
|
*****************************************************************************/
|
|
-static int serial_open (struct tty_struct *tty, struct file *filp)
|
|
+
|
|
+/**
|
|
+ * serial_install - install tty
|
|
+ * @driver: the driver (USB in our case)
|
|
+ * @tty: the tty being created
|
|
+ *
|
|
+ * Create the termios objects for this tty. We use the default
|
|
+ * USB serial settings but permit them to be overridden by
|
|
+ * serial->type->init_termios.
|
|
+ *
|
|
+ * This is the first place a new tty gets used. Hence this is where we
|
|
+ * acquire references to the usb_serial structure and the driver module,
|
|
+ * where we store a pointer to the port, and where we do an autoresume.
|
|
+ * All these actions are reversed in serial_release().
|
|
+ */
|
|
+static int serial_install(struct tty_driver *driver, struct tty_struct *tty)
|
|
{
|
|
+ int idx = tty->index;
|
|
struct usb_serial *serial;
|
|
struct usb_serial_port *port;
|
|
- unsigned int portNumber;
|
|
- int retval = 0;
|
|
- int first = 0;
|
|
+ int retval = -ENODEV;
|
|
|
|
dbg("%s", __func__);
|
|
|
|
- /* get the serial object associated with this tty pointer */
|
|
- serial = usb_serial_get_by_index(tty->index);
|
|
- if (!serial) {
|
|
- tty->driver_data = NULL;
|
|
- return -ENODEV;
|
|
- }
|
|
+ serial = usb_serial_get_by_index(idx);
|
|
+ if (!serial)
|
|
+ return retval;
|
|
|
|
- mutex_lock(&serial->disc_mutex);
|
|
- portNumber = tty->index - serial->minor;
|
|
- port = serial->port[portNumber];
|
|
- if (!port || serial->disconnected)
|
|
- retval = -ENODEV;
|
|
- else
|
|
- get_device(&port->dev);
|
|
- /*
|
|
- * Note: Our locking order requirement does not allow port->mutex
|
|
- * to be acquired while serial->disc_mutex is held.
|
|
- */
|
|
- mutex_unlock(&serial->disc_mutex);
|
|
+ port = serial->port[idx - serial->minor];
|
|
+ if (!port)
|
|
+ goto error_no_port;
|
|
+ if (!try_module_get(serial->type->driver.owner))
|
|
+ goto error_module_get;
|
|
+
|
|
+ /* perform the standard setup */
|
|
+ retval = tty_init_termios(tty);
|
|
if (retval)
|
|
- goto bailout_serial_put;
|
|
+ goto error_init_termios;
|
|
|
|
- if (mutex_lock_interruptible(&port->mutex)) {
|
|
- retval = -ERESTARTSYS;
|
|
- goto bailout_port_put;
|
|
- }
|
|
+ retval = usb_autopm_get_interface(serial->interface);
|
|
+ if (retval)
|
|
+ goto error_get_interface;
|
|
+
|
|
+ mutex_unlock(&serial->disc_mutex);
|
|
|
|
- ++port->port.count;
|
|
+ /* allow the driver to update the settings */
|
|
+ if (serial->type->init_termios)
|
|
+ serial->type->init_termios(tty);
|
|
|
|
- /* set up our port structure making the tty driver
|
|
- * remember our port object, and us it */
|
|
tty->driver_data = port;
|
|
- tty_port_tty_set(&port->port, tty);
|
|
|
|
- /* If the console is attached, the device is already open */
|
|
- if (port->port.count == 1 && !port->console) {
|
|
- first = 1;
|
|
- /* lock this module before we call it
|
|
- * this may fail, which means we must bail out,
|
|
- * safe because we are called with BKL held */
|
|
- if (!try_module_get(serial->type->driver.owner)) {
|
|
- retval = -ENODEV;
|
|
- goto bailout_mutex_unlock;
|
|
- }
|
|
+ /* Final install (we use the default method) */
|
|
+ tty_driver_kref_get(driver);
|
|
+ tty->count++;
|
|
+ driver->ttys[idx] = tty;
|
|
+ return retval;
|
|
|
|
+ error_get_interface:
|
|
+ error_init_termios:
|
|
+ module_put(serial->type->driver.owner);
|
|
+ error_module_get:
|
|
+ error_no_port:
|
|
+ usb_serial_put(serial);
|
|
+ mutex_unlock(&serial->disc_mutex);
|
|
+ return retval;
|
|
+}
|
|
+
|
|
+static int serial_open(struct tty_struct *tty, struct file *filp)
|
|
+{
|
|
+ struct usb_serial_port *port = tty->driver_data;
|
|
+ struct usb_serial *serial = port->serial;
|
|
+ int retval;
|
|
+
|
|
+ dbg("%s - port %d", __func__, port->number);
|
|
+
|
|
+ spin_lock_irq(&port->port.lock);
|
|
+ if (!tty_hung_up_p(filp))
|
|
+ ++port->port.count;
|
|
+ spin_unlock_irq(&port->port.lock);
|
|
+ tty_port_tty_set(&port->port, tty);
|
|
+
|
|
+ /* Do the device-specific open only if the hardware isn't
|
|
+ * already initialized.
|
|
+ */
|
|
+ if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) {
|
|
+ if (mutex_lock_interruptible(&port->mutex))
|
|
+ return -ERESTARTSYS;
|
|
mutex_lock(&serial->disc_mutex);
|
|
if (serial->disconnected)
|
|
retval = -ENODEV;
|
|
else
|
|
- retval = usb_autopm_get_interface(serial->interface);
|
|
- if (retval)
|
|
- goto bailout_module_put;
|
|
-
|
|
- /* only call the device specific open if this
|
|
- * is the first time the port is opened */
|
|
- retval = serial->type->open(tty, port, filp);
|
|
- if (retval)
|
|
- goto bailout_interface_put;
|
|
+ retval = port->serial->type->open(tty, port, filp);
|
|
mutex_unlock(&serial->disc_mutex);
|
|
+ mutex_unlock(&port->mutex);
|
|
+ if (retval)
|
|
+ return retval;
|
|
set_bit(ASYNCB_INITIALIZED, &port->port.flags);
|
|
}
|
|
- mutex_unlock(&port->mutex);
|
|
+
|
|
/* Now do the correct tty layer semantics */
|
|
retval = tty_port_block_til_ready(&port->port, tty, filp);
|
|
- if (retval == 0) {
|
|
- if (!first)
|
|
- usb_serial_put(serial);
|
|
- return 0;
|
|
- }
|
|
- mutex_lock(&port->mutex);
|
|
- if (first == 0)
|
|
- goto bailout_mutex_unlock;
|
|
- /* Undo the initial port actions */
|
|
- mutex_lock(&serial->disc_mutex);
|
|
-bailout_interface_put:
|
|
- usb_autopm_put_interface(serial->interface);
|
|
-bailout_module_put:
|
|
- mutex_unlock(&serial->disc_mutex);
|
|
- module_put(serial->type->driver.owner);
|
|
-bailout_mutex_unlock:
|
|
- port->port.count = 0;
|
|
- tty->driver_data = NULL;
|
|
- tty_port_tty_set(&port->port, NULL);
|
|
- mutex_unlock(&port->mutex);
|
|
-bailout_port_put:
|
|
- put_device(&port->dev);
|
|
-bailout_serial_put:
|
|
- usb_serial_put(serial);
|
|
return retval;
|
|
}
|
|
|
|
/**
|
|
- * serial_do_down - shut down hardware
|
|
- * @port: port to shut down
|
|
- *
|
|
- * Shut down a USB port unless it is the console. We never shut down the
|
|
- * console hardware as it will always be in use.
|
|
+ * serial_down - shut down hardware
|
|
+ * @port: port to shut down
|
|
*
|
|
- * Don't free any resources at this point
|
|
+ * Shut down a USB serial port unless it is the console. We never
|
|
+ * shut down the console hardware as it will always be in use.
|
|
*/
|
|
-static void serial_do_down(struct usb_serial_port *port)
|
|
+static void serial_down(struct usb_serial_port *port)
|
|
{
|
|
struct usb_serial_driver *drv = port->serial->type;
|
|
struct usb_serial *serial;
|
|
struct module *owner;
|
|
|
|
- /* The console is magical, do not hang up the console hardware
|
|
- or there will be tears */
|
|
+ /*
|
|
+ * The console is magical. Do not hang up the console hardware
|
|
+ * or there will be tears.
|
|
+ */
|
|
if (port->console)
|
|
return;
|
|
|
|
+ /* Don't call the close method if the hardware hasn't been
|
|
+ * initialized.
|
|
+ */
|
|
+ if (!test_and_clear_bit(ASYNCB_INITIALIZED, &port->port.flags))
|
|
+ return;
|
|
+
|
|
mutex_lock(&port->mutex);
|
|
serial = port->serial;
|
|
owner = serial->type->driver.owner;
|
|
@@ -310,79 +318,69 @@ static void serial_do_down(struct usb_serial_port *port)
|
|
mutex_unlock(&port->mutex);
|
|
}
|
|
|
|
-/**
|
|
- * serial_do_free - free resources post close/hangup
|
|
- * @port: port to free up
|
|
- *
|
|
- * Do the resource freeing and refcount dropping for the port. We must
|
|
- * be careful about ordering and we must avoid freeing up the console.
|
|
- */
|
|
-
|
|
-static void serial_do_free(struct usb_serial_port *port)
|
|
+static void serial_hangup(struct tty_struct *tty)
|
|
{
|
|
- struct usb_serial *serial;
|
|
- struct module *owner;
|
|
+ struct usb_serial_port *port = tty->driver_data;
|
|
|
|
- /* The console is magical, do not hang up the console hardware
|
|
- or there will be tears */
|
|
- if (port->console)
|
|
- return;
|
|
+ dbg("%s - port %d", __func__, port->number);
|
|
|
|
- serial = port->serial;
|
|
- owner = serial->type->driver.owner;
|
|
- put_device(&port->dev);
|
|
- /* Mustn't dereference port any more */
|
|
- mutex_lock(&serial->disc_mutex);
|
|
- if (!serial->disconnected)
|
|
- usb_autopm_put_interface(serial->interface);
|
|
- mutex_unlock(&serial->disc_mutex);
|
|
- usb_serial_put(serial);
|
|
- /* Mustn't dereference serial any more */
|
|
- module_put(owner);
|
|
+ serial_down(port);
|
|
+ tty_port_hangup(&port->port);
|
|
}
|
|
|
|
static void serial_close(struct tty_struct *tty, struct file *filp)
|
|
{
|
|
struct usb_serial_port *port = tty->driver_data;
|
|
|
|
- if (!port)
|
|
- return;
|
|
-
|
|
dbg("%s - port %d", __func__, port->number);
|
|
|
|
- /* FIXME:
|
|
- This leaves a very narrow race. Really we should do the
|
|
- serial_do_free() on tty->shutdown(), but tty->shutdown can
|
|
- be called from IRQ context and serial_do_free can sleep.
|
|
-
|
|
- The right fix is probably to make the tty free (which is rare)
|
|
- and thus tty->shutdown() occur via a work queue and simplify all
|
|
- the drivers that use it.
|
|
- */
|
|
- if (tty_hung_up_p(filp)) {
|
|
- /* serial_hangup already called serial_down at this point.
|
|
- Another user may have already reopened the port but
|
|
- serial_do_free is refcounted */
|
|
- serial_do_free(port);
|
|
+ if (tty_hung_up_p(filp))
|
|
return;
|
|
- }
|
|
-
|
|
if (tty_port_close_start(&port->port, tty, filp) == 0)
|
|
return;
|
|
-
|
|
- serial_do_down(port);
|
|
+ serial_down(port);
|
|
tty_port_close_end(&port->port, tty);
|
|
tty_port_tty_set(&port->port, NULL);
|
|
- serial_do_free(port);
|
|
}
|
|
|
|
-static void serial_hangup(struct tty_struct *tty)
|
|
+/**
|
|
+ * serial_release - free resources post close/hangup
|
|
+ * @port: port to free up
|
|
+ *
|
|
+ * Do the resource freeing and refcount dropping for the port.
|
|
+ * Avoid freeing the console.
|
|
+ *
|
|
+ * Called when the last tty kref is dropped.
|
|
+ */
|
|
+static void serial_release(struct tty_struct *tty)
|
|
{
|
|
struct usb_serial_port *port = tty->driver_data;
|
|
- serial_do_down(port);
|
|
- tty_port_hangup(&port->port);
|
|
- /* We must not free port yet - the USB serial layer depends on it's
|
|
- continued existence */
|
|
+ struct usb_serial *serial;
|
|
+ struct module *owner;
|
|
+
|
|
+ /* The console is magical. Do not hang up the console hardware
|
|
+ * or there will be tears.
|
|
+ */
|
|
+ if (port->console)
|
|
+ return;
|
|
+
|
|
+ dbg("%s - port %d", __func__, port->number);
|
|
+
|
|
+ /* Standard shutdown processing */
|
|
+ tty_shutdown(tty);
|
|
+
|
|
+ tty->driver_data = NULL;
|
|
+
|
|
+ serial = port->serial;
|
|
+ owner = serial->type->driver.owner;
|
|
+
|
|
+ mutex_lock(&serial->disc_mutex);
|
|
+ if (!serial->disconnected)
|
|
+ usb_autopm_put_interface(serial->interface);
|
|
+ mutex_unlock(&serial->disc_mutex);
|
|
+
|
|
+ usb_serial_put(serial);
|
|
+ module_put(owner);
|
|
}
|
|
|
|
static int serial_write(struct tty_struct *tty, const unsigned char *buf,
|
|
@@ -527,6 +525,7 @@ static int serial_proc_show(struct seq_file *m, void *v)
|
|
|
|
seq_putc(m, '\n');
|
|
usb_serial_put(serial);
|
|
+ mutex_unlock(&serial->disc_mutex);
|
|
}
|
|
return 0;
|
|
}
|
|
@@ -596,14 +595,6 @@ static void usb_serial_port_work(struct work_struct *work)
|
|
tty_kref_put(tty);
|
|
}
|
|
|
|
-static void port_release(struct device *dev)
|
|
-{
|
|
- struct usb_serial_port *port = to_usb_serial_port(dev);
|
|
-
|
|
- dbg ("%s - %s", __func__, dev_name(dev));
|
|
- port_free(port);
|
|
-}
|
|
-
|
|
static void kill_traffic(struct usb_serial_port *port)
|
|
{
|
|
usb_kill_urb(port->read_urb);
|
|
@@ -623,8 +614,12 @@ static void kill_traffic(struct usb_serial_port *port)
|
|
usb_kill_urb(port->interrupt_out_urb);
|
|
}
|
|
|
|
-static void port_free(struct usb_serial_port *port)
|
|
+static void port_release(struct device *dev)
|
|
{
|
|
+ struct usb_serial_port *port = to_usb_serial_port(dev);
|
|
+
|
|
+ dbg ("%s - %s", __func__, dev_name(dev));
|
|
+
|
|
/*
|
|
* Stop all the traffic before cancelling the work, so that
|
|
* nobody will restart it by calling usb_serial_port_softint.
|
|
@@ -935,6 +930,11 @@ int usb_serial_probe(struct usb_interface *interface,
|
|
mutex_init(&port->mutex);
|
|
INIT_WORK(&port->work, usb_serial_port_work);
|
|
serial->port[i] = port;
|
|
+ port->dev.parent = &interface->dev;
|
|
+ port->dev.driver = NULL;
|
|
+ port->dev.bus = &usb_serial_bus_type;
|
|
+ port->dev.release = &port_release;
|
|
+ device_initialize(&port->dev);
|
|
}
|
|
|
|
/* set up the endpoint information */
|
|
@@ -1077,15 +1077,10 @@ int usb_serial_probe(struct usb_interface *interface,
|
|
/* register all of the individual ports with the driver core */
|
|
for (i = 0; i < num_ports; ++i) {
|
|
port = serial->port[i];
|
|
- port->dev.parent = &interface->dev;
|
|
- port->dev.driver = NULL;
|
|
- port->dev.bus = &usb_serial_bus_type;
|
|
- port->dev.release = &port_release;
|
|
-
|
|
dev_set_name(&port->dev, "ttyUSB%d", port->number);
|
|
dbg ("%s - registering %s", __func__, dev_name(&port->dev));
|
|
port->dev_state = PORT_REGISTERING;
|
|
- retval = device_register(&port->dev);
|
|
+ retval = device_add(&port->dev);
|
|
if (retval) {
|
|
dev_err(&port->dev, "Error registering port device, "
|
|
"continuing\n");
|
|
@@ -1103,39 +1098,7 @@ exit:
|
|
return 0;
|
|
|
|
probe_error:
|
|
- for (i = 0; i < num_bulk_in; ++i) {
|
|
- port = serial->port[i];
|
|
- if (!port)
|
|
- continue;
|
|
- usb_free_urb(port->read_urb);
|
|
- kfree(port->bulk_in_buffer);
|
|
- }
|
|
- for (i = 0; i < num_bulk_out; ++i) {
|
|
- port = serial->port[i];
|
|
- if (!port)
|
|
- continue;
|
|
- usb_free_urb(port->write_urb);
|
|
- kfree(port->bulk_out_buffer);
|
|
- }
|
|
- for (i = 0; i < num_interrupt_in; ++i) {
|
|
- port = serial->port[i];
|
|
- if (!port)
|
|
- continue;
|
|
- usb_free_urb(port->interrupt_in_urb);
|
|
- kfree(port->interrupt_in_buffer);
|
|
- }
|
|
- for (i = 0; i < num_interrupt_out; ++i) {
|
|
- port = serial->port[i];
|
|
- if (!port)
|
|
- continue;
|
|
- usb_free_urb(port->interrupt_out_urb);
|
|
- kfree(port->interrupt_out_buffer);
|
|
- }
|
|
-
|
|
- /* free up any memory that we allocated */
|
|
- for (i = 0; i < serial->num_port_pointers; ++i)
|
|
- kfree(serial->port[i]);
|
|
- kfree(serial);
|
|
+ usb_serial_put(serial);
|
|
return -EIO;
|
|
}
|
|
EXPORT_SYMBOL_GPL(usb_serial_probe);
|
|
@@ -1161,10 +1124,7 @@ void usb_serial_disconnect(struct usb_interface *interface)
|
|
if (port) {
|
|
struct tty_struct *tty = tty_port_tty_get(&port->port);
|
|
if (tty) {
|
|
- /* The hangup will occur asynchronously but
|
|
- the object refcounts will sort out all the
|
|
- cleanup */
|
|
- tty_hangup(tty);
|
|
+ tty_vhangup(tty);
|
|
tty_kref_put(tty);
|
|
}
|
|
kill_traffic(port);
|
|
@@ -1189,8 +1149,7 @@ void usb_serial_disconnect(struct usb_interface *interface)
|
|
}
|
|
serial->type->disconnect(serial);
|
|
|
|
- /* let the last holder of this object
|
|
- * cause it to be cleaned up */
|
|
+ /* let the last holder of this object cause it to be cleaned up */
|
|
usb_serial_put(serial);
|
|
dev_info(dev, "device disconnected\n");
|
|
}
|
|
@@ -1246,6 +1205,8 @@ static const struct tty_operations serial_ops = {
|
|
.chars_in_buffer = serial_chars_in_buffer,
|
|
.tiocmget = serial_tiocmget,
|
|
.tiocmset = serial_tiocmset,
|
|
+ .shutdown = serial_release,
|
|
+ .install = serial_install,
|
|
.proc_fops = &serial_proc_fops,
|
|
};
|
|
|
|
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
|
|
index 8d126dd..f7232b1 100644
|
|
--- a/drivers/usb/serial/whiteheat.c
|
|
+++ b/drivers/usb/serial/whiteheat.c
|
|
@@ -259,7 +259,7 @@ static int firm_send_command(struct usb_serial_port *port, __u8 command,
|
|
__u8 *data, __u8 datasize);
|
|
static int firm_open(struct usb_serial_port *port);
|
|
static int firm_close(struct usb_serial_port *port);
|
|
-static int firm_setup_port(struct tty_struct *tty);
|
|
+static void firm_setup_port(struct tty_struct *tty);
|
|
static int firm_set_rts(struct usb_serial_port *port, __u8 onoff);
|
|
static int firm_set_dtr(struct usb_serial_port *port, __u8 onoff);
|
|
static int firm_set_break(struct usb_serial_port *port, __u8 onoff);
|
|
@@ -1211,7 +1211,7 @@ static int firm_close(struct usb_serial_port *port)
|
|
}
|
|
|
|
|
|
-static int firm_setup_port(struct tty_struct *tty)
|
|
+static void firm_setup_port(struct tty_struct *tty)
|
|
{
|
|
struct usb_serial_port *port = tty->driver_data;
|
|
struct whiteheat_port_settings port_settings;
|
|
@@ -1286,7 +1286,7 @@ static int firm_setup_port(struct tty_struct *tty)
|
|
port_settings.lloop = 0;
|
|
|
|
/* now send the message to the device */
|
|
- return firm_send_command(port, WHITEHEAT_SETUP_PORT,
|
|
+ firm_send_command(port, WHITEHEAT_SETUP_PORT,
|
|
(__u8 *)&port_settings, sizeof(port_settings));
|
|
}
|
|
|
|
diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c
|
|
index ec17c96..105d900 100644
|
|
--- a/drivers/usb/storage/initializers.c
|
|
+++ b/drivers/usb/storage/initializers.c
|
|
@@ -102,5 +102,5 @@ int usb_stor_huawei_e220_init(struct us_data *us)
|
|
USB_TYPE_STANDARD | USB_RECIP_DEVICE,
|
|
0x01, 0x0, NULL, 0x0, 1000);
|
|
US_DEBUGP("Huawei mode set result is %d\n", result);
|
|
- return (result ? 0 : -ENODEV);
|
|
+ return 0;
|
|
}
|
|
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
|
|
index 380233b..80e65f2 100644
|
|
--- a/drivers/usb/storage/onetouch.c
|
|
+++ b/drivers/usb/storage/onetouch.c
|
|
@@ -163,7 +163,7 @@ static void usb_onetouch_pm_hook(struct us_data *us, int action)
|
|
usb_kill_urb(onetouch->irq);
|
|
break;
|
|
case US_RESUME:
|
|
- if (usb_submit_urb(onetouch->irq, GFP_KERNEL) != 0)
|
|
+ if (usb_submit_urb(onetouch->irq, GFP_NOIO) != 0)
|
|
dev_err(&onetouch->irq->dev->dev,
|
|
"usb_submit_urb failed\n");
|
|
break;
|
|
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
|
|
index 3a44695..29ff5ea 100644
|
|
--- a/drivers/video/console/fbcon.c
|
|
+++ b/drivers/video/console/fbcon.c
|
|
@@ -114,6 +114,7 @@ static int last_fb_vc = MAX_NR_CONSOLES - 1;
|
|
static int fbcon_is_default = 1;
|
|
static int fbcon_has_exited;
|
|
static int primary_device = -1;
|
|
+static int fbcon_has_console_bind;
|
|
|
|
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
|
|
static int map_override;
|
|
@@ -544,6 +545,8 @@ static int fbcon_takeover(int show_logo)
|
|
con2fb_map[i] = -1;
|
|
}
|
|
info_idx = -1;
|
|
+ } else {
|
|
+ fbcon_has_console_bind = 1;
|
|
}
|
|
|
|
return err;
|
|
@@ -2923,6 +2926,10 @@ static int fbcon_unbind(void)
|
|
|
|
ret = unbind_con_driver(&fb_con, first_fb_vc, last_fb_vc,
|
|
fbcon_is_default);
|
|
+
|
|
+ if (!ret)
|
|
+ fbcon_has_console_bind = 0;
|
|
+
|
|
return ret;
|
|
}
|
|
#else
|
|
@@ -2936,6 +2943,9 @@ static int fbcon_fb_unbind(int idx)
|
|
{
|
|
int i, new_idx = -1, ret = 0;
|
|
|
|
+ if (!fbcon_has_console_bind)
|
|
+ return 0;
|
|
+
|
|
for (i = first_fb_vc; i <= last_fb_vc; i++) {
|
|
if (con2fb_map[i] != idx &&
|
|
con2fb_map[i] != -1) {
|
|
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
|
|
index 5a72083..adf9632 100644
|
|
--- a/drivers/video/s3c-fb.c
|
|
+++ b/drivers/video/s3c-fb.c
|
|
@@ -1036,7 +1036,7 @@ static int s3c_fb_resume(struct platform_device *pdev)
|
|
|
|
static struct platform_driver s3c_fb_driver = {
|
|
.probe = s3c_fb_probe,
|
|
- .remove = s3c_fb_remove,
|
|
+ .remove = __devexit_p(s3c_fb_remove),
|
|
.suspend = s3c_fb_suspend,
|
|
.resume = s3c_fb_resume,
|
|
.driver = {
|
|
diff --git a/drivers/video/sis/vstruct.h b/drivers/video/sis/vstruct.h
|
|
index 705c853..bef4aae 100644
|
|
--- a/drivers/video/sis/vstruct.h
|
|
+++ b/drivers/video/sis/vstruct.h
|
|
@@ -342,7 +342,7 @@ struct SiS_Private
|
|
unsigned short SiS_RY4COE;
|
|
unsigned short SiS_LCDHDES;
|
|
unsigned short SiS_LCDVDES;
|
|
- unsigned short SiS_DDC_Port;
|
|
+ SISIOADDRESS SiS_DDC_Port;
|
|
unsigned short SiS_DDC_Index;
|
|
unsigned short SiS_DDC_Data;
|
|
unsigned short SiS_DDC_NData;
|
|
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
|
|
index ec2a39b..7c28434 100644
|
|
--- a/drivers/xen/Makefile
|
|
+++ b/drivers/xen/Makefile
|
|
@@ -1,6 +1,9 @@
|
|
obj-y += grant-table.o features.o events.o manage.o
|
|
obj-y += xenbus/
|
|
|
|
+nostackp := $(call cc-option, -fno-stack-protector)
|
|
+CFLAGS_features.o := $(nostackp)
|
|
+
|
|
obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o
|
|
obj-$(CONFIG_XEN_XENCOMM) += xencomm.o
|
|
obj-$(CONFIG_XEN_BALLOON) += balloon.o
|
|
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
|
|
index 6084d63..3cfec69 100644
|
|
--- a/fs/cifs/cifsglob.h
|
|
+++ b/fs/cifs/cifsglob.h
|
|
@@ -572,9 +572,9 @@ require use of the stronger protocol */
|
|
#define CIFSSEC_MUST_LANMAN 0x10010
|
|
#define CIFSSEC_MUST_PLNTXT 0x20020
|
|
#ifdef CONFIG_CIFS_UPCALL
|
|
-#define CIFSSEC_MASK 0xAF0AF /* allows weak security but also krb5 */
|
|
+#define CIFSSEC_MASK 0xBF0BF /* allows weak security but also krb5 */
|
|
#else
|
|
-#define CIFSSEC_MASK 0xA70A7 /* current flags supported if weak */
|
|
+#define CIFSSEC_MASK 0xB70B7 /* current flags supported if weak */
|
|
#endif /* UPCALL */
|
|
#else /* do not allow weak pw hash */
|
|
#ifdef CONFIG_CIFS_UPCALL
|
|
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
|
|
index b91851f..f0b53df 100644
|
|
--- a/fs/ecryptfs/crypto.c
|
|
+++ b/fs/ecryptfs/crypto.c
|
|
@@ -797,6 +797,7 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat)
|
|
kfree(full_alg_name);
|
|
if (IS_ERR(crypt_stat->tfm)) {
|
|
rc = PTR_ERR(crypt_stat->tfm);
|
|
+ crypt_stat->tfm = NULL;
|
|
ecryptfs_printk(KERN_ERR, "cryptfs: init_crypt_ctx(): "
|
|
"Error initializing cipher [%s]\n",
|
|
crypt_stat->cipher);
|
|
@@ -1702,7 +1703,7 @@ ecryptfs_encrypt_filename(struct ecryptfs_filename *filename,
|
|
} else {
|
|
printk(KERN_ERR "%s: No support for requested filename "
|
|
"encryption method in this release\n", __func__);
|
|
- rc = -ENOTSUPP;
|
|
+ rc = -EOPNOTSUPP;
|
|
goto out;
|
|
}
|
|
out:
|
|
@@ -2166,7 +2167,7 @@ int ecryptfs_encrypt_and_encode_filename(
|
|
(*encoded_name)[(*encoded_name_size)] = '\0';
|
|
(*encoded_name_size)++;
|
|
} else {
|
|
- rc = -ENOTSUPP;
|
|
+ rc = -EOPNOTSUPP;
|
|
}
|
|
if (rc) {
|
|
printk(KERN_ERR "%s: Error attempting to encode "
|
|
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
|
|
index 2f0945d..056fed6 100644
|
|
--- a/fs/ecryptfs/inode.c
|
|
+++ b/fs/ecryptfs/inode.c
|
|
@@ -476,6 +476,7 @@ static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry)
|
|
struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir);
|
|
struct dentry *lower_dir_dentry;
|
|
|
|
+ dget(lower_dentry);
|
|
lower_dir_dentry = lock_parent(lower_dentry);
|
|
rc = vfs_unlink(lower_dir_inode, lower_dentry);
|
|
if (rc) {
|
|
@@ -489,6 +490,7 @@ static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry)
|
|
d_drop(dentry);
|
|
out_unlock:
|
|
unlock_dir(lower_dir_dentry);
|
|
+ dput(lower_dentry);
|
|
return rc;
|
|
}
|
|
|
|
diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c
|
|
index 259525c..c77438f 100644
|
|
--- a/fs/ecryptfs/keystore.c
|
|
+++ b/fs/ecryptfs/keystore.c
|
|
@@ -416,7 +416,9 @@ ecryptfs_find_global_auth_tok_for_sig(
|
|
&mount_crypt_stat->global_auth_tok_list,
|
|
mount_crypt_stat_list) {
|
|
if (memcmp(walker->sig, sig, ECRYPTFS_SIG_SIZE_HEX) == 0) {
|
|
- (*global_auth_tok) = walker;
|
|
+ rc = key_validate(walker->global_auth_tok_key);
|
|
+ if (!rc)
|
|
+ (*global_auth_tok) = walker;
|
|
goto out;
|
|
}
|
|
}
|
|
@@ -612,7 +614,12 @@ ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes,
|
|
}
|
|
/* TODO: Support other key modules than passphrase for
|
|
* filename encryption */
|
|
- BUG_ON(s->auth_tok->token_type != ECRYPTFS_PASSWORD);
|
|
+ if (s->auth_tok->token_type != ECRYPTFS_PASSWORD) {
|
|
+ rc = -EOPNOTSUPP;
|
|
+ printk(KERN_INFO "%s: Filename encryption only supports "
|
|
+ "password tokens\n", __func__);
|
|
+ goto out_free_unlock;
|
|
+ }
|
|
sg_init_one(
|
|
&s->hash_sg,
|
|
(u8 *)s->auth_tok->token.password.session_key_encryption_key,
|
|
@@ -910,7 +917,12 @@ ecryptfs_parse_tag_70_packet(char **filename, size_t *filename_size,
|
|
}
|
|
/* TODO: Support other key modules than passphrase for
|
|
* filename encryption */
|
|
- BUG_ON(s->auth_tok->token_type != ECRYPTFS_PASSWORD);
|
|
+ if (s->auth_tok->token_type != ECRYPTFS_PASSWORD) {
|
|
+ rc = -EOPNOTSUPP;
|
|
+ printk(KERN_INFO "%s: Filename encryption only supports "
|
|
+ "password tokens\n", __func__);
|
|
+ goto out_free_unlock;
|
|
+ }
|
|
rc = crypto_blkcipher_setkey(
|
|
s->desc.tfm,
|
|
s->auth_tok->token.password.session_key_encryption_key,
|
|
@@ -1316,8 +1328,10 @@ parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat,
|
|
rc = -EINVAL;
|
|
goto out_free;
|
|
}
|
|
- ecryptfs_cipher_code_to_string(crypt_stat->cipher,
|
|
- (u16)data[(*packet_size)]);
|
|
+ rc = ecryptfs_cipher_code_to_string(crypt_stat->cipher,
|
|
+ (u16)data[(*packet_size)]);
|
|
+ if (rc)
|
|
+ goto out_free;
|
|
/* A little extra work to differentiate among the AES key
|
|
* sizes; see RFC2440 */
|
|
switch(data[(*packet_size)++]) {
|
|
@@ -1328,7 +1342,9 @@ parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat,
|
|
crypt_stat->key_size =
|
|
(*new_auth_tok)->session_key.encrypted_key_size;
|
|
}
|
|
- ecryptfs_init_crypt_ctx(crypt_stat);
|
|
+ rc = ecryptfs_init_crypt_ctx(crypt_stat);
|
|
+ if (rc)
|
|
+ goto out_free;
|
|
if (unlikely(data[(*packet_size)++] != 0x03)) {
|
|
printk(KERN_WARNING "Only S2K ID 3 is currently supported\n");
|
|
rc = -ENOSYS;
|
|
diff --git a/fs/ecryptfs/kthread.c b/fs/ecryptfs/kthread.c
|
|
index c6d7a4d..e14cf7e 100644
|
|
--- a/fs/ecryptfs/kthread.c
|
|
+++ b/fs/ecryptfs/kthread.c
|
|
@@ -136,6 +136,7 @@ int ecryptfs_privileged_open(struct file **lower_file,
|
|
const struct cred *cred)
|
|
{
|
|
struct ecryptfs_open_req *req;
|
|
+ int flags = O_LARGEFILE;
|
|
int rc = 0;
|
|
|
|
/* Corresponding dput() and mntput() are done when the
|
|
@@ -143,10 +144,14 @@ int ecryptfs_privileged_open(struct file **lower_file,
|
|
* destroyed. */
|
|
dget(lower_dentry);
|
|
mntget(lower_mnt);
|
|
- (*lower_file) = dentry_open(lower_dentry, lower_mnt,
|
|
- (O_RDWR | O_LARGEFILE), cred);
|
|
+ flags |= IS_RDONLY(lower_dentry->d_inode) ? O_RDONLY : O_RDWR;
|
|
+ (*lower_file) = dentry_open(lower_dentry, lower_mnt, flags, cred);
|
|
if (!IS_ERR(*lower_file))
|
|
goto out;
|
|
+ if (flags & O_RDONLY) {
|
|
+ rc = PTR_ERR((*lower_file));
|
|
+ goto out;
|
|
+ }
|
|
req = kmem_cache_alloc(ecryptfs_open_req_cache, GFP_KERNEL);
|
|
if (!req) {
|
|
rc = -ENOMEM;
|
|
@@ -180,21 +185,8 @@ int ecryptfs_privileged_open(struct file **lower_file,
|
|
__func__);
|
|
goto out_unlock;
|
|
}
|
|
- if (IS_ERR(*req->lower_file)) {
|
|
+ if (IS_ERR(*req->lower_file))
|
|
rc = PTR_ERR(*req->lower_file);
|
|
- dget(lower_dentry);
|
|
- mntget(lower_mnt);
|
|
- (*lower_file) = dentry_open(lower_dentry, lower_mnt,
|
|
- (O_RDONLY | O_LARGEFILE), cred);
|
|
- if (IS_ERR(*lower_file)) {
|
|
- rc = PTR_ERR(*req->lower_file);
|
|
- (*lower_file) = NULL;
|
|
- printk(KERN_WARNING "%s: Error attempting privileged "
|
|
- "open of lower file with either RW or RO "
|
|
- "perms; rc = [%d]. Giving up.\n",
|
|
- __func__, rc);
|
|
- }
|
|
- }
|
|
out_unlock:
|
|
mutex_unlock(&req->mux);
|
|
out_free:
|
|
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
|
|
index 9f0aa98..101fe4c 100644
|
|
--- a/fs/ecryptfs/main.c
|
|
+++ b/fs/ecryptfs/main.c
|
|
@@ -129,11 +129,10 @@ int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry)
|
|
lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
|
|
rc = ecryptfs_privileged_open(&inode_info->lower_file,
|
|
lower_dentry, lower_mnt, cred);
|
|
- if (rc || IS_ERR(inode_info->lower_file)) {
|
|
+ if (rc) {
|
|
printk(KERN_ERR "Error opening lower persistent file "
|
|
"for lower_dentry [0x%p] and lower_mnt [0x%p]; "
|
|
"rc = [%d]\n", lower_dentry, lower_mnt, rc);
|
|
- rc = PTR_ERR(inode_info->lower_file);
|
|
inode_info->lower_file = NULL;
|
|
}
|
|
}
|
|
diff --git a/fs/inode.c b/fs/inode.c
|
|
index ae7b67e..1a959c0 100644
|
|
--- a/fs/inode.c
|
|
+++ b/fs/inode.c
|
|
@@ -697,13 +697,15 @@ void unlock_new_inode(struct inode *inode)
|
|
}
|
|
#endif
|
|
/*
|
|
- * This is special! We do not need the spinlock
|
|
- * when clearing I_LOCK, because we're guaranteed
|
|
- * that nobody else tries to do anything about the
|
|
- * state of the inode when it is locked, as we
|
|
- * just created it (so there can be no old holders
|
|
- * that haven't tested I_LOCK).
|
|
+ * This is special! We do not need the spinlock when clearing I_LOCK,
|
|
+ * because we're guaranteed that nobody else tries to do anything about
|
|
+ * the state of the inode when it is locked, as we just created it (so
|
|
+ * there can be no old holders that haven't tested I_LOCK).
|
|
+ * However we must emit the memory barrier so that other CPUs reliably
|
|
+ * see the clearing of I_LOCK after the other inode initialisation has
|
|
+ * completed.
|
|
*/
|
|
+ smp_mb();
|
|
WARN_ON((inode->i_state & (I_LOCK|I_NEW)) != (I_LOCK|I_NEW));
|
|
inode->i_state &= ~(I_LOCK|I_NEW);
|
|
wake_up_inode(inode);
|
|
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
|
|
index 3fd23f7..bf9b470 100644
|
|
--- a/fs/nfsd/nfs4callback.c
|
|
+++ b/fs/nfsd/nfs4callback.c
|
|
@@ -444,6 +444,7 @@ static struct rpc_cred *lookup_cb_cred(struct nfs4_cb_conn *cb)
|
|
struct auth_cred acred = {
|
|
.machine_cred = 1
|
|
};
|
|
+ struct rpc_auth *auth = cb->cb_client->cl_auth;
|
|
|
|
/*
|
|
* Note in the gss case this doesn't actually have to wait for a
|
|
@@ -451,8 +452,7 @@ static struct rpc_cred *lookup_cb_cred(struct nfs4_cb_conn *cb)
|
|
* non-uptodate cred which the rpc state machine will fill in with
|
|
* a refresh_upcall later.
|
|
*/
|
|
- return rpcauth_lookup_credcache(cb->cb_client->cl_auth, &acred,
|
|
- RPCAUTH_LOOKUP_NEW);
|
|
+ return auth->au_ops->lookup_cred(auth, &acred, RPCAUTH_LOOKUP_NEW);
|
|
}
|
|
|
|
void do_probe_callback(struct nfs4_client *clp)
|
|
diff --git a/fs/nilfs2/btnode.c b/fs/nilfs2/btnode.c
|
|
index c668bca..5be2c8b 100644
|
|
--- a/fs/nilfs2/btnode.c
|
|
+++ b/fs/nilfs2/btnode.c
|
|
@@ -36,6 +36,7 @@
|
|
|
|
void nilfs_btnode_cache_init_once(struct address_space *btnc)
|
|
{
|
|
+ memset(btnc, 0, sizeof(*btnc));
|
|
INIT_RADIX_TREE(&btnc->page_tree, GFP_ATOMIC);
|
|
spin_lock_init(&btnc->tree_lock);
|
|
INIT_LIST_HEAD(&btnc->private_list);
|
|
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c
|
|
index 59b43a0..5fd7d2b 100644
|
|
--- a/fs/proc/kcore.c
|
|
+++ b/fs/proc/kcore.c
|
|
@@ -361,7 +361,13 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
|
|
/* don't dump ioremap'd stuff! (TA) */
|
|
if (m->flags & VM_IOREMAP)
|
|
continue;
|
|
- memcpy(elf_buf + (vmstart - start),
|
|
+ /*
|
|
+ * we may access memory holes, then use
|
|
+ * ex_table. checking return value just for
|
|
+ * avoid warnings.
|
|
+ */
|
|
+ vmsize = __copy_from_user_inatomic(
|
|
+ elf_buf + (vmstart - start),
|
|
(char *)vmstart, vmsize);
|
|
}
|
|
read_unlock(&vmlist_lock);
|
|
diff --git a/fs/proc/uptime.c b/fs/proc/uptime.c
|
|
index 0c10a0b..766b1d4 100644
|
|
--- a/fs/proc/uptime.c
|
|
+++ b/fs/proc/uptime.c
|
|
@@ -4,13 +4,18 @@
|
|
#include <linux/sched.h>
|
|
#include <linux/seq_file.h>
|
|
#include <linux/time.h>
|
|
+#include <linux/kernel_stat.h>
|
|
#include <asm/cputime.h>
|
|
|
|
static int uptime_proc_show(struct seq_file *m, void *v)
|
|
{
|
|
struct timespec uptime;
|
|
struct timespec idle;
|
|
- cputime_t idletime = cputime_add(init_task.utime, init_task.stime);
|
|
+ int i;
|
|
+ cputime_t idletime = cputime_zero;
|
|
+
|
|
+ for_each_possible_cpu(i)
|
|
+ idletime = cputime64_add(idletime, kstat_cpu(i).cpustat.idle);
|
|
|
|
do_posix_clock_monotonic_gettime(&uptime);
|
|
monotonic_to_bootbased(&uptime);
|
|
diff --git a/include/linux/tty.h b/include/linux/tty.h
|
|
index e8c6c91..b982a17 100644
|
|
--- a/include/linux/tty.h
|
|
+++ b/include/linux/tty.h
|
|
@@ -185,7 +185,12 @@ struct tty_port;
|
|
struct tty_port_operations {
|
|
/* Return 1 if the carrier is raised */
|
|
int (*carrier_raised)(struct tty_port *port);
|
|
+ /* Control the DTR line */
|
|
void (*dtr_rts)(struct tty_port *port, int raise);
|
|
+ /* Called when the last close completes or a hangup finishes
|
|
+ IFF the port was initialized. Do not use to free resources */
|
|
+ void (*shutdown)(struct tty_port *port);
|
|
+ void (*drop)(struct tty_port *port);
|
|
};
|
|
|
|
struct tty_port {
|
|
@@ -457,7 +462,8 @@ extern int tty_port_block_til_ready(struct tty_port *port,
|
|
extern int tty_port_close_start(struct tty_port *port,
|
|
struct tty_struct *tty, struct file *filp);
|
|
extern void tty_port_close_end(struct tty_port *port, struct tty_struct *tty);
|
|
-
|
|
+extern void tty_port_close(struct tty_port *port,
|
|
+ struct tty_struct *tty, struct file *filp);
|
|
extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc);
|
|
extern int tty_unregister_ldisc(int disc);
|
|
extern int tty_set_ldisc(struct tty_struct *tty, int ldisc);
|
|
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
|
|
index 0ec50ba..73f121e 100644
|
|
--- a/include/linux/usb/serial.h
|
|
+++ b/include/linux/usb/serial.h
|
|
@@ -261,6 +261,9 @@ struct usb_serial_driver {
|
|
be an attached tty at this point */
|
|
void (*dtr_rts)(struct usb_serial_port *port, int on);
|
|
int (*carrier_raised)(struct usb_serial_port *port);
|
|
+ /* Called by the usb serial hooks to allow the user to rework the
|
|
+ termios state */
|
|
+ void (*init_termios)(struct tty_struct *tty);
|
|
/* USB events */
|
|
void (*read_int_callback)(struct urb *urb);
|
|
void (*write_int_callback)(struct urb *urb);
|
|
diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h
|
|
index 9b4ac93..56677eb 100644
|
|
--- a/include/pcmcia/ss.h
|
|
+++ b/include/pcmcia/ss.h
|
|
@@ -279,7 +279,7 @@ extern struct pccard_resource_ops pccard_iodyn_ops;
|
|
extern struct pccard_resource_ops pccard_nonstatic_ops;
|
|
|
|
/* socket drivers are expected to use these callbacks in their .drv struct */
|
|
-extern int pcmcia_socket_dev_suspend(struct device *dev, pm_message_t state);
|
|
+extern int pcmcia_socket_dev_suspend(struct device *dev);
|
|
extern int pcmcia_socket_dev_resume(struct device *dev);
|
|
|
|
/* socket drivers use this callback in their IRQ handler */
|
|
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c
|
|
index 3f49f53..b1dc468 100644
|
|
--- a/kernel/perf_counter.c
|
|
+++ b/kernel/perf_counter.c
|
|
@@ -4143,8 +4143,8 @@ done:
|
|
static int perf_copy_attr(struct perf_counter_attr __user *uattr,
|
|
struct perf_counter_attr *attr)
|
|
{
|
|
- int ret;
|
|
u32 size;
|
|
+ int ret;
|
|
|
|
if (!access_ok(VERIFY_WRITE, uattr, PERF_ATTR_SIZE_VER0))
|
|
return -EFAULT;
|
|
@@ -4169,19 +4169,19 @@ static int perf_copy_attr(struct perf_counter_attr __user *uattr,
|
|
|
|
/*
|
|
* If we're handed a bigger struct than we know of,
|
|
- * ensure all the unknown bits are 0.
|
|
+ * ensure all the unknown bits are 0 - i.e. new
|
|
+ * user-space does not rely on any kernel feature
|
|
+ * extensions we dont know about yet.
|
|
*/
|
|
if (size > sizeof(*attr)) {
|
|
- unsigned long val;
|
|
- unsigned long __user *addr;
|
|
- unsigned long __user *end;
|
|
+ unsigned char __user *addr;
|
|
+ unsigned char __user *end;
|
|
+ unsigned char val;
|
|
|
|
- addr = PTR_ALIGN((void __user *)uattr + sizeof(*attr),
|
|
- sizeof(unsigned long));
|
|
- end = PTR_ALIGN((void __user *)uattr + size,
|
|
- sizeof(unsigned long));
|
|
+ addr = (void __user *)uattr + sizeof(*attr);
|
|
+ end = (void __user *)uattr + size;
|
|
|
|
- for (; addr < end; addr += sizeof(unsigned long)) {
|
|
+ for (; addr < end; addr++) {
|
|
ret = get_user(val, addr);
|
|
if (ret)
|
|
return ret;
|
|
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
|
|
index cafdcee..cae0337 100644
|
|
--- a/mm/hugetlb.c
|
|
+++ b/mm/hugetlb.c
|
|
@@ -1010,6 +1010,7 @@ int __weak alloc_bootmem_huge_page(struct hstate *h)
|
|
NODE_DATA(h->hugetlb_next_nid),
|
|
huge_page_size(h), huge_page_size(h), 0);
|
|
|
|
+ hstate_next_node(h);
|
|
if (addr) {
|
|
/*
|
|
* Use the beginning of the huge page to store the
|
|
@@ -1019,7 +1020,6 @@ int __weak alloc_bootmem_huge_page(struct hstate *h)
|
|
m = addr;
|
|
goto found;
|
|
}
|
|
- hstate_next_node(h);
|
|
nr_nodes--;
|
|
}
|
|
return 0;
|
|
diff --git a/mm/memory.c b/mm/memory.c
|
|
index aede2ce..753b2e6 100644
|
|
--- a/mm/memory.c
|
|
+++ b/mm/memory.c
|
|
@@ -2638,7 +2638,8 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
|
|
goto oom_free_page;
|
|
|
|
entry = mk_pte(page, vma->vm_page_prot);
|
|
- entry = maybe_mkwrite(pte_mkdirty(entry), vma);
|
|
+ if (vma->vm_flags & VM_WRITE)
|
|
+ entry = pte_mkwrite(pte_mkdirty(entry));
|
|
|
|
page_table = pte_offset_map_lock(mm, pmd, address, &ptl);
|
|
if (!pte_none(*page_table))
|
|
diff --git a/mm/mlock.c b/mm/mlock.c
|
|
index 45eb650..e13918d 100644
|
|
--- a/mm/mlock.c
|
|
+++ b/mm/mlock.c
|
|
@@ -139,49 +139,36 @@ static void munlock_vma_page(struct page *page)
|
|
}
|
|
|
|
/**
|
|
- * __mlock_vma_pages_range() - mlock/munlock a range of pages in the vma.
|
|
+ * __mlock_vma_pages_range() - mlock a range of pages in the vma.
|
|
* @vma: target vma
|
|
* @start: start address
|
|
* @end: end address
|
|
- * @mlock: 0 indicate munlock, otherwise mlock.
|
|
*
|
|
- * If @mlock == 0, unlock an mlocked range;
|
|
- * else mlock the range of pages. This takes care of making the pages present ,
|
|
- * too.
|
|
+ * This takes care of making the pages present too.
|
|
*
|
|
* return 0 on success, negative error code on error.
|
|
*
|
|
* vma->vm_mm->mmap_sem must be held for at least read.
|
|
*/
|
|
static long __mlock_vma_pages_range(struct vm_area_struct *vma,
|
|
- unsigned long start, unsigned long end,
|
|
- int mlock)
|
|
+ unsigned long start, unsigned long end)
|
|
{
|
|
struct mm_struct *mm = vma->vm_mm;
|
|
unsigned long addr = start;
|
|
struct page *pages[16]; /* 16 gives a reasonable batch */
|
|
int nr_pages = (end - start) / PAGE_SIZE;
|
|
int ret = 0;
|
|
- int gup_flags = 0;
|
|
+ int gup_flags;
|
|
|
|
VM_BUG_ON(start & ~PAGE_MASK);
|
|
VM_BUG_ON(end & ~PAGE_MASK);
|
|
VM_BUG_ON(start < vma->vm_start);
|
|
VM_BUG_ON(end > vma->vm_end);
|
|
- VM_BUG_ON((!rwsem_is_locked(&mm->mmap_sem)) &&
|
|
- (atomic_read(&mm->mm_users) != 0));
|
|
-
|
|
- /*
|
|
- * mlock: don't page populate if vma has PROT_NONE permission.
|
|
- * munlock: always do munlock although the vma has PROT_NONE
|
|
- * permission, or SIGKILL is pending.
|
|
- */
|
|
- if (!mlock)
|
|
- gup_flags |= GUP_FLAGS_IGNORE_VMA_PERMISSIONS |
|
|
- GUP_FLAGS_IGNORE_SIGKILL;
|
|
+ VM_BUG_ON(!rwsem_is_locked(&mm->mmap_sem));
|
|
|
|
+ gup_flags = 0;
|
|
if (vma->vm_flags & VM_WRITE)
|
|
- gup_flags |= GUP_FLAGS_WRITE;
|
|
+ gup_flags = GUP_FLAGS_WRITE;
|
|
|
|
while (nr_pages > 0) {
|
|
int i;
|
|
@@ -201,19 +188,10 @@ static long __mlock_vma_pages_range(struct vm_area_struct *vma,
|
|
* This can happen for, e.g., VM_NONLINEAR regions before
|
|
* a page has been allocated and mapped at a given offset,
|
|
* or for addresses that map beyond end of a file.
|
|
- * We'll mlock the the pages if/when they get faulted in.
|
|
+ * We'll mlock the pages if/when they get faulted in.
|
|
*/
|
|
if (ret < 0)
|
|
break;
|
|
- if (ret == 0) {
|
|
- /*
|
|
- * We know the vma is there, so the only time
|
|
- * we cannot get a single page should be an
|
|
- * error (ret < 0) case.
|
|
- */
|
|
- WARN_ON(1);
|
|
- break;
|
|
- }
|
|
|
|
lru_add_drain(); /* push cached pages to LRU */
|
|
|
|
@@ -224,28 +202,22 @@ static long __mlock_vma_pages_range(struct vm_area_struct *vma,
|
|
/*
|
|
* Because we lock page here and migration is blocked
|
|
* by the elevated reference, we need only check for
|
|
- * page truncation (file-cache only).
|
|
+ * file-cache page truncation. This page->mapping
|
|
+ * check also neatly skips over the ZERO_PAGE(),
|
|
+ * though if that's common we'd prefer not to lock it.
|
|
*/
|
|
- if (page->mapping) {
|
|
- if (mlock)
|
|
- mlock_vma_page(page);
|
|
- else
|
|
- munlock_vma_page(page);
|
|
- }
|
|
+ if (page->mapping)
|
|
+ mlock_vma_page(page);
|
|
unlock_page(page);
|
|
- put_page(page); /* ref from get_user_pages() */
|
|
-
|
|
- /*
|
|
- * here we assume that get_user_pages() has given us
|
|
- * a list of virtually contiguous pages.
|
|
- */
|
|
- addr += PAGE_SIZE; /* for next get_user_pages() */
|
|
- nr_pages--;
|
|
+ put_page(page); /* ref from get_user_pages() */
|
|
}
|
|
+
|
|
+ addr += ret * PAGE_SIZE;
|
|
+ nr_pages -= ret;
|
|
ret = 0;
|
|
}
|
|
|
|
- return ret; /* count entire vma as locked_vm */
|
|
+ return ret; /* 0 or negative error code */
|
|
}
|
|
|
|
/*
|
|
@@ -289,7 +261,7 @@ long mlock_vma_pages_range(struct vm_area_struct *vma,
|
|
is_vm_hugetlb_page(vma) ||
|
|
vma == get_gate_vma(current))) {
|
|
|
|
- __mlock_vma_pages_range(vma, start, end, 1);
|
|
+ __mlock_vma_pages_range(vma, start, end);
|
|
|
|
/* Hide errors from mmap() and other callers */
|
|
return 0;
|
|
@@ -310,7 +282,6 @@ no_mlock:
|
|
return nr_pages; /* error or pages NOT mlocked */
|
|
}
|
|
|
|
-
|
|
/*
|
|
* munlock_vma_pages_range() - munlock all pages in the vma range.'
|
|
* @vma - vma containing range to be munlock()ed.
|
|
@@ -330,10 +301,24 @@ no_mlock:
|
|
* free them. This will result in freeing mlocked pages.
|
|
*/
|
|
void munlock_vma_pages_range(struct vm_area_struct *vma,
|
|
- unsigned long start, unsigned long end)
|
|
+ unsigned long start, unsigned long end)
|
|
{
|
|
+ unsigned long addr;
|
|
+
|
|
+ lru_add_drain();
|
|
vma->vm_flags &= ~VM_LOCKED;
|
|
- __mlock_vma_pages_range(vma, start, end, 0);
|
|
+
|
|
+ for (addr = start; addr < end; addr += PAGE_SIZE) {
|
|
+ struct page *page = follow_page(vma, addr, FOLL_GET);
|
|
+ if (page) {
|
|
+ lock_page(page);
|
|
+ if (page->mapping)
|
|
+ munlock_vma_page(page);
|
|
+ unlock_page(page);
|
|
+ put_page(page);
|
|
+ }
|
|
+ cond_resched();
|
|
+ }
|
|
}
|
|
|
|
/*
|
|
@@ -400,18 +385,14 @@ success:
|
|
* It's okay if try_to_unmap_one unmaps a page just after we
|
|
* set VM_LOCKED, __mlock_vma_pages_range will bring it back.
|
|
*/
|
|
- vma->vm_flags = newflags;
|
|
|
|
if (lock) {
|
|
- ret = __mlock_vma_pages_range(vma, start, end, 1);
|
|
-
|
|
- if (ret > 0) {
|
|
- mm->locked_vm -= ret;
|
|
- ret = 0;
|
|
- } else
|
|
- ret = __mlock_posix_error_return(ret); /* translate if needed */
|
|
+ vma->vm_flags = newflags;
|
|
+ ret = __mlock_vma_pages_range(vma, start, end);
|
|
+ if (ret < 0)
|
|
+ ret = __mlock_posix_error_return(ret);
|
|
} else {
|
|
- __mlock_vma_pages_range(vma, start, end, 0);
|
|
+ munlock_vma_pages_range(vma, start, end);
|
|
}
|
|
|
|
out:
|
|
diff --git a/mm/mmap.c b/mm/mmap.c
|
|
index 8101de4..cbb7cb3 100644
|
|
--- a/mm/mmap.c
|
|
+++ b/mm/mmap.c
|
|
@@ -570,9 +570,9 @@ again: remove_next = 1 + (end > next->vm_end);
|
|
|
|
/*
|
|
* When changing only vma->vm_end, we don't really need
|
|
- * anon_vma lock: but is that case worth optimizing out?
|
|
+ * anon_vma lock.
|
|
*/
|
|
- if (vma->anon_vma)
|
|
+ if (vma->anon_vma && (insert || importer || start != vma->vm_start))
|
|
anon_vma = vma->anon_vma;
|
|
if (anon_vma) {
|
|
spin_lock(&anon_vma->lock);
|
|
diff --git a/mm/nommu.c b/mm/nommu.c
|
|
index 66e81e7..82fedca 100644
|
|
--- a/mm/nommu.c
|
|
+++ b/mm/nommu.c
|
|
@@ -1056,7 +1056,7 @@ static int do_mmap_shared_file(struct vm_area_struct *vma)
|
|
ret = vma->vm_file->f_op->mmap(vma->vm_file, vma);
|
|
if (ret == 0) {
|
|
vma->vm_region->vm_top = vma->vm_region->vm_end;
|
|
- return ret;
|
|
+ return 0;
|
|
}
|
|
if (ret != -ENOSYS)
|
|
return ret;
|
|
@@ -1073,7 +1073,8 @@ static int do_mmap_shared_file(struct vm_area_struct *vma)
|
|
*/
|
|
static int do_mmap_private(struct vm_area_struct *vma,
|
|
struct vm_region *region,
|
|
- unsigned long len)
|
|
+ unsigned long len,
|
|
+ unsigned long capabilities)
|
|
{
|
|
struct page *pages;
|
|
unsigned long total, point, n, rlen;
|
|
@@ -1084,13 +1085,13 @@ static int do_mmap_private(struct vm_area_struct *vma,
|
|
* shared mappings on devices or memory
|
|
* - VM_MAYSHARE will be set if it may attempt to share
|
|
*/
|
|
- if (vma->vm_file) {
|
|
+ if (capabilities & BDI_CAP_MAP_DIRECT) {
|
|
ret = vma->vm_file->f_op->mmap(vma->vm_file, vma);
|
|
if (ret == 0) {
|
|
/* shouldn't return success if we're not sharing */
|
|
BUG_ON(!(vma->vm_flags & VM_MAYSHARE));
|
|
vma->vm_region->vm_top = vma->vm_region->vm_end;
|
|
- return ret;
|
|
+ return 0;
|
|
}
|
|
if (ret != -ENOSYS)
|
|
return ret;
|
|
@@ -1328,7 +1329,7 @@ unsigned long do_mmap_pgoff(struct file *file,
|
|
* - this is the hook for quasi-memory character devices to
|
|
* tell us the location of a shared mapping
|
|
*/
|
|
- if (file && file->f_op->get_unmapped_area) {
|
|
+ if (capabilities & BDI_CAP_MAP_DIRECT) {
|
|
addr = file->f_op->get_unmapped_area(file, addr, len,
|
|
pgoff, flags);
|
|
if (IS_ERR((void *) addr)) {
|
|
@@ -1352,15 +1353,17 @@ unsigned long do_mmap_pgoff(struct file *file,
|
|
}
|
|
|
|
vma->vm_region = region;
|
|
- add_nommu_region(region);
|
|
|
|
- /* set up the mapping */
|
|
+ /* set up the mapping
|
|
+ * - the region is filled in if BDI_CAP_MAP_DIRECT is still set
|
|
+ */
|
|
if (file && vma->vm_flags & VM_SHARED)
|
|
ret = do_mmap_shared_file(vma);
|
|
else
|
|
- ret = do_mmap_private(vma, region, len);
|
|
+ ret = do_mmap_private(vma, region, len, capabilities);
|
|
if (ret < 0)
|
|
- goto error_put_region;
|
|
+ goto error_just_free;
|
|
+ add_nommu_region(region);
|
|
|
|
/* okay... we have a mapping; now we have to register it */
|
|
result = vma->vm_start;
|
|
@@ -1378,19 +1381,6 @@ share:
|
|
kleave(" = %lx", result);
|
|
return result;
|
|
|
|
-error_put_region:
|
|
- __put_nommu_region(region);
|
|
- if (vma) {
|
|
- if (vma->vm_file) {
|
|
- fput(vma->vm_file);
|
|
- if (vma->vm_flags & VM_EXECUTABLE)
|
|
- removed_exe_file_vma(vma->vm_mm);
|
|
- }
|
|
- kmem_cache_free(vm_area_cachep, vma);
|
|
- }
|
|
- kleave(" = %d [pr]", ret);
|
|
- return ret;
|
|
-
|
|
error_just_free:
|
|
up_write(&nommu_region_sem);
|
|
error:
|
|
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
|
|
index a0de15f..0b3c6cb 100644
|
|
--- a/mm/page_alloc.c
|
|
+++ b/mm/page_alloc.c
|
|
@@ -2783,7 +2783,8 @@ static void setup_zone_migrate_reserve(struct zone *zone)
|
|
{
|
|
unsigned long start_pfn, pfn, end_pfn;
|
|
struct page *page;
|
|
- unsigned long reserve, block_migratetype;
|
|
+ unsigned long block_migratetype;
|
|
+ int reserve;
|
|
|
|
/* Get the start pfn, end pfn and the number of blocks to reserve */
|
|
start_pfn = zone->zone_start_pfn;
|
|
@@ -2791,6 +2792,15 @@ static void setup_zone_migrate_reserve(struct zone *zone)
|
|
reserve = roundup(min_wmark_pages(zone), pageblock_nr_pages) >>
|
|
pageblock_order;
|
|
|
|
+ /*
|
|
+ * Reserve blocks are generally in place to help high-order atomic
|
|
+ * allocations that are short-lived. A min_free_kbytes value that
|
|
+ * would result in more than 2 reserve blocks for atomic allocations
|
|
+ * is assumed to be in place to help anti-fragmentation for the
|
|
+ * future allocation of hugepages at runtime.
|
|
+ */
|
|
+ reserve = min(2, reserve);
|
|
+
|
|
for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) {
|
|
if (!pfn_valid(pfn))
|
|
continue;
|
|
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
|
|
index da0f64f..f03529c 100644
|
|
--- a/net/ax25/af_ax25.c
|
|
+++ b/net/ax25/af_ax25.c
|
|
@@ -538,7 +538,7 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname,
|
|
if (level != SOL_AX25)
|
|
return -ENOPROTOOPT;
|
|
|
|
- if (optlen < sizeof(int))
|
|
+ if (optlen < (int)sizeof(int))
|
|
return -EINVAL;
|
|
|
|
if (get_user(opt, (int __user *)optval))
|
|
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
|
|
index d22f611..991fe40 100644
|
|
--- a/net/bridge/br_netfilter.c
|
|
+++ b/net/bridge/br_netfilter.c
|
|
@@ -359,7 +359,7 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb)
|
|
},
|
|
.proto = 0,
|
|
};
|
|
- struct in_device *in_dev = in_dev_get(dev);
|
|
+ struct in_device *in_dev = __in_dev_get_rcu(dev);
|
|
|
|
/* If err equals -EHOSTUNREACH the error is due to a
|
|
* martian destination or due to the fact that
|
|
diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c
|
|
index 133eeae..ce50688 100644
|
|
--- a/net/bridge/netfilter/ebt_ulog.c
|
|
+++ b/net/bridge/netfilter/ebt_ulog.c
|
|
@@ -266,7 +266,7 @@ static bool ebt_ulog_tg_check(const struct xt_tgchk_param *par)
|
|
if (uloginfo->qthreshold > EBT_ULOG_MAX_QLEN)
|
|
uloginfo->qthreshold = EBT_ULOG_MAX_QLEN;
|
|
|
|
- return 0;
|
|
+ return true;
|
|
}
|
|
|
|
static struct xt_target ebt_ulog_tg_reg __read_mostly = {
|
|
diff --git a/net/can/af_can.c b/net/can/af_can.c
|
|
index e733725..264c968 100644
|
|
--- a/net/can/af_can.c
|
|
+++ b/net/can/af_can.c
|
|
@@ -199,6 +199,8 @@ static int can_create(struct net *net, struct socket *sock, int protocol)
|
|
* @skb: pointer to socket buffer with CAN frame in data section
|
|
* @loop: loopback for listeners on local CAN sockets (recommended default!)
|
|
*
|
|
+ * Due to the loopback this routine must not be called from hardirq context.
|
|
+ *
|
|
* Return:
|
|
* 0 on success
|
|
* -ENETDOWN when the selected interface is down
|
|
@@ -278,7 +280,7 @@ int can_send(struct sk_buff *skb, int loop)
|
|
}
|
|
|
|
if (newskb)
|
|
- netif_rx(newskb);
|
|
+ netif_rx_ni(newskb);
|
|
|
|
/* update statistics */
|
|
can_stats.tx_frames++;
|
|
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
|
|
index 3229e0a..b6ddd56 100644
|
|
--- a/net/ipv4/netfilter/nf_nat_core.c
|
|
+++ b/net/ipv4/netfilter/nf_nat_core.c
|
|
@@ -212,7 +212,7 @@ find_best_ips_proto(struct nf_conntrack_tuple *tuple,
|
|
maxip = ntohl(range->max_ip);
|
|
j = jhash_2words((__force u32)tuple->src.u3.ip,
|
|
range->flags & IP_NAT_RANGE_PERSISTENT ?
|
|
- (__force u32)tuple->dst.u3.ip : 0, 0);
|
|
+ 0 : (__force u32)tuple->dst.u3.ip, 0);
|
|
j = ((u64)j * (maxip - minip + 1)) >> 32;
|
|
*var_ipp = htonl(minip + j);
|
|
}
|
|
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
|
|
index b5869b9..b8614c6 100644
|
|
--- a/net/netfilter/nf_conntrack_core.c
|
|
+++ b/net/netfilter/nf_conntrack_core.c
|
|
@@ -1089,14 +1089,14 @@ void nf_conntrack_flush_report(struct net *net, u32 pid, int report)
|
|
}
|
|
EXPORT_SYMBOL_GPL(nf_conntrack_flush_report);
|
|
|
|
-static void nf_ct_release_dying_list(void)
|
|
+static void nf_ct_release_dying_list(struct net *net)
|
|
{
|
|
struct nf_conntrack_tuple_hash *h;
|
|
struct nf_conn *ct;
|
|
struct hlist_nulls_node *n;
|
|
|
|
spin_lock_bh(&nf_conntrack_lock);
|
|
- hlist_nulls_for_each_entry(h, n, &init_net.ct.dying, hnnode) {
|
|
+ hlist_nulls_for_each_entry(h, n, &net->ct.dying, hnnode) {
|
|
ct = nf_ct_tuplehash_to_ctrack(h);
|
|
/* never fails to remove them, no listeners at this point */
|
|
nf_ct_kill(ct);
|
|
@@ -1115,7 +1115,7 @@ static void nf_conntrack_cleanup_net(struct net *net)
|
|
{
|
|
i_see_dead_people:
|
|
nf_ct_iterate_cleanup(net, kill_all, NULL);
|
|
- nf_ct_release_dying_list();
|
|
+ nf_ct_release_dying_list(net);
|
|
if (atomic_read(&net->ct.count) != 0) {
|
|
schedule();
|
|
goto i_see_dead_people;
|
|
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
|
|
index ebe5718..f9f7177 100644
|
|
--- a/net/packet/af_packet.c
|
|
+++ b/net/packet/af_packet.c
|
|
@@ -1836,7 +1836,7 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
|
|
static int packet_getsockopt(struct socket *sock, int level, int optname,
|
|
char __user *optval, int __user *optlen)
|
|
{
|
|
- int len;
|
|
+ unsigned int len;
|
|
int val;
|
|
struct sock *sk = sock->sk;
|
|
struct packet_sock *po = pkt_sk(sk);
|
|
@@ -1849,7 +1849,7 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
|
|
if (get_user(len, optlen))
|
|
return -EFAULT;
|
|
|
|
- if (len < 0)
|
|
+ if ((int)len < 0)
|
|
return -EINVAL;
|
|
|
|
switch (optname) {
|
|
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
|
|
index c29be8f..43300b3 100644
|
|
--- a/scripts/Kbuild.include
|
|
+++ b/scripts/Kbuild.include
|
|
@@ -105,12 +105,12 @@ as-instr = $(call try-run,\
|
|
# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
|
|
|
|
cc-option = $(call try-run,\
|
|
- $(CC) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",$(1),$(2))
|
|
+ $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",$(1),$(2))
|
|
|
|
# cc-option-yn
|
|
# Usage: flag := $(call cc-option-yn,-march=winchip-c6)
|
|
cc-option-yn = $(call try-run,\
|
|
- $(CC) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",y,n)
|
|
+ $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",y,n)
|
|
|
|
# cc-option-align
|
|
# Prefix align with either -falign or -malign
|
|
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
|
|
index 64343cc..86c3896 100644
|
|
--- a/scripts/kallsyms.c
|
|
+++ b/scripts/kallsyms.c
|
|
@@ -585,7 +585,7 @@ static int prefix_underscores_count(const char *str)
|
|
{
|
|
const char *tail = str;
|
|
|
|
- while (*tail != '_')
|
|
+ while (*tail == '_')
|
|
tail++;
|
|
|
|
return tail - str;
|
|
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
|
|
index 5e17de9..5010952 100644
|
|
--- a/tools/perf/builtin-annotate.c
|
|
+++ b/tools/perf/builtin-annotate.c
|
|
@@ -1335,8 +1335,8 @@ static int __cmd_annotate(void)
|
|
exit(-1);
|
|
}
|
|
|
|
- if (!force && (stat.st_uid != geteuid())) {
|
|
- fprintf(stderr, "file: %s not owned by current user\n", input_name);
|
|
+ if (!force && stat.st_uid && (stat.st_uid != geteuid())) {
|
|
+ fprintf(stderr, "file: %s not owned by current user or root\n", input_name);
|
|
exit(-1);
|
|
}
|
|
|
|
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
|
|
index 8b2ec88..b8a75f6 100644
|
|
--- a/tools/perf/builtin-report.c
|
|
+++ b/tools/perf/builtin-report.c
|
|
@@ -1857,8 +1857,8 @@ static int __cmd_report(void)
|
|
exit(-1);
|
|
}
|
|
|
|
- if (!force && (stat.st_uid != geteuid())) {
|
|
- fprintf(stderr, "file: %s not owned by current user\n", input_name);
|
|
+ if (!force && stat.st_uid && (stat.st_uid != geteuid())) {
|
|
+ fprintf(stderr, "file: %s not owned by current user or root\n", input_name);
|
|
exit(-1);
|
|
}
|
|
|
|
diff --git a/tools/perf/util/module.c b/tools/perf/util/module.c
|
|
index ddabe92..702083d 100644
|
|
--- a/tools/perf/util/module.c
|
|
+++ b/tools/perf/util/module.c
|
|
@@ -422,7 +422,7 @@ static int mod_dso__load_module_paths(struct mod_dso *self)
|
|
len += strlen(uts.release);
|
|
len += strlen("/modules.dep");
|
|
|
|
- path = calloc(1, len);
|
|
+ path = calloc(1, len + 1);
|
|
if (path == NULL)
|
|
goto out_failure;
|
|
|