Commit 69887ac1 authored by David Woodhouse's avatar David Woodhouse

Merge with master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6.git

parents 5e014b10 118326e9
...@@ -478,7 +478,7 @@ static int s3c2440_clk_add(struct sys_device *sysdev) ...@@ -478,7 +478,7 @@ static int s3c2440_clk_add(struct sys_device *sysdev)
{ {
unsigned long upllcon = __raw_readl(S3C2410_UPLLCON); unsigned long upllcon = __raw_readl(S3C2410_UPLLCON);
s3c2440_clk_upll.rate = s3c2410_get_pll(upllcon, clk_xtal.rate) * 2; s3c2440_clk_upll.rate = s3c2410_get_pll(upllcon, clk_xtal.rate);
printk("S3C2440: Clock Support, UPLL %ld.%03ld MHz\n", printk("S3C2440: Clock Support, UPLL %ld.%03ld MHz\n",
print_mhz(s3c2440_clk_upll.rate)); print_mhz(s3c2440_clk_upll.rate));
......
...@@ -192,9 +192,11 @@ void __init s3c2440_map_io(struct map_desc *mach_desc, int size) ...@@ -192,9 +192,11 @@ void __init s3c2440_map_io(struct map_desc *mach_desc, int size)
iotable_init(s3c2440_iodesc, ARRAY_SIZE(s3c2440_iodesc)); iotable_init(s3c2440_iodesc, ARRAY_SIZE(s3c2440_iodesc));
iotable_init(mach_desc, size); iotable_init(mach_desc, size);
/* rename any peripherals used differing from the s3c2410 */ /* rename any peripherals used differing from the s3c2410 */
s3c_device_i2c.name = "s3c2440-i2c"; s3c_device_i2c.name = "s3c2440-i2c";
s3c_device_nand.name = "s3c2440-nand";
/* change irq for watchdog */ /* change irq for watchdog */
...@@ -225,7 +227,7 @@ void __init s3c2440_init_clocks(int xtal) ...@@ -225,7 +227,7 @@ void __init s3c2440_init_clocks(int xtal)
break; break;
case S3C2440_CLKDIVN_HDIVN_2: case S3C2440_CLKDIVN_HDIVN_2:
hdiv = 1; hdiv = 2;
break; break;
case S3C2440_CLKDIVN_HDIVN_4_8: case S3C2440_CLKDIVN_HDIVN_4_8:
......
...@@ -412,21 +412,20 @@ config CPU_BPREDICT_DISABLE ...@@ -412,21 +412,20 @@ config CPU_BPREDICT_DISABLE
config TLS_REG_EMUL config TLS_REG_EMUL
bool bool
default y if (SMP || CPU_32v6) && (CPU_32v5 || CPU_32v4 || CPU_32v3) default y if SMP && (CPU_32v5 || CPU_32v4 || CPU_32v3)
help help
We might be running on an ARMv6+ processor which should have the TLS An SMP system using a pre-ARMv6 processor (there are apparently
register but for some reason we can't use it, or maybe an SMP system a few prototypes like that in existence) and therefore access to
using a pre-ARMv6 processor (there are apparently a few prototypes that required register must be emulated.
like that in existence) and therefore access to that register must
be emulated.
config HAS_TLS_REG config HAS_TLS_REG
bool bool
depends on CPU_32v6 depends on !TLS_REG_EMUL
default y if !TLS_REG_EMUL default y if SMP || CPU_32v7
help help
This selects support for the CP15 thread register. This selects support for the CP15 thread register.
It is defined to be available on ARMv6 or later. If a particular It is defined to be available on some ARMv6 processors (including
ARMv6 or later CPU doesn't support it then it must omc;ide "select all SMP capable ARMv6's) or later processors. User space may
TLS_REG_EMUL" along with its other caracteristics. assume directly accessing that register and always obtain the
expected value only on ARMv7 and above.
/*
* linux/arch/arm/lib/copy_page-armv4mc.S
*
* Copyright (C) 1995-2001 Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* ASM optimised string functions
*/
#include <linux/linkage.h>
#include <linux/init.h>
#include <asm/constants.h>
.text
.align 5
/*
* ARMv4 mini-dcache optimised copy_user_page
*
* We flush the destination cache lines just before we write the data into the
* corresponding address. Since the Dcache is read-allocate, this removes the
* Dcache aliasing issue. The writes will be forwarded to the write buffer,
* and merged as appropriate.
*
* Note: We rely on all ARMv4 processors implementing the "invalidate D line"
* instruction. If your processor does not supply this, you have to write your
* own copy_user_page that does the right thing.
*/
ENTRY(v4_mc_copy_user_page)
stmfd sp!, {r4, lr} @ 2
mov r4, r0
mov r0, r1
bl map_page_minicache
mov r1, #PAGE_SZ/64 @ 1
ldmia r0!, {r2, r3, ip, lr} @ 4
1: mcr p15, 0, r4, c7, c6, 1 @ 1 invalidate D line
stmia r4!, {r2, r3, ip, lr} @ 4
ldmia r0!, {r2, r3, ip, lr} @ 4+1
stmia r4!, {r2, r3, ip, lr} @ 4
ldmia r0!, {r2, r3, ip, lr} @ 4
mcr p15, 0, r4, c7, c6, 1 @ 1 invalidate D line
stmia r4!, {r2, r3, ip, lr} @ 4
ldmia r0!, {r2, r3, ip, lr} @ 4
subs r1, r1, #1 @ 1
stmia r4!, {r2, r3, ip, lr} @ 4
ldmneia r0!, {r2, r3, ip, lr} @ 4
bne 1b @ 1
ldmfd sp!, {r4, pc} @ 3
.align 5
/*
* ARMv4 optimised clear_user_page
*
* Same story as above.
*/
ENTRY(v4_mc_clear_user_page)
str lr, [sp, #-4]!
mov r1, #PAGE_SZ/64 @ 1
mov r2, #0 @ 1
mov r3, #0 @ 1
mov ip, #0 @ 1
mov lr, #0 @ 1
1: mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line
stmia r0!, {r2, r3, ip, lr} @ 4
stmia r0!, {r2, r3, ip, lr} @ 4
mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line
stmia r0!, {r2, r3, ip, lr} @ 4
stmia r0!, {r2, r3, ip, lr} @ 4
subs r1, r1, #1 @ 1
bne 1b @ 1
ldr pc, [sp], #4
__INITDATA
.type v4_mc_user_fns, #object
ENTRY(v4_mc_user_fns)
.long v4_mc_clear_user_page
.long v4_mc_copy_user_page
.size v4_mc_user_fns, . - v4_mc_user_fns
/*
* linux/arch/arm/lib/copypage-armv4mc.S
*
* Copyright (C) 1995-2005 Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This handles the mini data cache, as found on SA11x0 and XScale
* processors. When we copy a user page page, we map it in such a way
* that accesses to this page will not touch the main data cache, but
* will be cached in the mini data cache. This prevents us thrashing
* the main data cache on page faults.
*/
#include <linux/init.h>
#include <linux/mm.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
/*
* 0xffff8000 to 0xffffffff is reserved for any ARM architecture
* specific hacks for copying pages efficiently.
*/
#define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \
L_PTE_CACHEABLE)
#define TOP_PTE(x) pte_offset_kernel(top_pmd, x)
static DEFINE_SPINLOCK(minicache_lock);
/*
* ARMv4 mini-dcache optimised copy_user_page
*
* We flush the destination cache lines just before we write the data into the
* corresponding address. Since the Dcache is read-allocate, this removes the
* Dcache aliasing issue. The writes will be forwarded to the write buffer,
* and merged as appropriate.
*
* Note: We rely on all ARMv4 processors implementing the "invalidate D line"
* instruction. If your processor does not supply this, you have to write your
* own copy_user_page that does the right thing.
*/
static void __attribute__((naked))
mc_copy_user_page(void *from, void *to)
{
asm volatile(
"stmfd sp!, {r4, lr} @ 2\n\
mov r4, %2 @ 1\n\
ldmia %0!, {r2, r3, ip, lr} @ 4\n\
1: mcr p15, 0, %1, c7, c6, 1 @ 1 invalidate D line\n\
stmia %1!, {r2, r3, ip, lr} @ 4\n\
ldmia %0!, {r2, r3, ip, lr} @ 4+1\n\
stmia %1!, {r2, r3, ip, lr} @ 4\n\
ldmia %0!, {r2, r3, ip, lr} @ 4\n\
mcr p15, 0, %1, c7, c6, 1 @ 1 invalidate D line\n\
stmia %1!, {r2, r3, ip, lr} @ 4\n\
ldmia %0!, {r2, r3, ip, lr} @ 4\n\
subs r4, r4, #1 @ 1\n\
stmia %1!, {r2, r3, ip, lr} @ 4\n\
ldmneia %0!, {r2, r3, ip, lr} @ 4\n\
bne 1b @ 1\n\
ldmfd sp!, {r4, pc} @ 3"
:
: "r" (from), "r" (to), "I" (PAGE_SIZE / 64));
}
void v4_mc_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr)
{
spin_lock(&minicache_lock);
set_pte(TOP_PTE(0xffff8000), pfn_pte(__pa(kfrom) >> PAGE_SHIFT, minicache_pgprot));
flush_tlb_kernel_page(0xffff8000);
mc_copy_user_page((void *)0xffff8000, kto);
spin_unlock(&minicache_lock);
}
/*
* ARMv4 optimised clear_user_page
*/
void __attribute__((naked))
v4_mc_clear_user_page(void *kaddr, unsigned long vaddr)
{
asm volatile(
"str lr, [sp, #-4]!\n\
mov r1, %0 @ 1\n\
mov r2, #0 @ 1\n\
mov r3, #0 @ 1\n\
mov ip, #0 @ 1\n\
mov lr, #0 @ 1\n\
1: mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line\n\
stmia r0!, {r2, r3, ip, lr} @ 4\n\
stmia r0!, {r2, r3, ip, lr} @ 4\n\
mcr p15, 0, r0, c7, c6, 1 @ 1 invalidate D line\n\
stmia r0!, {r2, r3, ip, lr} @ 4\n\
stmia r0!, {r2, r3, ip, lr} @ 4\n\
subs r1, r1, #1 @ 1\n\
bne 1b @ 1\n\
ldr pc, [sp], #4"
:
: "I" (PAGE_SIZE / 64));
}
struct cpu_user_fns v4_mc_user_fns __initdata = {
.cpu_clear_user_page = v4_mc_clear_user_page,
.cpu_copy_user_page = v4_mc_copy_user_page,
};
...@@ -26,8 +26,8 @@ ...@@ -26,8 +26,8 @@
#define to_address (0xffffc000) #define to_address (0xffffc000)
#define to_pgprot PAGE_KERNEL #define to_pgprot PAGE_KERNEL
static pte_t *from_pte; #define TOP_PTE(x) pte_offset_kernel(top_pmd, x)
static pte_t *to_pte;
static DEFINE_SPINLOCK(v6_lock); static DEFINE_SPINLOCK(v6_lock);
#define DCACHE_COLOUR(vaddr) ((vaddr & (SHMLBA - 1)) >> PAGE_SHIFT) #define DCACHE_COLOUR(vaddr) ((vaddr & (SHMLBA - 1)) >> PAGE_SHIFT)
...@@ -74,8 +74,8 @@ void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned long vadd ...@@ -74,8 +74,8 @@ void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned long vadd
*/ */
spin_lock(&v6_lock); spin_lock(&v6_lock);
set_pte(from_pte + offset, pfn_pte(__pa(kfrom) >> PAGE_SHIFT, from_pgprot)); set_pte(TOP_PTE(from_address) + offset, pfn_pte(__pa(kfrom) >> PAGE_SHIFT, from_pgprot));
set_pte(to_pte + offset, pfn_pte(__pa(kto) >> PAGE_SHIFT, to_pgprot)); set_pte(TOP_PTE(to_address) + offset, pfn_pte(__pa(kto) >> PAGE_SHIFT, to_pgprot));
from = from_address + (offset << PAGE_SHIFT); from = from_address + (offset << PAGE_SHIFT);
to = to_address + (offset << PAGE_SHIFT); to = to_address + (offset << PAGE_SHIFT);
...@@ -114,7 +114,7 @@ void v6_clear_user_page_aliasing(void *kaddr, unsigned long vaddr) ...@@ -114,7 +114,7 @@ void v6_clear_user_page_aliasing(void *kaddr, unsigned long vaddr)
*/ */
spin_lock(&v6_lock); spin_lock(&v6_lock);
set_pte(to_pte + offset, pfn_pte(__pa(kaddr) >> PAGE_SHIFT, to_pgprot)); set_pte(TOP_PTE(to_address) + offset, pfn_pte(__pa(kaddr) >> PAGE_SHIFT, to_pgprot));
flush_tlb_kernel_page(to); flush_tlb_kernel_page(to);
clear_page((void *)to); clear_page((void *)to);
...@@ -129,21 +129,6 @@ struct cpu_user_fns v6_user_fns __initdata = { ...@@ -129,21 +129,6 @@ struct cpu_user_fns v6_user_fns __initdata = {
static int __init v6_userpage_init(void) static int __init v6_userpage_init(void)
{ {
if (cache_is_vipt_aliasing()) { if (cache_is_vipt_aliasing()) {
pgd_t *pgd;
pmd_t *pmd;
pgd = pgd_offset_k(from_address);
pmd = pmd_alloc(&init_mm, pgd, from_address);
if (!pmd)
BUG();
from_pte = pte_alloc_kernel(&init_mm, pmd, from_address);
if (!from_pte)
BUG();
to_pte = pte_alloc_kernel(&init_mm, pmd, to_address);
if (!to_pte)
BUG();
cpu_user.cpu_clear_user_page = v6_clear_user_page_aliasing; cpu_user.cpu_clear_user_page = v6_clear_user_page_aliasing;
cpu_user.cpu_copy_user_page = v6_copy_user_page_aliasing; cpu_user.cpu_copy_user_page = v6_copy_user_page_aliasing;
} }
...@@ -151,5 +136,4 @@ static int __init v6_userpage_init(void) ...@@ -151,5 +136,4 @@ static int __init v6_userpage_init(void)
return 0; return 0;
} }
__initcall(v6_userpage_init); core_initcall(v6_userpage_init);
...@@ -13,6 +13,29 @@ ...@@ -13,6 +13,29 @@
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/tlbflush.h>
#ifdef CONFIG_CPU_CACHE_VIPT
#define ALIAS_FLUSH_START 0xffff4000
#define TOP_PTE(x) pte_offset_kernel(top_pmd, x)
static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr)
{
unsigned long to = ALIAS_FLUSH_START + (CACHE_COLOUR(vaddr) << PAGE_SHIFT);
set_pte(TOP_PTE(to), pfn_pte(pfn, PAGE_KERNEL));
flush_tlb_kernel_page(to);
asm( "mcrr p15, 0, %1, %0, c14\n"
" mcrr p15, 0, %1, %0, c5\n"
:
: "r" (to), "r" (to + PAGE_SIZE - L1_CACHE_BYTES)
: "cc");
}
#else
#define flush_pfn_alias(pfn,vaddr) do { } while (0)
#endif
static void __flush_dcache_page(struct address_space *mapping, struct page *page) static void __flush_dcache_page(struct address_space *mapping, struct page *page)
{ {
...@@ -36,6 +59,18 @@ static void __flush_dcache_page(struct address_space *mapping, struct page *page ...@@ -36,6 +59,18 @@ static void __flush_dcache_page(struct address_space *mapping, struct page *page
if (!mapping) if (!mapping)
return; return;
/*
* This is a page cache page. If we have a VIPT cache, we
* only need to do one flush - which would be at the relevant
* userspace colour, which is congruent with page->index.
*/
if (cache_is_vipt()) {
if (cache_is_vipt_aliasing())
flush_pfn_alias(page_to_pfn(page),
page->index << PAGE_CACHE_SHIFT);
return;
}
/* /*
* There are possible user space mappings of this page: * There are possible user space mappings of this page:
* - VIVT cache: we need to also write back and invalidate all user * - VIVT cache: we need to also write back and invalidate all user
...@@ -57,8 +92,6 @@ static void __flush_dcache_page(struct address_space *mapping, struct page *page ...@@ -57,8 +92,6 @@ static void __flush_dcache_page(struct address_space *mapping, struct page *page
continue; continue;
offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT; offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT;
flush_cache_page(mpnt, mpnt->vm_start + offset, page_to_pfn(page)); flush_cache_page(mpnt, mpnt->vm_start + offset, page_to_pfn(page));
if (cache_is_vipt())
break;
} }
flush_dcache_mmap_unlock(mapping); flush_dcache_mmap_unlock(mapping);
} }
......
...@@ -37,6 +37,8 @@ pgprot_t pgprot_kernel; ...@@ -37,6 +37,8 @@ pgprot_t pgprot_kernel;
EXPORT_SYMBOL(pgprot_kernel); EXPORT_SYMBOL(pgprot_kernel);
pmd_t *top_pmd;
struct cachepolicy { struct cachepolicy {
const char policy[16]; const char policy[16];
unsigned int cr_mask; unsigned int cr_mask;
...@@ -142,6 +144,16 @@ __setup("noalign", noalign_setup); ...@@ -142,6 +144,16 @@ __setup("noalign", noalign_setup);
#define FIRST_KERNEL_PGD_NR (FIRST_USER_PGD_NR + USER_PTRS_PER_PGD) #define FIRST_KERNEL_PGD_NR (FIRST_USER_PGD_NR + USER_PTRS_PER_PGD)
static inline pmd_t *pmd_off(pgd_t *pgd, unsigned long virt)
{
return pmd_offset(pgd, virt);
}
static inline pmd_t *pmd_off_k(unsigned long virt)
{
return pmd_off(pgd_offset_k(virt), virt);
}
/* /*
* need to get a 16k page for level 1 * need to get a 16k page for level 1
*/ */
...@@ -220,7 +232,7 @@ void free_pgd_slow(pgd_t *pgd) ...@@ -220,7 +232,7 @@ void free_pgd_slow(pgd_t *pgd)
return; return;
/* pgd is always present and good */ /* pgd is always present and good */
pmd = (pmd_t *)pgd; pmd = pmd_off(pgd, 0);
if (pmd_none(*pmd)) if (pmd_none(*pmd))
goto free; goto free;
if (pmd_bad(*pmd)) { if (pmd_bad(*pmd)) {
...@@ -246,9 +258,8 @@ void free_pgd_slow(pgd_t *pgd) ...@@ -246,9 +258,8 @@ void free_pgd_slow(pgd_t *pgd)
static inline void static inline void
alloc_init_section(unsigned long virt, unsigned long phys, int prot) alloc_init_section(unsigned long virt, unsigned long phys, int prot)
{ {
pmd_t *pmdp; pmd_t *pmdp = pmd_off_k(virt);
pmdp = pmd_offset(pgd_offset_k(virt), virt);
if (virt & (1 << 20)) if (virt & (1 << 20))
pmdp++; pmdp++;
...@@ -283,11 +294,9 @@ alloc_init_supersection(unsigned long virt, unsigned long phys, int prot) ...@@ -283,11 +294,9 @@ alloc_init_supersection(unsigned long virt, unsigned long phys, int prot)
static inline void static inline void
alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pgprot_t prot) alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pgprot_t prot)
{ {
pmd_t *pmdp; pmd_t *pmdp = pmd_off_k(virt);
pte_t *ptep; pte_t *ptep;
pmdp = pmd_offset(pgd_offset_k(virt), virt);
if (pmd_none(*pmdp)) { if (pmd_none(*pmdp)) {
unsigned long pmdval; unsigned long pmdval;
ptep = alloc_bootmem_low_pages(2 * PTRS_PER_PTE * ptep = alloc_bootmem_low_pages(2 * PTRS_PER_PTE *
...@@ -310,7 +319,7 @@ alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pg ...@@ -310,7 +319,7 @@ alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pg
*/ */
static inline void clear_mapping(unsigned long virt) static inline void clear_mapping(unsigned long virt)
{ {
pmd_clear(pmd_offset(pgd_offset_k(virt), virt)); pmd_clear(pmd_off_k(virt));
} }
struct mem_types { struct mem_types {
...@@ -578,7 +587,7 @@ void setup_mm_for_reboot(char mode) ...@@ -578,7 +587,7 @@ void setup_mm_for_reboot(char mode)
PMD_TYPE_SECT; PMD_TYPE_SECT;
if (cpu_arch <= CPU_ARCH_ARMv5) if (cpu_arch <= CPU_ARCH_ARMv5)
pmdval |= PMD_BIT4; pmdval |= PMD_BIT4;
pmd = pmd_offset(pgd + i, i << PGDIR_SHIFT); pmd = pmd_off(pgd, i << PGDIR_SHIFT);
pmd[0] = __pmd(pmdval); pmd[0] = __pmd(pmdval);
pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1))); pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1)));
flush_pmd_entry(pmd); flush_pmd_entry(pmd);
...@@ -675,6 +684,8 @@ void __init memtable_init(struct meminfo *mi) ...@@ -675,6 +684,8 @@ void __init memtable_init(struct meminfo *mi)
flush_cache_all(); flush_cache_all();
flush_tlb_all(); flush_tlb_all();
top_pmd = pmd_off_k(0xffff0000);
} }
/* /*
......
...@@ -237,3 +237,5 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg) ...@@ -237,3 +237,5 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
} }
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(blkdev_ioctl);
...@@ -2406,7 +2406,7 @@ static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u ...@@ -2406,7 +2406,7 @@ static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
case CDROM_LAST_WRITTEN: case CDROM_LAST_WRITTEN:
case CDROM_SEND_PACKET: case CDROM_SEND_PACKET:
case SCSI_IOCTL_SEND_COMMAND: case SCSI_IOCTL_SEND_COMMAND:
return ioctl_by_bdev(pd->bdev, cmd, arg); return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg);
case CDROMEJECT: case CDROMEJECT:
/* /*
...@@ -2414,7 +2414,7 @@ static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u ...@@ -2414,7 +2414,7 @@ static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
* have to unlock it or else the eject command fails. * have to unlock it or else the eject command fails.
*/ */
pkt_lock_door(pd, 0); pkt_lock_door(pd, 0);
return ioctl_by_bdev(pd->bdev, cmd, arg); return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg);
default: default:
printk("pktcdvd: Unknown ioctl for %s (%x)\n", pd->name, cmd); printk("pktcdvd: Unknown ioctl for %s (%x)\n", pd->name, cmd);
......
...@@ -122,7 +122,7 @@ raw_ioctl(struct inode *inode, struct file *filp, ...@@ -122,7 +122,7 @@ raw_ioctl(struct inode *inode, struct file *filp,
{ {
struct block_device *bdev = filp->private_data; struct block_device *bdev = filp->private_data;
return ioctl_by_bdev(bdev, command, arg); return blkdev_ioctl(bdev->bd_inode, filp, command, arg);
} }
static void bind_device(struct raw_config_request *rq) static void bind_device(struct raw_config_request *rq)
......
...@@ -51,7 +51,7 @@ config MMC_PXA ...@@ -51,7 +51,7 @@ config MMC_PXA
config MMC_WBSD config MMC_WBSD
tristate "Winbond W83L51xD SD/MMC Card Interface support" tristate "Winbond W83L51xD SD/MMC Card Interface support"
depends on MMC && ISA && ISA_DMA_API depends on MMC && ISA_DMA_API
help help
This selects the Winbond(R) W83L51xD Secure digital and This selects the Winbond(R) W83L51xD Secure digital and
Multimedia card Interface. Multimedia card Interface.
......
...@@ -28,7 +28,9 @@ ...@@ -28,7 +28,9 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/pnp.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/protocol.h> #include <linux/mmc/protocol.h>
...@@ -40,7 +42,7 @@ ...@@ -40,7 +42,7 @@
#include "wbsd.h" #include "wbsd.h"
#define DRIVER_NAME "wbsd" #define DRIVER_NAME "wbsd"
#define DRIVER_VERSION "1.1" #define DRIVER_VERSION "1.2"
#ifdef CONFIG_MMC_DEBUG #ifdef CONFIG_MMC_DEBUG
#define DBG(x...) \ #define DBG(x...) \
...@@ -52,10 +54,6 @@ ...@@ -52,10 +54,6 @@
#define DBGF(x...) do { } while (0) #define DBGF(x...) do { } while (0)
#endif #endif
static unsigned int io = 0x248;
static unsigned int irq = 6;
static int dma = 2;
#ifdef CONFIG_MMC_DEBUG #ifdef CONFIG_MMC_DEBUG
void DBG_REG(int reg, u8 value) void DBG_REG(int reg, u8 value)
{ {
...@@ -78,29 +76,62 @@ void DBG_REG(int reg, u8 value) ...@@ -78,29 +76,62 @@ void DBG_REG(int reg, u8 value)
#define DBG_REG(r, v) do {} while (0) #define DBG_REG(r, v) do {} while (0)
#endif #endif
/*
* Device resources
*/
#ifdef CONFIG_PNP
static const struct pnp_device_id pnp_dev_table[] = {
{ "WEC0517", 0 },
{ "WEC0518", 0 },
{ "", 0 },
};
MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
#endif /* CONFIG_PNP */
#ifdef CONFIG_PNP
static unsigned int nopnp = 0;
#else
static const unsigned int nopnp = 1;
#endif
static unsigned int io = 0x248;
static unsigned int irq = 6;
static int dma = 2;
/* /*
* Basic functions * Basic functions
*/ */
static inline void wbsd_unlock_config(struct wbsd_host* host) static inline void wbsd_unlock_config(struct wbsd_host* host)
{ {
BUG_ON(host->config == 0);
outb(host->unlock_code, host->config); outb(host->unlock_code, host->config);
outb(host->unlock_code, host->config); outb(host->unlock_code, host->config);
} }
static inline void wbsd_lock_config(struct wbsd_host* host) static inline void wbsd_lock_config(struct wbsd_host* host)
{ {
BUG_ON(host->config == 0);
outb(LOCK_CODE, host->config); outb(LOCK_CODE, host->config);
} }
static inline void wbsd_write_config(struct wbsd_host* host, u8 reg, u8 value) static inline void wbsd_write_config(struct wbsd_host* host, u8 reg, u8 value)
{ {
BUG_ON(host->config == 0);
outb(reg, host->config); outb(reg, host->config);
outb(value, host->config + 1); outb(value, host->config + 1);
} }
static inline u8 wbsd_read_config(struct wbsd_host* host, u8 reg) static inline u8 wbsd_read_config(struct wbsd_host* host, u8 reg)
{ {
BUG_ON(host->config == 0);
outb(reg, host->config); outb(reg, host->config);
return inb(host->config + 1); return inb(host->config + 1);
} }
...@@ -132,6 +163,13 @@ static void wbsd_init_device(struct wbsd_host* host) ...@@ -132,6 +163,13 @@ static void wbsd_init_device(struct wbsd_host* host)
setup |= WBSD_FIFO_RESET | WBSD_SOFT_RESET; setup |= WBSD_FIFO_RESET | WBSD_SOFT_RESET;
wbsd_write_index(host, WBSD_IDX_SETUP, setup); wbsd_write_index(host, WBSD_IDX_SETUP, setup);
/*
* Set DAT3 to input
*/
setup &= ~WBSD_DAT3_H;
wbsd_write_index(host, WBSD_IDX_SETUP, setup);
host->flags &= ~WBSD_FIGNORE_DETECT;
/* /*
* Read back default clock. * Read back default clock.
*/ */
...@@ -147,6 +185,14 @@ static void wbsd_init_device(struct wbsd_host* host) ...@@ -147,6 +185,14 @@ static void wbsd_init_device(struct wbsd_host* host)
*/ */
wbsd_write_index(host, WBSD_IDX_TAAC, 0x7F); wbsd_write_index(host, WBSD_IDX_TAAC, 0x7F);
/*
* Test for card presence
*/
if (inb(host->base + WBSD_CSR) & WBSD_CARDPRESENT)
host->flags |= WBSD_FCARD_PRESENT;
else
host->flags &= ~WBSD_FCARD_PRESENT;
/* /*
* Enable interesting interrupts. * Enable interesting interrupts.
*/ */
...@@ -407,8 +453,6 @@ static inline void wbsd_get_long_reply(struct wbsd_host* host, ...@@ -407,8 +453,6 @@ static inline void wbsd_get_long_reply(struct wbsd_host* host,
} }
} }
static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs);
static void wbsd_send_command(struct wbsd_host* host, struct mmc_command* cmd) static void wbsd_send_command(struct wbsd_host* host, struct mmc_command* cmd)
{ {
int i; int i;
...@@ -646,6 +690,13 @@ static void wbsd_fill_fifo(struct wbsd_host* host) ...@@ -646,6 +690,13 @@ static void wbsd_fill_fifo(struct wbsd_host* host)
} }
wbsd_kunmap_sg(host); wbsd_kunmap_sg(host);
/*
* The controller stops sending interrupts for
* 'FIFO empty' under certain conditions. So we
* need to be a bit more pro-active.
*/
tasklet_schedule(&host->fifo_tasklet);
} }
static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data) static void wbsd_prepare_data(struct wbsd_host* host, struct mmc_data* data)
...@@ -850,9 +901,11 @@ static void wbsd_finish_data(struct wbsd_host* host, struct mmc_data* data) ...@@ -850,9 +901,11 @@ static void wbsd_finish_data(struct wbsd_host* host, struct mmc_data* data)
wbsd_request_end(host, host->mrq); wbsd_request_end(host, host->mrq);
} }
/* /*****************************************************************************\
* MMC Callbacks * *
*/ * MMC layer callbacks *
* *
\*****************************************************************************/
static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq) static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq)
{ {
...@@ -874,7 +927,7 @@ static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq) ...@@ -874,7 +927,7 @@ static void wbsd_request(struct mmc_host* mmc, struct mmc_request* mrq)
* If there is no card in the slot then * If there is no card in the slot then
* timeout immediatly. * timeout immediatly.
*/ */
if (!(inb(host->base + WBSD_CSR) & WBSD_CARDPRESENT)) if (!(host->flags & WBSD_FCARD_PRESENT))
{ {
cmd->error = MMC_ERR_TIMEOUT; cmd->error = MMC_ERR_TIMEOUT;
goto done; goto done;
...@@ -953,33 +1006,50 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) ...@@ -953,33 +1006,50 @@ static void wbsd_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
host->clk = clk; host->clk = clk;
} }
if (ios->power_mode != MMC_POWER_OFF)
{
/* /*
* Power up card. * Power up card.
*/ */
if (ios->power_mode != MMC_POWER_OFF)
{
pwr = inb(host->base + WBSD_CSR); pwr = inb(host->base + WBSD_CSR);
pwr &= ~WBSD_POWER_N; pwr &= ~WBSD_POWER_N;
outb(pwr, host->base + WBSD_CSR); outb(pwr, host->base + WBSD_CSR);
}
/* /*
* This behaviour is stolen from the * MMC cards need to have pin 1 high during init.
* Windows driver. Don't know why, but * Init time corresponds rather nicely with the bus mode.
* it is needed. * It wreaks havoc with the card detection though so
* that needs to be disabed.
*/ */
setup = wbsd_read_index(host, WBSD_IDX_SETUP); setup = wbsd_read_index(host, WBSD_IDX_SETUP);
if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) if ((ios->power_mode == MMC_POWER_ON) &&
(ios->bus_mode == MMC_BUSMODE_OPENDRAIN))
{
setup |= WBSD_DAT3_H; setup |= WBSD_DAT3_H;
host->flags |= WBSD_FIGNORE_DETECT;
}
else else
{
setup &= ~WBSD_DAT3_H; setup &= ~WBSD_DAT3_H;
wbsd_write_index(host, WBSD_IDX_SETUP, setup); host->flags &= ~WBSD_FIGNORE_DETECT;
mdelay(1);
} }
wbsd_write_index(host, WBSD_IDX_SETUP, setup);
spin_unlock_bh(&host->lock); spin_unlock_bh(&host->lock);
} }
static struct mmc_host_ops wbsd_ops = {
.request = wbsd_request,
.set_ios = wbsd_set_ios,
};
/*****************************************************************************\
* *
* Interrupt handling *
* *
\*****************************************************************************/
/* /*
* Tasklets * Tasklets
*/ */
...@@ -1005,17 +1075,33 @@ static void wbsd_tasklet_card(unsigned long param) ...@@ -1005,17 +1075,33 @@ static void wbsd_tasklet_card(unsigned long param)
{ {
struct wbsd_host* host = (struct wbsd_host*)param; struct wbsd_host* host = (struct wbsd_host*)param;
u8 csr; u8 csr;
int change = 0;
spin_lock(&host->lock); spin_lock(&host->lock);
if (host->flags & WBSD_FIGNORE_DETECT)
{
spin_unlock(&host->lock);
return;
}
csr = inb(host->base + WBSD_CSR); csr = inb(host->base + WBSD_CSR);
WARN_ON(csr == 0xff); WARN_ON(csr == 0xff);
if (csr & WBSD_CARDPRESENT) if (csr & WBSD_CARDPRESENT)
{
if (!(host->flags & WBSD_FCARD_PRESENT))
{
DBG("Card inserted\n"); DBG("Card inserted\n");
else host->flags |= WBSD_FCARD_PRESENT;
change = 1;
}
}
else if (host->flags & WBSD_FCARD_PRESENT)
{ {
DBG("Card removed\n"); DBG("Card removed\n");
host->flags &= ~WBSD_FCARD_PRESENT;
change = 1;
if (host->mrq) if (host->mrq)
{ {
...@@ -1033,6 +1119,7 @@ static void wbsd_tasklet_card(unsigned long param) ...@@ -1033,6 +1119,7 @@ static void wbsd_tasklet_card(unsigned long param)
*/ */
spin_unlock(&host->lock); spin_unlock(&host->lock);
if (change)
mmc_detect_change(host->mmc); mmc_detect_change(host->mmc);
} }
...@@ -1200,11 +1287,85 @@ static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs) ...@@ -1200,11 +1287,85 @@ static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
/*****************************************************************************\
* *
* Device initialisation and shutdown *
* *
\*****************************************************************************/
/* /*
* Support functions for probe * Allocate/free MMC structure.
*/ */
static int wbsd_scan(struct wbsd_host* host) static int __devinit wbsd_alloc_mmc(struct device* dev)
{
struct mmc_host* mmc;
struct wbsd_host* host;
/*
* Allocate MMC structure.
*/
mmc = mmc_alloc_host(sizeof(struct wbsd_host), dev);
if (!mmc)
return -ENOMEM;
host = mmc_priv(mmc);
host->mmc = mmc;
host->dma = -1;
/*
* Set host parameters.
*/
mmc->ops = &wbsd_ops;
mmc->f_min = 375000;
mmc->f_max = 24000000;
mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
spin_lock_init(&host->lock);
/*
* Maximum number of segments. Worst case is one sector per segment
* so this will be 64kB/512.
*/
mmc->max_hw_segs = 128;
mmc->max_phys_segs = 128;
/*
* Maximum number of sectors in one transfer. Also limited by 64kB
* buffer.
*/
mmc->max_sectors = 128;
/*
* Maximum segment size. Could be one segment with the maximum number
* of segments.
*/
mmc->max_seg_size = mmc->max_sectors * 512;
dev_set_drvdata(dev, mmc);
return 0;
}
static void __devexit wbsd_free_mmc(struct device* dev)
{
struct mmc_host* mmc;
mmc = dev_get_drvdata(dev);
if (!mmc)
return;
mmc_free_host(mmc);
dev_set_drvdata(dev, NULL);
}
/*
* Scan for known chip id:s
*/
static int __devinit wbsd_scan(struct wbsd_host* host)
{ {
int i, j, k; int i, j, k;
int id; int id;
...@@ -1258,12 +1419,16 @@ static int wbsd_scan(struct wbsd_host* host) ...@@ -1258,12 +1419,16 @@ static int wbsd_scan(struct wbsd_host* host)
return -ENODEV; return -ENODEV;
} }
static int wbsd_request_regions(struct wbsd_host* host) /*
* Allocate/free io port ranges
*/
static int __devinit wbsd_request_region(struct wbsd_host* host, int base)
{ {
if (io & 0x7) if (io & 0x7)
return -EINVAL; return -EINVAL;
if (!request_region(io, 8, DRIVER_NAME)) if (!request_region(base, 8, DRIVER_NAME))
return -EIO; return -EIO;
host->base = io; host->base = io;
...@@ -1271,19 +1436,25 @@ static int wbsd_request_regions(struct wbsd_host* host) ...@@ -1271,19 +1436,25 @@ static int wbsd_request_regions(struct wbsd_host* host)
return 0; return 0;
} }
static void wbsd_release_regions(struct wbsd_host* host) static void __devexit wbsd_release_regions(struct wbsd_host* host)
{ {
if (host->base) if (host->base)
release_region(host->base, 8); release_region(host->base, 8);
host->base = 0;
if (host->config) if (host->config)
release_region(host->config, 2); release_region(host->config, 2);
host->config = 0;
} }
static void wbsd_init_dma(struct wbsd_host* host) /*
{ * Allocate/free DMA port and buffer
host->dma = -1; */
static void __devinit wbsd_request_dma(struct wbsd_host* host, int dma)
{
if (dma < 0) if (dma < 0)
return; return;
...@@ -1294,7 +1465,7 @@ static void wbsd_init_dma(struct wbsd_host* host) ...@@ -1294,7 +1465,7 @@ static void wbsd_init_dma(struct wbsd_host* host)
* We need to allocate a special buffer in * We need to allocate a special buffer in
* order for ISA to be able to DMA to it. * order for ISA to be able to DMA to it.
*/ */
host->dma_buffer = kmalloc(65536, host->dma_buffer = kmalloc(WBSD_DMA_SIZE,
GFP_NOIO | GFP_DMA | __GFP_REPEAT | __GFP_NOWARN); GFP_NOIO | GFP_DMA | __GFP_REPEAT | __GFP_NOWARN);
if (!host->dma_buffer) if (!host->dma_buffer)
goto free; goto free;
...@@ -1302,7 +1473,8 @@ static void wbsd_init_dma(struct wbsd_host* host) ...@@ -1302,7 +1473,8 @@ static void wbsd_init_dma(struct wbsd_host* host)
/* /*
* Translate the address to a physical address. * Translate the address to a physical address.
*/ */
host->dma_addr = isa_virt_to_bus(host->dma_buffer); host->dma_addr = dma_map_single(host->mmc->dev, host->dma_buffer,
WBSD_DMA_SIZE, DMA_BIDIRECTIONAL);
/* /*
* ISA DMA must be aligned on a 64k basis. * ISA DMA must be aligned on a 64k basis.
...@@ -1325,6 +1497,10 @@ static void wbsd_init_dma(struct wbsd_host* host) ...@@ -1325,6 +1497,10 @@ static void wbsd_init_dma(struct wbsd_host* host)
*/ */
BUG_ON(1); BUG_ON(1);
dma_unmap_single(host->mmc->dev, host->dma_addr, WBSD_DMA_SIZE,
DMA_BIDIRECTIONAL);
host->dma_addr = (dma_addr_t)NULL;
kfree(host->dma_buffer); kfree(host->dma_buffer);
host->dma_buffer = NULL; host->dma_buffer = NULL;
...@@ -1336,60 +1512,122 @@ static void wbsd_init_dma(struct wbsd_host* host) ...@@ -1336,60 +1512,122 @@ static void wbsd_init_dma(struct wbsd_host* host)
"Falling back on FIFO.\n", dma); "Falling back on FIFO.\n", dma);
} }
static struct mmc_host_ops wbsd_ops = { static void __devexit wbsd_release_dma(struct wbsd_host* host)
.request = wbsd_request, {
.set_ios = wbsd_set_ios, if (host->dma_addr)
}; dma_unmap_single(host->mmc->dev, host->dma_addr, WBSD_DMA_SIZE,
DMA_BIDIRECTIONAL);
if (host->dma_buffer)
kfree(host->dma_buffer);
if (host->dma >= 0)
free_dma(host->dma);
host->dma = -1;
host->dma_buffer = NULL;
host->dma_addr = (dma_addr_t)NULL;
}
/* /*
* Device probe * Allocate/free IRQ.
*/ */
static int wbsd_probe(struct device* dev) static int __devinit wbsd_request_irq(struct wbsd_host* host, int irq)
{ {
struct wbsd_host* host = NULL;
struct mmc_host* mmc = NULL;
int ret; int ret;
/* /*
* Allocate MMC structure. * Allocate interrupt.
*/ */
mmc = mmc_alloc_host(sizeof(struct wbsd_host), dev);
if (!mmc)
return -ENOMEM;
host = mmc_priv(mmc); ret = request_irq(irq, wbsd_irq, SA_SHIRQ, DRIVER_NAME, host);
host->mmc = mmc; if (ret)
return ret;
host->irq = irq;
/* /*
* Scan for hardware. * Set up tasklets.
*/ */
ret = wbsd_scan(host); tasklet_init(&host->card_tasklet, wbsd_tasklet_card, (unsigned long)host);
if (ret) tasklet_init(&host->fifo_tasklet, wbsd_tasklet_fifo, (unsigned long)host);
goto freemmc; tasklet_init(&host->crc_tasklet, wbsd_tasklet_crc, (unsigned long)host);
tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout, (unsigned long)host);
tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish, (unsigned long)host);
tasklet_init(&host->block_tasklet, wbsd_tasklet_block, (unsigned long)host);
/* return 0;
* Reset the chip. }
static void __devexit wbsd_release_irq(struct wbsd_host* host)
{
if (!host->irq)
return;
free_irq(host->irq, host);
host->irq = 0;
tasklet_kill(&host->card_tasklet);
tasklet_kill(&host->fifo_tasklet);
tasklet_kill(&host->crc_tasklet);
tasklet_kill(&host->timeout_tasklet);
tasklet_kill(&host->finish_tasklet);
tasklet_kill(&host->block_tasklet);
}
/*
* Allocate all resources for the host.
*/ */
wbsd_write_config(host, WBSD_CONF_SWRST, 1);
wbsd_write_config(host, WBSD_CONF_SWRST, 0); static int __devinit wbsd_request_resources(struct wbsd_host* host,
int base, int irq, int dma)
{
int ret;
/* /*
* Allocate I/O ports. * Allocate I/O ports.
*/ */
ret = wbsd_request_regions(host); ret = wbsd_request_region(host, base);
if (ret) if (ret)
goto release; return ret;
/* /*
* Set host parameters. * Allocate interrupt.
*/ */
mmc->ops = &wbsd_ops; ret = wbsd_request_irq(host, irq);
mmc->f_min = 375000; if (ret)
mmc->f_max = 24000000; return ret;
mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
spin_lock_init(&host->lock); /*
* Allocate DMA.
*/
wbsd_request_dma(host, dma);
return 0;
}
/*
* Release all resources for the host.
*/
static void __devexit wbsd_release_resources(struct wbsd_host* host)
{
wbsd_release_dma(host);
wbsd_release_irq(host);
wbsd_release_regions(host);
}
/*
* Configure the resources the chip should use.
*/
static void __devinit wbsd_chip_config(struct wbsd_host* host)
{
/*
* Reset the chip.
*/
wbsd_write_config(host, WBSD_CONF_SWRST, 1);
wbsd_write_config(host, WBSD_CONF_SWRST, 0);
/* /*
* Select SD/MMC function. * Select SD/MMC function.
...@@ -1399,132 +1637,178 @@ static int wbsd_probe(struct device* dev) ...@@ -1399,132 +1637,178 @@ static int wbsd_probe(struct device* dev)
/* /*
* Set up card detection. * Set up card detection.
*/ */
wbsd_write_config(host, WBSD_CONF_PINS, 0x02); wbsd_write_config(host, WBSD_CONF_PINS, WBSD_PINS_DETECT_GP11);
/* /*
* Configure I/O port. * Configure chip
*/ */
wbsd_write_config(host, WBSD_CONF_PORT_HI, host->base >> 8); wbsd_write_config(host, WBSD_CONF_PORT_HI, host->base >> 8);
wbsd_write_config(host, WBSD_CONF_PORT_LO, host->base & 0xff); wbsd_write_config(host, WBSD_CONF_PORT_LO, host->base & 0xff);
/* wbsd_write_config(host, WBSD_CONF_IRQ, host->irq);
* Allocate interrupt.
*/
ret = request_irq(irq, wbsd_irq, SA_SHIRQ, DRIVER_NAME, host);
if (ret)
goto release;
host->irq = irq; if (host->dma >= 0)
wbsd_write_config(host, WBSD_CONF_DRQ, host->dma);
/* /*
* Set up tasklets. * Enable and power up chip.
*/ */
tasklet_init(&host->card_tasklet, wbsd_tasklet_card, (unsigned long)host); wbsd_write_config(host, WBSD_CONF_ENABLE, 1);
tasklet_init(&host->fifo_tasklet, wbsd_tasklet_fifo, (unsigned long)host); wbsd_write_config(host, WBSD_CONF_POWER, 0x20);
tasklet_init(&host->crc_tasklet, wbsd_tasklet_crc, (unsigned long)host); }
tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout, (unsigned long)host);
tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish, (unsigned long)host);
tasklet_init(&host->block_tasklet, wbsd_tasklet_block, (unsigned long)host);
/* /*
* Configure interrupt. * Check that configured resources are correct.
*/ */
wbsd_write_config(host, WBSD_CONF_IRQ, host->irq);
/* static int __devinit wbsd_chip_validate(struct wbsd_host* host)
* Allocate DMA. {
*/ int base, irq, dma;
wbsd_init_dma(host);
/* /*
* If all went well, then configure DMA. * Select SD/MMC function.
*/ */
if (host->dma >= 0) wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
wbsd_write_config(host, WBSD_CONF_DRQ, host->dma);
/* /*
* Maximum number of segments. Worst case is one sector per segment * Read configuration.
* so this will be 64kB/512.
*/ */
mmc->max_hw_segs = 128; base = wbsd_read_config(host, WBSD_CONF_PORT_HI) << 8;
mmc->max_phys_segs = 128; base |= wbsd_read_config(host, WBSD_CONF_PORT_LO);
irq = wbsd_read_config(host, WBSD_CONF_IRQ);
dma = wbsd_read_config(host, WBSD_CONF_DRQ);
/* /*
* Maximum number of sectors in one transfer. Also limited by 64kB * Validate against given configuration.
* buffer.
*/ */
mmc->max_sectors = 128; if (base != host->base)
return 0;
if (irq != host->irq)
return 0;
if ((dma != host->dma) && (host->dma != -1))
return 0;
return 1;
}
/*****************************************************************************\
* *
* Devices setup and shutdown *
* *
\*****************************************************************************/
static int __devinit wbsd_init(struct device* dev, int base, int irq, int dma,
int pnp)
{
struct wbsd_host* host = NULL;
struct mmc_host* mmc = NULL;
int ret;
ret = wbsd_alloc_mmc(dev);
if (ret)
return ret;
mmc = dev_get_drvdata(dev);
host = mmc_priv(mmc);
/* /*
* Maximum segment size. Could be one segment with the maximum number * Scan for hardware.
* of segments.
*/ */
mmc->max_seg_size = mmc->max_sectors * 512; ret = wbsd_scan(host);
if (ret)
{
if (pnp && (ret == -ENODEV))
{
printk(KERN_WARNING DRIVER_NAME
": Unable to confirm device presence. You may "
"experience lock-ups.\n");
}
else
{
wbsd_free_mmc(dev);
return ret;
}
}
/* /*
* Enable chip. * Request resources.
*/ */
wbsd_write_config(host, WBSD_CONF_ENABLE, 1); ret = wbsd_request_resources(host, io, irq, dma);
if (ret)
{
wbsd_release_resources(host);
wbsd_free_mmc(dev);
return ret;
}
/* /*
* Power up chip. * See if chip needs to be configured.
*/ */
wbsd_write_config(host, WBSD_CONF_POWER, 0x20); if (pnp && (host->config != 0))
{
if (!wbsd_chip_validate(host))
{
printk(KERN_WARNING DRIVER_NAME
": PnP active but chip not configured! "
"You probably have a buggy BIOS. "
"Configuring chip manually.\n");
wbsd_chip_config(host);
}
}
else
wbsd_chip_config(host);
/* /*
* Power Management stuff. No idea how this works. * Power Management stuff. No idea how this works.
* Not tested. * Not tested.
*/ */
#ifdef CONFIG_PM #ifdef CONFIG_PM
if (host->config)
wbsd_write_config(host, WBSD_CONF_PME, 0xA0); wbsd_write_config(host, WBSD_CONF_PME, 0xA0);
#endif #endif
/*
* Allow device to initialise itself properly.
*/
mdelay(5);
/* /*
* Reset the chip into a known state. * Reset the chip into a known state.
*/ */
wbsd_init_device(host); wbsd_init_device(host);
dev_set_drvdata(dev, mmc);
/*
* Add host to MMC layer.
*/
mmc_add_host(mmc); mmc_add_host(mmc);
printk(KERN_INFO "%s: W83L51xD id %x at 0x%x irq %d dma %d\n", printk(KERN_INFO "%s: W83L51xD", mmc->host_name);
mmc->host_name, (int)host->chip_id, (int)host->base, if (host->chip_id != 0)
(int)host->irq, (int)host->dma); printk(" id %x", (int)host->chip_id);
printk(" at 0x%x irq %d", (int)host->base, (int)host->irq);
if (host->dma >= 0)
printk(" dma %d", (int)host->dma);
else
printk(" FIFO");
if (pnp)
printk(" PnP");
printk("\n");
return 0; return 0;
release:
wbsd_release_regions(host);
freemmc:
mmc_free_host(mmc);
return ret;
} }
/* static void __devexit wbsd_shutdown(struct device* dev, int pnp)
* Device remove
*/
static int wbsd_remove(struct device* dev)
{ {
struct mmc_host* mmc = dev_get_drvdata(dev); struct mmc_host* mmc = dev_get_drvdata(dev);
struct wbsd_host* host; struct wbsd_host* host;
if (!mmc) if (!mmc)
return 0; return;
host = mmc_priv(mmc); host = mmc_priv(mmc);
/*
* Unregister host with MMC layer.
*/
mmc_remove_host(mmc); mmc_remove_host(mmc);
if (!pnp)
{
/* /*
* Power down the SD/MMC function. * Power down the SD/MMC function.
*/ */
...@@ -1532,32 +1816,62 @@ static int wbsd_remove(struct device* dev) ...@@ -1532,32 +1816,62 @@ static int wbsd_remove(struct device* dev)
wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD); wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
wbsd_write_config(host, WBSD_CONF_ENABLE, 0); wbsd_write_config(host, WBSD_CONF_ENABLE, 0);
wbsd_lock_config(host); wbsd_lock_config(host);
}
/* wbsd_release_resources(host);
* Free resources.
wbsd_free_mmc(dev);
}
/*
* Non-PnP
*/ */
if (host->dma_buffer)
kfree(host->dma_buffer);
if (host->dma >= 0) static int __devinit wbsd_probe(struct device* dev)
free_dma(host->dma); {
return wbsd_init(dev, io, irq, dma, 0);
}
free_irq(host->irq, host); static int __devexit wbsd_remove(struct device* dev)
{
wbsd_shutdown(dev, 0);
tasklet_kill(&host->card_tasklet); return 0;
tasklet_kill(&host->fifo_tasklet); }
tasklet_kill(&host->crc_tasklet);
tasklet_kill(&host->timeout_tasklet);
tasklet_kill(&host->finish_tasklet);
tasklet_kill(&host->block_tasklet);
wbsd_release_regions(host); /*
* PnP
*/
mmc_free_host(mmc); #ifdef CONFIG_PNP
return 0; static int __devinit
wbsd_pnp_probe(struct pnp_dev * pnpdev, const struct pnp_device_id *dev_id)
{
int io, irq, dma;
/*
* Get resources from PnP layer.
*/
io = pnp_port_start(pnpdev, 0);
irq = pnp_irq(pnpdev, 0);
if (pnp_dma_valid(pnpdev, 0))
dma = pnp_dma(pnpdev, 0);
else
dma = -1;
DBGF("PnP resources: port %3x irq %d dma %d\n", io, irq, dma);
return wbsd_init(&pnpdev->dev, io, irq, dma, 1);
}
static void __devexit wbsd_pnp_remove(struct pnp_dev * dev)
{
wbsd_shutdown(&dev->dev, 1);
} }
#endif /* CONFIG_PNP */
/* /*
* Power management * Power management
*/ */
...@@ -1581,17 +1895,7 @@ static int wbsd_resume(struct device *dev, u32 level) ...@@ -1581,17 +1895,7 @@ static int wbsd_resume(struct device *dev, u32 level)
#define wbsd_resume NULL #define wbsd_resume NULL
#endif #endif
static void wbsd_release(struct device *dev) static struct platform_device *wbsd_device;
{
}
static struct platform_device wbsd_device = {
.name = DRIVER_NAME,
.id = -1,
.dev = {
.release = wbsd_release,
},
};
static struct device_driver wbsd_driver = { static struct device_driver wbsd_driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
...@@ -1603,6 +1907,17 @@ static struct device_driver wbsd_driver = { ...@@ -1603,6 +1907,17 @@ static struct device_driver wbsd_driver = {
.resume = wbsd_resume, .resume = wbsd_resume,
}; };
#ifdef CONFIG_PNP
static struct pnp_driver wbsd_pnp_driver = {
.name = DRIVER_NAME,
.id_table = pnp_dev_table,
.probe = wbsd_pnp_probe,
.remove = wbsd_pnp_remove,
};
#endif /* CONFIG_PNP */
/* /*
* Module loading/unloading * Module loading/unloading
*/ */
...@@ -1616,28 +1931,56 @@ static int __init wbsd_drv_init(void) ...@@ -1616,28 +1931,56 @@ static int __init wbsd_drv_init(void)
DRIVER_VERSION "\n"); DRIVER_VERSION "\n");
printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n");
result = driver_register(&wbsd_driver); #ifdef CONFIG_PNP
if (!nopnp)
{
result = pnp_register_driver(&wbsd_pnp_driver);
if (result < 0) if (result < 0)
return result; return result;
}
result = platform_device_register(&wbsd_device); #endif /* CONFIG_PNP */
if (nopnp)
{
result = driver_register(&wbsd_driver);
if (result < 0) if (result < 0)
return result; return result;
wbsd_device = platform_device_register_simple(DRIVER_NAME, -1,
NULL, 0);
if (IS_ERR(wbsd_device))
return PTR_ERR(wbsd_device);
}
return 0; return 0;
} }
static void __exit wbsd_drv_exit(void) static void __exit wbsd_drv_exit(void)
{ {
platform_device_unregister(&wbsd_device); #ifdef CONFIG_PNP
if (!nopnp)
pnp_unregister_driver(&wbsd_pnp_driver);
#endif /* CONFIG_PNP */
if (nopnp)
{
platform_device_unregister(wbsd_device);
driver_unregister(&wbsd_driver); driver_unregister(&wbsd_driver);
}
DBG("unloaded\n"); DBG("unloaded\n");
} }
module_init(wbsd_drv_init); module_init(wbsd_drv_init);
module_exit(wbsd_drv_exit); module_exit(wbsd_drv_exit);
#ifdef CONFIG_PNP
module_param(nopnp, uint, 0444);
#endif
module_param(io, uint, 0444); module_param(io, uint, 0444);
module_param(irq, uint, 0444); module_param(irq, uint, 0444);
module_param(dma, int, 0444); module_param(dma, int, 0444);
...@@ -1646,6 +1989,9 @@ MODULE_LICENSE("GPL"); ...@@ -1646,6 +1989,9 @@ MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Winbond W83L51xD SD/MMC card interface driver"); MODULE_DESCRIPTION("Winbond W83L51xD SD/MMC card interface driver");
MODULE_VERSION(DRIVER_VERSION); MODULE_VERSION(DRIVER_VERSION);
#ifdef CONFIG_PNP
MODULE_PARM_DESC(nopnp, "Scan for device instead of relying on PNP. (default 0)");
#endif
MODULE_PARM_DESC(io, "I/O base to allocate. Must be 8 byte aligned. (default 0x248)"); MODULE_PARM_DESC(io, "I/O base to allocate. Must be 8 byte aligned. (default 0x248)");
MODULE_PARM_DESC(irq, "IRQ to allocate. (default 6)"); MODULE_PARM_DESC(irq, "IRQ to allocate. (default 6)");
MODULE_PARM_DESC(dma, "DMA channel to allocate. -1 for no DMA. (default 2)"); MODULE_PARM_DESC(dma, "DMA channel to allocate. -1 for no DMA. (default 2)");
...@@ -35,6 +35,12 @@ const int valid_ids[] = { ...@@ -35,6 +35,12 @@ const int valid_ids[] = {
#define DEVICE_SD 0x03 #define DEVICE_SD 0x03
#define WBSD_PINS_DAT3_HI 0x20
#define WBSD_PINS_DAT3_OUT 0x10
#define WBSD_PINS_GP11_HI 0x04
#define WBSD_PINS_DETECT_GP11 0x02
#define WBSD_PINS_DETECT_DAT3 0x01
#define WBSD_CMDR 0x00 #define WBSD_CMDR 0x00
#define WBSD_DFR 0x01 #define WBSD_DFR 0x01
#define WBSD_EIR 0x02 #define WBSD_EIR 0x02
...@@ -133,6 +139,7 @@ const int valid_ids[] = { ...@@ -133,6 +139,7 @@ const int valid_ids[] = {
#define WBSD_CRC_OK 0x05 /* S010E (00101) */ #define WBSD_CRC_OK 0x05 /* S010E (00101) */
#define WBSD_CRC_FAIL 0x0B /* S101E (01011) */ #define WBSD_CRC_FAIL 0x0B /* S101E (01011) */
#define WBSD_DMA_SIZE 65536
struct wbsd_host struct wbsd_host
{ {
...@@ -140,6 +147,11 @@ struct wbsd_host ...@@ -140,6 +147,11 @@ struct wbsd_host
spinlock_t lock; /* Mutex */ spinlock_t lock; /* Mutex */
int flags; /* Driver states */
#define WBSD_FCARD_PRESENT (1<<0) /* Card is present */
#define WBSD_FIGNORE_DETECT (1<<1) /* Ignore card detection */
struct mmc_request* mrq; /* Current request */ struct mmc_request* mrq; /* Current request */
u8 isr; /* Accumulated ISR */ u8 isr; /* Accumulated ISR */
......
...@@ -187,7 +187,7 @@ obj-$(CONFIG_TR) += tokenring/ ...@@ -187,7 +187,7 @@ obj-$(CONFIG_TR) += tokenring/
obj-$(CONFIG_WAN) += wan/ obj-$(CONFIG_WAN) += wan/
obj-$(CONFIG_ARCNET) += arcnet/ obj-$(CONFIG_ARCNET) += arcnet/
obj-$(CONFIG_NET_PCMCIA) += pcmcia/ obj-$(CONFIG_NET_PCMCIA) += pcmcia/
obj-$(CONFIG_NET_WIRELESS) += wireless/ obj-$(CONFIG_NET_RADIO) += wireless/
obj-$(CONFIG_NET_TULIP) += tulip/ obj-$(CONFIG_NET_TULIP) += tulip/
obj-$(CONFIG_HAMRADIO) += hamradio/ obj-$(CONFIG_HAMRADIO) += hamradio/
obj-$(CONFIG_IRDA) += irda/ obj-$(CONFIG_IRDA) += irda/
......
...@@ -1595,7 +1595,7 @@ static struct ethtool_ops emac_ethtool_ops = { ...@@ -1595,7 +1595,7 @@ static struct ethtool_ops emac_ethtool_ops = {
static int emac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static int emac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{ {
struct ocp_enet_private *fep = dev->priv; struct ocp_enet_private *fep = dev->priv;
uint *data = (uint *) & rq->ifr_ifru; uint16_t *data = (uint16_t *) & rq->ifr_ifru;
switch (cmd) { switch (cmd) {
case SIOCGMIIPHY: case SIOCGMIIPHY:
......
...@@ -1104,7 +1104,7 @@ static void set_rx_mode(struct net_device *dev) ...@@ -1104,7 +1104,7 @@ static void set_rx_mode(struct net_device *dev)
if (entry != 0) { if (entry != 0) {
/* Avoid a chip errata by prefixing a dummy entry. Don't do /* Avoid a chip errata by prefixing a dummy entry. Don't do
this on the ULI526X as it triggers a different problem */ this on the ULI526X as it triggers a different problem */
if (!(tp->chip_id == ULI526X && (tp->revision = 0x40 || tp->revision == 0x50))) { if (!(tp->chip_id == ULI526X && (tp->revision == 0x40 || tp->revision == 0x50))) {
tp->tx_buffers[entry].skb = NULL; tp->tx_buffers[entry].skb = NULL;
tp->tx_buffers[entry].mapping = 0; tp->tx_buffers[entry].mapping = 0;
tp->tx_ring[entry].length = tp->tx_ring[entry].length =
......
...@@ -323,7 +323,7 @@ config PRISM54 ...@@ -323,7 +323,7 @@ config PRISM54
For a complete list of supported cards visit <http://prism54.org>. For a complete list of supported cards visit <http://prism54.org>.
Here is the latest confirmed list of supported cards: Here is the latest confirmed list of supported cards:
3com OfficeConnect 11g Cardbus Card aka 3CRWE154G72 3com OfficeConnect 11g Cardbus Card aka 3CRWE154G72 (version 1)
Allnet ALL0271 PCI Card Allnet ALL0271 PCI Card
Compex WL54G Cardbus Card Compex WL54G Cardbus Card
Corega CG-WLCB54GT Cardbus Card Corega CG-WLCB54GT Cardbus Card
......
...@@ -126,18 +126,8 @@ static irqreturn_t serial21285_rx_chars(int irq, void *dev_id, struct pt_regs *r ...@@ -126,18 +126,8 @@ static irqreturn_t serial21285_rx_chars(int irq, void *dev_id, struct pt_regs *r
flag = TTY_FRAME; flag = TTY_FRAME;
} }
if ((rxs & port->ignore_status_mask) == 0) { uart_insert_char(port, rxs, RXSTAT_OVERRUN, ch, flag);
tty_insert_flip_char(tty, ch, flag);
}
if ((rxs & RXSTAT_OVERRUN) &&
tty->flip.count < TTY_FLIPBUF_SIZE) {
/*
* Overrun is special, since it's reported
* immediately, and doesn't affect the current
* character.
*/
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
}
status = *CSR_UARTFLG; status = *CSR_UARTFLG;
} }
tty_flip_buffer_push(tty); tty_flip_buffer_push(tty);
......
...@@ -1122,18 +1122,9 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs) ...@@ -1122,18 +1122,9 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
} }
if (uart_handle_sysrq_char(&up->port, ch, regs)) if (uart_handle_sysrq_char(&up->port, ch, regs))
goto ignore_char; goto ignore_char;
if ((lsr & up->port.ignore_status_mask) == 0) {
tty_insert_flip_char(tty, ch, flag); uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);
}
if ((lsr & UART_LSR_OE) &&
tty->flip.count < TTY_FLIPBUF_SIZE) {
/*
* Overrun is special, since it's reported
* immediately, and doesn't affect the current
* character.
*/
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
}
ignore_char: ignore_char:
lsr = serial_inp(up, UART_LSR); lsr = serial_inp(up, UART_LSR);
} while ((lsr & UART_LSR_DR) && (max_count-- > 0)); } while ((lsr & UART_LSR_DR) && (max_count-- > 0));
......
...@@ -198,18 +198,8 @@ pl010_rx_chars(struct uart_port *port) ...@@ -198,18 +198,8 @@ pl010_rx_chars(struct uart_port *port)
if (uart_handle_sysrq_char(port, ch, regs)) if (uart_handle_sysrq_char(port, ch, regs))
goto ignore_char; goto ignore_char;
if ((rsr & port->ignore_status_mask) == 0) { uart_insert_char(port, rsr, UART01x_RSR_OE, ch, flag);
tty_insert_flip_char(tty, ch, flag);
}
if ((rsr & UART01x_RSR_OE) &&
tty->flip.count < TTY_FLIPBUF_SIZE) {
/*
* Overrun is special, since it's reported
* immediately, and doesn't affect the current
* character
*/
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
}
ignore_char: ignore_char:
status = UART_GET_FR(port); status = UART_GET_FR(port);
} }
......
...@@ -163,18 +163,8 @@ pl011_rx_chars(struct uart_amba_port *uap) ...@@ -163,18 +163,8 @@ pl011_rx_chars(struct uart_amba_port *uap)
if (uart_handle_sysrq_char(&uap->port, ch, regs)) if (uart_handle_sysrq_char(&uap->port, ch, regs))
goto ignore_char; goto ignore_char;
if ((rsr & uap->port.ignore_status_mask) == 0) { uart_insert_char(&uap->port, rsr, UART01x_RSR_OE, ch, flag);
tty_insert_flip_char(tty, ch, flag);
}
if ((rsr & UART01x_RSR_OE) &&
tty->flip.count < TTY_FLIPBUF_SIZE) {
/*
* Overrun is special, since it's reported
* immediately, and doesn't affect the current
* character
*/
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
}
ignore_char: ignore_char:
status = readw(uap->port.membase + UART01x_FR); status = readw(uap->port.membase + UART01x_FR);
} }
......
...@@ -143,10 +143,7 @@ static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id, struct pt_regs *re ...@@ -143,10 +143,7 @@ static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id, struct pt_regs *re
* CHECK: does overrun affect the current character? * CHECK: does overrun affect the current character?
* ASSUMPTION: it does not. * ASSUMPTION: it does not.
*/ */
if ((ch & port->ignore_status_mask & ~RXSTAT_OVERRUN) == 0) uart_insert_char(port, ch, UARTDR_OVERR, ch, flg);
tty_insert_flip_char(tty, ch, flg);
if ((ch & ~port->ignore_status_mask & RXSTAT_OVERRUN) == 0)
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
ignore_char: ignore_char:
status = clps_readl(SYSFLG(port)); status = clps_readl(SYSFLG(port));
......
...@@ -161,20 +161,12 @@ receive_chars(struct uart_pxa_port *up, int *status, struct pt_regs *regs) ...@@ -161,20 +161,12 @@ receive_chars(struct uart_pxa_port *up, int *status, struct pt_regs *regs)
else if (*status & UART_LSR_FE) else if (*status & UART_LSR_FE)
flag = TTY_FRAME; flag = TTY_FRAME;
} }
if (uart_handle_sysrq_char(&up->port, ch, regs)) if (uart_handle_sysrq_char(&up->port, ch, regs))
goto ignore_char; goto ignore_char;
if ((*status & up->port.ignore_status_mask) == 0) {
tty_insert_flip_char(tty, ch, flag); uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag);
}
if ((*status & UART_LSR_OE) &&
tty->flip.count < TTY_FLIPBUF_SIZE) {
/*
* Overrun is special, since it's reported
* immediately, and doesn't affect the current
* character.
*/
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
}
ignore_char: ignore_char:
*status = serial_in(up, UART_LSR); *status = serial_in(up, UART_LSR);
} while ((*status & UART_LSR_DR) && (max_count-- > 0)); } while ((*status & UART_LSR_DR) && (max_count-- > 0));
......
...@@ -394,20 +394,7 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id, struct pt_regs *regs) ...@@ -394,20 +394,7 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id, struct pt_regs *regs)
if (uart_handle_sysrq_char(port, ch, regs)) if (uart_handle_sysrq_char(port, ch, regs))
goto ignore_char; goto ignore_char;
if ((uerstat & port->ignore_status_mask) == 0) { uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN, ch, flag);
tty_insert_flip_char(tty, ch, flag);
}
if ((uerstat & S3C2410_UERSTAT_OVERRUN) &&
tty->flip.count < TTY_FLIPBUF_SIZE) {
/*
* Overrun is special, since it's reported
* immediately, and doesn't affect the current
* character.
*/
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
}
ignore_char: ignore_char:
continue; continue;
......
...@@ -237,10 +237,7 @@ sa1100_rx_chars(struct sa1100_port *sport, struct pt_regs *regs) ...@@ -237,10 +237,7 @@ sa1100_rx_chars(struct sa1100_port *sport, struct pt_regs *regs)
if (uart_handle_sysrq_char(&sport->port, ch, regs)) if (uart_handle_sysrq_char(&sport->port, ch, regs))
goto ignore_char; goto ignore_char;
if ((status & port->ignore_status_mask & ~UTSR1_TO_SM(UTSR1_ROR)) == 0) uart_insert_char(&sport->port, status, UTSR1_TO_SM(UTSR1_ROR), ch, flg);
tty_insert_flip_char(tty, ch, flg);
if (status & ~port->ignore_status_mask & UTSR1_TO_SM(UTSR1_ROR))
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
ignore_char: ignore_char:
status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) | status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) |
......
...@@ -190,18 +190,7 @@ lh7a40xuart_rx_chars (struct uart_port* port) ...@@ -190,18 +190,7 @@ lh7a40xuart_rx_chars (struct uart_port* port)
if (uart_handle_sysrq_char (port, (unsigned char) data, regs)) if (uart_handle_sysrq_char (port, (unsigned char) data, regs))
continue; continue;
if ((data & port->ignore_status_mask) == 0) { uart_insert_char(port, data, RxOverrunError, data, flag);
tty_insert_flip_char(tty, data, flag);
}
if ((data & RxOverrunError)
&& tty->flip.count < TTY_FLIPBUF_SIZE) {
/*
* Overrun is special, since it's reported
* immediately, and doesn't affect the current
* character
*/
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
}
} }
tty_flip_buffer_push (tty); tty_flip_buffer_push (tty);
return; return;
......
...@@ -350,18 +350,9 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *r ...@@ -350,18 +350,9 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *r
} }
if (uart_handle_sysrq_char(&up->port, ch, regs)) if (uart_handle_sysrq_char(&up->port, ch, regs))
goto ignore_char; goto ignore_char;
if ((disr & up->port.ignore_status_mask) == 0) {
tty_insert_flip_char(tty, ch, flag); uart_insert_char(&up->port, disr, TXX9_SIDISR_UOER, ch, flag);
}
if ((disr & TXX9_SIDISR_UOER) &&
tty->flip.count < TTY_FLIPBUF_SIZE) {
/*
* Overrun is special, since it's reported
* immediately, and doesn't affect the current
* character.
*/
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
}
ignore_char: ignore_char:
disr = sio_in(up, TXX9_SIDISR); disr = sio_in(up, TXX9_SIDISR);
} while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0)); } while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0));
......
...@@ -412,10 +412,8 @@ static inline void receive_chars(struct uart_port *port, uint8_t *status, ...@@ -412,10 +412,8 @@ static inline void receive_chars(struct uart_port *port, uint8_t *status,
if (uart_handle_sysrq_char(port, ch, regs)) if (uart_handle_sysrq_char(port, ch, regs))
goto ignore_char; goto ignore_char;
if ((lsr & port->ignore_status_mask) == 0)
tty_insert_flip_char(tty, ch, flag); uart_insert_char(port, lsr, UART_LSR_OE, ch, flag);
if ((lsr & UART_LSR_OE) && (tty->flip.count < TTY_FLIPBUF_SIZE))
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
ignore_char: ignore_char:
lsr = siu_read(port, UART_LSR); lsr = siu_read(port, UART_LSR);
......
...@@ -251,7 +251,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec, ...@@ -251,7 +251,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr * exec,
} }
/* Populate argv and envp */ /* Populate argv and envp */
p = current->mm->arg_start; p = current->mm->arg_end = current->mm->arg_start;
while (argc-- > 0) { while (argc-- > 0) {
size_t len; size_t len;
__put_user((elf_addr_t)p, argv++); __put_user((elf_addr_t)p, argv++);
...@@ -1301,7 +1301,7 @@ static void fill_prstatus(struct elf_prstatus *prstatus, ...@@ -1301,7 +1301,7 @@ static void fill_prstatus(struct elf_prstatus *prstatus,
static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
struct mm_struct *mm) struct mm_struct *mm)
{ {
int i, len; unsigned int i, len;
/* first copy the parameters from user space */ /* first copy the parameters from user space */
memset(psinfo, 0, sizeof(struct elf_prpsinfo)); memset(psinfo, 0, sizeof(struct elf_prpsinfo));
......
...@@ -227,6 +227,30 @@ ...@@ -227,6 +227,30 @@
#define PD31_PF_TMR2OUT ( GPIO_PORTD | GPIO_PF | 31 ) #define PD31_PF_TMR2OUT ( GPIO_PORTD | GPIO_PF | 31 )
#define PD31_BIN_SPI2_TXD ( GPIO_PORTD | GPIO_BIN | 31 ) #define PD31_BIN_SPI2_TXD ( GPIO_PORTD | GPIO_BIN | 31 )
/*
* PWM controller
*/
#define PWMC __REG(IMX_PWM_BASE + 0x00) /* PWM Control Register */
#define PWMS __REG(IMX_PWM_BASE + 0x04) /* PWM Sample Register */
#define PWMP __REG(IMX_PWM_BASE + 0x08) /* PWM Period Register */
#define PWMCNT __REG(IMX_PWM_BASE + 0x0C) /* PWM Counter Register */
#define PWMC_HCTR (0x01<<18) /* Halfword FIFO Data Swapping */
#define PWMC_BCTR (0x01<<17) /* Byte FIFO Data Swapping */
#define PWMC_SWR (0x01<<16) /* Software Reset */
#define PWMC_CLKSRC (0x01<<15) /* Clock Source */
#define PWMC_PRESCALER(x) (((x-1) & 0x7F) << 8) /* PRESCALER */
#define PWMC_IRQ (0x01<< 7) /* Interrupt Request */
#define PWMC_IRQEN (0x01<< 6) /* Interrupt Request Enable */
#define PWMC_FIFOAV (0x01<< 5) /* FIFO Available */
#define PWMC_EN (0x01<< 4) /* Enables/Disables the PWM */
#define PWMC_REPEAT(x) (((x) & 0x03) << 2) /* Sample Repeats */
#define PWMC_CLKSEL(x) (((x) & 0x03) << 0) /* Clock Selection */
#define PWMS_SAMPLE(x) ((x) & 0xFFFF) /* Contains a two-sample word */
#define PWMP_PERIOD(x) ((x) & 0xFFFF) /* Represents the PWM's period */
#define PWMC_COUNTER(x) ((x) & 0xFFFF) /* Represents the current count value */
/* /*
* DMA Controller * DMA Controller
*/ */
......
/* linux/include/asm-arm/arch-s3c2410/regs-nand.h /* linux/include/asm-arm/arch-s3c2410/regs-nand.h
* *
* Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk> * Copyright (c) 2004,2005 Simtec Electronics <linux@simtec.co.uk>
* http://www.simtec.co.uk/products/SWLINUX/ * http://www.simtec.co.uk/products/SWLINUX/
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
* *
* S3C2410 clock register definitions * S3C2410 NAND register definitions
* *
* Changelog: * Changelog:
* 18-Aug-2004 BJD Copied file from 2.4 and updated * 18-Aug-2004 BJD Copied file from 2.4 and updated
* 01-May-2005 BJD Added definitions for s3c2440 controller
*/ */
#ifndef __ASM_ARM_REGS_NAND #ifndef __ASM_ARM_REGS_NAND
...@@ -26,6 +27,22 @@ ...@@ -26,6 +27,22 @@
#define S3C2410_NFSTAT S3C2410_NFREG(0x10) #define S3C2410_NFSTAT S3C2410_NFREG(0x10)
#define S3C2410_NFECC S3C2410_NFREG(0x14) #define S3C2410_NFECC S3C2410_NFREG(0x14)
#define S3C2440_NFCONT S3C2410_NFREG(0x04)
#define S3C2440_NFCMD S3C2410_NFREG(0x08)
#define S3C2440_NFADDR S3C2410_NFREG(0x0C)
#define S3C2440_NFDATA S3C2410_NFREG(0x10)
#define S3C2440_NFECCD0 S3C2410_NFREG(0x14)
#define S3C2440_NFECCD1 S3C2410_NFREG(0x18)
#define S3C2440_NFECCD S3C2410_NFREG(0x1C)
#define S3C2440_NFSTAT S3C2410_NFREG(0x20)
#define S3C2440_NFESTAT0 S3C2410_NFREG(0x24)
#define S3C2440_NFESTAT1 S3C2410_NFREG(0x28)
#define S3C2440_NFMECC0 S3C2410_NFREG(0x2C)
#define S3C2440_NFMECC1 S3C2410_NFREG(0x30)
#define S3C2440_NFSECC S3C2410_NFREG(0x34)
#define S3C2440_NFSBLK S3C2410_NFREG(0x38)
#define S3C2440_NFEBLK S3C2410_NFREG(0x3C)
#define S3C2410_NFCONF_EN (1<<15) #define S3C2410_NFCONF_EN (1<<15)
#define S3C2410_NFCONF_512BYTE (1<<14) #define S3C2410_NFCONF_512BYTE (1<<14)
#define S3C2410_NFCONF_4STEP (1<<13) #define S3C2410_NFCONF_4STEP (1<<13)
...@@ -37,7 +54,28 @@ ...@@ -37,7 +54,28 @@
#define S3C2410_NFSTAT_BUSY (1<<0) #define S3C2410_NFSTAT_BUSY (1<<0)
/* think ECC can only be 8bit read? */ #define S3C2440_NFCONF_BUSWIDTH_8 (0<<0)
#define S3C2440_NFCONF_BUSWIDTH_16 (1<<0)
#define S3C2440_NFCONF_ADVFLASH (1<<3)
#define S3C2440_NFCONF_TACLS(x) ((x)<<12)
#define S3C2440_NFCONF_TWRPH0(x) ((x)<<8)
#define S3C2440_NFCONF_TWRPH1(x) ((x)<<4)
#define S3C2440_NFCONT_LOCKTIGHT (1<<13)
#define S3C2440_NFCONT_SOFTLOCK (1<<12)
#define S3C2440_NFCONT_ILLEGALACC_EN (1<<10)
#define S3C2440_NFCONT_RNBINT_EN (1<<9)
#define S3C2440_NFCONT_RN_FALLING (1<<8)
#define S3C2440_NFCONT_SPARE_ECCLOCK (1<<6)
#define S3C2440_NFCONT_MAIN_ECCLOCK (1<<5)
#define S3C2440_NFCONT_INITECC (1<<4)
#define S3C2440_NFCONT_nFCE (1<<1)
#define S3C2440_NFCONT_ENABLE (1<<0)
#define S3C2440_NFSTAT_READY (1<<0)
#define S3C2440_NFSTAT_nCE (1<<1)
#define S3C2440_NFSTAT_RnB_CHANGE (1<<2)
#define S3C2440_NFSTAT_ILLEGAL_ACCESS (1<<3)
#endif /* __ASM_ARM_REGS_NAND */ #endif /* __ASM_ARM_REGS_NAND */
...@@ -114,19 +114,8 @@ extern void __cpu_copy_user_page(void *to, const void *from, ...@@ -114,19 +114,8 @@ extern void __cpu_copy_user_page(void *to, const void *from,
unsigned long user); unsigned long user);
#endif #endif
#define clear_user_page(addr,vaddr,pg) \ #define clear_user_page(addr,vaddr,pg) __cpu_clear_user_page(addr, vaddr)
do { \ #define copy_user_page(to,from,vaddr,pg) __cpu_copy_user_page(to, from, vaddr)
preempt_disable(); \
__cpu_clear_user_page(addr, vaddr); \
preempt_enable(); \
} while (0)
#define copy_user_page(to,from,vaddr,pg) \
do { \
preempt_disable(); \
__cpu_copy_user_page(to, from, vaddr); \
preempt_enable(); \
} while (0)
#define clear_page(page) memzero((void *)(page), PAGE_SIZE) #define clear_page(page) memzero((void *)(page), PAGE_SIZE)
extern void copy_page(void *to, const void *from); extern void copy_page(void *to, const void *from);
...@@ -171,6 +160,9 @@ typedef unsigned long pgprot_t; ...@@ -171,6 +160,9 @@ typedef unsigned long pgprot_t;
#endif /* STRICT_MM_TYPECHECKS */ #endif /* STRICT_MM_TYPECHECKS */
/* the upper-most page table pointer */
extern pmd_t *top_pmd;
/* Pure 2^n version of get_order */ /* Pure 2^n version of get_order */
static inline int get_order(unsigned long size) static inline int get_order(unsigned long size)
{ {
......
...@@ -479,6 +479,25 @@ uart_handle_cts_change(struct uart_port *port, unsigned int status) ...@@ -479,6 +479,25 @@ uart_handle_cts_change(struct uart_port *port, unsigned int status)
} }
} }
#include <linux/tty_flip.h>
static inline void
uart_insert_char(struct uart_port *port, unsigned int status,
unsigned int overrun, unsigned int ch, unsigned int flag)
{
struct tty_struct *tty = port->info->tty;
if ((status & port->ignore_status_mask & ~overrun) == 0)
tty_insert_flip_char(tty, ch, flag);
/*
* Overrun is special. Since it's reported immediately,
* it doesn't affect the current character.
*/
if (status & ~port->ignore_status_mask & overrun)
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
}
/* /*
* UART_ENABLE_MS - determine if port should enable modem status irqs * UART_ENABLE_MS - determine if port should enable modem status irqs
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment