From f36440c35e717e6f903f518cf16bbd945c47e94e Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 13 Jan 2011 15:36:09 -0700 Subject: [PATCH] --- yaml --- r: 231726 b: refs/heads/master c: 672c54466d24994eb9633f993862c89539504a42 h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/Documentation/filesystems/Locking | 7 +- trunk/Documentation/filesystems/vfs.txt | 43 - trunk/arch/alpha/Kconfig | 3 - trunk/arch/alpha/include/asm/io.h | 8 +- trunk/arch/alpha/kernel/Makefile | 4 +- trunk/arch/alpha/kernel/irq.c | 31 +- trunk/arch/alpha/kernel/irq_alpha.c | 24 +- trunk/arch/alpha/kernel/irq_i8259.c | 26 +- trunk/arch/alpha/kernel/irq_pyxis.c | 27 +- trunk/arch/alpha/kernel/irq_srm.c | 27 +- trunk/arch/alpha/kernel/osf_sys.c | 3 + trunk/arch/alpha/kernel/sys_alcor.c | 27 +- trunk/arch/alpha/kernel/sys_cabriolet.c | 28 +- trunk/arch/alpha/kernel/sys_dp264.c | 50 +- trunk/arch/alpha/kernel/sys_eb64p.c | 27 +- trunk/arch/alpha/kernel/sys_eiger.c | 27 +- trunk/arch/alpha/kernel/sys_jensen.c | 55 +- trunk/arch/alpha/kernel/sys_marvel.c | 50 +- trunk/arch/alpha/kernel/sys_mikasa.c | 27 +- trunk/arch/alpha/kernel/sys_noritake.c | 27 +- trunk/arch/alpha/kernel/sys_rawhide.c | 27 +- trunk/arch/alpha/kernel/sys_rx164.c | 27 +- trunk/arch/alpha/kernel/sys_sable.c | 28 +- trunk/arch/alpha/kernel/sys_takara.c | 27 +- trunk/arch/alpha/kernel/sys_titan.c | 31 +- trunk/arch/alpha/kernel/sys_wildfire.c | 42 +- trunk/arch/alpha/lib/Makefile | 4 +- trunk/arch/alpha/math-emu/Makefile | 2 +- trunk/arch/alpha/mm/Makefile | 2 +- trunk/arch/alpha/oprofile/Makefile | 2 +- trunk/arch/arm/mach-omap1/board-ams-delta.c | 17 - .../arm/plat-nomadik/include/plat/ste_dma40.h | 8 - .../arch/arm/plat-omap/include/plat/onenand.h | 1 - trunk/arch/microblaze/kernel/prom.c | 4 +- trunk/arch/mips/kernel/prom.c | 6 +- trunk/arch/parisc/include/asm/pgtable.h | 4 +- trunk/arch/powerpc/kernel/prom.c | 4 +- trunk/drivers/acpi/apei/hest.c | 6 +- trunk/drivers/acpi/pci_root.c | 4 +- trunk/drivers/dma/Kconfig | 9 +- trunk/drivers/dma/amba-pl08x.c | 1168 +++++++++-------- trunk/drivers/dma/at_hdmac.c | 19 +- trunk/drivers/dma/fsldma.c | 4 +- trunk/drivers/dma/intel_mid_dma.c | 33 +- trunk/drivers/dma/iop-adma.c | 4 +- trunk/drivers/dma/pch_dma.c | 19 +- trunk/drivers/dma/ste_dma40.c | 191 +-- trunk/drivers/dma/ste_dma40_ll.c | 246 ++-- trunk/drivers/dma/ste_dma40_ll.h | 36 +- trunk/drivers/gpu/drm/nouveau/nouveau_drv.h | 15 - trunk/drivers/gpu/drm/nouveau/nouveau_fbcon.c | 4 +- trunk/drivers/gpu/drm/nouveau/nouveau_mem.c | 26 +- trunk/drivers/gpu/drm/nouveau/nouveau_mm.c | 182 ++- trunk/drivers/gpu/drm/nouveau/nouveau_mm.h | 4 +- trunk/drivers/gpu/drm/nouveau/nv40_graph.c | 3 +- trunk/drivers/gpu/drm/nouveau/nv40_grctx.c | 21 +- trunk/drivers/gpu/drm/nouveau/nv40_mc.c | 14 +- trunk/drivers/gpu/drm/nouveau/nv50_instmem.c | 7 +- trunk/drivers/gpu/drm/nouveau/nvc0_graph.c | 3 +- trunk/drivers/gpu/drm/nouveau/nvc0_vm.c | 4 +- trunk/drivers/gpu/drm/radeon/evergreen.c | 30 +- trunk/drivers/gpu/drm/radeon/r100.c | 11 +- trunk/drivers/gpu/drm/radeon/r300.c | 11 +- trunk/drivers/gpu/drm/radeon/r600.c | 23 +- trunk/drivers/gpu/drm/radeon/radeon.h | 1 - trunk/drivers/gpu/drm/radeon/radeon_drv.c | 4 - .../drivers/gpu/drm/radeon/reg_srcs/evergreen | 2 +- trunk/drivers/gpu/drm/radeon/rs600.c | 16 +- trunk/drivers/gpu/drm/radeon/rv770.c | 5 +- trunk/drivers/mtd/Kconfig | 19 +- trunk/drivers/mtd/Makefile | 2 +- trunk/drivers/mtd/chips/cfi_cmdset_0001.c | 55 +- trunk/drivers/mtd/chips/cfi_cmdset_0002.c | 116 +- trunk/drivers/mtd/chips/cfi_cmdset_0020.c | 1 - trunk/drivers/mtd/chips/cfi_util.c | 2 +- trunk/drivers/mtd/chips/fwh_lock.h | 2 +- trunk/drivers/mtd/devices/m25p80.c | 39 +- trunk/drivers/mtd/devices/sst25l.c | 4 +- trunk/drivers/mtd/maps/amd76xrom.c | 7 +- trunk/drivers/mtd/maps/bcm963xx-flash.c | 5 - trunk/drivers/mtd/maps/ck804xrom.c | 7 +- trunk/drivers/mtd/maps/esb2rom.c | 9 +- trunk/drivers/mtd/maps/ichxrom.c | 9 +- trunk/drivers/mtd/maps/physmap_of.c | 4 +- trunk/drivers/mtd/maps/scx200_docflash.c | 5 +- trunk/drivers/mtd/maps/tqm8xxl.c | 2 +- trunk/drivers/mtd/mtdchar.c | 12 +- trunk/drivers/mtd/mtdconcat.c | 1 - trunk/drivers/mtd/mtdoops.c | 3 +- trunk/drivers/mtd/mtdpart.c | 30 +- trunk/drivers/mtd/nand/Kconfig | 1 - trunk/drivers/mtd/nand/ams-delta.c | 80 +- trunk/drivers/mtd/nand/fsl_elbc_nand.c | 2 - trunk/drivers/mtd/nand/fsmc_nand.c | 89 +- trunk/drivers/mtd/nand/jz4740_nand.c | 57 +- trunk/drivers/mtd/nand/mxc_nand.c | 2 +- trunk/drivers/mtd/nand/nand_base.c | 25 +- trunk/drivers/mtd/nand/nand_bbt.c | 3 +- trunk/drivers/mtd/nand/nandsim.c | 39 +- trunk/drivers/mtd/nand/pasemi_nand.c | 2 +- trunk/drivers/mtd/nand/pxa3xx_nand.c | 2 +- trunk/drivers/mtd/nand/txx9ndfmc.c | 5 +- trunk/drivers/mtd/onenand/omap2.c | 80 +- trunk/drivers/mtd/onenand/onenand_base.c | 81 +- trunk/drivers/mtd/onenand/onenand_bbt.c | 10 +- trunk/drivers/mtd/onenand/samsung.c | 7 +- trunk/drivers/mtd/ubi/build.c | 28 +- trunk/drivers/mtd/ubi/vtbl.c | 6 +- trunk/drivers/net/Kconfig | 3 +- trunk/drivers/nfc/pn544.c | 2 +- trunk/drivers/of/fdt.c | 8 +- trunk/drivers/staging/autofs/dirhash.c | 5 +- trunk/drivers/staging/smbfs/dir.c | 4 +- trunk/fs/Kconfig | 17 +- trunk/fs/afs/dir.c | 1 - trunk/fs/afs/inode.c | 3 +- trunk/fs/afs/internal.h | 1 - trunk/fs/afs/mntpt.c | 56 +- trunk/fs/aio.c | 2 +- trunk/fs/anon_inodes.c | 2 +- trunk/fs/autofs4/autofs_i.h | 99 +- trunk/fs/autofs4/dev-ioctl.c | 2 +- trunk/fs/autofs4/expire.c | 51 +- trunk/fs/autofs4/inode.c | 26 +- trunk/fs/autofs4/root.c | 673 ++++++---- trunk/fs/autofs4/waitq.c | 17 +- trunk/fs/btrfs/ctree.h | 1 - trunk/fs/btrfs/file.c | 113 -- trunk/fs/btrfs/inode.c | 111 ++ trunk/fs/cifs/cifs_dfs_ref.c | 120 +- trunk/fs/cifs/cifsfs.h | 6 - trunk/fs/cifs/connect.c | 2 - trunk/fs/cifs/dir.c | 2 - trunk/fs/cifs/inode.c | 8 +- trunk/fs/cifs/netmisc.c | 4 +- trunk/fs/compat.c | 10 +- trunk/fs/configfs/Kconfig | 4 +- trunk/fs/dcache.c | 5 +- trunk/fs/dlm/Kconfig | 3 +- trunk/fs/ext4/ext4.h | 2 +- trunk/fs/ext4/extents.c | 11 +- trunk/fs/ext4/file.c | 2 +- trunk/fs/file_table.c | 2 +- trunk/fs/fs_struct.c | 35 +- trunk/fs/gfs2/file.c | 258 ---- trunk/fs/gfs2/ops_inode.c | 258 ++++ trunk/fs/hpfs/inode.c | 2 +- trunk/fs/internal.h | 4 - trunk/fs/ioctl.c | 10 +- trunk/fs/jffs2/build.c | 5 +- trunk/fs/jffs2/jffs2_fs_sb.h | 2 +- trunk/fs/jffs2/xattr.c | 12 +- trunk/fs/namei.c | 358 ++--- trunk/fs/namespace.c | 223 ++-- trunk/fs/nfs/dir.c | 4 +- trunk/fs/nfs/inode.c | 4 +- trunk/fs/nfs/internal.h | 1 - trunk/fs/nfs/namespace.c | 77 +- trunk/fs/nfsd/vfs.c | 5 +- trunk/fs/ocfs2/Kconfig | 3 +- trunk/fs/ocfs2/file.c | 10 +- trunk/fs/open.c | 4 +- trunk/fs/pipe.c | 2 +- trunk/fs/squashfs/Kconfig | 18 +- trunk/fs/squashfs/Makefile | 1 - trunk/fs/squashfs/block.c | 1 + trunk/fs/squashfs/cache.c | 1 + trunk/fs/squashfs/decompressor.c | 16 +- trunk/fs/squashfs/decompressor.h | 9 - trunk/fs/squashfs/fragment.c | 1 + trunk/fs/squashfs/id.c | 1 + trunk/fs/squashfs/lzo_wrapper.c | 1 + trunk/fs/squashfs/squashfs.h | 8 + trunk/fs/squashfs/squashfs_fs.h | 1 - trunk/fs/squashfs/squashfs_fs_i.h | 6 - trunk/fs/squashfs/xattr_id.c | 1 + trunk/fs/squashfs/xz_wrapper.c | 153 --- trunk/fs/squashfs/zlib_wrapper.c | 15 +- trunk/fs/stat.c | 4 +- trunk/fs/super.c | 2 +- trunk/fs/xfs/linux-2.6/xfs_file.c | 56 - trunk/fs/xfs/linux-2.6/xfs_iops.c | 57 + trunk/include/asm-generic/pgtable.h | 14 +- trunk/include/linux/amba/pl08x.h | 99 +- trunk/include/linux/auto_fs4.h | 2 +- trunk/include/linux/dcache.h | 16 +- trunk/include/linux/dmaengine.h | 2 +- trunk/include/linux/fcntl.h | 1 - trunk/include/linux/file.h | 2 +- trunk/include/linux/fs.h | 10 +- trunk/include/linux/mount.h | 11 +- trunk/include/linux/mtd/cfi.h | 3 +- trunk/include/linux/mtd/fsmc.h | 26 +- trunk/include/linux/mtd/mtd.h | 11 - trunk/include/linux/mtd/nand.h | 2 - trunk/include/linux/mtd/onenand.h | 14 - trunk/include/linux/mtd/partitions.h | 2 +- trunk/include/linux/namei.h | 5 +- trunk/include/linux/nfs_fs.h | 1 + trunk/include/linux/of_fdt.h | 2 +- trunk/include/linux/path.h | 2 + trunk/include/linux/pci-acpi.h | 3 + trunk/mm/pgtable-generic.c | 11 +- 204 files changed, 3370 insertions(+), 3613 deletions(-) delete mode 100644 trunk/fs/squashfs/xz_wrapper.c diff --git a/[refs] b/[refs] index 15ca28ef7543..af8844497d01 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 1a47f7a84ef386c1f7f55f669598bd9894ceb73a +refs/heads/master: 672c54466d24994eb9633f993862c89539504a42 diff --git a/trunk/Documentation/filesystems/Locking b/trunk/Documentation/filesystems/Locking index 4471a416c274..ef9349a4b5d1 100644 --- a/trunk/Documentation/filesystems/Locking +++ b/trunk/Documentation/filesystems/Locking @@ -19,8 +19,6 @@ prototypes: void (*d_release)(struct dentry *); void (*d_iput)(struct dentry *, struct inode *); char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen); - struct vfsmount *(*d_automount)(struct path *path); - int (*d_manage)(struct dentry *, bool); locking rules: rename_lock ->d_lock may block rcu-walk @@ -31,8 +29,6 @@ d_delete: no yes no no d_release: no no yes no d_iput: no no yes no d_dname: no no no no -d_automount: no no yes no -d_manage: no no yes (ref-walk) maybe --------------------------- inode_operations --------------------------- prototypes: @@ -60,6 +56,7 @@ ata *); ssize_t (*listxattr) (struct dentry *, char *, size_t); int (*removexattr) (struct dentry *, const char *); void (*truncate_range)(struct inode *, loff_t, loff_t); + long (*fallocate)(struct inode *inode, int mode, loff_t offset, loff_t len); int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len); locking rules: @@ -87,6 +84,7 @@ getxattr: no listxattr: no removexattr: yes truncate_range: yes +fallocate: no fiemap: no Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on victim. @@ -435,7 +433,6 @@ prototypes: ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); int (*setlease)(struct file *, long, struct file_lock **); - long (*fallocate)(struct file *, int, loff_t, loff_t); }; locking rules: diff --git a/trunk/Documentation/filesystems/vfs.txt b/trunk/Documentation/filesystems/vfs.txt index 94cf97b901d7..cae6d27c9f5b 100644 --- a/trunk/Documentation/filesystems/vfs.txt +++ b/trunk/Documentation/filesystems/vfs.txt @@ -864,8 +864,6 @@ struct dentry_operations { void (*d_release)(struct dentry *); void (*d_iput)(struct dentry *, struct inode *); char *(*d_dname)(struct dentry *, char *, int); - struct vfsmount *(*d_automount)(struct path *); - int (*d_manage)(struct dentry *, bool, bool); }; d_revalidate: called when the VFS needs to revalidate a dentry. This @@ -932,47 +930,6 @@ struct dentry_operations { at the end of the buffer, and returns a pointer to the first char. dynamic_dname() helper function is provided to take care of this. - d_automount: called when an automount dentry is to be traversed (optional). - This should create a new VFS mount record and return the record to the - caller. The caller is supplied with a path parameter giving the - automount directory to describe the automount target and the parent - VFS mount record to provide inheritable mount parameters. NULL should - be returned if someone else managed to make the automount first. If - the vfsmount creation failed, then an error code should be returned. - If -EISDIR is returned, then the directory will be treated as an - ordinary directory and returned to pathwalk to continue walking. - - If a vfsmount is returned, the caller will attempt to mount it on the - mountpoint and will remove the vfsmount from its expiration list in - the case of failure. The vfsmount should be returned with 2 refs on - it to prevent automatic expiration - the caller will clean up the - additional ref. - - This function is only used if DCACHE_NEED_AUTOMOUNT is set on the - dentry. This is set by __d_instantiate() if S_AUTOMOUNT is set on the - inode being added. - - d_manage: called to allow the filesystem to manage the transition from a - dentry (optional). This allows autofs, for example, to hold up clients - waiting to explore behind a 'mountpoint' whilst letting the daemon go - past and construct the subtree there. 0 should be returned to let the - calling process continue. -EISDIR can be returned to tell pathwalk to - use this directory as an ordinary directory and to ignore anything - mounted on it and not to check the automount flag. Any other error - code will abort pathwalk completely. - - If the 'mounting_here' parameter is true, then namespace_sem is being - held by the caller and the function should not initiate any mounts or - unmounts that it will then wait for. - - If the 'rcu_walk' parameter is true, then the caller is doing a - pathwalk in RCU-walk mode. Sleeping is not permitted in this mode, - and the caller can be asked to leave it and call again by returing - -ECHILD. - - This function is only used if DCACHE_MANAGE_TRANSIT is set on the - dentry being transited from. - Example : static char *pipefs_dname(struct dentry *dent, char *buffer, int buflen) diff --git a/trunk/arch/alpha/Kconfig b/trunk/arch/alpha/Kconfig index fc95ee1bcf6f..943fe6930f77 100644 --- a/trunk/arch/alpha/Kconfig +++ b/trunk/arch/alpha/Kconfig @@ -68,9 +68,6 @@ config GENERIC_IOMAP bool default n -config GENERIC_HARDIRQS_NO__DO_IRQ - def_bool y - config GENERIC_HARDIRQS bool default y diff --git a/trunk/arch/alpha/include/asm/io.h b/trunk/arch/alpha/include/asm/io.h index 56ff96501350..eda9b909aa05 100644 --- a/trunk/arch/alpha/include/asm/io.h +++ b/trunk/arch/alpha/include/asm/io.h @@ -37,9 +37,8 @@ */ extern inline void __set_hae(unsigned long new_hae) { - unsigned long flags = swpipl(IPL_MAX); - - barrier(); + unsigned long flags; + local_irq_save(flags); alpha_mv.hae_cache = new_hae; *alpha_mv.hae_register = new_hae; @@ -47,8 +46,7 @@ extern inline void __set_hae(unsigned long new_hae) /* Re-read to make sure it was written. */ new_hae = *alpha_mv.hae_register; - setipl(flags); - barrier(); + local_irq_restore(flags); } extern inline void set_hae(unsigned long new_hae) diff --git a/trunk/arch/alpha/kernel/Makefile b/trunk/arch/alpha/kernel/Makefile index 9bb7b858ed23..1ee9b5b629b8 100644 --- a/trunk/arch/alpha/kernel/Makefile +++ b/trunk/arch/alpha/kernel/Makefile @@ -3,8 +3,8 @@ # extra-y := head.o vmlinux.lds -asflags-y := $(KBUILD_CFLAGS) -ccflags-y := -Werror -Wno-sign-compare +EXTRA_AFLAGS := $(KBUILD_CFLAGS) +EXTRA_CFLAGS := -Werror -Wno-sign-compare obj-y := entry.o traps.o process.o init_task.o osf_sys.o irq.o \ irq_alpha.o signal.o setup.o ptrace.o time.o \ diff --git a/trunk/arch/alpha/kernel/irq.c b/trunk/arch/alpha/kernel/irq.c index 9ab234f48dd8..fe912984d9b1 100644 --- a/trunk/arch/alpha/kernel/irq.c +++ b/trunk/arch/alpha/kernel/irq.c @@ -44,11 +44,10 @@ static char irq_user_affinity[NR_IRQS]; int irq_select_affinity(unsigned int irq) { - struct irq_desc *desc = irq_to_desc[irq]; static int last_cpu; int cpu = last_cpu + 1; - if (!desc || !get_irq_desc_chip(desc)->set_affinity || irq_user_affinity[irq]) + if (!irq_desc[irq].chip->set_affinity || irq_user_affinity[irq]) return 1; while (!cpu_possible(cpu) || @@ -56,8 +55,8 @@ int irq_select_affinity(unsigned int irq) cpu = (cpu < (NR_CPUS-1) ? cpu + 1 : 0); last_cpu = cpu; - cpumask_copy(desc->affinity, cpumask_of(cpu)); - get_irq_desc_chip(desc)->set_affinity(irq, cpumask_of(cpu)); + cpumask_copy(irq_desc[irq].affinity, cpumask_of(cpu)); + irq_desc[irq].chip->set_affinity(irq, cpumask_of(cpu)); return 0; } #endif /* CONFIG_SMP */ @@ -68,7 +67,6 @@ show_interrupts(struct seq_file *p, void *v) int j; int irq = *(loff_t *) v; struct irqaction * action; - struct irq_desc *desc; unsigned long flags; #ifdef CONFIG_SMP @@ -81,13 +79,8 @@ show_interrupts(struct seq_file *p, void *v) #endif if (irq < ACTUAL_NR_IRQS) { - desc = irq_to_desc(irq); - - if (!desc) - return 0; - - raw_spin_lock_irqsave(&desc->lock, flags); - action = desc->action; + raw_spin_lock_irqsave(&irq_desc[irq].lock, flags); + action = irq_desc[irq].action; if (!action) goto unlock; seq_printf(p, "%3d: ", irq); @@ -97,7 +90,7 @@ show_interrupts(struct seq_file *p, void *v) for_each_online_cpu(j) seq_printf(p, "%10u ", kstat_irqs_cpu(irq, j)); #endif - seq_printf(p, " %14s", get_irq_desc_chip(desc)->name); + seq_printf(p, " %14s", irq_desc[irq].chip->name); seq_printf(p, " %c%s", (action->flags & IRQF_DISABLED)?'+':' ', action->name); @@ -110,7 +103,7 @@ show_interrupts(struct seq_file *p, void *v) seq_putc(p, '\n'); unlock: - raw_spin_unlock_irqrestore(&desc->lock, flags); + raw_spin_unlock_irqrestore(&irq_desc[irq].lock, flags); } else if (irq == ACTUAL_NR_IRQS) { #ifdef CONFIG_SMP seq_puts(p, "IPI: "); @@ -149,10 +142,8 @@ handle_irq(int irq) * handled by some other CPU. (or is disabled) */ static unsigned int illegal_count=0; - struct irq_desc *desc = irq_to_desc(irq); - if (!desc || ((unsigned) irq > ACTUAL_NR_IRQS && - illegal_count < MAX_ILLEGAL_IRQS)) { + if ((unsigned) irq > ACTUAL_NR_IRQS && illegal_count < MAX_ILLEGAL_IRQS ) { irq_err_count++; illegal_count++; printk(KERN_CRIT "device_interrupt: invalid interrupt %d\n", @@ -160,14 +151,14 @@ handle_irq(int irq) return; } + irq_enter(); /* - * From here we must proceed with IPL_MAX. Note that we do not + * __do_IRQ() must be called with IPL_MAX. Note that we do not * explicitly enable interrupts afterwards - some MILO PALcode * (namely LX164 one) seems to have severe problems with RTI * at IPL 0. */ local_irq_disable(); - irq_enter(); - generic_handle_irq_desc(irq, desc); + __do_IRQ(irq); irq_exit(); } diff --git a/trunk/arch/alpha/kernel/irq_alpha.c b/trunk/arch/alpha/kernel/irq_alpha.c index 2d0679b60939..4c8bb374eb0a 100644 --- a/trunk/arch/alpha/kernel/irq_alpha.c +++ b/trunk/arch/alpha/kernel/irq_alpha.c @@ -219,23 +219,31 @@ process_mcheck_info(unsigned long vector, unsigned long la_ptr, * processed by PALcode, and comes in via entInt vector 1. */ +static void rtc_enable_disable(unsigned int irq) { } +static unsigned int rtc_startup(unsigned int irq) { return 0; } + struct irqaction timer_irqaction = { .handler = timer_interrupt, .flags = IRQF_DISABLED, .name = "timer", }; +static struct irq_chip rtc_irq_type = { + .name = "RTC", + .startup = rtc_startup, + .shutdown = rtc_enable_disable, + .enable = rtc_enable_disable, + .disable = rtc_enable_disable, + .ack = rtc_enable_disable, + .end = rtc_enable_disable, +}; + void __init init_rtc_irq(void) { - struct irq_desc *desc = irq_to_desc(RTC_IRQ); - - if (desc) { - desc->status |= IRQ_DISABLED; - set_irq_chip_and_handler_name(RTC_IRQ, &no_irq_chip, - handle_simple_irq, "RTC"); - setup_irq(RTC_IRQ, &timer_irqaction); - } + irq_desc[RTC_IRQ].status = IRQ_DISABLED; + irq_desc[RTC_IRQ].chip = &rtc_irq_type; + setup_irq(RTC_IRQ, &timer_irqaction); } /* Dummy irqactions. */ diff --git a/trunk/arch/alpha/kernel/irq_i8259.c b/trunk/arch/alpha/kernel/irq_i8259.c index 956ea0ed1694..83a9ac280890 100644 --- a/trunk/arch/alpha/kernel/irq_i8259.c +++ b/trunk/arch/alpha/kernel/irq_i8259.c @@ -69,11 +69,28 @@ i8259a_mask_and_ack_irq(unsigned int irq) spin_unlock(&i8259_irq_lock); } +unsigned int +i8259a_startup_irq(unsigned int irq) +{ + i8259a_enable_irq(irq); + return 0; /* never anything pending */ +} + +void +i8259a_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + i8259a_enable_irq(irq); +} + struct irq_chip i8259a_irq_type = { .name = "XT-PIC", - .unmask = i8259a_enable_irq, - .mask = i8259a_disable_irq, - .mask_ack = i8259a_mask_and_ack_irq, + .startup = i8259a_startup_irq, + .shutdown = i8259a_disable_irq, + .enable = i8259a_enable_irq, + .disable = i8259a_disable_irq, + .ack = i8259a_mask_and_ack_irq, + .end = i8259a_end_irq, }; void __init @@ -90,7 +107,8 @@ init_i8259a_irqs(void) outb(0xff, 0xA1); /* mask all of 8259A-2 */ for (i = 0; i < 16; i++) { - set_irq_chip_and_handler(i, &i8259a_irq_type, handle_level_irq); + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].chip = &i8259a_irq_type; } setup_irq(2, &cascade); diff --git a/trunk/arch/alpha/kernel/irq_pyxis.c b/trunk/arch/alpha/kernel/irq_pyxis.c index 2863458c853e..989ce46a0cf3 100644 --- a/trunk/arch/alpha/kernel/irq_pyxis.c +++ b/trunk/arch/alpha/kernel/irq_pyxis.c @@ -40,6 +40,20 @@ pyxis_disable_irq(unsigned int irq) pyxis_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16))); } +static unsigned int +pyxis_startup_irq(unsigned int irq) +{ + pyxis_enable_irq(irq); + return 0; +} + +static void +pyxis_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + pyxis_enable_irq(irq); +} + static void pyxis_mask_and_ack_irq(unsigned int irq) { @@ -58,9 +72,12 @@ pyxis_mask_and_ack_irq(unsigned int irq) static struct irq_chip pyxis_irq_type = { .name = "PYXIS", - .mask_ack = pyxis_mask_and_ack_irq, - .mask = pyxis_disable_irq, - .unmask = pyxis_enable_irq, + .startup = pyxis_startup_irq, + .shutdown = pyxis_disable_irq, + .enable = pyxis_enable_irq, + .disable = pyxis_disable_irq, + .ack = pyxis_mask_and_ack_irq, + .end = pyxis_end_irq, }; void @@ -102,8 +119,8 @@ init_pyxis_irqs(unsigned long ignore_mask) for (i = 16; i < 48; ++i) { if ((ignore_mask >> i) & 1) continue; - set_irq_chip_and_handler(i, &pyxis_irq_type, handle_level_irq); - irq_to_desc(i)->status |= IRQ_LEVEL; + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[i].chip = &pyxis_irq_type; } setup_irq(16+7, &isa_cascade_irqaction); diff --git a/trunk/arch/alpha/kernel/irq_srm.c b/trunk/arch/alpha/kernel/irq_srm.c index 0e57e828b413..d63e93e1e8bf 100644 --- a/trunk/arch/alpha/kernel/irq_srm.c +++ b/trunk/arch/alpha/kernel/irq_srm.c @@ -33,12 +33,29 @@ srm_disable_irq(unsigned int irq) spin_unlock(&srm_irq_lock); } +static unsigned int +srm_startup_irq(unsigned int irq) +{ + srm_enable_irq(irq); + return 0; +} + +static void +srm_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + srm_enable_irq(irq); +} + /* Handle interrupts from the SRM, assuming no additional weirdness. */ static struct irq_chip srm_irq_type = { .name = "SRM", - .unmask = srm_enable_irq, - .mask = srm_disable_irq, - .mask_ack = srm_disable_irq, + .startup = srm_startup_irq, + .shutdown = srm_disable_irq, + .enable = srm_enable_irq, + .disable = srm_disable_irq, + .ack = srm_disable_irq, + .end = srm_end_irq, }; void __init @@ -51,8 +68,8 @@ init_srm_irqs(long max, unsigned long ignore_mask) for (i = 16; i < max; ++i) { if (i < 64 && ((ignore_mask >> i) & 1)) continue; - set_irq_chip_and_handler(i, &srm_irq_type, handle_level_irq); - irq_to_desc(i)->status |= IRQ_LEVEL; + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[i].chip = &srm_irq_type; } } diff --git a/trunk/arch/alpha/kernel/osf_sys.c b/trunk/arch/alpha/kernel/osf_sys.c index fe698b5045e9..547e8b84b2f7 100644 --- a/trunk/arch/alpha/kernel/osf_sys.c +++ b/trunk/arch/alpha/kernel/osf_sys.c @@ -951,6 +951,9 @@ SYSCALL_DEFINE2(osf_utimes, const char __user *, filename, return do_utimes(AT_FDCWD, filename, tvs ? tv : NULL, 0); } +#define MAX_SELECT_SECONDS \ + ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1) + SYSCALL_DEFINE5(osf_select, int, n, fd_set __user *, inp, fd_set __user *, outp, fd_set __user *, exp, struct timeval32 __user *, tvp) { diff --git a/trunk/arch/alpha/kernel/sys_alcor.c b/trunk/arch/alpha/kernel/sys_alcor.c index 7bef61768236..20a30b8b9655 100644 --- a/trunk/arch/alpha/kernel/sys_alcor.c +++ b/trunk/arch/alpha/kernel/sys_alcor.c @@ -65,6 +65,13 @@ alcor_mask_and_ack_irq(unsigned int irq) *(vuip)GRU_INT_CLEAR = 0; mb(); } +static unsigned int +alcor_startup_irq(unsigned int irq) +{ + alcor_enable_irq(irq); + return 0; +} + static void alcor_isa_mask_and_ack_irq(unsigned int irq) { @@ -75,11 +82,21 @@ alcor_isa_mask_and_ack_irq(unsigned int irq) *(vuip)GRU_INT_CLEAR = 0; mb(); } +static void +alcor_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + alcor_enable_irq(irq); +} + static struct irq_chip alcor_irq_type = { .name = "ALCOR", - .unmask = alcor_enable_irq, - .mask = alcor_disable_irq, - .mask_ack = alcor_mask_and_ack_irq, + .startup = alcor_startup_irq, + .shutdown = alcor_disable_irq, + .enable = alcor_enable_irq, + .disable = alcor_disable_irq, + .ack = alcor_mask_and_ack_irq, + .end = alcor_end_irq, }; static void @@ -125,8 +142,8 @@ alcor_init_irq(void) on while IRQ probing. */ if (i >= 16+20 && i <= 16+30) continue; - set_irq_chip_and_handler(i, &alcor_irq_type, handle_level_irq); - irq_to_desc(i)->status |= IRQ_LEVEL; + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[i].chip = &alcor_irq_type; } i8259a_irq_type.ack = alcor_isa_mask_and_ack_irq; diff --git a/trunk/arch/alpha/kernel/sys_cabriolet.c b/trunk/arch/alpha/kernel/sys_cabriolet.c index b0c916493aea..14c8898d19ec 100644 --- a/trunk/arch/alpha/kernel/sys_cabriolet.c +++ b/trunk/arch/alpha/kernel/sys_cabriolet.c @@ -57,11 +57,28 @@ cabriolet_disable_irq(unsigned int irq) cabriolet_update_irq_hw(irq, cached_irq_mask |= 1UL << irq); } +static unsigned int +cabriolet_startup_irq(unsigned int irq) +{ + cabriolet_enable_irq(irq); + return 0; /* never anything pending */ +} + +static void +cabriolet_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + cabriolet_enable_irq(irq); +} + static struct irq_chip cabriolet_irq_type = { .name = "CABRIOLET", - .unmask = cabriolet_enable_irq, - .mask = cabriolet_disable_irq, - .mask_ack = cabriolet_disable_irq, + .startup = cabriolet_startup_irq, + .shutdown = cabriolet_disable_irq, + .enable = cabriolet_enable_irq, + .disable = cabriolet_disable_irq, + .ack = cabriolet_disable_irq, + .end = cabriolet_end_irq, }; static void @@ -105,9 +122,8 @@ common_init_irq(void (*srm_dev_int)(unsigned long v)) outb(0xff, 0x806); for (i = 16; i < 35; ++i) { - set_irq_chip_and_handler(i, &cabriolet_irq_type, - handle_level_irq); - irq_to_desc(i)->status |= IRQ_LEVEL; + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[i].chip = &cabriolet_irq_type; } } diff --git a/trunk/arch/alpha/kernel/sys_dp264.c b/trunk/arch/alpha/kernel/sys_dp264.c index edad5f759ccd..4026502ab707 100644 --- a/trunk/arch/alpha/kernel/sys_dp264.c +++ b/trunk/arch/alpha/kernel/sys_dp264.c @@ -115,6 +115,20 @@ dp264_disable_irq(unsigned int irq) spin_unlock(&dp264_irq_lock); } +static unsigned int +dp264_startup_irq(unsigned int irq) +{ + dp264_enable_irq(irq); + return 0; /* never anything pending */ +} + +static void +dp264_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + dp264_enable_irq(irq); +} + static void clipper_enable_irq(unsigned int irq) { @@ -133,6 +147,20 @@ clipper_disable_irq(unsigned int irq) spin_unlock(&dp264_irq_lock); } +static unsigned int +clipper_startup_irq(unsigned int irq) +{ + clipper_enable_irq(irq); + return 0; /* never anything pending */ +} + +static void +clipper_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + clipper_enable_irq(irq); +} + static void cpu_set_irq_affinity(unsigned int irq, cpumask_t affinity) { @@ -172,17 +200,23 @@ clipper_set_affinity(unsigned int irq, const struct cpumask *affinity) static struct irq_chip dp264_irq_type = { .name = "DP264", - .unmask = dp264_enable_irq, - .mask = dp264_disable_irq, - .mask_ack = dp264_disable_irq, + .startup = dp264_startup_irq, + .shutdown = dp264_disable_irq, + .enable = dp264_enable_irq, + .disable = dp264_disable_irq, + .ack = dp264_disable_irq, + .end = dp264_end_irq, .set_affinity = dp264_set_affinity, }; static struct irq_chip clipper_irq_type = { .name = "CLIPPER", - .unmask = clipper_enable_irq, - .mask = clipper_disable_irq, - .mask_ack = clipper_disable_irq, + .startup = clipper_startup_irq, + .shutdown = clipper_disable_irq, + .enable = clipper_enable_irq, + .disable = clipper_disable_irq, + .ack = clipper_disable_irq, + .end = clipper_end_irq, .set_affinity = clipper_set_affinity, }; @@ -268,8 +302,8 @@ init_tsunami_irqs(struct irq_chip * ops, int imin, int imax) { long i; for (i = imin; i <= imax; ++i) { - irq_to_desc(i)->status |= IRQ_LEVEL; - set_irq_chip_and_handler(i, ops, handle_level_irq); + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[i].chip = ops; } } diff --git a/trunk/arch/alpha/kernel/sys_eb64p.c b/trunk/arch/alpha/kernel/sys_eb64p.c index ae5f29d127b0..df2090ce5e7f 100644 --- a/trunk/arch/alpha/kernel/sys_eb64p.c +++ b/trunk/arch/alpha/kernel/sys_eb64p.c @@ -55,11 +55,28 @@ eb64p_disable_irq(unsigned int irq) eb64p_update_irq_hw(irq, cached_irq_mask |= 1 << irq); } +static unsigned int +eb64p_startup_irq(unsigned int irq) +{ + eb64p_enable_irq(irq); + return 0; /* never anything pending */ +} + +static void +eb64p_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + eb64p_enable_irq(irq); +} + static struct irq_chip eb64p_irq_type = { .name = "EB64P", - .unmask = eb64p_enable_irq, - .mask = eb64p_disable_irq, - .mask_ack = eb64p_disable_irq, + .startup = eb64p_startup_irq, + .shutdown = eb64p_disable_irq, + .enable = eb64p_enable_irq, + .disable = eb64p_disable_irq, + .ack = eb64p_disable_irq, + .end = eb64p_end_irq, }; static void @@ -118,8 +135,8 @@ eb64p_init_irq(void) init_i8259a_irqs(); for (i = 16; i < 32; ++i) { - irq_to_desc(i)->status |= IRQ_LEVEL; - set_irq_chip_and_handler(i, &eb64p_irq_type, handle_level_irq); + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[i].chip = &eb64p_irq_type; } common_init_isa_dma(); diff --git a/trunk/arch/alpha/kernel/sys_eiger.c b/trunk/arch/alpha/kernel/sys_eiger.c index 1121bc5c6c6c..3ca1dbcf4044 100644 --- a/trunk/arch/alpha/kernel/sys_eiger.c +++ b/trunk/arch/alpha/kernel/sys_eiger.c @@ -66,11 +66,28 @@ eiger_disable_irq(unsigned int irq) eiger_update_irq_hw(irq, mask); } +static unsigned int +eiger_startup_irq(unsigned int irq) +{ + eiger_enable_irq(irq); + return 0; /* never anything pending */ +} + +static void +eiger_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + eiger_enable_irq(irq); +} + static struct irq_chip eiger_irq_type = { .name = "EIGER", - .unmask = eiger_enable_irq, - .mask = eiger_disable_irq, - .mask_ack = eiger_disable_irq, + .startup = eiger_startup_irq, + .shutdown = eiger_disable_irq, + .enable = eiger_enable_irq, + .disable = eiger_disable_irq, + .ack = eiger_disable_irq, + .end = eiger_end_irq, }; static void @@ -136,8 +153,8 @@ eiger_init_irq(void) init_i8259a_irqs(); for (i = 16; i < 128; ++i) { - irq_to_desc(i)->status |= IRQ_LEVEL; - set_irq_chip_and_handler(i, &eiger_irq_type, handle_level_irq); + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[i].chip = &eiger_irq_type; } } diff --git a/trunk/arch/alpha/kernel/sys_jensen.c b/trunk/arch/alpha/kernel/sys_jensen.c index 34f55e03d331..7a7ae36fff91 100644 --- a/trunk/arch/alpha/kernel/sys_jensen.c +++ b/trunk/arch/alpha/kernel/sys_jensen.c @@ -62,6 +62,30 @@ * world. */ +static unsigned int +jensen_local_startup(unsigned int irq) +{ + /* the parport is really hw IRQ 1, silly Jensen. */ + if (irq == 7) + i8259a_startup_irq(1); + else + /* + * For all true local interrupts, set the flag that prevents + * the IPL from being dropped during handler processing. + */ + if (irq_desc[irq].action) + irq_desc[irq].action->flags |= IRQF_DISABLED; + return 0; +} + +static void +jensen_local_shutdown(unsigned int irq) +{ + /* the parport is really hw IRQ 1, silly Jensen. */ + if (irq == 7) + i8259a_disable_irq(1); +} + static void jensen_local_enable(unsigned int irq) { @@ -79,18 +103,29 @@ jensen_local_disable(unsigned int irq) } static void -jensen_local_mask_ack(unsigned int irq) +jensen_local_ack(unsigned int irq) { /* the parport is really hw IRQ 1, silly Jensen. */ if (irq == 7) i8259a_mask_and_ack_irq(1); } +static void +jensen_local_end(unsigned int irq) +{ + /* the parport is really hw IRQ 1, silly Jensen. */ + if (irq == 7) + i8259a_end_irq(1); +} + static struct irq_chip jensen_local_irq_type = { .name = "LOCAL", - .unmask = jensen_local_enable, - .mask = jensen_local_disable, - .mask_ack = jensen_local_mask_ack, + .startup = jensen_local_startup, + .shutdown = jensen_local_shutdown, + .enable = jensen_local_enable, + .disable = jensen_local_disable, + .ack = jensen_local_ack, + .end = jensen_local_end, }; static void @@ -123,7 +158,7 @@ jensen_device_interrupt(unsigned long vector) } /* If there is no handler yet... */ - if (!irq_has_action(irq)) { + if (irq_desc[irq].action == NULL) { /* If it is a local interrupt that cannot be masked... */ if (vector >= 0x900) { @@ -171,11 +206,11 @@ jensen_init_irq(void) { init_i8259a_irqs(); - set_irq_chip_and_handler(1, &jensen_local_irq_type, handle_level_irq); - set_irq_chip_and_handler(4, &jensen_local_irq_type, handle_level_irq); - set_irq_chip_and_handler(3, &jensen_local_irq_type, handle_level_irq); - set_irq_chip_and_handler(7, &jensen_local_irq_type, handle_level_irq); - set_irq_chip_and_handler(9, &jensen_local_irq_type, handle_level_irq); + irq_desc[1].chip = &jensen_local_irq_type; + irq_desc[4].chip = &jensen_local_irq_type; + irq_desc[3].chip = &jensen_local_irq_type; + irq_desc[7].chip = &jensen_local_irq_type; + irq_desc[9].chip = &jensen_local_irq_type; common_init_isa_dma(); } diff --git a/trunk/arch/alpha/kernel/sys_marvel.c b/trunk/arch/alpha/kernel/sys_marvel.c index 2bfc9f1b1ddc..0bb3b5c4f693 100644 --- a/trunk/arch/alpha/kernel/sys_marvel.c +++ b/trunk/arch/alpha/kernel/sys_marvel.c @@ -143,6 +143,20 @@ io7_disable_irq(unsigned int irq) spin_unlock(&io7->irq_lock); } +static unsigned int +io7_startup_irq(unsigned int irq) +{ + io7_enable_irq(irq); + return 0; /* never anything pending */ +} + +static void +io7_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + io7_enable_irq(irq); +} + static void marvel_irq_noop(unsigned int irq) { @@ -157,22 +171,32 @@ marvel_irq_noop_return(unsigned int irq) static struct irq_chip marvel_legacy_irq_type = { .name = "LEGACY", - .mask = marvel_irq_noop, - .unmask = marvel_irq_noop, + .startup = marvel_irq_noop_return, + .shutdown = marvel_irq_noop, + .enable = marvel_irq_noop, + .disable = marvel_irq_noop, + .ack = marvel_irq_noop, + .end = marvel_irq_noop, }; static struct irq_chip io7_lsi_irq_type = { .name = "LSI", - .unmask = io7_enable_irq, - .mask = io7_disable_irq, - .mask_ack = io7_disable_irq, + .startup = io7_startup_irq, + .shutdown = io7_disable_irq, + .enable = io7_enable_irq, + .disable = io7_disable_irq, + .ack = io7_disable_irq, + .end = io7_end_irq, }; static struct irq_chip io7_msi_irq_type = { .name = "MSI", - .unmask = io7_enable_irq, - .mask = io7_disable_irq, + .startup = io7_startup_irq, + .shutdown = io7_disable_irq, + .enable = io7_enable_irq, + .disable = io7_disable_irq, .ack = marvel_irq_noop, + .end = io7_end_irq, }; static void @@ -280,8 +304,8 @@ init_io7_irqs(struct io7 *io7, /* Set up the lsi irqs. */ for (i = 0; i < 128; ++i) { - irq_to_desc(base + i)->status |= IRQ_LEVEL; - set_irq_chip_and_handler(base + i, lsi_ops, handle_level_irq); + irq_desc[base + i].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[base + i].chip = lsi_ops; } /* Disable the implemented irqs in hardware. */ @@ -294,8 +318,8 @@ init_io7_irqs(struct io7 *io7, /* Set up the msi irqs. */ for (i = 128; i < (128 + 512); ++i) { - irq_to_desc(base + i)->status |= IRQ_LEVEL; - set_irq_chip_and_handler(base + i, msi_ops, handle_level_irq); + irq_desc[base + i].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[base + i].chip = msi_ops; } for (i = 0; i < 16; ++i) @@ -312,8 +336,8 @@ marvel_init_irq(void) /* Reserve the legacy irqs. */ for (i = 0; i < 16; ++i) { - set_irq_chip_and_handler(i, &marvel_legacy_irq_type, - handle_level_irq); + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].chip = &marvel_legacy_irq_type; } /* Init the io7 irqs. */ diff --git a/trunk/arch/alpha/kernel/sys_mikasa.c b/trunk/arch/alpha/kernel/sys_mikasa.c index bcc1639e8efb..ee8865169811 100644 --- a/trunk/arch/alpha/kernel/sys_mikasa.c +++ b/trunk/arch/alpha/kernel/sys_mikasa.c @@ -54,11 +54,28 @@ mikasa_disable_irq(unsigned int irq) mikasa_update_irq_hw(cached_irq_mask &= ~(1 << (irq - 16))); } +static unsigned int +mikasa_startup_irq(unsigned int irq) +{ + mikasa_enable_irq(irq); + return 0; +} + +static void +mikasa_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + mikasa_enable_irq(irq); +} + static struct irq_chip mikasa_irq_type = { .name = "MIKASA", - .unmask = mikasa_enable_irq, - .mask = mikasa_disable_irq, - .mask_ack = mikasa_disable_irq, + .startup = mikasa_startup_irq, + .shutdown = mikasa_disable_irq, + .enable = mikasa_enable_irq, + .disable = mikasa_disable_irq, + .ack = mikasa_disable_irq, + .end = mikasa_end_irq, }; static void @@ -98,8 +115,8 @@ mikasa_init_irq(void) mikasa_update_irq_hw(0); for (i = 16; i < 32; ++i) { - irq_to_desc(i)->status |= IRQ_LEVEL; - set_irq_chip_and_handler(i, &mikasa_irq_type, handle_level_irq); + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[i].chip = &mikasa_irq_type; } init_i8259a_irqs(); diff --git a/trunk/arch/alpha/kernel/sys_noritake.c b/trunk/arch/alpha/kernel/sys_noritake.c index e88f4ae1260e..86503fe73a88 100644 --- a/trunk/arch/alpha/kernel/sys_noritake.c +++ b/trunk/arch/alpha/kernel/sys_noritake.c @@ -59,11 +59,28 @@ noritake_disable_irq(unsigned int irq) noritake_update_irq_hw(irq, cached_irq_mask &= ~(1 << (irq - 16))); } +static unsigned int +noritake_startup_irq(unsigned int irq) +{ + noritake_enable_irq(irq); + return 0; +} + +static void +noritake_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + noritake_enable_irq(irq); +} + static struct irq_chip noritake_irq_type = { .name = "NORITAKE", - .unmask = noritake_enable_irq, - .mask = noritake_disable_irq, - .mask_ack = noritake_disable_irq, + .startup = noritake_startup_irq, + .shutdown = noritake_disable_irq, + .enable = noritake_enable_irq, + .disable = noritake_disable_irq, + .ack = noritake_disable_irq, + .end = noritake_end_irq, }; static void @@ -127,8 +144,8 @@ noritake_init_irq(void) outw(0, 0x54c); for (i = 16; i < 48; ++i) { - irq_to_desc(i)->status |= IRQ_LEVEL; - set_irq_chip_and_handler(i, &noritake_irq_type, handle_level_irq); + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[i].chip = &noritake_irq_type; } init_i8259a_irqs(); diff --git a/trunk/arch/alpha/kernel/sys_rawhide.c b/trunk/arch/alpha/kernel/sys_rawhide.c index 6a51364dd1cc..26c322bf89ee 100644 --- a/trunk/arch/alpha/kernel/sys_rawhide.c +++ b/trunk/arch/alpha/kernel/sys_rawhide.c @@ -121,11 +121,28 @@ rawhide_mask_and_ack_irq(unsigned int irq) spin_unlock(&rawhide_irq_lock); } +static unsigned int +rawhide_startup_irq(unsigned int irq) +{ + rawhide_enable_irq(irq); + return 0; +} + +static void +rawhide_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + rawhide_enable_irq(irq); +} + static struct irq_chip rawhide_irq_type = { .name = "RAWHIDE", - .unmask = rawhide_enable_irq, - .mask = rawhide_disable_irq, - .mask_ack = rawhide_mask_and_ack_irq, + .startup = rawhide_startup_irq, + .shutdown = rawhide_disable_irq, + .enable = rawhide_enable_irq, + .disable = rawhide_disable_irq, + .ack = rawhide_mask_and_ack_irq, + .end = rawhide_end_irq, }; static void @@ -177,8 +194,8 @@ rawhide_init_irq(void) } for (i = 16; i < 128; ++i) { - irq_to_desc(i)->status |= IRQ_LEVEL; - set_irq_chip_and_handler(i, &rawhide_irq_type, handle_level_irq); + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[i].chip = &rawhide_irq_type; } init_i8259a_irqs(); diff --git a/trunk/arch/alpha/kernel/sys_rx164.c b/trunk/arch/alpha/kernel/sys_rx164.c index 89e7e37ec84c..be161129eab9 100644 --- a/trunk/arch/alpha/kernel/sys_rx164.c +++ b/trunk/arch/alpha/kernel/sys_rx164.c @@ -58,11 +58,28 @@ rx164_disable_irq(unsigned int irq) rx164_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16))); } +static unsigned int +rx164_startup_irq(unsigned int irq) +{ + rx164_enable_irq(irq); + return 0; +} + +static void +rx164_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + rx164_enable_irq(irq); +} + static struct irq_chip rx164_irq_type = { .name = "RX164", - .unmask = rx164_enable_irq, - .mask = rx164_disable_irq, - .mask_ack = rx164_disable_irq, + .startup = rx164_startup_irq, + .shutdown = rx164_disable_irq, + .enable = rx164_enable_irq, + .disable = rx164_disable_irq, + .ack = rx164_disable_irq, + .end = rx164_end_irq, }; static void @@ -99,8 +116,8 @@ rx164_init_irq(void) rx164_update_irq_hw(0); for (i = 16; i < 40; ++i) { - irq_to_desc(i)->status |= IRQ_LEVEL; - set_irq_chip_and_handler(i, &rx164_irq_type, handle_level_irq); + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[i].chip = &rx164_irq_type; } init_i8259a_irqs(); diff --git a/trunk/arch/alpha/kernel/sys_sable.c b/trunk/arch/alpha/kernel/sys_sable.c index 5c4423d1b06c..b2abe27a23cf 100644 --- a/trunk/arch/alpha/kernel/sys_sable.c +++ b/trunk/arch/alpha/kernel/sys_sable.c @@ -474,6 +474,20 @@ sable_lynx_disable_irq(unsigned int irq) #endif } +static unsigned int +sable_lynx_startup_irq(unsigned int irq) +{ + sable_lynx_enable_irq(irq); + return 0; +} + +static void +sable_lynx_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + sable_lynx_enable_irq(irq); +} + static void sable_lynx_mask_and_ack_irq(unsigned int irq) { @@ -489,9 +503,12 @@ sable_lynx_mask_and_ack_irq(unsigned int irq) static struct irq_chip sable_lynx_irq_type = { .name = "SABLE/LYNX", - .unmask = sable_lynx_enable_irq, - .mask = sable_lynx_disable_irq, - .mask_ack = sable_lynx_mask_and_ack_irq, + .startup = sable_lynx_startup_irq, + .shutdown = sable_lynx_disable_irq, + .enable = sable_lynx_enable_irq, + .disable = sable_lynx_disable_irq, + .ack = sable_lynx_mask_and_ack_irq, + .end = sable_lynx_end_irq, }; static void @@ -518,9 +535,8 @@ sable_lynx_init_irq(int nr_of_irqs) long i; for (i = 0; i < nr_of_irqs; ++i) { - irq_to_desc(i)->status |= IRQ_LEVEL; - set_irq_chip_and_handler(i, &sable_lynx_irq_type, - handle_level_irq); + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[i].chip = &sable_lynx_irq_type; } common_init_isa_dma(); diff --git a/trunk/arch/alpha/kernel/sys_takara.c b/trunk/arch/alpha/kernel/sys_takara.c index f8a1e8a862fb..4da596b6adbb 100644 --- a/trunk/arch/alpha/kernel/sys_takara.c +++ b/trunk/arch/alpha/kernel/sys_takara.c @@ -60,11 +60,28 @@ takara_disable_irq(unsigned int irq) takara_update_irq_hw(irq, mask); } +static unsigned int +takara_startup_irq(unsigned int irq) +{ + takara_enable_irq(irq); + return 0; /* never anything pending */ +} + +static void +takara_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + takara_enable_irq(irq); +} + static struct irq_chip takara_irq_type = { .name = "TAKARA", - .unmask = takara_enable_irq, - .mask = takara_disable_irq, - .mask_ack = takara_disable_irq, + .startup = takara_startup_irq, + .shutdown = takara_disable_irq, + .enable = takara_enable_irq, + .disable = takara_disable_irq, + .ack = takara_disable_irq, + .end = takara_end_irq, }; static void @@ -136,8 +153,8 @@ takara_init_irq(void) takara_update_irq_hw(i, -1); for (i = 16; i < 128; ++i) { - irq_to_desc(i)->status |= IRQ_LEVEL; - set_irq_chip_and_handler(i, &takara_irq_type, handle_level_irq); + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[i].chip = &takara_irq_type; } common_init_isa_dma(); diff --git a/trunk/arch/alpha/kernel/sys_titan.c b/trunk/arch/alpha/kernel/sys_titan.c index e02494bf5ef3..9008d0f20c53 100644 --- a/trunk/arch/alpha/kernel/sys_titan.c +++ b/trunk/arch/alpha/kernel/sys_titan.c @@ -129,6 +129,20 @@ titan_disable_irq(unsigned int irq) spin_unlock(&titan_irq_lock); } +static unsigned int +titan_startup_irq(unsigned int irq) +{ + titan_enable_irq(irq); + return 0; /* never anything pending */ +} + +static void +titan_end_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + titan_enable_irq(irq); +} + static void titan_cpu_set_irq_affinity(unsigned int irq, cpumask_t affinity) { @@ -175,17 +189,20 @@ init_titan_irqs(struct irq_chip * ops, int imin, int imax) { long i; for (i = imin; i <= imax; ++i) { - irq_to_desc(i)->status |= IRQ_LEVEL; - set_irq_chip_and_handler(i, ops, handle_level_irq); + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[i].chip = ops; } } static struct irq_chip titan_irq_type = { - .name = "TITAN", - .unmask = titan_enable_irq, - .mask = titan_disable_irq, - .mask_ack = titan_disable_irq, - .set_affinity = titan_set_irq_affinity, + .name = "TITAN", + .startup = titan_startup_irq, + .shutdown = titan_disable_irq, + .enable = titan_enable_irq, + .disable = titan_disable_irq, + .ack = titan_disable_irq, + .end = titan_end_irq, + .set_affinity = titan_set_irq_affinity, }; static irqreturn_t diff --git a/trunk/arch/alpha/kernel/sys_wildfire.c b/trunk/arch/alpha/kernel/sys_wildfire.c index eec52594d410..62fd972e18ef 100644 --- a/trunk/arch/alpha/kernel/sys_wildfire.c +++ b/trunk/arch/alpha/kernel/sys_wildfire.c @@ -139,11 +139,32 @@ wildfire_mask_and_ack_irq(unsigned int irq) spin_unlock(&wildfire_irq_lock); } +static unsigned int +wildfire_startup_irq(unsigned int irq) +{ + wildfire_enable_irq(irq); + return 0; /* never anything pending */ +} + +static void +wildfire_end_irq(unsigned int irq) +{ +#if 0 + if (!irq_desc[irq].action) + printk("got irq %d\n", irq); +#endif + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + wildfire_enable_irq(irq); +} + static struct irq_chip wildfire_irq_type = { .name = "WILDFIRE", - .unmask = wildfire_enable_irq, - .mask = wildfire_disable_irq, - .mask_ack = wildfire_mask_and_ack_irq, + .startup = wildfire_startup_irq, + .shutdown = wildfire_disable_irq, + .enable = wildfire_enable_irq, + .disable = wildfire_disable_irq, + .ack = wildfire_mask_and_ack_irq, + .end = wildfire_end_irq, }; static void __init @@ -177,18 +198,15 @@ wildfire_init_irq_per_pca(int qbbno, int pcano) for (i = 0; i < 16; ++i) { if (i == 2) continue; - irq_to_desc(i+irq_bias)->status |= IRQ_LEVEL; - set_irq_chip_and_handler(i+irq_bias, &wildfire_irq_type, - handle_level_irq); + irq_desc[i+irq_bias].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[i+irq_bias].chip = &wildfire_irq_type; } - irq_to_desc(36+irq_bias)->status |= IRQ_LEVEL; - set_irq_chip_and_handler(36+irq_bias, &wildfire_irq_type, - handle_level_irq); + irq_desc[36+irq_bias].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[36+irq_bias].chip = &wildfire_irq_type; for (i = 40; i < 64; ++i) { - irq_to_desc(i+irq_bias)->status |= IRQ_LEVEL; - set_irq_chip_and_handler(i+irq_bias, &wildfire_irq_type, - handle_level_irq); + irq_desc[i+irq_bias].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[i+irq_bias].chip = &wildfire_irq_type; } setup_irq(32+irq_bias, &isa_enable); diff --git a/trunk/arch/alpha/lib/Makefile b/trunk/arch/alpha/lib/Makefile index c0a83ab62b78..9b72c59c95be 100644 --- a/trunk/arch/alpha/lib/Makefile +++ b/trunk/arch/alpha/lib/Makefile @@ -2,8 +2,8 @@ # Makefile for alpha-specific library files.. # -asflags-y := $(KBUILD_CFLAGS) -ccflags-y := -Werror +EXTRA_AFLAGS := $(KBUILD_CFLAGS) +EXTRA_CFLAGS := -Werror # Many of these routines have implementations tuned for ev6. # Choose them iff we're targeting ev6 specifically. diff --git a/trunk/arch/alpha/math-emu/Makefile b/trunk/arch/alpha/math-emu/Makefile index 7f4671995245..359ef087e69e 100644 --- a/trunk/arch/alpha/math-emu/Makefile +++ b/trunk/arch/alpha/math-emu/Makefile @@ -2,7 +2,7 @@ # Makefile for the FPU instruction emulation. # -ccflags-y := -w +EXTRA_CFLAGS := -w obj-$(CONFIG_MATHEMU) += math-emu.o diff --git a/trunk/arch/alpha/mm/Makefile b/trunk/arch/alpha/mm/Makefile index c993d3f93cf6..09399c5386cb 100644 --- a/trunk/arch/alpha/mm/Makefile +++ b/trunk/arch/alpha/mm/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux alpha-specific parts of the memory manager. # -ccflags-y := -Werror +EXTRA_CFLAGS := -Werror obj-y := init.o fault.o extable.o diff --git a/trunk/arch/alpha/oprofile/Makefile b/trunk/arch/alpha/oprofile/Makefile index 3473de751b03..4aa56247bdc6 100644 --- a/trunk/arch/alpha/oprofile/Makefile +++ b/trunk/arch/alpha/oprofile/Makefile @@ -1,4 +1,4 @@ -ccflags-y := -Werror -Wno-sign-compare +EXTRA_CFLAGS := -Werror -Wno-sign-compare obj-$(CONFIG_OPROFILE) += oprofile.o diff --git a/trunk/arch/arm/mach-omap1/board-ams-delta.c b/trunk/arch/arm/mach-omap1/board-ams-delta.c index 22cc8c8df6cb..bd0495a9ac3b 100644 --- a/trunk/arch/arm/mach-omap1/board-ams-delta.c +++ b/trunk/arch/arm/mach-omap1/board-ams-delta.c @@ -179,22 +179,6 @@ static struct omap_board_config_kernel ams_delta_config[] = { { OMAP_TAG_LCD, &ams_delta_lcd_config }, }; -static struct resource ams_delta_nand_resources[] = { - [0] = { - .start = OMAP1_MPUIO_BASE, - .end = OMAP1_MPUIO_BASE + - OMAP_MPUIO_IO_CNTL + sizeof(u32) - 1, - .flags = IORESOURCE_MEM, - }, -}; - -static struct platform_device ams_delta_nand_device = { - .name = "ams-delta-nand", - .id = -1, - .num_resources = ARRAY_SIZE(ams_delta_nand_resources), - .resource = ams_delta_nand_resources, -}; - static struct resource ams_delta_kp_resources[] = { [0] = { .start = INT_KEYBOARD, @@ -281,7 +265,6 @@ static struct omap1_cam_platform_data ams_delta_camera_platform_data = { }; static struct platform_device *ams_delta_devices[] __initdata = { - &ams_delta_nand_device, &ams_delta_kp_device, &ams_delta_lcd_device, &ams_delta_led_device, diff --git a/trunk/arch/arm/plat-nomadik/include/plat/ste_dma40.h b/trunk/arch/arm/plat-nomadik/include/plat/ste_dma40.h index 4d6dd4c39b75..74b62f10d07f 100644 --- a/trunk/arch/arm/plat-nomadik/include/plat/ste_dma40.h +++ b/trunk/arch/arm/plat-nomadik/include/plat/ste_dma40.h @@ -13,14 +13,6 @@ #include #include -/* - * Maxium size for a single dma descriptor - * Size is limited to 16 bits. - * Size is in the units of addr-widths (1,2,4,8 bytes) - * Larger transfers will be split up to multiple linked desc - */ -#define STEDMA40_MAX_SEG_SIZE 0xFFFF - /* dev types for memcpy */ #define STEDMA40_DEV_DST_MEMORY (-1) #define STEDMA40_DEV_SRC_MEMORY (-1) diff --git a/trunk/arch/arm/plat-omap/include/plat/onenand.h b/trunk/arch/arm/plat-omap/include/plat/onenand.h index affe87e9ece7..72f433d7d827 100644 --- a/trunk/arch/arm/plat-omap/include/plat/onenand.h +++ b/trunk/arch/arm/plat-omap/include/plat/onenand.h @@ -23,7 +23,6 @@ struct omap_onenand_platform_data { int (*onenand_setup)(void __iomem *, int freq); int dma_channel; u8 flags; - u8 regulator_can_sleep; }; #define ONENAND_MAX_PARTITIONS 8 diff --git a/trunk/arch/microblaze/kernel/prom.c b/trunk/arch/microblaze/kernel/prom.c index c881393f07fd..bceaa5543e39 100644 --- a/trunk/arch/microblaze/kernel/prom.c +++ b/trunk/arch/microblaze/kernel/prom.c @@ -47,9 +47,9 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size) memblock_add(base, size); } -u64 __init early_init_dt_alloc_memory_arch(u64 size, u64 align) +void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) { - return memblock_alloc(size, align); + return __va(memblock_alloc(size, align)); } #ifdef CONFIG_EARLY_PRINTK diff --git a/trunk/arch/mips/kernel/prom.c b/trunk/arch/mips/kernel/prom.c index 9dbe58368953..a19811e98a41 100644 --- a/trunk/arch/mips/kernel/prom.c +++ b/trunk/arch/mips/kernel/prom.c @@ -45,11 +45,9 @@ void __init free_mem_mach(unsigned long addr, unsigned long size) return free_bootmem(addr, size); } -u64 __init early_init_dt_alloc_memory_arch(u64 size, u64 align) +void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) { - return virt_to_phys( - __alloc_bootmem(size, align, __pa(MAX_DMA_ADDRESS)) - ); + return __alloc_bootmem(size, align, __pa(MAX_DMA_ADDRESS)); } #ifdef CONFIG_BLK_DEV_INITRD diff --git a/trunk/arch/parisc/include/asm/pgtable.h b/trunk/arch/parisc/include/asm/pgtable.h index 6f1f65d3c0ef..865f37a8a881 100644 --- a/trunk/arch/parisc/include/asm/pgtable.h +++ b/trunk/arch/parisc/include/asm/pgtable.h @@ -10,13 +10,11 @@ * we simulate an x86-style page table for the linux mm code */ +#include /* for vm_area_struct */ #include -#include #include #include -struct vm_area_struct; - /* * kern_addr_valid(ADDR) tests if ADDR is pointing to valid kernel * memory. For the return value to be meaningful, ADDR must be >= diff --git a/trunk/arch/powerpc/kernel/prom.c b/trunk/arch/powerpc/kernel/prom.c index 9e3132db718b..7185f0da7dc3 100644 --- a/trunk/arch/powerpc/kernel/prom.c +++ b/trunk/arch/powerpc/kernel/prom.c @@ -519,9 +519,9 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size) memblock_add(base, size); } -u64 __init early_init_dt_alloc_memory_arch(u64 size, u64 align) +void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) { - return memblock_alloc(size, align); + return __va(memblock_alloc(size, align)); } #ifdef CONFIG_BLK_DEV_INITRD diff --git a/trunk/drivers/acpi/apei/hest.c b/trunk/drivers/acpi/apei/hest.c index abda3786a5d7..4ee58e72b730 100644 --- a/trunk/drivers/acpi/apei/hest.c +++ b/trunk/drivers/acpi/apei/hest.c @@ -201,14 +201,14 @@ void __init acpi_hest_init(void) int rc = -ENODEV; unsigned int ghes_count = 0; + if (acpi_disabled) + return; + if (hest_disable) { pr_info(HEST_PFX "Table parsing disabled.\n"); return; } - if (acpi_disabled) - goto err; - status = acpi_get_table(ACPI_SIG_HEST, 0, (struct acpi_table_header **)&hest_tab); if (status == AE_NOT_FOUND) { diff --git a/trunk/drivers/acpi/pci_root.c b/trunk/drivers/acpi/pci_root.c index 85249395623b..d9766797cd98 100644 --- a/trunk/drivers/acpi/pci_root.c +++ b/trunk/drivers/acpi/pci_root.c @@ -633,11 +633,11 @@ static int acpi_pci_root_remove(struct acpi_device *device, int type) static int __init acpi_pci_root_init(void) { - acpi_hest_init(); - if (acpi_pci_disabled) return 0; + acpi_hest_init(); + pci_acpi_crs_quirks(); if (acpi_bus_register_driver(&acpi_pci_root_driver) < 0) return -ENODEV; diff --git a/trunk/drivers/dma/Kconfig b/trunk/drivers/dma/Kconfig index 1c28816152fa..ef138731c0ea 100644 --- a/trunk/drivers/dma/Kconfig +++ b/trunk/drivers/dma/Kconfig @@ -200,16 +200,11 @@ config PL330_DMA platform_data for a dma-pl330 device. config PCH_DMA - tristate "Intel EG20T PCH / OKI SEMICONDUCTOR ML7213 IOH DMA support" + tristate "Topcliff (Intel EG20T) PCH DMA support" depends on PCI && X86 select DMA_ENGINE help - Enable support for Intel EG20T PCH DMA engine. - - This driver also can be used for OKI SEMICONDUCTOR ML7213 IOH(Input/ - Output Hub) which is for IVI(In-Vehicle Infotainment) use. - ML7213 is companion chip for Intel Atom E6xx series. - ML7213 is completely compatible for Intel EG20T PCH. + Enable support for the Topcliff (Intel EG20T) PCH DMA engine. config IMX_SDMA tristate "i.MX SDMA support" diff --git a/trunk/drivers/dma/amba-pl08x.c b/trunk/drivers/dma/amba-pl08x.c index 297f48b0cba9..b605cc9ac3a2 100644 --- a/trunk/drivers/dma/amba-pl08x.c +++ b/trunk/drivers/dma/amba-pl08x.c @@ -19,14 +19,14 @@ * this program; if not, write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * The full GNU General Public License is in this distribution in the file - * called COPYING. + * The full GNU General Public License is iin this distribution in the + * file called COPYING. * * Documentation: ARM DDI 0196G == PL080 - * Documentation: ARM DDI 0218E == PL081 + * Documentation: ARM DDI 0218E == PL081 * - * PL080 & PL081 both have 16 sets of DMA signals that can be routed to any - * channel. + * PL080 & PL081 both have 16 sets of DMA signals that can be routed to + * any channel. * * The PL080 has 8 channels available for simultaneous use, and the PL081 * has only two channels. So on these DMA controllers the number of channels @@ -53,23 +53,7 @@ * * ASSUMES default (little) endianness for DMA transfers * - * The PL08x has two flow control settings: - * - DMAC flow control: the transfer size defines the number of transfers - * which occur for the current LLI entry, and the DMAC raises TC at the - * end of every LLI entry. Observed behaviour shows the DMAC listening - * to both the BREQ and SREQ signals (contrary to documented), - * transferring data if either is active. The LBREQ and LSREQ signals - * are ignored. - * - * - Peripheral flow control: the transfer size is ignored (and should be - * zero). The data is transferred from the current LLI entry, until - * after the final transfer signalled by LBREQ or LSREQ. The DMAC - * will then move to the next LLI entry. - * - * Only the former works sanely with scatter lists, so we only implement - * the DMAC flow control method. However, peripherals which use the LBREQ - * and LSREQ signals (eg, MMCI) are unable to use this mode, which through - * these hardware restrictions prevents them from using scatter DMA. + * Only DMAC flow control is implemented * * Global TODO: * - Break out common code from arch/arm/mach-s3c64xx and share @@ -77,39 +61,50 @@ #include #include #include +#include #include #include #include -#include #include +#include #include #include #include #include +#include +#include +#include +#include +#include #define DRIVER_NAME "pl08xdmac" /** - * struct vendor_data - vendor-specific config parameters for PL08x derivatives + * struct vendor_data - vendor-specific config parameters + * for PL08x derivates + * @name: the name of this specific variant * @channels: the number of channels available in this variant - * @dualmaster: whether this version supports dual AHB masters or not. + * @dualmaster: whether this version supports dual AHB masters + * or not. */ struct vendor_data { + char *name; u8 channels; bool dualmaster; }; /* * PL08X private data structures - * An LLI struct - see PL08x TRM. Note that next uses bit[0] as a bus bit, - * start & end do not - their bus bit info is in cctl. Also note that these - * are fixed 32-bit quantities. + * An LLI struct - see pl08x TRM + * Note that next uses bit[0] as a bus bit, + * start & end do not - their bus bit info + * is in cctl */ -struct pl08x_lli { - u32 src; - u32 dst; - u32 lli; +struct lli { + dma_addr_t src; + dma_addr_t dst; + dma_addr_t next; u32 cctl; }; @@ -124,8 +119,6 @@ struct pl08x_lli { * @phy_chans: array of data for the physical channels * @pool: a pool for the LLI descriptors * @pool_ctr: counter of LLIs in the pool - * @lli_buses: bitmask to or in to LLI pointer selecting AHB port for LLI fetches - * @mem_buses: set to indicate memory transfers on AHB2. * @lock: a spinlock for this struct */ struct pl08x_driver_data { @@ -133,13 +126,11 @@ struct pl08x_driver_data { struct dma_device memcpy; void __iomem *base; struct amba_device *adev; - const struct vendor_data *vd; + struct vendor_data *vd; struct pl08x_platform_data *pd; struct pl08x_phy_chan *phy_chans; struct dma_pool *pool; int pool_ctr; - u8 lli_buses; - u8 mem_buses; spinlock_t lock; }; @@ -161,9 +152,9 @@ struct pl08x_driver_data { /* Size (bytes) of each LLI buffer allocated for one transfer */ # define PL08X_LLI_TSFR_SIZE 0x2000 -/* Maximum times we call dma_pool_alloc on this pool without freeing */ +/* Maximimum times we call dma_pool_alloc on this pool without freeing */ #define PL08X_MAX_ALLOCS 0x40 -#define MAX_NUM_TSFR_LLIS (PL08X_LLI_TSFR_SIZE/sizeof(struct pl08x_lli)) +#define MAX_NUM_TSFR_LLIS (PL08X_LLI_TSFR_SIZE/sizeof(struct lli)) #define PL08X_ALIGN 8 static inline struct pl08x_dma_chan *to_pl08x_chan(struct dma_chan *chan) @@ -171,11 +162,6 @@ static inline struct pl08x_dma_chan *to_pl08x_chan(struct dma_chan *chan) return container_of(chan, struct pl08x_dma_chan, chan); } -static inline struct pl08x_txd *to_pl08x_txd(struct dma_async_tx_descriptor *tx) -{ - return container_of(tx, struct pl08x_txd, tx); -} - /* * Physical channel handling */ @@ -191,47 +177,88 @@ static int pl08x_phy_channel_busy(struct pl08x_phy_chan *ch) /* * Set the initial DMA register values i.e. those for the first LLI - * The next LLI pointer and the configuration interrupt bit have - * been set when the LLIs were constructed. Poke them into the hardware - * and start the transfer. + * The next lli pointer and the configuration interrupt bit have + * been set when the LLIs were constructed */ -static void pl08x_start_txd(struct pl08x_dma_chan *plchan, - struct pl08x_txd *txd) +static void pl08x_set_cregs(struct pl08x_driver_data *pl08x, + struct pl08x_phy_chan *ch) { - struct pl08x_driver_data *pl08x = plchan->host; + /* Wait for channel inactive */ + while (pl08x_phy_channel_busy(ch)) + ; + + dev_vdbg(&pl08x->adev->dev, + "WRITE channel %d: csrc=%08x, cdst=%08x, " + "cctl=%08x, clli=%08x, ccfg=%08x\n", + ch->id, + ch->csrc, + ch->cdst, + ch->cctl, + ch->clli, + ch->ccfg); + + writel(ch->csrc, ch->base + PL080_CH_SRC_ADDR); + writel(ch->cdst, ch->base + PL080_CH_DST_ADDR); + writel(ch->clli, ch->base + PL080_CH_LLI); + writel(ch->cctl, ch->base + PL080_CH_CONTROL); + writel(ch->ccfg, ch->base + PL080_CH_CONFIG); +} + +static inline void pl08x_config_phychan_for_txd(struct pl08x_dma_chan *plchan) +{ + struct pl08x_channel_data *cd = plchan->cd; struct pl08x_phy_chan *phychan = plchan->phychan; - struct pl08x_lli *lli = &txd->llis_va[0]; - u32 val; + struct pl08x_txd *txd = plchan->at; + + /* Copy the basic control register calculated at transfer config */ + phychan->csrc = txd->csrc; + phychan->cdst = txd->cdst; + phychan->clli = txd->clli; + phychan->cctl = txd->cctl; + + /* Assign the signal to the proper control registers */ + phychan->ccfg = cd->ccfg; + phychan->ccfg &= ~PL080_CONFIG_SRC_SEL_MASK; + phychan->ccfg &= ~PL080_CONFIG_DST_SEL_MASK; + /* If it wasn't set from AMBA, ignore it */ + if (txd->direction == DMA_TO_DEVICE) + /* Select signal as destination */ + phychan->ccfg |= + (phychan->signal << PL080_CONFIG_DST_SEL_SHIFT); + else if (txd->direction == DMA_FROM_DEVICE) + /* Select signal as source */ + phychan->ccfg |= + (phychan->signal << PL080_CONFIG_SRC_SEL_SHIFT); + /* Always enable error interrupts */ + phychan->ccfg |= PL080_CONFIG_ERR_IRQ_MASK; + /* Always enable terminal interrupts */ + phychan->ccfg |= PL080_CONFIG_TC_IRQ_MASK; +} - plchan->at = txd; +/* + * Enable the DMA channel + * Assumes all other configuration bits have been set + * as desired before this code is called + */ +static void pl08x_enable_phy_chan(struct pl08x_driver_data *pl08x, + struct pl08x_phy_chan *ch) +{ + u32 val; - /* Wait for channel inactive */ - while (pl08x_phy_channel_busy(phychan)) - cpu_relax(); + /* + * Do not access config register until channel shows as disabled + */ + while (readl(pl08x->base + PL080_EN_CHAN) & (1 << ch->id)) + ; - dev_vdbg(&pl08x->adev->dev, - "WRITE channel %d: csrc=0x%08x, cdst=0x%08x, " - "clli=0x%08x, cctl=0x%08x, ccfg=0x%08x\n", - phychan->id, lli->src, lli->dst, lli->lli, lli->cctl, - txd->ccfg); - - writel(lli->src, phychan->base + PL080_CH_SRC_ADDR); - writel(lli->dst, phychan->base + PL080_CH_DST_ADDR); - writel(lli->lli, phychan->base + PL080_CH_LLI); - writel(lli->cctl, phychan->base + PL080_CH_CONTROL); - writel(txd->ccfg, phychan->base + PL080_CH_CONFIG); - - /* Enable the DMA channel */ - /* Do not access config register until channel shows as disabled */ - while (readl(pl08x->base + PL080_EN_CHAN) & (1 << phychan->id)) - cpu_relax(); - - /* Do not access config register until channel shows as inactive */ - val = readl(phychan->base + PL080_CH_CONFIG); + /* + * Do not access config register until channel shows as inactive + */ + val = readl(ch->base + PL080_CH_CONFIG); while ((val & PL080_CONFIG_ACTIVE) || (val & PL080_CONFIG_ENABLE)) - val = readl(phychan->base + PL080_CH_CONFIG); + val = readl(ch->base + PL080_CH_CONFIG); - writel(val | PL080_CONFIG_ENABLE, phychan->base + PL080_CH_CONFIG); + writel(val | PL080_CONFIG_ENABLE, ch->base + PL080_CH_CONFIG); } /* @@ -239,8 +266,10 @@ static void pl08x_start_txd(struct pl08x_dma_chan *plchan, * * Disabling individual channels could lose data. * - * Disable the peripheral DMA after disabling the DMAC in order to allow - * the DMAC FIFO to drain, and hence allow the channel to show inactive + * Disable the peripheral DMA after disabling the DMAC + * in order to allow the DMAC FIFO to drain, and + * hence allow the channel to show inactive + * */ static void pl08x_pause_phy_chan(struct pl08x_phy_chan *ch) { @@ -253,7 +282,7 @@ static void pl08x_pause_phy_chan(struct pl08x_phy_chan *ch) /* Wait for channel inactive */ while (pl08x_phy_channel_busy(ch)) - cpu_relax(); + ; } static void pl08x_resume_phy_chan(struct pl08x_phy_chan *ch) @@ -304,56 +333,54 @@ static inline u32 get_bytes_in_cctl(u32 cctl) static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan) { struct pl08x_phy_chan *ch; + struct pl08x_txd *txdi = NULL; struct pl08x_txd *txd; unsigned long flags; - size_t bytes = 0; + u32 bytes = 0; spin_lock_irqsave(&plchan->lock, flags); + ch = plchan->phychan; txd = plchan->at; /* - * Follow the LLIs to get the number of remaining - * bytes in the currently active transaction. + * Next follow the LLIs to get the number of pending bytes in the + * currently active transaction. */ if (ch && txd) { - u32 clli = readl(ch->base + PL080_CH_LLI) & ~PL080_LLI_LM_AHB2; + struct lli *llis_va = txd->llis_va; + struct lli *llis_bus = (struct lli *) txd->llis_bus; + u32 clli = readl(ch->base + PL080_CH_LLI); - /* First get the remaining bytes in the active transfer */ + /* First get the bytes in the current active LLI */ bytes = get_bytes_in_cctl(readl(ch->base + PL080_CH_CONTROL)); if (clli) { - struct pl08x_lli *llis_va = txd->llis_va; - dma_addr_t llis_bus = txd->llis_bus; - int index; - - BUG_ON(clli < llis_bus || clli >= llis_bus + - sizeof(struct pl08x_lli) * MAX_NUM_TSFR_LLIS); - - /* - * Locate the next LLI - as this is an array, - * it's simple maths to find. - */ - index = (clli - llis_bus) / sizeof(struct pl08x_lli); + int i = 0; - for (; index < MAX_NUM_TSFR_LLIS; index++) { - bytes += get_bytes_in_cctl(llis_va[index].cctl); + /* Forward to the LLI pointed to by clli */ + while ((clli != (u32) &(llis_bus[i])) && + (i < MAX_NUM_TSFR_LLIS)) + i++; + while (clli) { + bytes += get_bytes_in_cctl(llis_va[i].cctl); /* - * A LLI pointer of 0 terminates the LLI list + * A clli of 0x00000000 will terminate the + * LLI list */ - if (!llis_va[index].lli) - break; + clli = llis_va[i].next; + i++; } } } /* Sum up all queued transactions */ - if (!list_empty(&plchan->pend_list)) { - struct pl08x_txd *txdi; - list_for_each_entry(txdi, &plchan->pend_list, node) { + if (!list_empty(&plchan->desc_list)) { + list_for_each_entry(txdi, &plchan->desc_list, node) { bytes += txdi->len; } + } spin_unlock_irqrestore(&plchan->lock, flags); @@ -363,10 +390,6 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan) /* * Allocate a physical channel for a virtual channel - * - * Try to locate a physical channel to be used for this transfer. If all - * are taken return NULL and the requester will have to cope by using - * some fallback PIO mode or retrying later. */ static struct pl08x_phy_chan * pl08x_get_phy_channel(struct pl08x_driver_data *pl08x, @@ -376,6 +399,12 @@ pl08x_get_phy_channel(struct pl08x_driver_data *pl08x, unsigned long flags; int i; + /* + * Try to locate a physical channel to be used for + * this transfer. If all are taken return NULL and + * the requester will have to cope by using some fallback + * PIO mode or retrying later. + */ for (i = 0; i < pl08x->vd->channels; i++) { ch = &pl08x->phy_chans[i]; @@ -436,11 +465,11 @@ static inline unsigned int pl08x_get_bytes_for_cctl(unsigned int coded) } static inline u32 pl08x_cctl_bits(u32 cctl, u8 srcwidth, u8 dstwidth, - size_t tsize) + u32 tsize) { u32 retbits = cctl; - /* Remove all src, dst and transfer size bits */ + /* Remove all src, dst and transfersize bits */ retbits &= ~PL080_CONTROL_DWIDTH_MASK; retbits &= ~PL080_CONTROL_SWIDTH_MASK; retbits &= ~PL080_CONTROL_TRANSFER_SIZE_MASK; @@ -480,87 +509,95 @@ static inline u32 pl08x_cctl_bits(u32 cctl, u8 srcwidth, u8 dstwidth, return retbits; } -struct pl08x_lli_build_data { - struct pl08x_txd *txd; - struct pl08x_driver_data *pl08x; - struct pl08x_bus_data srcbus; - struct pl08x_bus_data dstbus; - size_t remainder; -}; - /* - * Autoselect a master bus to use for the transfer this prefers the - * destination bus if both available if fixed address on one bus the - * other will be chosen + * Autoselect a master bus to use for the transfer + * this prefers the destination bus if both available + * if fixed address on one bus the other will be chosen */ -static void pl08x_choose_master_bus(struct pl08x_lli_build_data *bd, - struct pl08x_bus_data **mbus, struct pl08x_bus_data **sbus, u32 cctl) +void pl08x_choose_master_bus(struct pl08x_bus_data *src_bus, + struct pl08x_bus_data *dst_bus, struct pl08x_bus_data **mbus, + struct pl08x_bus_data **sbus, u32 cctl) { if (!(cctl & PL080_CONTROL_DST_INCR)) { - *mbus = &bd->srcbus; - *sbus = &bd->dstbus; + *mbus = src_bus; + *sbus = dst_bus; } else if (!(cctl & PL080_CONTROL_SRC_INCR)) { - *mbus = &bd->dstbus; - *sbus = &bd->srcbus; + *mbus = dst_bus; + *sbus = src_bus; } else { - if (bd->dstbus.buswidth == 4) { - *mbus = &bd->dstbus; - *sbus = &bd->srcbus; - } else if (bd->srcbus.buswidth == 4) { - *mbus = &bd->srcbus; - *sbus = &bd->dstbus; - } else if (bd->dstbus.buswidth == 2) { - *mbus = &bd->dstbus; - *sbus = &bd->srcbus; - } else if (bd->srcbus.buswidth == 2) { - *mbus = &bd->srcbus; - *sbus = &bd->dstbus; + if (dst_bus->buswidth == 4) { + *mbus = dst_bus; + *sbus = src_bus; + } else if (src_bus->buswidth == 4) { + *mbus = src_bus; + *sbus = dst_bus; + } else if (dst_bus->buswidth == 2) { + *mbus = dst_bus; + *sbus = src_bus; + } else if (src_bus->buswidth == 2) { + *mbus = src_bus; + *sbus = dst_bus; } else { - /* bd->srcbus.buswidth == 1 */ - *mbus = &bd->dstbus; - *sbus = &bd->srcbus; + /* src_bus->buswidth == 1 */ + *mbus = dst_bus; + *sbus = src_bus; } } } /* - * Fills in one LLI for a certain transfer descriptor and advance the counter + * Fills in one LLI for a certain transfer descriptor + * and advance the counter */ -static void pl08x_fill_lli_for_desc(struct pl08x_lli_build_data *bd, - int num_llis, int len, u32 cctl) +int pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x, + struct pl08x_txd *txd, int num_llis, int len, + u32 cctl, u32 *remainder) { - struct pl08x_lli *llis_va = bd->txd->llis_va; - dma_addr_t llis_bus = bd->txd->llis_bus; + struct lli *llis_va = txd->llis_va; + struct lli *llis_bus = (struct lli *) txd->llis_bus; BUG_ON(num_llis >= MAX_NUM_TSFR_LLIS); - llis_va[num_llis].cctl = cctl; - llis_va[num_llis].src = bd->srcbus.addr; - llis_va[num_llis].dst = bd->dstbus.addr; - llis_va[num_llis].lli = llis_bus + (num_llis + 1) * sizeof(struct pl08x_lli); - if (bd->pl08x->lli_buses & PL08X_AHB2) - llis_va[num_llis].lli |= PL080_LLI_LM_AHB2; + llis_va[num_llis].cctl = cctl; + llis_va[num_llis].src = txd->srcbus.addr; + llis_va[num_llis].dst = txd->dstbus.addr; + + /* + * On versions with dual masters, you can optionally AND on + * PL080_LLI_LM_AHB2 to the LLI to tell the hardware to read + * in new LLIs with that controller, but we always try to + * choose AHB1 to point into memory. The idea is to have AHB2 + * fixed on the peripheral and AHB1 messing around in the + * memory. So we don't manipulate this bit currently. + */ + + llis_va[num_llis].next = + (dma_addr_t)((u32) &(llis_bus[num_llis + 1])); if (cctl & PL080_CONTROL_SRC_INCR) - bd->srcbus.addr += len; + txd->srcbus.addr += len; if (cctl & PL080_CONTROL_DST_INCR) - bd->dstbus.addr += len; + txd->dstbus.addr += len; - BUG_ON(bd->remainder < len); + *remainder -= len; - bd->remainder -= len; + return num_llis + 1; } /* - * Return number of bytes to fill to boundary, or len. - * This calculation works for any value of addr. + * Return number of bytes to fill to boundary, or len */ -static inline size_t pl08x_pre_boundary(u32 addr, size_t len) +static inline u32 pl08x_pre_boundary(u32 addr, u32 len) { - size_t boundary_len = PL08X_BOUNDARY_SIZE - - (addr & (PL08X_BOUNDARY_SIZE - 1)); + u32 boundary; + + boundary = ((addr >> PL08X_BOUNDARY_SHIFT) + 1) + << PL08X_BOUNDARY_SHIFT; - return min(boundary_len, len); + if (boundary < addr + len) + return boundary - addr; + else + return len; } /* @@ -571,13 +608,20 @@ static inline size_t pl08x_pre_boundary(u32 addr, size_t len) static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, struct pl08x_txd *txd) { + struct pl08x_channel_data *cd = txd->cd; struct pl08x_bus_data *mbus, *sbus; - struct pl08x_lli_build_data bd; + u32 remainder; int num_llis = 0; u32 cctl; - size_t max_bytes_per_lli; - size_t total_bytes = 0; - struct pl08x_lli *llis_va; + int max_bytes_per_lli; + int total_bytes = 0; + struct lli *llis_va; + struct lli *llis_bus; + + if (!txd) { + dev_err(&pl08x->adev->dev, "%s no descriptor\n", __func__); + return 0; + } txd->llis_va = dma_pool_alloc(pl08x->pool, GFP_NOWAIT, &txd->llis_bus); @@ -588,79 +632,121 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, pl08x->pool_ctr++; - /* Get the default CCTL */ - cctl = txd->cctl; + /* + * Initialize bus values for this transfer + * from the passed optimal values + */ + if (!cd) { + dev_err(&pl08x->adev->dev, "%s no channel data\n", __func__); + return 0; + } - bd.txd = txd; - bd.pl08x = pl08x; - bd.srcbus.addr = txd->src_addr; - bd.dstbus.addr = txd->dst_addr; + /* Get the default CCTL from the platform data */ + cctl = cd->cctl; + + /* + * On the PL080 we have two bus masters and we + * should select one for source and one for + * destination. We try to use AHB2 for the + * bus which does not increment (typically the + * peripheral) else we just choose something. + */ + cctl &= ~(PL080_CONTROL_DST_AHB2 | PL080_CONTROL_SRC_AHB2); + if (pl08x->vd->dualmaster) { + if (cctl & PL080_CONTROL_SRC_INCR) + /* Source increments, use AHB2 for destination */ + cctl |= PL080_CONTROL_DST_AHB2; + else if (cctl & PL080_CONTROL_DST_INCR) + /* Destination increments, use AHB2 for source */ + cctl |= PL080_CONTROL_SRC_AHB2; + else + /* Just pick something, source AHB1 dest AHB2 */ + cctl |= PL080_CONTROL_DST_AHB2; + } /* Find maximum width of the source bus */ - bd.srcbus.maxwidth = + txd->srcbus.maxwidth = pl08x_get_bytes_for_cctl((cctl & PL080_CONTROL_SWIDTH_MASK) >> PL080_CONTROL_SWIDTH_SHIFT); /* Find maximum width of the destination bus */ - bd.dstbus.maxwidth = + txd->dstbus.maxwidth = pl08x_get_bytes_for_cctl((cctl & PL080_CONTROL_DWIDTH_MASK) >> PL080_CONTROL_DWIDTH_SHIFT); /* Set up the bus widths to the maximum */ - bd.srcbus.buswidth = bd.srcbus.maxwidth; - bd.dstbus.buswidth = bd.dstbus.maxwidth; + txd->srcbus.buswidth = txd->srcbus.maxwidth; + txd->dstbus.buswidth = txd->dstbus.maxwidth; dev_vdbg(&pl08x->adev->dev, "%s source bus is %d bytes wide, dest bus is %d bytes wide\n", - __func__, bd.srcbus.buswidth, bd.dstbus.buswidth); + __func__, txd->srcbus.buswidth, txd->dstbus.buswidth); /* * Bytes transferred == tsize * MIN(buswidths), not max(buswidths) */ - max_bytes_per_lli = min(bd.srcbus.buswidth, bd.dstbus.buswidth) * + max_bytes_per_lli = min(txd->srcbus.buswidth, txd->dstbus.buswidth) * PL080_CONTROL_TRANSFER_SIZE_MASK; dev_vdbg(&pl08x->adev->dev, - "%s max bytes per lli = %zu\n", + "%s max bytes per lli = %d\n", __func__, max_bytes_per_lli); /* We need to count this down to zero */ - bd.remainder = txd->len; + remainder = txd->len; dev_vdbg(&pl08x->adev->dev, - "%s remainder = %zu\n", - __func__, bd.remainder); + "%s remainder = %d\n", + __func__, remainder); /* * Choose bus to align to * - prefers destination bus if both available * - if fixed address on one bus chooses other + * - modifies cctl to choose an apropriate master + */ + pl08x_choose_master_bus(&txd->srcbus, &txd->dstbus, + &mbus, &sbus, cctl); + + + /* + * The lowest bit of the LLI register + * is also used to indicate which master to + * use for reading the LLIs. */ - pl08x_choose_master_bus(&bd, &mbus, &sbus, cctl); if (txd->len < mbus->buswidth) { - /* Less than a bus width available - send as single bytes */ - while (bd.remainder) { + /* + * Less than a bus width available + * - send as single bytes + */ + while (remainder) { dev_vdbg(&pl08x->adev->dev, "%s single byte LLIs for a transfer of " - "less than a bus width (remain 0x%08x)\n", - __func__, bd.remainder); + "less than a bus width (remain %08x)\n", + __func__, remainder); cctl = pl08x_cctl_bits(cctl, 1, 1, 1); - pl08x_fill_lli_for_desc(&bd, num_llis++, 1, cctl); + num_llis = + pl08x_fill_lli_for_desc(pl08x, txd, num_llis, 1, + cctl, &remainder); total_bytes++; } } else { - /* Make one byte LLIs until master bus is aligned */ + /* + * Make one byte LLIs until master bus is aligned + * - slave will then be aligned also + */ while ((mbus->addr) % (mbus->buswidth)) { dev_vdbg(&pl08x->adev->dev, "%s adjustment lli for less than bus width " - "(remain 0x%08x)\n", - __func__, bd.remainder); + "(remain %08x)\n", + __func__, remainder); cctl = pl08x_cctl_bits(cctl, 1, 1, 1); - pl08x_fill_lli_for_desc(&bd, num_llis++, 1, cctl); + num_llis = pl08x_fill_lli_for_desc + (pl08x, txd, num_llis, 1, cctl, &remainder); total_bytes++; } /* - * Master now aligned + * Master now aligned * - if slave is not then we must set its width down */ if (sbus->addr % sbus->buswidth) { @@ -675,51 +761,63 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, * Make largest possible LLIs until less than one bus * width left */ - while (bd.remainder > (mbus->buswidth - 1)) { - size_t lli_len, target_len, tsize, odd_bytes; + while (remainder > (mbus->buswidth - 1)) { + int lli_len, target_len; + int tsize; + int odd_bytes; /* * If enough left try to send max possible, * otherwise try to send the remainder */ - target_len = min(bd.remainder, max_bytes_per_lli); + target_len = remainder; + if (remainder > max_bytes_per_lli) + target_len = max_bytes_per_lli; /* - * Set bus lengths for incrementing buses to the - * number of bytes which fill to next memory boundary, - * limiting on the target length calculated above. + * Set bus lengths for incrementing busses + * to number of bytes which fill to next memory + * boundary */ if (cctl & PL080_CONTROL_SRC_INCR) - bd.srcbus.fill_bytes = - pl08x_pre_boundary(bd.srcbus.addr, - target_len); + txd->srcbus.fill_bytes = + pl08x_pre_boundary( + txd->srcbus.addr, + remainder); else - bd.srcbus.fill_bytes = target_len; + txd->srcbus.fill_bytes = + max_bytes_per_lli; if (cctl & PL080_CONTROL_DST_INCR) - bd.dstbus.fill_bytes = - pl08x_pre_boundary(bd.dstbus.addr, - target_len); + txd->dstbus.fill_bytes = + pl08x_pre_boundary( + txd->dstbus.addr, + remainder); else - bd.dstbus.fill_bytes = target_len; + txd->dstbus.fill_bytes = + max_bytes_per_lli; - /* Find the nearest */ - lli_len = min(bd.srcbus.fill_bytes, - bd.dstbus.fill_bytes); + /* + * Find the nearest + */ + lli_len = min(txd->srcbus.fill_bytes, + txd->dstbus.fill_bytes); - BUG_ON(lli_len > bd.remainder); + BUG_ON(lli_len > remainder); if (lli_len <= 0) { dev_err(&pl08x->adev->dev, - "%s lli_len is %zu, <= 0\n", + "%s lli_len is %d, <= 0\n", __func__, lli_len); return 0; } if (lli_len == target_len) { /* - * Can send what we wanted. - * Maintain alignment + * Can send what we wanted + */ + /* + * Maintain alignment */ lli_len = (lli_len/mbus->buswidth) * mbus->buswidth; @@ -727,14 +825,17 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, } else { /* * So now we know how many bytes to transfer - * to get to the nearest boundary. The next - * LLI will past the boundary. However, we - * may be working to a boundary on the slave - * bus. We need to ensure the master stays - * aligned, and that we are working in - * multiples of the bus widths. + * to get to the nearest boundary + * The next lli will past the boundary + * - however we may be working to a boundary + * on the slave bus + * We need to ensure the master stays aligned */ odd_bytes = lli_len % mbus->buswidth; + /* + * - and that we are working in multiples + * of the bus widths + */ lli_len -= odd_bytes; } @@ -754,38 +855,41 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, if (target_len != lli_len) { dev_vdbg(&pl08x->adev->dev, - "%s can't send what we want. Desired 0x%08zx, lli of 0x%08zx bytes in txd of 0x%08zx\n", + "%s can't send what we want. Desired %08x, lli of %08x bytes in txd of %08x\n", __func__, target_len, lli_len, txd->len); } cctl = pl08x_cctl_bits(cctl, - bd.srcbus.buswidth, - bd.dstbus.buswidth, + txd->srcbus.buswidth, + txd->dstbus.buswidth, tsize); dev_vdbg(&pl08x->adev->dev, - "%s fill lli with single lli chunk of size 0x%08zx (remainder 0x%08zx)\n", - __func__, lli_len, bd.remainder); - pl08x_fill_lli_for_desc(&bd, num_llis++, - lli_len, cctl); + "%s fill lli with single lli chunk of size %08x (remainder %08x)\n", + __func__, lli_len, remainder); + num_llis = pl08x_fill_lli_for_desc(pl08x, txd, + num_llis, lli_len, cctl, + &remainder); total_bytes += lli_len; } if (odd_bytes) { /* - * Creep past the boundary, maintaining - * master alignment + * Creep past the boundary, + * maintaining master alignment */ int j; for (j = 0; (j < mbus->buswidth) - && (bd.remainder); j++) { + && (remainder); j++) { cctl = pl08x_cctl_bits(cctl, 1, 1, 1); dev_vdbg(&pl08x->adev->dev, - "%s align with boundary, single byte (remain 0x%08zx)\n", - __func__, bd.remainder); - pl08x_fill_lli_for_desc(&bd, - num_llis++, 1, cctl); + "%s align with boundardy, single byte (remain %08x)\n", + __func__, remainder); + num_llis = + pl08x_fill_lli_for_desc(pl08x, + txd, num_llis, 1, + cctl, &remainder); total_bytes++; } } @@ -794,18 +898,25 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, /* * Send any odd bytes */ - while (bd.remainder) { + if (remainder < 0) { + dev_err(&pl08x->adev->dev, "%s remainder not fitted 0x%08x bytes\n", + __func__, remainder); + return 0; + } + + while (remainder) { cctl = pl08x_cctl_bits(cctl, 1, 1, 1); dev_vdbg(&pl08x->adev->dev, - "%s align with boundary, single odd byte (remain %zu)\n", - __func__, bd.remainder); - pl08x_fill_lli_for_desc(&bd, num_llis++, 1, cctl); + "%s align with boundardy, single odd byte (remain %d)\n", + __func__, remainder); + num_llis = pl08x_fill_lli_for_desc(pl08x, txd, num_llis, + 1, cctl, &remainder); total_bytes++; } } if (total_bytes != txd->len) { dev_err(&pl08x->adev->dev, - "%s size of encoded lli:s don't match total txd, transferred 0x%08zx from size 0x%08zx\n", + "%s size of encoded lli:s don't match total txd, transferred 0x%08x from size 0x%08x\n", __func__, total_bytes, txd->len); return 0; } @@ -816,12 +927,41 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, __func__, (u32) MAX_NUM_TSFR_LLIS); return 0; } - + /* + * Decide whether this is a loop or a terminated transfer + */ llis_va = txd->llis_va; - /* The final LLI terminates the LLI. */ - llis_va[num_llis - 1].lli = 0; - /* The final LLI element shall also fire an interrupt. */ - llis_va[num_llis - 1].cctl |= PL080_CONTROL_TC_IRQ_EN; + llis_bus = (struct lli *) txd->llis_bus; + + if (cd->circular_buffer) { + /* + * Loop the circular buffer so that the next element + * points back to the beginning of the LLI. + */ + llis_va[num_llis - 1].next = + (dma_addr_t)((unsigned int)&(llis_bus[0])); + } else { + /* + * On non-circular buffers, the final LLI terminates + * the LLI. + */ + llis_va[num_llis - 1].next = 0; + /* + * The final LLI element shall also fire an interrupt + */ + llis_va[num_llis - 1].cctl |= PL080_CONTROL_TC_IRQ_EN; + } + + /* Now store the channel register values */ + txd->csrc = llis_va[0].src; + txd->cdst = llis_va[0].dst; + if (num_llis > 1) + txd->clli = llis_va[0].next; + else + txd->clli = 0; + + txd->cctl = llis_va[0].cctl; + /* ccfg will be set at physical channel allocation time */ #ifdef VERBOSE_DEBUG { @@ -829,13 +969,13 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, for (i = 0; i < num_llis; i++) { dev_vdbg(&pl08x->adev->dev, - "lli %d @%p: csrc=0x%08x, cdst=0x%08x, cctl=0x%08x, clli=0x%08x\n", + "lli %d @%p: csrc=%08x, cdst=%08x, cctl=%08x, clli=%08x\n", i, &llis_va[i], llis_va[i].src, llis_va[i].dst, llis_va[i].cctl, - llis_va[i].lli + llis_va[i].next ); } } @@ -848,8 +988,14 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x, static void pl08x_free_txd(struct pl08x_driver_data *pl08x, struct pl08x_txd *txd) { + if (!txd) + dev_err(&pl08x->adev->dev, + "%s no descriptor to free\n", + __func__); + /* Free the LLI */ - dma_pool_free(pl08x->pool, txd->llis_va, txd->llis_bus); + dma_pool_free(pl08x->pool, txd->llis_va, + txd->llis_bus); pl08x->pool_ctr--; @@ -862,12 +1008,13 @@ static void pl08x_free_txd_list(struct pl08x_driver_data *pl08x, struct pl08x_txd *txdi = NULL; struct pl08x_txd *next; - if (!list_empty(&plchan->pend_list)) { + if (!list_empty(&plchan->desc_list)) { list_for_each_entry_safe(txdi, - next, &plchan->pend_list, node) { + next, &plchan->desc_list, node) { list_del(&txdi->node); pl08x_free_txd(pl08x, txdi); } + } } @@ -922,12 +1069,6 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan, return -EBUSY; } ch->signal = ret; - - /* Assign the flow control signal to this channel */ - if (txd->direction == DMA_TO_DEVICE) - txd->ccfg |= ch->signal << PL080_CONFIG_DST_SEL_SHIFT; - else if (txd->direction == DMA_FROM_DEVICE) - txd->ccfg |= ch->signal << PL080_CONFIG_SRC_SEL_SHIFT; } dev_dbg(&pl08x->adev->dev, "allocated physical channel %d and signal %d for xfer on %s\n", @@ -935,54 +1076,19 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan, ch->signal, plchan->name); - plchan->phychan_hold++; plchan->phychan = ch; return 0; } -static void release_phy_channel(struct pl08x_dma_chan *plchan) -{ - struct pl08x_driver_data *pl08x = plchan->host; - - if ((plchan->phychan->signal >= 0) && pl08x->pd->put_signal) { - pl08x->pd->put_signal(plchan); - plchan->phychan->signal = -1; - } - pl08x_put_phy_channel(pl08x, plchan->phychan); - plchan->phychan = NULL; -} - static dma_cookie_t pl08x_tx_submit(struct dma_async_tx_descriptor *tx) { struct pl08x_dma_chan *plchan = to_pl08x_chan(tx->chan); - struct pl08x_txd *txd = to_pl08x_txd(tx); - unsigned long flags; - spin_lock_irqsave(&plchan->lock, flags); - - plchan->chan.cookie += 1; - if (plchan->chan.cookie < 0) - plchan->chan.cookie = 1; - tx->cookie = plchan->chan.cookie; - - /* Put this onto the pending list */ - list_add_tail(&txd->node, &plchan->pend_list); - - /* - * If there was no physical channel available for this memcpy, - * stack the request up and indicate that the channel is waiting - * for a free physical channel. - */ - if (!plchan->slave && !plchan->phychan) { - /* Do this memcpy whenever there is a channel ready */ - plchan->state = PL08X_CHAN_WAITING; - plchan->waiting = txd; - } else { - plchan->phychan_hold--; - } - - spin_unlock_irqrestore(&plchan->lock, flags); + atomic_inc(&plchan->last_issued); + tx->cookie = atomic_read(&plchan->last_issued); + /* This unlock follows the lock in the prep() function */ + spin_unlock_irqrestore(&plchan->lock, plchan->lockflags); return tx->cookie; } @@ -996,9 +1102,10 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_interrupt( } /* - * Code accessing dma_async_is_complete() in a tight loop may give problems. - * If slaves are relying on interrupts to signal completion this function - * must not be called with interrupts disabled. + * Code accessing dma_async_is_complete() in a tight loop + * may give problems - could schedule where indicated. + * If slaves are relying on interrupts to signal completion this + * function must not be called with interrupts disabled */ static enum dma_status pl08x_dma_tx_status(struct dma_chan *chan, @@ -1011,7 +1118,7 @@ pl08x_dma_tx_status(struct dma_chan *chan, enum dma_status ret; u32 bytesleft = 0; - last_used = plchan->chan.cookie; + last_used = atomic_read(&plchan->last_issued); last_complete = plchan->lc; ret = dma_async_is_complete(cookie, last_complete, last_used); @@ -1020,10 +1127,14 @@ pl08x_dma_tx_status(struct dma_chan *chan, return ret; } + /* + * schedule(); could be inserted here + */ + /* * This cookie not complete yet */ - last_used = plchan->chan.cookie; + last_used = atomic_read(&plchan->last_issued); last_complete = plchan->lc; /* Get number of bytes left in the active transactions and queue */ @@ -1088,35 +1199,37 @@ static const struct burst_table burst_sizes[] = { }, }; -static int dma_set_runtime_config(struct dma_chan *chan, - struct dma_slave_config *config) +static void dma_set_runtime_config(struct dma_chan *chan, + struct dma_slave_config *config) { struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); struct pl08x_driver_data *pl08x = plchan->host; struct pl08x_channel_data *cd = plchan->cd; enum dma_slave_buswidth addr_width; - dma_addr_t addr; u32 maxburst; u32 cctl = 0; - int i; - - if (!plchan->slave) - return -EINVAL; + /* Mask out all except src and dst channel */ + u32 ccfg = cd->ccfg & 0x000003DEU; + int i = 0; /* Transfer direction */ plchan->runtime_direction = config->direction; if (config->direction == DMA_TO_DEVICE) { - addr = config->dst_addr; + plchan->runtime_addr = config->dst_addr; + cctl |= PL080_CONTROL_SRC_INCR; + ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT; addr_width = config->dst_addr_width; maxburst = config->dst_maxburst; } else if (config->direction == DMA_FROM_DEVICE) { - addr = config->src_addr; + plchan->runtime_addr = config->src_addr; + cctl |= PL080_CONTROL_DST_INCR; + ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT; addr_width = config->src_addr_width; maxburst = config->src_maxburst; } else { dev_err(&pl08x->adev->dev, "bad runtime_config: alien transfer direction\n"); - return -EINVAL; + return; } switch (addr_width) { @@ -1135,40 +1248,42 @@ static int dma_set_runtime_config(struct dma_chan *chan, default: dev_err(&pl08x->adev->dev, "bad runtime_config: alien address width\n"); - return -EINVAL; + return; } /* * Now decide on a maxburst: - * If this channel will only request single transfers, set this - * down to ONE element. Also select one element if no maxburst - * is specified. + * If this channel will only request single transfers, set + * this down to ONE element. */ - if (plchan->cd->single || maxburst == 0) { + if (plchan->cd->single) { cctl |= (PL080_BSIZE_1 << PL080_CONTROL_SB_SIZE_SHIFT) | (PL080_BSIZE_1 << PL080_CONTROL_DB_SIZE_SHIFT); } else { - for (i = 0; i < ARRAY_SIZE(burst_sizes); i++) + while (i < ARRAY_SIZE(burst_sizes)) { if (burst_sizes[i].burstwords <= maxburst) break; + i++; + } cctl |= burst_sizes[i].reg; } - plchan->runtime_addr = addr; + /* Access the cell in privileged mode, non-bufferable, non-cacheable */ + cctl &= ~PL080_CONTROL_PROT_MASK; + cctl |= PL080_CONTROL_PROT_SYS; /* Modify the default channel data to fit PrimeCell request */ cd->cctl = cctl; + cd->ccfg = ccfg; dev_dbg(&pl08x->adev->dev, "configured channel %s (%s) for %s, data width %d, " - "maxburst %d words, LE, CCTL=0x%08x\n", + "maxburst %d words, LE, CCTL=%08x, CCFG=%08x\n", dma_chan_name(chan), plchan->name, (config->direction == DMA_FROM_DEVICE) ? "RX" : "TX", addr_width, maxburst, - cctl); - - return 0; + cctl, ccfg); } /* @@ -1178,26 +1293,35 @@ static int dma_set_runtime_config(struct dma_chan *chan, static void pl08x_issue_pending(struct dma_chan *chan) { struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); + struct pl08x_driver_data *pl08x = plchan->host; unsigned long flags; spin_lock_irqsave(&plchan->lock, flags); - /* Something is already active, or we're waiting for a channel... */ - if (plchan->at || plchan->state == PL08X_CHAN_WAITING) { - spin_unlock_irqrestore(&plchan->lock, flags); - return; + /* Something is already active */ + if (plchan->at) { + spin_unlock_irqrestore(&plchan->lock, flags); + return; } + /* Didn't get a physical channel so waiting for it ... */ + if (plchan->state == PL08X_CHAN_WAITING) + return; + /* Take the first element in the queue and execute it */ - if (!list_empty(&plchan->pend_list)) { + if (!list_empty(&plchan->desc_list)) { struct pl08x_txd *next; - next = list_first_entry(&plchan->pend_list, + next = list_first_entry(&plchan->desc_list, struct pl08x_txd, node); list_del(&next->node); + plchan->at = next; plchan->state = PL08X_CHAN_RUNNING; - pl08x_start_txd(plchan, next); + /* Configure the physical channel for the active txd */ + pl08x_config_phychan_for_txd(plchan); + pl08x_set_cregs(pl08x, plchan->phychan); + pl08x_enable_phy_chan(pl08x, plchan->phychan); } spin_unlock_irqrestore(&plchan->lock, flags); @@ -1206,17 +1330,30 @@ static void pl08x_issue_pending(struct dma_chan *chan) static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, struct pl08x_txd *txd) { + int num_llis; struct pl08x_driver_data *pl08x = plchan->host; - unsigned long flags; - int num_llis, ret; + int ret; num_llis = pl08x_fill_llis_for_desc(pl08x, txd); - if (!num_llis) { - kfree(txd); + + if (!num_llis) return -EINVAL; - } - spin_lock_irqsave(&plchan->lock, flags); + spin_lock_irqsave(&plchan->lock, plchan->lockflags); + + /* + * If this device is not using a circular buffer then + * queue this new descriptor for transfer. + * The descriptor for a circular buffer continues + * to be used until the channel is freed. + */ + if (txd->cd->circular_buffer) + dev_err(&pl08x->adev->dev, + "%s attempting to queue a circular buffer\n", + __func__); + else + list_add_tail(&txd->node, + &plchan->desc_list); /* * See if we already have a physical channel allocated, @@ -1225,73 +1362,44 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan, ret = prep_phy_channel(plchan, txd); if (ret) { /* - * No physical channel was available. - * - * memcpy transfers can be sorted out at submission time. - * - * Slave transfers may have been denied due to platform - * channel muxing restrictions. Since there is no guarantee - * that this will ever be resolved, and the signal must be - * acquired AFTER acquiring the physical channel, we will let - * them be NACK:ed with -EBUSY here. The drivers can retry - * the prep() call if they are eager on doing this using DMA. + * No physical channel available, we will + * stack up the memcpy channels until there is a channel + * available to handle it whereas slave transfers may + * have been denied due to platform channel muxing restrictions + * and since there is no guarantee that this will ever be + * resolved, and since the signal must be aquired AFTER + * aquiring the physical channel, we will let them be NACK:ed + * with -EBUSY here. The drivers can alway retry the prep() + * call if they are eager on doing this using DMA. */ if (plchan->slave) { pl08x_free_txd_list(pl08x, plchan); - pl08x_free_txd(pl08x, txd); - spin_unlock_irqrestore(&plchan->lock, flags); + spin_unlock_irqrestore(&plchan->lock, plchan->lockflags); return -EBUSY; } + /* Do this memcpy whenever there is a channel ready */ + plchan->state = PL08X_CHAN_WAITING; + plchan->waiting = txd; } else /* - * Else we're all set, paused and ready to roll, status - * will switch to PL08X_CHAN_RUNNING when we call - * issue_pending(). If there is something running on the - * channel already we don't change its state. + * Else we're all set, paused and ready to roll, + * status will switch to PL08X_CHAN_RUNNING when + * we call issue_pending(). If there is something + * running on the channel already we don't change + * its state. */ if (plchan->state == PL08X_CHAN_IDLE) plchan->state = PL08X_CHAN_PAUSED; - spin_unlock_irqrestore(&plchan->lock, flags); + /* + * Notice that we leave plchan->lock locked on purpose: + * it will be unlocked in the subsequent tx_submit() + * call. This is a consequence of the current API. + */ return 0; } -/* - * Given the source and destination available bus masks, select which - * will be routed to each port. We try to have source and destination - * on separate ports, but always respect the allowable settings. - */ -static u32 pl08x_select_bus(struct pl08x_driver_data *pl08x, u8 src, u8 dst) -{ - u32 cctl = 0; - - if (!(dst & PL08X_AHB1) || ((dst & PL08X_AHB2) && (src & PL08X_AHB1))) - cctl |= PL080_CONTROL_DST_AHB2; - if (!(src & PL08X_AHB1) || ((src & PL08X_AHB2) && !(dst & PL08X_AHB2))) - cctl |= PL080_CONTROL_SRC_AHB2; - - return cctl; -} - -static struct pl08x_txd *pl08x_get_txd(struct pl08x_dma_chan *plchan, - unsigned long flags) -{ - struct pl08x_txd *txd = kzalloc(sizeof(struct pl08x_txd), GFP_NOWAIT); - - if (txd) { - dma_async_tx_descriptor_init(&txd->tx, &plchan->chan); - txd->tx.flags = flags; - txd->tx.tx_submit = pl08x_tx_submit; - INIT_LIST_HEAD(&txd->node); - - /* Always enable error and terminal interrupts */ - txd->ccfg = PL080_CONFIG_ERR_IRQ_MASK | - PL080_CONFIG_TC_IRQ_MASK; - } - return txd; -} - /* * Initialize a descriptor to be used by memcpy submit */ @@ -1304,38 +1412,40 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy( struct pl08x_txd *txd; int ret; - txd = pl08x_get_txd(plchan, flags); + txd = kzalloc(sizeof(struct pl08x_txd), GFP_NOWAIT); if (!txd) { dev_err(&pl08x->adev->dev, "%s no memory for descriptor\n", __func__); return NULL; } + dma_async_tx_descriptor_init(&txd->tx, chan); txd->direction = DMA_NONE; - txd->src_addr = src; - txd->dst_addr = dest; - txd->len = len; + txd->srcbus.addr = src; + txd->dstbus.addr = dest; /* Set platform data for m2m */ - txd->ccfg |= PL080_FLOW_MEM2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT; - txd->cctl = pl08x->pd->memcpy_channel.cctl & - ~(PL080_CONTROL_DST_AHB2 | PL080_CONTROL_SRC_AHB2); - + txd->cd = &pl08x->pd->memcpy_channel; /* Both to be incremented or the code will break */ - txd->cctl |= PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR; - - if (pl08x->vd->dualmaster) - txd->cctl |= pl08x_select_bus(pl08x, - pl08x->mem_buses, pl08x->mem_buses); + txd->cd->cctl |= PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR; + txd->tx.tx_submit = pl08x_tx_submit; + txd->tx.callback = NULL; + txd->tx.callback_param = NULL; + txd->len = len; + INIT_LIST_HEAD(&txd->node); ret = pl08x_prep_channel_resources(plchan, txd); if (ret) return NULL; + /* + * NB: the channel lock is held at this point so tx_submit() + * must be called in direct succession. + */ return &txd->tx; } -static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( +struct dma_async_tx_descriptor *pl08x_prep_slave_sg( struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, enum dma_data_direction direction, unsigned long flags) @@ -1343,7 +1453,6 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); struct pl08x_driver_data *pl08x = plchan->host; struct pl08x_txd *txd; - u8 src_buses, dst_buses; int ret; /* @@ -1358,12 +1467,14 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( dev_dbg(&pl08x->adev->dev, "%s prepare transaction of %d bytes from %s\n", __func__, sgl->length, plchan->name); - txd = pl08x_get_txd(plchan, flags); + txd = kzalloc(sizeof(struct pl08x_txd), GFP_NOWAIT); if (!txd) { dev_err(&pl08x->adev->dev, "%s no txd\n", __func__); return NULL; } + dma_async_tx_descriptor_init(&txd->tx, chan); + if (direction != plchan->runtime_direction) dev_err(&pl08x->adev->dev, "%s DMA setup does not match " "the direction configured for the PrimeCell\n", @@ -1375,47 +1486,37 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg( * channel target address dynamically at runtime. */ txd->direction = direction; - txd->len = sgl->length; - - txd->cctl = plchan->cd->cctl & - ~(PL080_CONTROL_SRC_AHB2 | PL080_CONTROL_DST_AHB2 | - PL080_CONTROL_SRC_INCR | PL080_CONTROL_DST_INCR | - PL080_CONTROL_PROT_MASK); - - /* Access the cell in privileged mode, non-bufferable, non-cacheable */ - txd->cctl |= PL080_CONTROL_PROT_SYS; - if (direction == DMA_TO_DEVICE) { - txd->ccfg |= PL080_FLOW_MEM2PER << PL080_CONFIG_FLOW_CONTROL_SHIFT; - txd->cctl |= PL080_CONTROL_SRC_INCR; - txd->src_addr = sgl->dma_address; + txd->srcbus.addr = sgl->dma_address; if (plchan->runtime_addr) - txd->dst_addr = plchan->runtime_addr; + txd->dstbus.addr = plchan->runtime_addr; else - txd->dst_addr = plchan->cd->addr; - src_buses = pl08x->mem_buses; - dst_buses = plchan->cd->periph_buses; + txd->dstbus.addr = plchan->cd->addr; } else if (direction == DMA_FROM_DEVICE) { - txd->ccfg |= PL080_FLOW_PER2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT; - txd->cctl |= PL080_CONTROL_DST_INCR; if (plchan->runtime_addr) - txd->src_addr = plchan->runtime_addr; + txd->srcbus.addr = plchan->runtime_addr; else - txd->src_addr = plchan->cd->addr; - txd->dst_addr = sgl->dma_address; - src_buses = plchan->cd->periph_buses; - dst_buses = pl08x->mem_buses; + txd->srcbus.addr = plchan->cd->addr; + txd->dstbus.addr = sgl->dma_address; } else { dev_err(&pl08x->adev->dev, "%s direction unsupported\n", __func__); return NULL; } - - txd->cctl |= pl08x_select_bus(pl08x, src_buses, dst_buses); + txd->cd = plchan->cd; + txd->tx.tx_submit = pl08x_tx_submit; + txd->tx.callback = NULL; + txd->tx.callback_param = NULL; + txd->len = sgl->length; + INIT_LIST_HEAD(&txd->node); ret = pl08x_prep_channel_resources(plchan, txd); if (ret) return NULL; + /* + * NB: the channel lock is held at this point so tx_submit() + * must be called in direct succession. + */ return &txd->tx; } @@ -1430,8 +1531,10 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, /* Controls applicable to inactive channels */ if (cmd == DMA_SLAVE_CONFIG) { - return dma_set_runtime_config(chan, - (struct dma_slave_config *)arg); + dma_set_runtime_config(chan, + (struct dma_slave_config *) + arg); + return 0; } /* @@ -1455,8 +1558,16 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, * Mark physical channel as free and free any slave * signal */ - release_phy_channel(plchan); + if ((plchan->phychan->signal >= 0) && + pl08x->pd->put_signal) { + pl08x->pd->put_signal(plchan); + plchan->phychan->signal = -1; + } + pl08x_put_phy_channel(pl08x, plchan->phychan); + plchan->phychan = NULL; } + /* Stop any pending tasklet */ + tasklet_disable(&plchan->tasklet); /* Dequeue jobs and free LLIs */ if (plchan->at) { pl08x_free_txd(pl08x, plchan->at); @@ -1498,9 +1609,10 @@ bool pl08x_filter_id(struct dma_chan *chan, void *chan_id) /* * Just check that the device is there and active - * TODO: turn this bit on/off depending on the number of physical channels - * actually used, if it is zero... well shut it off. That will save some - * power. Cut the clock at the same time. + * TODO: turn this bit on/off depending on the number of + * physical channels actually used, if it is zero... well + * shut it off. That will save some power. Cut the clock + * at the same time. */ static void pl08x_ensure_on(struct pl08x_driver_data *pl08x) { @@ -1508,66 +1620,78 @@ static void pl08x_ensure_on(struct pl08x_driver_data *pl08x) val = readl(pl08x->base + PL080_CONFIG); val &= ~(PL080_CONFIG_M2_BE | PL080_CONFIG_M1_BE | PL080_CONFIG_ENABLE); - /* We implicitly clear bit 1 and that means little-endian mode */ + /* We implictly clear bit 1 and that means little-endian mode */ val |= PL080_CONFIG_ENABLE; writel(val, pl08x->base + PL080_CONFIG); } -static void pl08x_unmap_buffers(struct pl08x_txd *txd) -{ - struct device *dev = txd->tx.chan->device->dev; - - if (!(txd->tx.flags & DMA_COMPL_SKIP_SRC_UNMAP)) { - if (txd->tx.flags & DMA_COMPL_SRC_UNMAP_SINGLE) - dma_unmap_single(dev, txd->src_addr, txd->len, - DMA_TO_DEVICE); - else - dma_unmap_page(dev, txd->src_addr, txd->len, - DMA_TO_DEVICE); - } - if (!(txd->tx.flags & DMA_COMPL_SKIP_DEST_UNMAP)) { - if (txd->tx.flags & DMA_COMPL_DEST_UNMAP_SINGLE) - dma_unmap_single(dev, txd->dst_addr, txd->len, - DMA_FROM_DEVICE); - else - dma_unmap_page(dev, txd->dst_addr, txd->len, - DMA_FROM_DEVICE); - } -} - static void pl08x_tasklet(unsigned long data) { struct pl08x_dma_chan *plchan = (struct pl08x_dma_chan *) data; + struct pl08x_phy_chan *phychan = plchan->phychan; struct pl08x_driver_data *pl08x = plchan->host; - struct pl08x_txd *txd; - unsigned long flags; - spin_lock_irqsave(&plchan->lock, flags); + if (!plchan) + BUG(); - txd = plchan->at; - plchan->at = NULL; + spin_lock(&plchan->lock); - if (txd) { - /* Update last completed */ - plchan->lc = txd->tx.cookie; - } + if (plchan->at) { + dma_async_tx_callback callback = + plchan->at->tx.callback; + void *callback_param = + plchan->at->tx.callback_param; - /* If a new descriptor is queued, set it up plchan->at is NULL here */ - if (!list_empty(&plchan->pend_list)) { + /* + * Update last completed + */ + plchan->lc = + (plchan->at->tx.cookie); + + /* + * Callback to signal completion + */ + if (callback) + callback(callback_param); + + /* + * Device callbacks should NOT clear + * the current transaction on the channel + * Linus: sometimes they should? + */ + if (!plchan->at) + BUG(); + + /* + * Free the descriptor if it's not for a device + * using a circular buffer + */ + if (!plchan->at->cd->circular_buffer) { + pl08x_free_txd(pl08x, plchan->at); + plchan->at = NULL; + } + /* + * else descriptor for circular + * buffers only freed when + * client has disabled dma + */ + } + /* + * If a new descriptor is queued, set it up + * plchan->at is NULL here + */ + if (!list_empty(&plchan->desc_list)) { struct pl08x_txd *next; - next = list_first_entry(&plchan->pend_list, + next = list_first_entry(&plchan->desc_list, struct pl08x_txd, node); list_del(&next->node); - - pl08x_start_txd(plchan, next); - } else if (plchan->phychan_hold) { - /* - * This channel is still in use - we have a new txd being - * prepared and will soon be queued. Don't give up the - * physical channel. - */ + plchan->at = next; + /* Configure the physical channel for the next txd */ + pl08x_config_phychan_for_txd(plchan); + pl08x_set_cregs(pl08x, plchan->phychan); + pl08x_enable_phy_chan(pl08x, plchan->phychan); } else { struct pl08x_dma_chan *waiting = NULL; @@ -1575,14 +1699,20 @@ static void pl08x_tasklet(unsigned long data) * No more jobs, so free up the physical channel * Free any allocated signal on slave transfers too */ - release_phy_channel(plchan); + if ((phychan->signal >= 0) && pl08x->pd->put_signal) { + pl08x->pd->put_signal(plchan); + phychan->signal = -1; + } + pl08x_put_phy_channel(pl08x, phychan); + plchan->phychan = NULL; plchan->state = PL08X_CHAN_IDLE; /* - * And NOW before anyone else can grab that free:d up - * physical channel, see if there is some memcpy pending - * that seriously needs to start because of being stacked - * up while we were choking the physical channels with data. + * And NOW before anyone else can grab that free:d + * up physical channel, see if there is some memcpy + * pending that seriously needs to start because of + * being stacked up while we were choking the + * physical channels with data. */ list_for_each_entry(waiting, &pl08x->memcpy.channels, chan.device_node) { @@ -1594,7 +1724,6 @@ static void pl08x_tasklet(unsigned long data) ret = prep_phy_channel(waiting, waiting->waiting); BUG_ON(ret); - waiting->phychan_hold--; waiting->state = PL08X_CHAN_RUNNING; waiting->waiting = NULL; pl08x_issue_pending(&waiting->chan); @@ -1603,25 +1732,7 @@ static void pl08x_tasklet(unsigned long data) } } - spin_unlock_irqrestore(&plchan->lock, flags); - - if (txd) { - dma_async_tx_callback callback = txd->tx.callback; - void *callback_param = txd->tx.callback_param; - - /* Don't try to unmap buffers on slave channels */ - if (!plchan->slave) - pl08x_unmap_buffers(txd); - - /* Free the descriptor */ - spin_lock_irqsave(&plchan->lock, flags); - pl08x_free_txd(pl08x, txd); - spin_unlock_irqrestore(&plchan->lock, flags); - - /* Callback to signal completion */ - if (callback) - callback(callback_param); - } + spin_unlock(&plchan->lock); } static irqreturn_t pl08x_irq(int irq, void *dev) @@ -1633,7 +1744,9 @@ static irqreturn_t pl08x_irq(int irq, void *dev) val = readl(pl08x->base + PL080_ERR_STATUS); if (val) { - /* An error interrupt (on one or more channels) */ + /* + * An error interrupt (on one or more channels) + */ dev_err(&pl08x->adev->dev, "%s error interrupt, register value 0x%08x\n", __func__, val); @@ -1657,7 +1770,9 @@ static irqreturn_t pl08x_irq(int irq, void *dev) mask |= (1 << i); } } - /* Clear only the terminal interrupts on channels we processed */ + /* + * Clear only the terminal interrupts on channels we processed + */ writel(mask, pl08x->base + PL080_TC_CLEAR); return mask ? IRQ_HANDLED : IRQ_NONE; @@ -1676,7 +1791,6 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x, int i; INIT_LIST_HEAD(&dmadev->channels); - /* * Register as many many memcpy as we have physical channels, * we won't always be able to use all but the code will have @@ -1705,23 +1819,16 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x, return -ENOMEM; } } - if (chan->cd->circular_buffer) { - dev_err(&pl08x->adev->dev, - "channel %s: circular buffers not supported\n", - chan->name); - kfree(chan); - continue; - } dev_info(&pl08x->adev->dev, "initialize virtual channel \"%s\"\n", chan->name); chan->chan.device = dmadev; - chan->chan.cookie = 0; - chan->lc = 0; + atomic_set(&chan->last_issued, 0); + chan->lc = atomic_read(&chan->last_issued); spin_lock_init(&chan->lock); - INIT_LIST_HEAD(&chan->pend_list); + INIT_LIST_HEAD(&chan->desc_list); tasklet_init(&chan->tasklet, pl08x_tasklet, (unsigned long) chan); @@ -1791,7 +1898,7 @@ static int pl08x_debugfs_show(struct seq_file *s, void *data) seq_printf(s, "CHANNEL:\tSTATE:\n"); seq_printf(s, "--------\t------\n"); list_for_each_entry(chan, &pl08x->memcpy.channels, chan.device_node) { - seq_printf(s, "%s\t\t%s\n", chan->name, + seq_printf(s, "%s\t\t\%s\n", chan->name, pl08x_state_str(chan->state)); } @@ -1799,7 +1906,7 @@ static int pl08x_debugfs_show(struct seq_file *s, void *data) seq_printf(s, "CHANNEL:\tSTATE:\n"); seq_printf(s, "--------\t------\n"); list_for_each_entry(chan, &pl08x->slave.channels, chan.device_node) { - seq_printf(s, "%s\t\t%s\n", chan->name, + seq_printf(s, "%s\t\t\%s\n", chan->name, pl08x_state_str(chan->state)); } @@ -1835,7 +1942,7 @@ static inline void init_pl08x_debugfs(struct pl08x_driver_data *pl08x) static int pl08x_probe(struct amba_device *adev, struct amba_id *id) { struct pl08x_driver_data *pl08x; - const struct vendor_data *vd = id->data; + struct vendor_data *vd = id->data; int ret = 0; int i; @@ -1883,14 +1990,6 @@ static int pl08x_probe(struct amba_device *adev, struct amba_id *id) pl08x->adev = adev; pl08x->vd = vd; - /* By default, AHB1 only. If dualmaster, from platform */ - pl08x->lli_buses = PL08X_AHB1; - pl08x->mem_buses = PL08X_AHB1; - if (pl08x->vd->dualmaster) { - pl08x->lli_buses = pl08x->pd->lli_buses; - pl08x->mem_buses = pl08x->pd->mem_buses; - } - /* A DMA memory pool for LLIs, align on 1-byte boundary */ pl08x->pool = dma_pool_create(DRIVER_NAME, &pl08x->adev->dev, PL08X_LLI_TSFR_SIZE, PL08X_ALIGN, 0); @@ -1910,12 +2009,14 @@ static int pl08x_probe(struct amba_device *adev, struct amba_id *id) /* Turn on the PL08x */ pl08x_ensure_on(pl08x); - /* Attach the interrupt handler */ + /* + * Attach the interrupt handler + */ writel(0x000000FF, pl08x->base + PL080_ERR_CLEAR); writel(0x000000FF, pl08x->base + PL080_TC_CLEAR); ret = request_irq(adev->irq[0], pl08x_irq, IRQF_DISABLED, - DRIVER_NAME, pl08x); + vd->name, pl08x); if (ret) { dev_err(&adev->dev, "%s failed to request interrupt %d\n", __func__, adev->irq[0]); @@ -1986,9 +2087,8 @@ static int pl08x_probe(struct amba_device *adev, struct amba_id *id) amba_set_drvdata(adev, pl08x); init_pl08x_debugfs(pl08x); - dev_info(&pl08x->adev->dev, "DMA: PL%03x rev%u at 0x%08llx irq %d\n", - amba_part(adev), amba_rev(adev), - (unsigned long long)adev->res.start, adev->irq[0]); + dev_info(&pl08x->adev->dev, "ARM(R) %s DMA block initialized @%08x\n", + vd->name, adev->res.start); return 0; out_no_slave_reg: @@ -2015,11 +2115,13 @@ static int pl08x_probe(struct amba_device *adev, struct amba_id *id) /* PL080 has 8 channels and the PL080 have just 2 */ static struct vendor_data vendor_pl080 = { + .name = "PL080", .channels = 8, .dualmaster = true, }; static struct vendor_data vendor_pl081 = { + .name = "PL081", .channels = 2, .dualmaster = false, }; @@ -2058,7 +2160,7 @@ static int __init pl08x_init(void) retval = amba_driver_register(&pl08x_amba_driver); if (retval) printk(KERN_WARNING DRIVER_NAME - "failed to register as an AMBA device (%d)\n", + "failed to register as an amba device (%d)\n", retval); return retval; } diff --git a/trunk/drivers/dma/at_hdmac.c b/trunk/drivers/dma/at_hdmac.c index 3d7d705f026f..ea0ee81cff53 100644 --- a/trunk/drivers/dma/at_hdmac.c +++ b/trunk/drivers/dma/at_hdmac.c @@ -253,7 +253,7 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc) /* move myself to free_list */ list_move(&desc->desc_node, &atchan->free_list); - /* unmap dma addresses (not on slave channels) */ + /* unmap dma addresses */ if (!atchan->chan_common.private) { struct device *parent = chan2parent(&atchan->chan_common); if (!(txd->flags & DMA_COMPL_SKIP_DEST_UNMAP)) { @@ -583,6 +583,7 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, desc->lli.ctrlb = ctrlb; desc->txd.cookie = 0; + async_tx_ack(&desc->txd); if (!first) { first = desc; @@ -603,7 +604,7 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, /* set end-of-link to the last link descriptor of list*/ set_desc_eol(desc); - first->txd.flags = flags; /* client is in control of this ack */ + desc->txd.flags = flags; /* client is in control of this ack */ return &first->txd; @@ -669,7 +670,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, if (!desc) goto err_desc_get; - mem = sg_dma_address(sg); + mem = sg_phys(sg); len = sg_dma_len(sg); mem_width = 2; if (unlikely(mem & 3 || len & 3)) @@ -711,7 +712,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, if (!desc) goto err_desc_get; - mem = sg_dma_address(sg); + mem = sg_phys(sg); len = sg_dma_len(sg); mem_width = 2; if (unlikely(mem & 3 || len & 3)) @@ -748,8 +749,8 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, first->txd.cookie = -EBUSY; first->len = total_len; - /* first link descriptor of list is responsible of flags */ - first->txd.flags = flags; /* client is in control of this ack */ + /* last link descriptor of list is responsible of flags */ + prev->txd.flags = flags; /* client is in control of this ack */ return &first->txd; @@ -853,11 +854,11 @@ static void atc_issue_pending(struct dma_chan *chan) dev_vdbg(chan2dev(chan), "issue_pending\n"); - spin_lock_bh(&atchan->lock); if (!atc_chan_is_enabled(atchan)) { + spin_lock_bh(&atchan->lock); atc_advance_work(atchan); + spin_unlock_bh(&atchan->lock); } - spin_unlock_bh(&atchan->lock); } /** @@ -1209,7 +1210,7 @@ static int __init at_dma_init(void) { return platform_driver_probe(&at_dma_driver, at_dma_probe); } -subsys_initcall(at_dma_init); +module_init(at_dma_init); static void __exit at_dma_exit(void) { diff --git a/trunk/drivers/dma/fsldma.c b/trunk/drivers/dma/fsldma.c index 4de947a450fc..e5e172d21692 100644 --- a/trunk/drivers/dma/fsldma.c +++ b/trunk/drivers/dma/fsldma.c @@ -1,7 +1,7 @@ /* * Freescale MPC85xx, MPC83xx DMA Engine support * - * Copyright (C) 2007-2010 Freescale Semiconductor, Inc. All rights reserved. + * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. * * Author: * Zhang Wei , Jul 2007 @@ -1324,8 +1324,6 @@ static int __devinit fsldma_of_probe(struct platform_device *op, fdev->common.device_control = fsl_dma_device_control; fdev->common.dev = &op->dev; - dma_set_mask(&(op->dev), DMA_BIT_MASK(36)); - dev_set_drvdata(&op->dev, fdev); /* diff --git a/trunk/drivers/dma/intel_mid_dma.c b/trunk/drivers/dma/intel_mid_dma.c index 798f46a4590d..78266382797e 100644 --- a/trunk/drivers/dma/intel_mid_dma.c +++ b/trunk/drivers/dma/intel_mid_dma.c @@ -664,20 +664,11 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_memcpy( /*calculate CTL_LO*/ ctl_lo.ctl_lo = 0; ctl_lo.ctlx.int_en = 1; + ctl_lo.ctlx.dst_tr_width = mids->dma_slave.dst_addr_width; + ctl_lo.ctlx.src_tr_width = mids->dma_slave.src_addr_width; ctl_lo.ctlx.dst_msize = mids->dma_slave.src_maxburst; ctl_lo.ctlx.src_msize = mids->dma_slave.dst_maxburst; - /* - * Here we need some translation from "enum dma_slave_buswidth" - * to the format for our dma controller - * standard intel_mid_dmac's format - * 1 Byte 0b000 - * 2 Bytes 0b001 - * 4 Bytes 0b010 - */ - ctl_lo.ctlx.dst_tr_width = mids->dma_slave.dst_addr_width / 2; - ctl_lo.ctlx.src_tr_width = mids->dma_slave.src_addr_width / 2; - if (mids->cfg_mode == LNW_DMA_MEM_TO_MEM) { ctl_lo.ctlx.tt_fc = 0; ctl_lo.ctlx.sinc = 0; @@ -755,18 +746,8 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_slave_sg( BUG_ON(!mids); if (!midc->dma->pimr_mask) { - /* We can still handle sg list with only one item */ - if (sg_len == 1) { - txd = intel_mid_dma_prep_memcpy(chan, - mids->dma_slave.dst_addr, - mids->dma_slave.src_addr, - sgl->length, - flags); - return txd; - } else { - pr_warn("MDMA: SG list is not supported by this controller\n"); - return NULL; - } + pr_debug("MDMA: SG list is not supported by this controller\n"); + return NULL; } pr_debug("MDMA: SG Length = %d, direction = %d, Flags = %#lx\n", @@ -777,7 +758,6 @@ static struct dma_async_tx_descriptor *intel_mid_dma_prep_slave_sg( pr_err("MDMA: Prep memcpy failed\n"); return NULL; } - desc = to_intel_mid_dma_desc(txd); desc->dirn = direction; ctl_lo.ctl_lo = desc->ctl_lo; @@ -1041,6 +1021,11 @@ static irqreturn_t intel_mid_dma_interrupt(int irq, void *data) /*DMA Interrupt*/ pr_debug("MDMA:Got an interrupt on irq %d\n", irq); + if (!mid) { + pr_err("ERR_MDMA:null pointer mid\n"); + return -EINVAL; + } + pr_debug("MDMA: Status %x, Mask %x\n", tfr_status, mid->intr_mask); tfr_status &= mid->intr_mask; if (tfr_status) { diff --git a/trunk/drivers/dma/iop-adma.c b/trunk/drivers/dma/iop-adma.c index c6b01f535b29..161c452923b8 100644 --- a/trunk/drivers/dma/iop-adma.c +++ b/trunk/drivers/dma/iop-adma.c @@ -1261,7 +1261,7 @@ iop_adma_xor_val_self_test(struct iop_adma_device *device) return err; } -#ifdef CONFIG_RAID6_PQ +#ifdef CONFIG_MD_RAID6_PQ static int __devinit iop_adma_pq_zero_sum_self_test(struct iop_adma_device *device) { @@ -1584,7 +1584,7 @@ static int __devinit iop_adma_probe(struct platform_device *pdev) if (dma_has_cap(DMA_PQ, dma_dev->cap_mask) && dma_has_cap(DMA_PQ_VAL, dma_dev->cap_mask)) { - #ifdef CONFIG_RAID6_PQ + #ifdef CONFIG_MD_RAID6_PQ ret = iop_adma_pq_zero_sum_self_test(adev); dev_dbg(&pdev->dev, "pq self test returned %d\n", ret); #else diff --git a/trunk/drivers/dma/pch_dma.c b/trunk/drivers/dma/pch_dma.c index 1c38418ae61f..c064c89420d0 100644 --- a/trunk/drivers/dma/pch_dma.c +++ b/trunk/drivers/dma/pch_dma.c @@ -1,7 +1,6 @@ /* * Topcliff PCH DMA controller driver * Copyright (c) 2010 Intel Corporation - * Copyright (C) 2011 OKI SEMICONDUCTOR CO., LTD. * * 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 @@ -922,19 +921,12 @@ static void __devexit pch_dma_remove(struct pci_dev *pdev) } /* PCI Device ID of DMA device */ -#define PCI_VENDOR_ID_ROHM 0x10DB -#define PCI_DEVICE_ID_EG20T_PCH_DMA_8CH 0x8810 -#define PCI_DEVICE_ID_EG20T_PCH_DMA_4CH 0x8815 -#define PCI_DEVICE_ID_ML7213_DMA1_8CH 0x8026 -#define PCI_DEVICE_ID_ML7213_DMA2_8CH 0x802B -#define PCI_DEVICE_ID_ML7213_DMA3_4CH 0x8034 +#define PCI_DEVICE_ID_PCH_DMA_8CH 0x8810 +#define PCI_DEVICE_ID_PCH_DMA_4CH 0x8815 static const struct pci_device_id pch_dma_id_table[] = { - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_EG20T_PCH_DMA_8CH), 8 }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_EG20T_PCH_DMA_4CH), 4 }, - { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_DMA1_8CH), 8}, /* UART Video */ - { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_DMA2_8CH), 8}, /* PCMIF SPI */ - { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_DMA3_4CH), 4}, /* FPGA */ + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_DMA_8CH), 8 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_DMA_4CH), 4 }, { 0, }, }; @@ -962,7 +954,6 @@ static void __exit pch_dma_exit(void) module_init(pch_dma_init); module_exit(pch_dma_exit); -MODULE_DESCRIPTION("Intel EG20T PCH / OKI SEMICONDUCTOR ML7213 IOH " - "DMA controller driver"); +MODULE_DESCRIPTION("Topcliff PCH DMA controller driver"); MODULE_AUTHOR("Yong Wang "); MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/dma/ste_dma40.c b/trunk/drivers/dma/ste_dma40.c index 6e1d46a65d0e..fab68a553205 100644 --- a/trunk/drivers/dma/ste_dma40.c +++ b/trunk/drivers/dma/ste_dma40.c @@ -1,6 +1,5 @@ /* - * Copyright (C) Ericsson AB 2007-2008 - * Copyright (C) ST-Ericsson SA 2008-2010 + * Copyright (C) ST-Ericsson SA 2007-2010 * Author: Per Forlin for ST-Ericsson * Author: Jonas Aaberg for ST-Ericsson * License terms: GNU General Public License (GPL) version 2 @@ -555,67 +554,9 @@ static struct d40_desc *d40_last_queued(struct d40_chan *d40c) return d; } -static int d40_psize_2_burst_size(bool is_log, int psize) -{ - if (is_log) { - if (psize == STEDMA40_PSIZE_LOG_1) - return 1; - } else { - if (psize == STEDMA40_PSIZE_PHY_1) - return 1; - } - - return 2 << psize; -} - -/* - * The dma only supports transmitting packages up to - * STEDMA40_MAX_SEG_SIZE << data_width. Calculate the total number of - * dma elements required to send the entire sg list - */ -static int d40_size_2_dmalen(int size, u32 data_width1, u32 data_width2) -{ - int dmalen; - u32 max_w = max(data_width1, data_width2); - u32 min_w = min(data_width1, data_width2); - u32 seg_max = ALIGN(STEDMA40_MAX_SEG_SIZE << min_w, 1 << max_w); - - if (seg_max > STEDMA40_MAX_SEG_SIZE) - seg_max -= (1 << max_w); - - if (!IS_ALIGNED(size, 1 << max_w)) - return -EINVAL; - - if (size <= seg_max) - dmalen = 1; - else { - dmalen = size / seg_max; - if (dmalen * seg_max < size) - dmalen++; - } - return dmalen; -} - -static int d40_sg_2_dmalen(struct scatterlist *sgl, int sg_len, - u32 data_width1, u32 data_width2) -{ - struct scatterlist *sg; - int i; - int len = 0; - int ret; - - for_each_sg(sgl, sg, sg_len, i) { - ret = d40_size_2_dmalen(sg_dma_len(sg), - data_width1, data_width2); - if (ret < 0) - return ret; - len += ret; - } - return len; -} - /* Support functions for logical channels */ + static int d40_channel_execute_command(struct d40_chan *d40c, enum d40_command command) { @@ -1300,21 +1241,6 @@ static int d40_validate_conf(struct d40_chan *d40c, res = -EINVAL; } - if (d40_psize_2_burst_size(is_log, conf->src_info.psize) * - (1 << conf->src_info.data_width) != - d40_psize_2_burst_size(is_log, conf->dst_info.psize) * - (1 << conf->dst_info.data_width)) { - /* - * The DMAC hardware only supports - * src (burst x width) == dst (burst x width) - */ - - dev_err(&d40c->chan.dev->device, - "[%s] src (burst x width) != dst (burst x width)\n", - __func__); - res = -EINVAL; - } - return res; } @@ -1712,21 +1638,13 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, if (d40d == NULL) goto err; - d40d->lli_len = d40_sg_2_dmalen(sgl_dst, sgl_len, - d40c->dma_cfg.src_info.data_width, - d40c->dma_cfg.dst_info.data_width); - if (d40d->lli_len < 0) { - dev_err(&d40c->chan.dev->device, - "[%s] Unaligned size\n", __func__); - goto err; - } - + d40d->lli_len = sgl_len; d40d->lli_current = 0; d40d->txd.flags = dma_flags; if (d40c->log_num != D40_PHY_CHAN) { - if (d40_pool_lli_alloc(d40d, d40d->lli_len, true) < 0) { + if (d40_pool_lli_alloc(d40d, sgl_len, true) < 0) { dev_err(&d40c->chan.dev->device, "[%s] Out of memory\n", __func__); goto err; @@ -1736,17 +1654,15 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, sgl_len, d40d->lli_log.src, d40c->log_def.lcsp1, - d40c->dma_cfg.src_info.data_width, - d40c->dma_cfg.dst_info.data_width); + d40c->dma_cfg.src_info.data_width); (void) d40_log_sg_to_lli(sgl_dst, sgl_len, d40d->lli_log.dst, d40c->log_def.lcsp3, - d40c->dma_cfg.dst_info.data_width, - d40c->dma_cfg.src_info.data_width); + d40c->dma_cfg.dst_info.data_width); } else { - if (d40_pool_lli_alloc(d40d, d40d->lli_len, false) < 0) { + if (d40_pool_lli_alloc(d40d, sgl_len, false) < 0) { dev_err(&d40c->chan.dev->device, "[%s] Out of memory\n", __func__); goto err; @@ -1759,7 +1675,6 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, virt_to_phys(d40d->lli_phy.src), d40c->src_def_cfg, d40c->dma_cfg.src_info.data_width, - d40c->dma_cfg.dst_info.data_width, d40c->dma_cfg.src_info.psize); if (res < 0) @@ -1772,7 +1687,6 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, virt_to_phys(d40d->lli_phy.dst), d40c->dst_def_cfg, d40c->dma_cfg.dst_info.data_width, - d40c->dma_cfg.src_info.data_width, d40c->dma_cfg.dst_info.psize); if (res < 0) @@ -1912,6 +1826,7 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan, struct d40_chan *d40c = container_of(chan, struct d40_chan, chan); unsigned long flags; + int err = 0; if (d40c->phy_chan == NULL) { dev_err(&d40c->chan.dev->device, @@ -1929,15 +1844,6 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan, } d40d->txd.flags = dma_flags; - d40d->lli_len = d40_size_2_dmalen(size, - d40c->dma_cfg.src_info.data_width, - d40c->dma_cfg.dst_info.data_width); - if (d40d->lli_len < 0) { - dev_err(&d40c->chan.dev->device, - "[%s] Unaligned size\n", __func__); - goto err; - } - dma_async_tx_descriptor_init(&d40d->txd, chan); @@ -1945,40 +1851,37 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan, if (d40c->log_num != D40_PHY_CHAN) { - if (d40_pool_lli_alloc(d40d, d40d->lli_len, true) < 0) { + if (d40_pool_lli_alloc(d40d, 1, true) < 0) { dev_err(&d40c->chan.dev->device, "[%s] Out of memory\n", __func__); goto err; } + d40d->lli_len = 1; d40d->lli_current = 0; - if (d40_log_buf_to_lli(d40d->lli_log.src, - src, - size, - d40c->log_def.lcsp1, - d40c->dma_cfg.src_info.data_width, - d40c->dma_cfg.dst_info.data_width, - true) == NULL) - goto err; + d40_log_fill_lli(d40d->lli_log.src, + src, + size, + d40c->log_def.lcsp1, + d40c->dma_cfg.src_info.data_width, + true); - if (d40_log_buf_to_lli(d40d->lli_log.dst, - dst, - size, - d40c->log_def.lcsp3, - d40c->dma_cfg.dst_info.data_width, - d40c->dma_cfg.src_info.data_width, - true) == NULL) - goto err; + d40_log_fill_lli(d40d->lli_log.dst, + dst, + size, + d40c->log_def.lcsp3, + d40c->dma_cfg.dst_info.data_width, + true); } else { - if (d40_pool_lli_alloc(d40d, d40d->lli_len, false) < 0) { + if (d40_pool_lli_alloc(d40d, 1, false) < 0) { dev_err(&d40c->chan.dev->device, "[%s] Out of memory\n", __func__); goto err; } - if (d40_phy_buf_to_lli(d40d->lli_phy.src, + err = d40_phy_fill_lli(d40d->lli_phy.src, src, size, d40c->dma_cfg.src_info.psize, @@ -1986,11 +1889,11 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan, d40c->src_def_cfg, true, d40c->dma_cfg.src_info.data_width, - d40c->dma_cfg.dst_info.data_width, - false) == NULL) - goto err; + false); + if (err) + goto err_fill_lli; - if (d40_phy_buf_to_lli(d40d->lli_phy.dst, + err = d40_phy_fill_lli(d40d->lli_phy.dst, dst, size, d40c->dma_cfg.dst_info.psize, @@ -1998,9 +1901,10 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan, d40c->dst_def_cfg, true, d40c->dma_cfg.dst_info.data_width, - d40c->dma_cfg.src_info.data_width, - false) == NULL) - goto err; + false); + + if (err) + goto err_fill_lli; (void) dma_map_single(d40c->base->dev, d40d->lli_phy.src, d40d->lli_pool.size, DMA_TO_DEVICE); @@ -2009,6 +1913,9 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan, spin_unlock_irqrestore(&d40c->lock, flags); return &d40d->txd; +err_fill_lli: + dev_err(&d40c->chan.dev->device, + "[%s] Failed filling in PHY LLI\n", __func__); err: if (d40d) d40_desc_free(d40c, d40d); @@ -2038,21 +1945,13 @@ static int d40_prep_slave_sg_log(struct d40_desc *d40d, dma_addr_t dev_addr = 0; int total_size; - d40d->lli_len = d40_sg_2_dmalen(sgl, sg_len, - d40c->dma_cfg.src_info.data_width, - d40c->dma_cfg.dst_info.data_width); - if (d40d->lli_len < 0) { - dev_err(&d40c->chan.dev->device, - "[%s] Unaligned size\n", __func__); - return -EINVAL; - } - - if (d40_pool_lli_alloc(d40d, d40d->lli_len, true) < 0) { + if (d40_pool_lli_alloc(d40d, sg_len, true) < 0) { dev_err(&d40c->chan.dev->device, "[%s] Out of memory\n", __func__); return -ENOMEM; } + d40d->lli_len = sg_len; d40d->lli_current = 0; if (direction == DMA_FROM_DEVICE) @@ -2094,21 +1993,13 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d, dma_addr_t dst_dev_addr; int res; - d40d->lli_len = d40_sg_2_dmalen(sgl, sgl_len, - d40c->dma_cfg.src_info.data_width, - d40c->dma_cfg.dst_info.data_width); - if (d40d->lli_len < 0) { - dev_err(&d40c->chan.dev->device, - "[%s] Unaligned size\n", __func__); - return -EINVAL; - } - - if (d40_pool_lli_alloc(d40d, d40d->lli_len, false) < 0) { + if (d40_pool_lli_alloc(d40d, sgl_len, false) < 0) { dev_err(&d40c->chan.dev->device, "[%s] Out of memory\n", __func__); return -ENOMEM; } + d40d->lli_len = sgl_len; d40d->lli_current = 0; if (direction == DMA_FROM_DEVICE) { @@ -2133,7 +2024,6 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d, virt_to_phys(d40d->lli_phy.src), d40c->src_def_cfg, d40c->dma_cfg.src_info.data_width, - d40c->dma_cfg.dst_info.data_width, d40c->dma_cfg.src_info.psize); if (res < 0) return res; @@ -2145,7 +2035,6 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d, virt_to_phys(d40d->lli_phy.dst), d40c->dst_def_cfg, d40c->dma_cfg.dst_info.data_width, - d40c->dma_cfg.src_info.data_width, d40c->dma_cfg.dst_info.psize); if (res < 0) return res; @@ -2355,8 +2244,6 @@ static void d40_set_runtime_config(struct dma_chan *chan, psize = STEDMA40_PSIZE_PHY_8; else if (config_maxburst >= 4) psize = STEDMA40_PSIZE_PHY_4; - else if (config_maxburst >= 2) - psize = STEDMA40_PSIZE_PHY_2; else psize = STEDMA40_PSIZE_PHY_1; } diff --git a/trunk/drivers/dma/ste_dma40_ll.c b/trunk/drivers/dma/ste_dma40_ll.c index 0b096a38322d..8557cb88b255 100644 --- a/trunk/drivers/dma/ste_dma40_ll.c +++ b/trunk/drivers/dma/ste_dma40_ll.c @@ -1,6 +1,6 @@ /* * Copyright (C) ST-Ericsson SA 2007-2010 - * Author: Per Forlin for ST-Ericsson + * Author: Per Friden for ST-Ericsson * Author: Jonas Aaberg for ST-Ericsson * License terms: GNU General Public License (GPL) version 2 */ @@ -122,15 +122,15 @@ void d40_phy_cfg(struct stedma40_chan_cfg *cfg, *dst_cfg = dst; } -static int d40_phy_fill_lli(struct d40_phy_lli *lli, - dma_addr_t data, - u32 data_size, - int psize, - dma_addr_t next_lli, - u32 reg_cfg, - bool term_int, - u32 data_width, - bool is_device) +int d40_phy_fill_lli(struct d40_phy_lli *lli, + dma_addr_t data, + u32 data_size, + int psize, + dma_addr_t next_lli, + u32 reg_cfg, + bool term_int, + u32 data_width, + bool is_device) { int num_elems; @@ -139,6 +139,13 @@ static int d40_phy_fill_lli(struct d40_phy_lli *lli, else num_elems = 2 << psize; + /* + * Size is 16bit. data_width is 8, 16, 32 or 64 bit + * Block large than 64 KiB must be split. + */ + if (data_size > (0xffff << data_width)) + return -EINVAL; + /* Must be aligned */ if (!IS_ALIGNED(data, 0x1 << data_width)) return -EINVAL; @@ -180,118 +187,55 @@ static int d40_phy_fill_lli(struct d40_phy_lli *lli, return 0; } -static int d40_seg_size(int size, int data_width1, int data_width2) -{ - u32 max_w = max(data_width1, data_width2); - u32 min_w = min(data_width1, data_width2); - u32 seg_max = ALIGN(STEDMA40_MAX_SEG_SIZE << min_w, 1 << max_w); - - if (seg_max > STEDMA40_MAX_SEG_SIZE) - seg_max -= (1 << max_w); - - if (size <= seg_max) - return size; - - if (size <= 2 * seg_max) - return ALIGN(size / 2, 1 << max_w); - - return seg_max; -} - -struct d40_phy_lli *d40_phy_buf_to_lli(struct d40_phy_lli *lli, - dma_addr_t addr, - u32 size, - int psize, - dma_addr_t lli_phys, - u32 reg_cfg, - bool term_int, - u32 data_width1, - u32 data_width2, - bool is_device) -{ - int err; - dma_addr_t next = lli_phys; - int size_rest = size; - int size_seg = 0; - - do { - size_seg = d40_seg_size(size_rest, data_width1, data_width2); - size_rest -= size_seg; - - if (term_int && size_rest == 0) - next = 0; - else - next = ALIGN(next + sizeof(struct d40_phy_lli), - D40_LLI_ALIGN); - - err = d40_phy_fill_lli(lli, - addr, - size_seg, - psize, - next, - reg_cfg, - !next, - data_width1, - is_device); - - if (err) - goto err; - - lli++; - if (!is_device) - addr += size_seg; - } while (size_rest); - - return lli; - - err: - return NULL; -} - int d40_phy_sg_to_lli(struct scatterlist *sg, int sg_len, dma_addr_t target, - struct d40_phy_lli *lli_sg, + struct d40_phy_lli *lli, dma_addr_t lli_phys, u32 reg_cfg, - u32 data_width1, - u32 data_width2, + u32 data_width, int psize) { int total_size = 0; int i; struct scatterlist *current_sg = sg; + dma_addr_t next_lli_phys; dma_addr_t dst; - struct d40_phy_lli *lli = lli_sg; - dma_addr_t l_phys = lli_phys; + int err = 0; for_each_sg(sg, current_sg, sg_len, i) { total_size += sg_dma_len(current_sg); + /* If this scatter list entry is the last one, no next link */ + if (sg_len - 1 == i) + next_lli_phys = 0; + else + next_lli_phys = ALIGN(lli_phys + (i + 1) * + sizeof(struct d40_phy_lli), + D40_LLI_ALIGN); + if (target) dst = target; else dst = sg_phys(current_sg); - l_phys = ALIGN(lli_phys + (lli - lli_sg) * - sizeof(struct d40_phy_lli), D40_LLI_ALIGN); - - lli = d40_phy_buf_to_lli(lli, - dst, - sg_dma_len(current_sg), - psize, - l_phys, - reg_cfg, - sg_len - 1 == i, - data_width1, - data_width2, - target == dst); - if (lli == NULL) - return -EINVAL; + err = d40_phy_fill_lli(&lli[i], + dst, + sg_dma_len(current_sg), + psize, + next_lli_phys, + reg_cfg, + !next_lli_phys, + data_width, + target == dst); + if (err) + goto err; } return total_size; +err: + return err; } @@ -371,20 +315,17 @@ void d40_log_lli_lcla_write(struct d40_log_lli *lcla, writel(lli_dst->lcsp13, &lcla[1].lcsp13); } -static void d40_log_fill_lli(struct d40_log_lli *lli, - dma_addr_t data, u32 data_size, - u32 reg_cfg, - u32 data_width, - bool addr_inc) +void d40_log_fill_lli(struct d40_log_lli *lli, + dma_addr_t data, u32 data_size, + u32 reg_cfg, + u32 data_width, + bool addr_inc) { lli->lcsp13 = reg_cfg; /* The number of elements to transfer */ lli->lcsp02 = ((data_size >> data_width) << D40_MEM_LCSP0_ECNT_POS) & D40_MEM_LCSP0_ECNT_MASK; - - BUG_ON((data_size >> data_width) > STEDMA40_MAX_SEG_SIZE); - /* 16 LSBs address of the current element */ lli->lcsp02 |= data & D40_MEM_LCSP0_SPTR_MASK; /* 16 MSBs address of the current element */ @@ -407,94 +348,55 @@ int d40_log_sg_to_dev(struct scatterlist *sg, int total_size = 0; struct scatterlist *current_sg = sg; int i; - struct d40_log_lli *lli_src = lli->src; - struct d40_log_lli *lli_dst = lli->dst; for_each_sg(sg, current_sg, sg_len, i) { total_size += sg_dma_len(current_sg); if (direction == DMA_TO_DEVICE) { - lli_src = - d40_log_buf_to_lli(lli_src, - sg_phys(current_sg), - sg_dma_len(current_sg), - lcsp->lcsp1, src_data_width, - dst_data_width, - true); - lli_dst = - d40_log_buf_to_lli(lli_dst, - dev_addr, - sg_dma_len(current_sg), - lcsp->lcsp3, dst_data_width, - src_data_width, - false); + d40_log_fill_lli(&lli->src[i], + sg_phys(current_sg), + sg_dma_len(current_sg), + lcsp->lcsp1, src_data_width, + true); + d40_log_fill_lli(&lli->dst[i], + dev_addr, + sg_dma_len(current_sg), + lcsp->lcsp3, dst_data_width, + false); } else { - lli_dst = - d40_log_buf_to_lli(lli_dst, - sg_phys(current_sg), - sg_dma_len(current_sg), - lcsp->lcsp3, dst_data_width, - src_data_width, - true); - lli_src = - d40_log_buf_to_lli(lli_src, - dev_addr, - sg_dma_len(current_sg), - lcsp->lcsp1, src_data_width, - dst_data_width, - false); + d40_log_fill_lli(&lli->dst[i], + sg_phys(current_sg), + sg_dma_len(current_sg), + lcsp->lcsp3, dst_data_width, + true); + d40_log_fill_lli(&lli->src[i], + dev_addr, + sg_dma_len(current_sg), + lcsp->lcsp1, src_data_width, + false); } } return total_size; } -struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg, - dma_addr_t addr, - int size, - u32 lcsp13, /* src or dst*/ - u32 data_width1, - u32 data_width2, - bool addr_inc) -{ - struct d40_log_lli *lli = lli_sg; - int size_rest = size; - int size_seg = 0; - - do { - size_seg = d40_seg_size(size_rest, data_width1, data_width2); - size_rest -= size_seg; - - d40_log_fill_lli(lli, - addr, - size_seg, - lcsp13, data_width1, - addr_inc); - if (addr_inc) - addr += size_seg; - lli++; - } while (size_rest); - - return lli; -} - int d40_log_sg_to_lli(struct scatterlist *sg, int sg_len, struct d40_log_lli *lli_sg, u32 lcsp13, /* src or dst*/ - u32 data_width1, u32 data_width2) + u32 data_width) { int total_size = 0; struct scatterlist *current_sg = sg; int i; - struct d40_log_lli *lli = lli_sg; for_each_sg(sg, current_sg, sg_len, i) { total_size += sg_dma_len(current_sg); - lli = d40_log_buf_to_lli(lli, - sg_phys(current_sg), - sg_dma_len(current_sg), - lcsp13, - data_width1, data_width2, true); + + d40_log_fill_lli(&lli_sg[i], + sg_phys(current_sg), + sg_dma_len(current_sg), + lcsp13, data_width, + true); } return total_size; } diff --git a/trunk/drivers/dma/ste_dma40_ll.h b/trunk/drivers/dma/ste_dma40_ll.h index 9cc43495bea2..9e419b907544 100644 --- a/trunk/drivers/dma/ste_dma40_ll.h +++ b/trunk/drivers/dma/ste_dma40_ll.h @@ -292,20 +292,18 @@ int d40_phy_sg_to_lli(struct scatterlist *sg, struct d40_phy_lli *lli, dma_addr_t lli_phys, u32 reg_cfg, - u32 data_width1, - u32 data_width2, + u32 data_width, int psize); -struct d40_phy_lli *d40_phy_buf_to_lli(struct d40_phy_lli *lli, - dma_addr_t data, - u32 data_size, - int psize, - dma_addr_t next_lli, - u32 reg_cfg, - bool term_int, - u32 data_width1, - u32 data_width2, - bool is_device); +int d40_phy_fill_lli(struct d40_phy_lli *lli, + dma_addr_t data, + u32 data_size, + int psize, + dma_addr_t next_lli, + u32 reg_cfg, + bool term_int, + u32 data_width, + bool is_device); void d40_phy_lli_write(void __iomem *virtbase, u32 phy_chan_num, @@ -314,12 +312,12 @@ void d40_phy_lli_write(void __iomem *virtbase, /* Logical channels */ -struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg, - dma_addr_t addr, - int size, - u32 lcsp13, /* src or dst*/ - u32 data_width1, u32 data_width2, - bool addr_inc); +void d40_log_fill_lli(struct d40_log_lli *lli, + dma_addr_t data, + u32 data_size, + u32 reg_cfg, + u32 data_width, + bool addr_inc); int d40_log_sg_to_dev(struct scatterlist *sg, int sg_len, @@ -334,7 +332,7 @@ int d40_log_sg_to_lli(struct scatterlist *sg, int sg_len, struct d40_log_lli *lli_sg, u32 lcsp13, /* src or dst*/ - u32 data_width1, u32 data_width2); + u32 data_width); void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa, struct d40_log_lli *lli_dst, diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_drv.h b/trunk/drivers/gpu/drm/nouveau/nouveau_drv.h index 01bffc4412d2..46e32573b3a3 100644 --- a/trunk/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/trunk/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -160,7 +160,6 @@ enum nouveau_flags { #define NVOBJ_FLAG_ZERO_ALLOC (1 << 1) #define NVOBJ_FLAG_ZERO_FREE (1 << 2) #define NVOBJ_FLAG_VM (1 << 3) -#define NVOBJ_FLAG_VM_USER (1 << 4) #define NVOBJ_CINST_GLOBAL 0xdeadbeef @@ -1577,20 +1576,6 @@ nv_match_device(struct drm_device *dev, unsigned device, dev->pdev->subsystem_device == sub_device; } -/* returns 1 if device is one of the nv4x using the 0x4497 object class, - * helpful to determine a number of other hardware features - */ -static inline int -nv44_graph_class(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - - if ((dev_priv->chipset & 0xf0) == 0x60) - return 1; - - return !(0x0baf & (1 << (dev_priv->chipset & 0x0f))); -} - /* memory type/access flags, do not match hardware values */ #define NV_MEM_ACCESS_RO 1 #define NV_MEM_ACCESS_WO 2 diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/trunk/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 60769d2f9a66..6d56a54b6e2e 100644 --- a/trunk/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/trunk/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -352,8 +352,8 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev, FBINFO_HWACCEL_IMAGEBLIT; info->flags |= FBINFO_CAN_FORCE_OUTPUT; info->fbops = &nouveau_fbcon_sw_ops; - info->fix.smem_start = nvbo->bo.mem.bus.base + - nvbo->bo.mem.bus.offset; + info->fix.smem_start = dev->mode_config.fb_base + + (nvbo->bo.mem.start << PAGE_SHIFT); info->fix.smem_len = size; info->screen_base = nvbo_kmap_obj_iovirtual(nouveau_fb->nvbo); diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_mem.c b/trunk/drivers/gpu/drm/nouveau/nouveau_mem.c index 26347b7cd872..69044eb104bb 100644 --- a/trunk/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/trunk/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -742,24 +742,30 @@ nouveau_vram_manager_debug(struct ttm_mem_type_manager *man, const char *prefix) { struct nouveau_mm *mm = man->priv; struct nouveau_mm_node *r; - u32 total = 0, free = 0; + u64 total = 0, ttotal[3] = {}, tused[3] = {}, tfree[3] = {}; + int i; mutex_lock(&mm->mutex); list_for_each_entry(r, &mm->nodes, nl_entry) { - printk(KERN_DEBUG "%s %d: 0x%010llx 0x%010llx\n", - prefix, r->type, ((u64)r->offset << 12), + printk(KERN_DEBUG "%s %s-%d: 0x%010llx 0x%010llx\n", + prefix, r->free ? "free" : "used", r->type, + ((u64)r->offset << 12), (((u64)r->offset + r->length) << 12)); - total += r->length; - if (!r->type) - free += r->length; + ttotal[r->type] += r->length; + if (r->free) + tfree[r->type] += r->length; + else + tused[r->type] += r->length; } mutex_unlock(&mm->mutex); - printk(KERN_DEBUG "%s total: 0x%010llx free: 0x%010llx\n", - prefix, (u64)total << 12, (u64)free << 12); - printk(KERN_DEBUG "%s block: 0x%08x\n", - prefix, mm->block_size << 12); + printk(KERN_DEBUG "%s total: 0x%010llx\n", prefix, total << 12); + for (i = 0; i < 3; i++) { + printk(KERN_DEBUG "%s type %d: 0x%010llx, " + "used 0x%010llx, free 0x%010llx\n", prefix, + i, ttotal[i] << 12, tused[i] << 12, tfree[i] << 12); + } } const struct ttm_mem_type_manager_func nouveau_vram_manager = { diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_mm.c b/trunk/drivers/gpu/drm/nouveau/nouveau_mm.c index 8844b50c3e54..cdbb11eb701b 100644 --- a/trunk/drivers/gpu/drm/nouveau/nouveau_mm.c +++ b/trunk/drivers/gpu/drm/nouveau/nouveau_mm.c @@ -48,76 +48,175 @@ region_split(struct nouveau_mm *rmm, struct nouveau_mm_node *a, u32 size) b->offset = a->offset; b->length = size; + b->free = a->free; b->type = a->type; a->offset += size; a->length -= size; list_add_tail(&b->nl_entry, &a->nl_entry); - if (b->type == 0) + if (b->free) list_add_tail(&b->fl_entry, &a->fl_entry); return b; } -#define node(root, dir) ((root)->nl_entry.dir == &rmm->nodes) ? NULL : \ - list_entry((root)->nl_entry.dir, struct nouveau_mm_node, nl_entry) +static struct nouveau_mm_node * +nouveau_mm_merge(struct nouveau_mm *rmm, struct nouveau_mm_node *this) +{ + struct nouveau_mm_node *prev, *next; + + /* try to merge with free adjacent entries of same type */ + prev = list_entry(this->nl_entry.prev, struct nouveau_mm_node, nl_entry); + if (this->nl_entry.prev != &rmm->nodes) { + if (prev->free && prev->type == this->type) { + prev->length += this->length; + region_put(rmm, this); + this = prev; + } + } + + next = list_entry(this->nl_entry.next, struct nouveau_mm_node, nl_entry); + if (this->nl_entry.next != &rmm->nodes) { + if (next->free && next->type == this->type) { + next->offset = this->offset; + next->length += this->length; + region_put(rmm, this); + this = next; + } + } + + return this; +} void nouveau_mm_put(struct nouveau_mm *rmm, struct nouveau_mm_node *this) { - struct nouveau_mm_node *prev = node(this, prev); - struct nouveau_mm_node *next = node(this, next); + u32 block_s, block_l; + this->free = true; list_add(&this->fl_entry, &rmm->free); - this->type = 0; + this = nouveau_mm_merge(rmm, this); + + /* any entirely free blocks now? we'll want to remove typing + * on them now so they can be use for any memory allocation + */ + block_s = roundup(this->offset, rmm->block_size); + if (block_s + rmm->block_size > this->offset + this->length) + return; - if (prev && prev->type == 0) { - prev->length += this->length; - region_put(rmm, this); - this = prev; + /* split off any still-typed region at the start */ + if (block_s != this->offset) { + if (!region_split(rmm, this, block_s - this->offset)) + return; } - if (next && next->type == 0) { - next->offset = this->offset; - next->length += this->length; - region_put(rmm, this); + /* split off the soon-to-be-untyped block(s) */ + block_l = rounddown(this->length, rmm->block_size); + if (block_l != this->length) { + this = region_split(rmm, this, block_l); + if (!this) + return; } + + /* mark as having no type, and retry merge with any adjacent + * untyped blocks + */ + this->type = 0; + nouveau_mm_merge(rmm, this); } int nouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc, u32 align, struct nouveau_mm_node **pnode) { - struct nouveau_mm_node *prev, *this, *next; - u32 min = size_nc ? size_nc : size; - u32 align_mask = align - 1; - u32 splitoff; - u32 s, e; - - list_for_each_entry(this, &rmm->free, fl_entry) { - e = this->offset + this->length; - s = this->offset; - - prev = node(this, prev); - if (prev && prev->type != type) - s = roundup(s, rmm->block_size); - - next = node(this, next); - if (next && next->type != type) - e = rounddown(e, rmm->block_size); - - s = (s + align_mask) & ~align_mask; - e &= ~align_mask; - if (s > e || e - s < min) + struct nouveau_mm_node *this, *tmp, *next; + u32 splitoff, avail, alloc; + + list_for_each_entry_safe(this, tmp, &rmm->free, fl_entry) { + next = list_entry(this->nl_entry.next, struct nouveau_mm_node, nl_entry); + if (this->nl_entry.next == &rmm->nodes) + next = NULL; + + /* skip wrongly typed blocks */ + if (this->type && this->type != type) continue; - splitoff = s - this->offset; - if (splitoff && !region_split(rmm, this, splitoff)) - return -ENOMEM; + /* account for alignment */ + splitoff = this->offset & (align - 1); + if (splitoff) + splitoff = align - splitoff; - this = region_split(rmm, this, min(size, e - s)); - if (!this) + if (this->length <= splitoff) + continue; + + /* determine total memory available from this, and + * the next block (if appropriate) + */ + avail = this->length; + if (next && next->free && (!next->type || next->type == type)) + avail += next->length; + + avail -= splitoff; + + /* determine allocation size */ + if (size_nc) { + alloc = min(avail, size); + alloc = rounddown(alloc, size_nc); + if (alloc == 0) + continue; + } else { + alloc = size; + if (avail < alloc) + continue; + } + + /* untyped block, split off a chunk that's a multiple + * of block_size and type it + */ + if (!this->type) { + u32 block = roundup(alloc + splitoff, rmm->block_size); + if (this->length < block) + continue; + + this = region_split(rmm, this, block); + if (!this) + return -ENOMEM; + + this->type = type; + } + + /* stealing memory from adjacent block */ + if (alloc > this->length) { + u32 amount = alloc - (this->length - splitoff); + + if (!next->type) { + amount = roundup(amount, rmm->block_size); + + next = region_split(rmm, next, amount); + if (!next) + return -ENOMEM; + + next->type = type; + } + + this->length += amount; + next->offset += amount; + next->length -= amount; + if (!next->length) { + list_del(&next->nl_entry); + list_del(&next->fl_entry); + kfree(next); + } + } + + if (splitoff) { + if (!region_split(rmm, this, splitoff)) + return -ENOMEM; + } + + this = region_split(rmm, this, alloc); + if (this == NULL) return -ENOMEM; - this->type = type; + this->free = false; list_del(&this->fl_entry); *pnode = this; return 0; @@ -135,6 +234,7 @@ nouveau_mm_init(struct nouveau_mm **prmm, u32 offset, u32 length, u32 block) heap = kzalloc(sizeof(*heap), GFP_KERNEL); if (!heap) return -ENOMEM; + heap->free = true; heap->offset = roundup(offset, block); heap->length = rounddown(offset + length, block) - heap->offset; diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_mm.h b/trunk/drivers/gpu/drm/nouveau/nouveau_mm.h index 798eaf39691c..af3844933036 100644 --- a/trunk/drivers/gpu/drm/nouveau/nouveau_mm.h +++ b/trunk/drivers/gpu/drm/nouveau/nouveau_mm.h @@ -30,7 +30,9 @@ struct nouveau_mm_node { struct list_head fl_entry; struct list_head rl_entry; - u8 type; + bool free; + int type; + u32 offset; u32 length; }; diff --git a/trunk/drivers/gpu/drm/nouveau/nv40_graph.c b/trunk/drivers/gpu/drm/nouveau/nv40_graph.c index 8870d72388c8..19ef92a0375a 100644 --- a/trunk/drivers/gpu/drm/nouveau/nv40_graph.c +++ b/trunk/drivers/gpu/drm/nouveau/nv40_graph.c @@ -451,7 +451,8 @@ nv40_graph_register(struct drm_device *dev) NVOBJ_CLASS(dev, 0x309e, GR); /* swzsurf */ /* curie */ - if (nv44_graph_class(dev)) + if (dev_priv->chipset >= 0x60 || + 0x00005450 & (1 << (dev_priv->chipset & 0x0f))) NVOBJ_CLASS(dev, 0x4497, GR); else NVOBJ_CLASS(dev, 0x4097, GR); diff --git a/trunk/drivers/gpu/drm/nouveau/nv40_grctx.c b/trunk/drivers/gpu/drm/nouveau/nv40_grctx.c index f70447d131d7..ce585093264e 100644 --- a/trunk/drivers/gpu/drm/nouveau/nv40_grctx.c +++ b/trunk/drivers/gpu/drm/nouveau/nv40_grctx.c @@ -117,6 +117,17 @@ * - get vs count from 0x1540 */ +static int +nv40_graph_4097(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + if ((dev_priv->chipset & 0xf0) == 0x60) + return 0; + + return !!(0x0baf & (1 << dev_priv->chipset)); +} + static int nv40_graph_vs_count(struct drm_device *dev) { @@ -208,7 +219,7 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx) gr_def(ctx, 0x4009dc, 0x80000000); } else { cp_ctx(ctx, 0x400840, 20); - if (nv44_graph_class(ctx->dev)) { + if (!nv40_graph_4097(ctx->dev)) { for (i = 0; i < 8; i++) gr_def(ctx, 0x400860 + (i * 4), 0x00000001); } @@ -217,7 +228,7 @@ nv40_graph_construct_general(struct nouveau_grctx *ctx) gr_def(ctx, 0x400888, 0x00000040); cp_ctx(ctx, 0x400894, 11); gr_def(ctx, 0x400894, 0x00000040); - if (!nv44_graph_class(ctx->dev)) { + if (nv40_graph_4097(ctx->dev)) { for (i = 0; i < 8; i++) gr_def(ctx, 0x4008a0 + (i * 4), 0x80000000); } @@ -535,7 +546,7 @@ nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx) static void nv40_graph_construct_state3d_3(struct nouveau_grctx *ctx) { - int len = nv44_graph_class(ctx->dev) ? 0x0084 : 0x0684; + int len = nv40_graph_4097(ctx->dev) ? 0x0684 : 0x0084; cp_out (ctx, 0x300000); cp_lsr (ctx, len - 4); @@ -571,11 +582,11 @@ nv40_graph_construct_shader(struct nouveau_grctx *ctx) } else { b0_offset = 0x1d40/4; /* 2200 */ b1_offset = 0x3f40/4; /* 0b00 : 0a40 */ - vs_len = nv44_graph_class(dev) ? 0x4980/4 : 0x4a40/4; + vs_len = nv40_graph_4097(dev) ? 0x4a40/4 : 0x4980/4; } cp_lsr(ctx, vs_len * vs_nr + 0x300/4); - cp_out(ctx, nv44_graph_class(dev) ? 0x800029 : 0x800041); + cp_out(ctx, nv40_graph_4097(dev) ? 0x800041 : 0x800029); offset = ctx->ctxvals_pos; ctx->ctxvals_pos += (0x0300/4 + (vs_nr * vs_len)); diff --git a/trunk/drivers/gpu/drm/nouveau/nv40_mc.c b/trunk/drivers/gpu/drm/nouveau/nv40_mc.c index 03c0d4c3f355..e4e72c12ab6a 100644 --- a/trunk/drivers/gpu/drm/nouveau/nv40_mc.c +++ b/trunk/drivers/gpu/drm/nouveau/nv40_mc.c @@ -6,17 +6,27 @@ int nv40_mc_init(struct drm_device *dev) { + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t tmp; + /* Power up everything, resetting each individual unit will * be done later if needed. */ nv_wr32(dev, NV03_PMC_ENABLE, 0xFFFFFFFF); - if (nv44_graph_class(dev)) { - u32 tmp = nv_rd32(dev, NV04_PFB_FIFO_DATA); + switch (dev_priv->chipset) { + case 0x44: + case 0x46: /* G72 */ + case 0x4e: + case 0x4c: /* C51_G7X */ + tmp = nv_rd32(dev, NV04_PFB_FIFO_DATA); nv_wr32(dev, NV40_PMC_1700, tmp); nv_wr32(dev, NV40_PMC_1704, 0); nv_wr32(dev, NV40_PMC_1708, 0); nv_wr32(dev, NV40_PMC_170C, tmp); + break; + default: + break; } return 0; diff --git a/trunk/drivers/gpu/drm/nouveau/nv50_instmem.c b/trunk/drivers/gpu/drm/nouveau/nv50_instmem.c index ea0041810ae3..2e1b1cd19a4b 100644 --- a/trunk/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/trunk/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -332,11 +332,8 @@ nv50_instmem_get(struct nouveau_gpuobj *gpuobj, u32 size, u32 align) gpuobj->vinst = node->vram->offset; if (gpuobj->flags & NVOBJ_FLAG_VM) { - u32 flags = NV_MEM_ACCESS_RW; - if (!(gpuobj->flags & NVOBJ_FLAG_VM_USER)) - flags |= NV_MEM_ACCESS_SYS; - - ret = nouveau_vm_get(dev_priv->chan_vm, size, 12, flags, + ret = nouveau_vm_get(dev_priv->chan_vm, size, 12, + NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS, &node->chan_vma); if (ret) { vram->put(dev, &node->vram); diff --git a/trunk/drivers/gpu/drm/nouveau/nvc0_graph.c b/trunk/drivers/gpu/drm/nouveau/nvc0_graph.c index e6ea7d83187f..5feacd5d5fa4 100644 --- a/trunk/drivers/gpu/drm/nouveau/nvc0_graph.c +++ b/trunk/drivers/gpu/drm/nouveau/nvc0_graph.c @@ -105,8 +105,7 @@ nvc0_graph_create_context_mmio_list(struct nouveau_channel *chan) if (ret) return ret; - ret = nouveau_gpuobj_new(dev, NULL, 384 * 1024, 4096, - NVOBJ_FLAG_VM | NVOBJ_FLAG_VM_USER, + ret = nouveau_gpuobj_new(dev, NULL, 384 * 1024, 4096, NVOBJ_FLAG_VM, &grch->unk418810); if (ret) return ret; diff --git a/trunk/drivers/gpu/drm/nouveau/nvc0_vm.c b/trunk/drivers/gpu/drm/nouveau/nvc0_vm.c index e4e83c2caf5b..4b9251bb0ff4 100644 --- a/trunk/drivers/gpu/drm/nouveau/nvc0_vm.c +++ b/trunk/drivers/gpu/drm/nouveau/nvc0_vm.c @@ -48,8 +48,8 @@ nvc0_vm_addr(struct nouveau_vma *vma, u64 phys, u32 memtype, u32 target) phys >>= 8; phys |= 0x00000001; /* present */ - if (vma->access & NV_MEM_ACCESS_SYS) - phys |= 0x00000002; +// if (vma->access & NV_MEM_ACCESS_SYS) +// phys |= 0x00000002; phys |= ((u64)target << 32); phys |= ((u64)memtype << 36); diff --git a/trunk/drivers/gpu/drm/radeon/evergreen.c b/trunk/drivers/gpu/drm/radeon/evergreen.c index a8973acb3987..7fe8ebdcdc0e 100644 --- a/trunk/drivers/gpu/drm/radeon/evergreen.c +++ b/trunk/drivers/gpu/drm/radeon/evergreen.c @@ -3002,6 +3002,31 @@ int evergreen_copy_blit(struct radeon_device *rdev, return 0; } +static bool evergreen_card_posted(struct radeon_device *rdev) +{ + u32 reg; + + /* first check CRTCs */ + if (rdev->flags & RADEON_IS_IGP) + reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) | + RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET); + else + reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) | + RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET) | + RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) | + RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET) | + RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET) | + RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET); + if (reg & EVERGREEN_CRTC_MASTER_EN) + return true; + + /* then check MEM_SIZE, in case the crtcs are off */ + if (RREG32(CONFIG_MEMSIZE)) + return true; + + return false; +} + /* Plan is to move initialization in that function and use * helper function so that radeon_device_init pretty much * do nothing more than calling asic specific function. This @@ -3038,7 +3063,7 @@ int evergreen_init(struct radeon_device *rdev) if (radeon_asic_reset(rdev)) dev_warn(rdev->dev, "GPU reset failed !\n"); /* Post card if necessary */ - if (!radeon_card_posted(rdev)) { + if (!evergreen_card_posted(rdev)) { if (!rdev->bios) { dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n"); return -EINVAL; @@ -3133,9 +3158,6 @@ static void evergreen_pcie_gen2_enable(struct radeon_device *rdev) { u32 link_width_cntl, speed_cntl; - if (radeon_pcie_gen2 == 0) - return; - if (rdev->flags & RADEON_IS_IGP) return; diff --git a/trunk/drivers/gpu/drm/radeon/r100.c b/trunk/drivers/gpu/drm/radeon/r100.c index 46da5142b131..f637595b14e1 100644 --- a/trunk/drivers/gpu/drm/radeon/r100.c +++ b/trunk/drivers/gpu/drm/radeon/r100.c @@ -2086,13 +2086,12 @@ int r100_asic_reset(struct radeon_device *rdev) { struct r100_mc_save save; u32 status, tmp; - int ret = 0; + r100_mc_stop(rdev, &save); status = RREG32(R_000E40_RBBM_STATUS); if (!G_000E40_GUI_ACTIVE(status)) { return 0; } - r100_mc_stop(rdev, &save); status = RREG32(R_000E40_RBBM_STATUS); dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); /* stop CP */ @@ -2132,11 +2131,11 @@ int r100_asic_reset(struct radeon_device *rdev) G_000E40_TAM_BUSY(status) || G_000E40_PB_BUSY(status)) { dev_err(rdev->dev, "failed to reset GPU\n"); rdev->gpu_lockup = true; - ret = -1; - } else - dev_info(rdev->dev, "GPU reset succeed\n"); + return -1; + } r100_mc_resume(rdev, &save); - return ret; + dev_info(rdev->dev, "GPU reset succeed\n"); + return 0; } void r100_set_common_regs(struct radeon_device *rdev) diff --git a/trunk/drivers/gpu/drm/radeon/r300.c b/trunk/drivers/gpu/drm/radeon/r300.c index cf862ca580bf..fae5e709f270 100644 --- a/trunk/drivers/gpu/drm/radeon/r300.c +++ b/trunk/drivers/gpu/drm/radeon/r300.c @@ -405,13 +405,12 @@ int r300_asic_reset(struct radeon_device *rdev) { struct r100_mc_save save; u32 status, tmp; - int ret = 0; + r100_mc_stop(rdev, &save); status = RREG32(R_000E40_RBBM_STATUS); if (!G_000E40_GUI_ACTIVE(status)) { return 0; } - r100_mc_stop(rdev, &save); status = RREG32(R_000E40_RBBM_STATUS); dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); /* stop CP */ @@ -452,11 +451,11 @@ int r300_asic_reset(struct radeon_device *rdev) if (G_000E40_GA_BUSY(status) || G_000E40_VAP_BUSY(status)) { dev_err(rdev->dev, "failed to reset GPU\n"); rdev->gpu_lockup = true; - ret = -1; - } else - dev_info(rdev->dev, "GPU reset succeed\n"); + return -1; + } r100_mc_resume(rdev, &save); - return ret; + dev_info(rdev->dev, "GPU reset succeed\n"); + return 0; } /* diff --git a/trunk/drivers/gpu/drm/radeon/r600.c b/trunk/drivers/gpu/drm/radeon/r600.c index aca2236268fa..6b50716267c0 100644 --- a/trunk/drivers/gpu/drm/radeon/r600.c +++ b/trunk/drivers/gpu/drm/radeon/r600.c @@ -2358,6 +2358,24 @@ void r600_clear_surface_reg(struct radeon_device *rdev, int reg) /* FIXME: implement */ } + +bool r600_card_posted(struct radeon_device *rdev) +{ + uint32_t reg; + + /* first check CRTCs */ + reg = RREG32(D1CRTC_CONTROL) | + RREG32(D2CRTC_CONTROL); + if (reg & CRTC_EN) + return true; + + /* then check MEM_SIZE, in case the crtcs are off */ + if (RREG32(CONFIG_MEMSIZE)) + return true; + + return false; +} + int r600_startup(struct radeon_device *rdev) { int r; @@ -2518,7 +2536,7 @@ int r600_init(struct radeon_device *rdev) if (r) return r; /* Post card if necessary */ - if (!radeon_card_posted(rdev)) { + if (!r600_card_posted(rdev)) { if (!rdev->bios) { dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n"); return -EINVAL; @@ -3640,9 +3658,6 @@ static void r600_pcie_gen2_enable(struct radeon_device *rdev) u32 link_width_cntl, lanes, speed_cntl, training_cntl, tmp; u16 link_cntl2; - if (radeon_pcie_gen2 == 0) - return; - if (rdev->flags & RADEON_IS_IGP) return; diff --git a/trunk/drivers/gpu/drm/radeon/radeon.h b/trunk/drivers/gpu/drm/radeon/radeon.h index 71d2a554bbe6..e9486630a467 100644 --- a/trunk/drivers/gpu/drm/radeon/radeon.h +++ b/trunk/drivers/gpu/drm/radeon/radeon.h @@ -92,7 +92,6 @@ extern int radeon_tv; extern int radeon_audio; extern int radeon_disp_priority; extern int radeon_hw_i2c; -extern int radeon_pcie_gen2; /* * Copy from radeon_drv.h so we don't have to include both and have conflicting diff --git a/trunk/drivers/gpu/drm/radeon/radeon_drv.c b/trunk/drivers/gpu/drm/radeon/radeon_drv.c index d5680a0c87af..be5cb4f28c29 100644 --- a/trunk/drivers/gpu/drm/radeon/radeon_drv.c +++ b/trunk/drivers/gpu/drm/radeon/radeon_drv.c @@ -104,7 +104,6 @@ int radeon_tv = 1; int radeon_audio = 1; int radeon_disp_priority = 0; int radeon_hw_i2c = 0; -int radeon_pcie_gen2 = 0; MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); module_param_named(no_wb, radeon_no_wb, int, 0444); @@ -148,9 +147,6 @@ module_param_named(disp_priority, radeon_disp_priority, int, 0444); MODULE_PARM_DESC(hw_i2c, "hw i2c engine enable (0 = disable)"); module_param_named(hw_i2c, radeon_hw_i2c, int, 0444); -MODULE_PARM_DESC(pcie_gen2, "PCIE Gen2 mode (1 = enable)"); -module_param_named(pcie_gen2, radeon_pcie_gen2, int, 0444); - static int radeon_suspend(struct drm_device *dev, pm_message_t state) { drm_radeon_private_t *dev_priv = dev->dev_private; diff --git a/trunk/drivers/gpu/drm/radeon/reg_srcs/evergreen b/trunk/drivers/gpu/drm/radeon/reg_srcs/evergreen index 9177f9191837..ac40fd39d787 100644 --- a/trunk/drivers/gpu/drm/radeon/reg_srcs/evergreen +++ b/trunk/drivers/gpu/drm/radeon/reg_srcs/evergreen @@ -439,7 +439,7 @@ evergreen 0x9400 0x000286EC SPI_COMPUTE_NUM_THREAD_X 0x000286F0 SPI_COMPUTE_NUM_THREAD_Y 0x000286F4 SPI_COMPUTE_NUM_THREAD_Z -0x00028724 GDS_ADDR_SIZE +0x000286F8 GDS_ADDR_SIZE 0x00028780 CB_BLEND0_CONTROL 0x00028784 CB_BLEND1_CONTROL 0x00028788 CB_BLEND2_CONTROL diff --git a/trunk/drivers/gpu/drm/radeon/rs600.c b/trunk/drivers/gpu/drm/radeon/rs600.c index 5afe294ed51f..b4192acaab5f 100644 --- a/trunk/drivers/gpu/drm/radeon/rs600.c +++ b/trunk/drivers/gpu/drm/radeon/rs600.c @@ -339,16 +339,16 @@ void rs600_bm_disable(struct radeon_device *rdev) int rs600_asic_reset(struct radeon_device *rdev) { - struct rv515_mc_save save; u32 status, tmp; - int ret = 0; + struct rv515_mc_save save; + + /* Stops all mc clients */ + rv515_mc_stop(rdev, &save); status = RREG32(R_000E40_RBBM_STATUS); if (!G_000E40_GUI_ACTIVE(status)) { return 0; } - /* Stops all mc clients */ - rv515_mc_stop(rdev, &save); status = RREG32(R_000E40_RBBM_STATUS); dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); /* stop CP */ @@ -392,11 +392,11 @@ int rs600_asic_reset(struct radeon_device *rdev) if (G_000E40_GA_BUSY(status) || G_000E40_VAP_BUSY(status)) { dev_err(rdev->dev, "failed to reset GPU\n"); rdev->gpu_lockup = true; - ret = -1; - } else - dev_info(rdev->dev, "GPU reset succeed\n"); + return -1; + } rv515_mc_resume(rdev, &save); - return ret; + dev_info(rdev->dev, "GPU reset succeed\n"); + return 0; } /* diff --git a/trunk/drivers/gpu/drm/radeon/rv770.c b/trunk/drivers/gpu/drm/radeon/rv770.c index 491dc9000655..3a264aa3a79a 100644 --- a/trunk/drivers/gpu/drm/radeon/rv770.c +++ b/trunk/drivers/gpu/drm/radeon/rv770.c @@ -1268,7 +1268,7 @@ int rv770_init(struct radeon_device *rdev) if (r) return r; /* Post card if necessary */ - if (!radeon_card_posted(rdev)) { + if (!r600_card_posted(rdev)) { if (!rdev->bios) { dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n"); return -EINVAL; @@ -1372,9 +1372,6 @@ static void rv770_pcie_gen2_enable(struct radeon_device *rdev) u32 link_width_cntl, lanes, speed_cntl, tmp; u16 link_cntl2; - if (radeon_pcie_gen2 == 0) - return; - if (rdev->flags & RADEON_IS_IGP) return; diff --git a/trunk/drivers/mtd/Kconfig b/trunk/drivers/mtd/Kconfig index 77414702cb00..b1f768917395 100644 --- a/trunk/drivers/mtd/Kconfig +++ b/trunk/drivers/mtd/Kconfig @@ -53,10 +53,9 @@ config MTD_PARTITIONS devices. Partitioning on NFTL 'devices' is a different - that's the 'normal' form of partitioning used on a block device. -if MTD_PARTITIONS - config MTD_REDBOOT_PARTS tristate "RedBoot partition table parsing" + depends on MTD_PARTITIONS ---help--- RedBoot is a ROM monitor and bootloader which deals with multiple 'images' in flash devices by putting a table one of the erase @@ -73,10 +72,9 @@ config MTD_REDBOOT_PARTS SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for example. -if MTD_REDBOOT_PARTS - config MTD_REDBOOT_DIRECTORY_BLOCK int "Location of RedBoot partition table" + depends on MTD_REDBOOT_PARTS default "-1" ---help--- This option is the Linux counterpart to the @@ -93,18 +91,18 @@ config MTD_REDBOOT_DIRECTORY_BLOCK config MTD_REDBOOT_PARTS_UNALLOCATED bool "Include unallocated flash regions" + depends on MTD_REDBOOT_PARTS help If you need to register each unallocated flash region as a MTD 'partition', enable this option. config MTD_REDBOOT_PARTS_READONLY bool "Force read-only for RedBoot system images" + depends on MTD_REDBOOT_PARTS help If you need to force read-only for 'RedBoot', 'RedBoot Config' and 'FIS directory' images, enable this option. -endif # MTD_REDBOOT_PARTS - config MTD_CMDLINE_PARTS bool "Command line partition table parsing" depends on MTD_PARTITIONS = "y" && MTD = "y" @@ -144,7 +142,7 @@ config MTD_CMDLINE_PARTS config MTD_AFS_PARTS tristate "ARM Firmware Suite partition parsing" - depends on ARM + depends on ARM && MTD_PARTITIONS ---help--- The ARM Firmware Suite allows the user to divide flash devices into multiple 'images'. Each such image has a header containing its name @@ -160,8 +158,8 @@ config MTD_AFS_PARTS example. config MTD_OF_PARTS - def_bool y - depends on OF + tristate "Flash partition map based on OF description" + depends on OF && MTD_PARTITIONS help This provides a partition parsing function which derives the partition map from the children of the flash node, @@ -169,11 +167,10 @@ config MTD_OF_PARTS config MTD_AR7_PARTS tristate "TI AR7 partitioning support" + depends on MTD_PARTITIONS ---help--- TI AR7 partitioning support -endif # MTD_PARTITIONS - comment "User Modules And Translation Layers" config MTD_CHAR diff --git a/trunk/drivers/mtd/Makefile b/trunk/drivers/mtd/Makefile index d4e7f25b1ebb..760abc533395 100644 --- a/trunk/drivers/mtd/Makefile +++ b/trunk/drivers/mtd/Makefile @@ -6,13 +6,13 @@ obj-$(CONFIG_MTD) += mtd.o mtd-y := mtdcore.o mtdsuper.o mtd-$(CONFIG_MTD_PARTITIONS) += mtdpart.o -mtd-$(CONFIG_MTD_OF_PARTS) += ofpart.o obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o obj-$(CONFIG_MTD_AFS_PARTS) += afs.o obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o +obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o # 'Users' - code which presents functionality to userspace. obj-$(CONFIG_MTD_CHAR) += mtdchar.o diff --git a/trunk/drivers/mtd/chips/cfi_cmdset_0001.c b/trunk/drivers/mtd/chips/cfi_cmdset_0001.c index a8c3e1c9b02a..ad9268b44416 100644 --- a/trunk/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/trunk/drivers/mtd/chips/cfi_cmdset_0001.c @@ -162,7 +162,7 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp) #endif /* Atmel chips don't use the same PRI format as Intel chips */ -static void fixup_convert_atmel_pri(struct mtd_info *mtd) +static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -202,7 +202,7 @@ static void fixup_convert_atmel_pri(struct mtd_info *mtd) cfi->cfiq->BufWriteTimeoutMax = 0; } -static void fixup_at49bv640dx_lock(struct mtd_info *mtd) +static void fixup_at49bv640dx_lock(struct mtd_info *mtd, void *param) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -214,7 +214,7 @@ static void fixup_at49bv640dx_lock(struct mtd_info *mtd) #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE /* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ -static void fixup_intel_strataflash(struct mtd_info *mtd) +static void fixup_intel_strataflash(struct mtd_info *mtd, void* param) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -227,7 +227,7 @@ static void fixup_intel_strataflash(struct mtd_info *mtd) #endif #ifdef CMDSET0001_DISABLE_WRITE_SUSPEND -static void fixup_no_write_suspend(struct mtd_info *mtd) +static void fixup_no_write_suspend(struct mtd_info *mtd, void* param) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -240,7 +240,7 @@ static void fixup_no_write_suspend(struct mtd_info *mtd) } #endif -static void fixup_st_m28w320ct(struct mtd_info *mtd) +static void fixup_st_m28w320ct(struct mtd_info *mtd, void* param) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -249,7 +249,7 @@ static void fixup_st_m28w320ct(struct mtd_info *mtd) cfi->cfiq->BufWriteTimeoutMax = 0; /* Not supported */ } -static void fixup_st_m28w320cb(struct mtd_info *mtd) +static void fixup_st_m28w320cb(struct mtd_info *mtd, void* param) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -259,7 +259,7 @@ static void fixup_st_m28w320cb(struct mtd_info *mtd) (cfi->cfiq->EraseRegionInfo[1] & 0xffff0000) | 0x3e; }; -static void fixup_use_point(struct mtd_info *mtd) +static void fixup_use_point(struct mtd_info *mtd, void *param) { struct map_info *map = mtd->priv; if (!mtd->point && map_is_linear(map)) { @@ -268,7 +268,7 @@ static void fixup_use_point(struct mtd_info *mtd) } } -static void fixup_use_write_buffers(struct mtd_info *mtd) +static void fixup_use_write_buffers(struct mtd_info *mtd, void *param) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -282,7 +282,7 @@ static void fixup_use_write_buffers(struct mtd_info *mtd) /* * Some chips power-up with all sectors locked by default. */ -static void fixup_unlock_powerup_lock(struct mtd_info *mtd) +static void fixup_unlock_powerup_lock(struct mtd_info *mtd, void *param) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -295,31 +295,31 @@ static void fixup_unlock_powerup_lock(struct mtd_info *mtd) } static struct cfi_fixup cfi_fixup_table[] = { - { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri }, - { CFI_MFR_ATMEL, AT49BV640D, fixup_at49bv640dx_lock }, - { CFI_MFR_ATMEL, AT49BV640DT, fixup_at49bv640dx_lock }, + { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL }, + { CFI_MFR_ATMEL, AT49BV640D, fixup_at49bv640dx_lock, NULL }, + { CFI_MFR_ATMEL, AT49BV640DT, fixup_at49bv640dx_lock, NULL }, #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE - { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash }, + { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL }, #endif #ifdef CMDSET0001_DISABLE_WRITE_SUSPEND - { CFI_MFR_ANY, CFI_ID_ANY, fixup_no_write_suspend }, + { CFI_MFR_ANY, CFI_ID_ANY, fixup_no_write_suspend, NULL }, #endif #if !FORCE_WORD_WRITE - { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers }, + { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL }, #endif - { CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct }, - { CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb }, - { CFI_MFR_INTEL, CFI_ID_ANY, fixup_unlock_powerup_lock }, - { 0, 0, NULL } + { CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL }, + { CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL }, + { CFI_MFR_INTEL, CFI_ID_ANY, fixup_unlock_powerup_lock, NULL, }, + { 0, 0, NULL, NULL } }; static struct cfi_fixup jedec_fixup_table[] = { - { CFI_MFR_INTEL, I82802AB, fixup_use_fwh_lock }, - { CFI_MFR_INTEL, I82802AC, fixup_use_fwh_lock }, - { CFI_MFR_ST, M50LPW080, fixup_use_fwh_lock }, - { CFI_MFR_ST, M50FLW080A, fixup_use_fwh_lock }, - { CFI_MFR_ST, M50FLW080B, fixup_use_fwh_lock }, - { 0, 0, NULL } + { CFI_MFR_INTEL, I82802AB, fixup_use_fwh_lock, NULL, }, + { CFI_MFR_INTEL, I82802AC, fixup_use_fwh_lock, NULL, }, + { CFI_MFR_ST, M50LPW080, fixup_use_fwh_lock, NULL, }, + { CFI_MFR_ST, M50FLW080A, fixup_use_fwh_lock, NULL, }, + { CFI_MFR_ST, M50FLW080B, fixup_use_fwh_lock, NULL, }, + { 0, 0, NULL, NULL } }; static struct cfi_fixup fixup_table[] = { /* The CFI vendor ids and the JEDEC vendor IDs appear @@ -327,8 +327,8 @@ static struct cfi_fixup fixup_table[] = { * well. This table is to pick all cases where * we know that is the case. */ - { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_point }, - { 0, 0, NULL } + { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_point, NULL }, + { 0, 0, NULL, NULL } }; static void cfi_fixup_major_minor(struct cfi_private *cfi, @@ -455,7 +455,6 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) mtd->flags = MTD_CAP_NORFLASH; mtd->name = map->name; mtd->writesize = 1; - mtd->writebufsize = 1 << cfi->cfiq->MaxBufWriteSize; mtd->reboot_notifier.notifier_call = cfi_intelext_reboot; diff --git a/trunk/drivers/mtd/chips/cfi_cmdset_0002.c b/trunk/drivers/mtd/chips/cfi_cmdset_0002.c index f072fcfde04e..3b8e32d87977 100644 --- a/trunk/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/trunk/drivers/mtd/chips/cfi_cmdset_0002.c @@ -134,7 +134,7 @@ static void cfi_tell_features(struct cfi_pri_amdstd *extp) #ifdef AMD_BOOTLOC_BUG /* Wheee. Bring me the head of someone at AMD. */ -static void fixup_amd_bootblock(struct mtd_info *mtd) +static void fixup_amd_bootblock(struct mtd_info *mtd, void* param) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -186,7 +186,7 @@ static void fixup_amd_bootblock(struct mtd_info *mtd) } #endif -static void fixup_use_write_buffers(struct mtd_info *mtd) +static void fixup_use_write_buffers(struct mtd_info *mtd, void *param) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -197,7 +197,7 @@ static void fixup_use_write_buffers(struct mtd_info *mtd) } /* Atmel chips don't use the same PRI format as AMD chips */ -static void fixup_convert_atmel_pri(struct mtd_info *mtd) +static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -228,14 +228,14 @@ static void fixup_convert_atmel_pri(struct mtd_info *mtd) cfi->cfiq->BufWriteTimeoutMax = 0; } -static void fixup_use_secsi(struct mtd_info *mtd) +static void fixup_use_secsi(struct mtd_info *mtd, void *param) { /* Setup for chips with a secsi area */ mtd->read_user_prot_reg = cfi_amdstd_secsi_read; mtd->read_fact_prot_reg = cfi_amdstd_secsi_read; } -static void fixup_use_erase_chip(struct mtd_info *mtd) +static void fixup_use_erase_chip(struct mtd_info *mtd, void *param) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -250,7 +250,7 @@ static void fixup_use_erase_chip(struct mtd_info *mtd) * Some Atmel chips (e.g. the AT49BV6416) power-up with all sectors * locked by default. */ -static void fixup_use_atmel_lock(struct mtd_info *mtd) +static void fixup_use_atmel_lock(struct mtd_info *mtd, void *param) { mtd->lock = cfi_atmel_lock; mtd->unlock = cfi_atmel_unlock; @@ -271,7 +271,7 @@ static void fixup_old_sst_eraseregion(struct mtd_info *mtd) cfi->cfiq->NumEraseRegions = 1; } -static void fixup_sst39vf(struct mtd_info *mtd) +static void fixup_sst39vf(struct mtd_info *mtd, void *param) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -282,7 +282,7 @@ static void fixup_sst39vf(struct mtd_info *mtd) cfi->addr_unlock2 = 0x2AAA; } -static void fixup_sst39vf_rev_b(struct mtd_info *mtd) +static void fixup_sst39vf_rev_b(struct mtd_info *mtd, void *param) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -295,12 +295,12 @@ static void fixup_sst39vf_rev_b(struct mtd_info *mtd) cfi->sector_erase_cmd = CMD(0x50); } -static void fixup_sst38vf640x_sectorsize(struct mtd_info *mtd) +static void fixup_sst38vf640x_sectorsize(struct mtd_info *mtd, void *param) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; - fixup_sst39vf_rev_b(mtd); + fixup_sst39vf_rev_b(mtd, param); /* * CFI reports 1024 sectors (0x03ff+1) of 64KBytes (0x0100*256) where @@ -310,7 +310,7 @@ static void fixup_sst38vf640x_sectorsize(struct mtd_info *mtd) pr_warning("%s: Bad 38VF640x CFI data; adjusting sector size from 64 to 8KiB\n", mtd->name); } -static void fixup_s29gl064n_sectors(struct mtd_info *mtd) +static void fixup_s29gl064n_sectors(struct mtd_info *mtd, void *param) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -321,7 +321,7 @@ static void fixup_s29gl064n_sectors(struct mtd_info *mtd) } } -static void fixup_s29gl032n_sectors(struct mtd_info *mtd) +static void fixup_s29gl032n_sectors(struct mtd_info *mtd, void *param) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -334,47 +334,47 @@ static void fixup_s29gl032n_sectors(struct mtd_info *mtd) /* Used to fix CFI-Tables of chips without Extended Query Tables */ static struct cfi_fixup cfi_nopri_fixup_table[] = { - { CFI_MFR_SST, 0x234a, fixup_sst39vf }, /* SST39VF1602 */ - { CFI_MFR_SST, 0x234b, fixup_sst39vf }, /* SST39VF1601 */ - { CFI_MFR_SST, 0x235a, fixup_sst39vf }, /* SST39VF3202 */ - { CFI_MFR_SST, 0x235b, fixup_sst39vf }, /* SST39VF3201 */ - { CFI_MFR_SST, 0x235c, fixup_sst39vf_rev_b }, /* SST39VF3202B */ - { CFI_MFR_SST, 0x235d, fixup_sst39vf_rev_b }, /* SST39VF3201B */ - { CFI_MFR_SST, 0x236c, fixup_sst39vf_rev_b }, /* SST39VF6402B */ - { CFI_MFR_SST, 0x236d, fixup_sst39vf_rev_b }, /* SST39VF6401B */ - { 0, 0, NULL } + { CFI_MFR_SST, 0x234A, fixup_sst39vf, NULL, }, /* SST39VF1602 */ + { CFI_MFR_SST, 0x234B, fixup_sst39vf, NULL, }, /* SST39VF1601 */ + { CFI_MFR_SST, 0x235A, fixup_sst39vf, NULL, }, /* SST39VF3202 */ + { CFI_MFR_SST, 0x235B, fixup_sst39vf, NULL, }, /* SST39VF3201 */ + { CFI_MFR_SST, 0x235C, fixup_sst39vf_rev_b, NULL, }, /* SST39VF3202B */ + { CFI_MFR_SST, 0x235D, fixup_sst39vf_rev_b, NULL, }, /* SST39VF3201B */ + { CFI_MFR_SST, 0x236C, fixup_sst39vf_rev_b, NULL, }, /* SST39VF6402B */ + { CFI_MFR_SST, 0x236D, fixup_sst39vf_rev_b, NULL, }, /* SST39VF6401B */ + { 0, 0, NULL, NULL } }; static struct cfi_fixup cfi_fixup_table[] = { - { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri }, + { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL }, #ifdef AMD_BOOTLOC_BUG - { CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock }, - { CFI_MFR_MACRONIX, CFI_ID_ANY, fixup_amd_bootblock }, + { CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock, NULL }, + { CFI_MFR_MACRONIX, CFI_ID_ANY, fixup_amd_bootblock, NULL }, #endif - { CFI_MFR_AMD, 0x0050, fixup_use_secsi }, - { CFI_MFR_AMD, 0x0053, fixup_use_secsi }, - { CFI_MFR_AMD, 0x0055, fixup_use_secsi }, - { CFI_MFR_AMD, 0x0056, fixup_use_secsi }, - { CFI_MFR_AMD, 0x005C, fixup_use_secsi }, - { CFI_MFR_AMD, 0x005F, fixup_use_secsi }, - { CFI_MFR_AMD, 0x0c01, fixup_s29gl064n_sectors }, - { CFI_MFR_AMD, 0x1301, fixup_s29gl064n_sectors }, - { CFI_MFR_AMD, 0x1a00, fixup_s29gl032n_sectors }, - { CFI_MFR_AMD, 0x1a01, fixup_s29gl032n_sectors }, - { CFI_MFR_SST, 0x536a, fixup_sst38vf640x_sectorsize }, /* SST38VF6402 */ - { CFI_MFR_SST, 0x536b, fixup_sst38vf640x_sectorsize }, /* SST38VF6401 */ - { CFI_MFR_SST, 0x536c, fixup_sst38vf640x_sectorsize }, /* SST38VF6404 */ - { CFI_MFR_SST, 0x536d, fixup_sst38vf640x_sectorsize }, /* SST38VF6403 */ + { CFI_MFR_AMD, 0x0050, fixup_use_secsi, NULL, }, + { CFI_MFR_AMD, 0x0053, fixup_use_secsi, NULL, }, + { CFI_MFR_AMD, 0x0055, fixup_use_secsi, NULL, }, + { CFI_MFR_AMD, 0x0056, fixup_use_secsi, NULL, }, + { CFI_MFR_AMD, 0x005C, fixup_use_secsi, NULL, }, + { CFI_MFR_AMD, 0x005F, fixup_use_secsi, NULL, }, + { CFI_MFR_AMD, 0x0c01, fixup_s29gl064n_sectors, NULL, }, + { 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_SST, 0x536A, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6402 */ + { CFI_MFR_SST, 0x536B, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6401 */ + { CFI_MFR_SST, 0x536C, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6404 */ + { CFI_MFR_SST, 0x536D, fixup_sst38vf640x_sectorsize, NULL, }, /* SST38VF6403 */ #if !FORCE_WORD_WRITE - { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers }, + { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, }, #endif - { 0, 0, NULL } + { 0, 0, NULL, NULL } }; static struct cfi_fixup jedec_fixup_table[] = { - { CFI_MFR_SST, SST49LF004B, fixup_use_fwh_lock }, - { CFI_MFR_SST, SST49LF040B, fixup_use_fwh_lock }, - { CFI_MFR_SST, SST49LF008A, fixup_use_fwh_lock }, - { 0, 0, NULL } + { CFI_MFR_SST, SST49LF004B, fixup_use_fwh_lock, NULL, }, + { CFI_MFR_SST, SST49LF040B, fixup_use_fwh_lock, NULL, }, + { CFI_MFR_SST, SST49LF008A, fixup_use_fwh_lock, NULL, }, + { 0, 0, NULL, NULL } }; static struct cfi_fixup fixup_table[] = { @@ -383,30 +383,18 @@ static struct cfi_fixup fixup_table[] = { * well. This table is to pick all cases where * we know that is the case. */ - { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_erase_chip }, - { CFI_MFR_ATMEL, AT49BV6416, fixup_use_atmel_lock }, - { 0, 0, NULL } + { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_erase_chip, NULL }, + { CFI_MFR_ATMEL, AT49BV6416, fixup_use_atmel_lock, NULL }, + { 0, 0, NULL, NULL } }; static void cfi_fixup_major_minor(struct cfi_private *cfi, struct cfi_pri_amdstd *extp) { - if (cfi->mfr == CFI_MFR_SAMSUNG) { - if ((extp->MajorVersion == '0' && extp->MinorVersion == '0') || - (extp->MajorVersion == '3' && extp->MinorVersion == '3')) { - /* - * Samsung K8P2815UQB and K8D6x16UxM chips - * report major=0 / minor=0. - * K8D3x16UxC chips report major=3 / minor=3. - */ - printk(KERN_NOTICE " Fixing Samsung's Amd/Fujitsu" - " Extended Query version to 1.%c\n", - extp->MinorVersion); - extp->MajorVersion = '1'; - } - } - + if (cfi->mfr == CFI_MFR_SAMSUNG && cfi->id == 0x257e && + extp->MajorVersion == '0') + extp->MajorVersion = '1'; /* * SST 38VF640x chips report major=0xFF / minor=0xFF. */ @@ -440,10 +428,6 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) mtd->flags = MTD_CAP_NORFLASH; mtd->name = map->name; mtd->writesize = 1; - mtd->writebufsize = 1 << cfi->cfiq->MaxBufWriteSize; - - DEBUG(MTD_DEBUG_LEVEL3, "MTD %s(): write buffer size %d\n", - __func__, mtd->writebufsize); mtd->reboot_notifier.notifier_call = cfi_amdstd_reboot; diff --git a/trunk/drivers/mtd/chips/cfi_cmdset_0020.c b/trunk/drivers/mtd/chips/cfi_cmdset_0020.c index c04b7658abe9..314af1f5a370 100644 --- a/trunk/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/trunk/drivers/mtd/chips/cfi_cmdset_0020.c @@ -238,7 +238,6 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map) mtd->resume = cfi_staa_resume; mtd->flags = MTD_CAP_NORFLASH & ~MTD_BIT_WRITEABLE; mtd->writesize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */ - mtd->writebufsize = 1 << cfi->cfiq->MaxBufWriteSize; map->fldrv = &cfi_staa_chipdrv; __module_get(THIS_MODULE); mtd->name = map->name; diff --git a/trunk/drivers/mtd/chips/cfi_util.c b/trunk/drivers/mtd/chips/cfi_util.c index 6ae3d111e1e7..360525c637d2 100644 --- a/trunk/drivers/mtd/chips/cfi_util.c +++ b/trunk/drivers/mtd/chips/cfi_util.c @@ -156,7 +156,7 @@ void cfi_fixup(struct mtd_info *mtd, struct cfi_fixup *fixups) for (f=fixups; f->fixup; f++) { if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi->mfr)) && ((f->id == CFI_ID_ANY) || (f->id == cfi->id))) { - f->fixup(mtd); + f->fixup(mtd, f->param); } } } diff --git a/trunk/drivers/mtd/chips/fwh_lock.h b/trunk/drivers/mtd/chips/fwh_lock.h index 5e3cc80128aa..d18064977192 100644 --- a/trunk/drivers/mtd/chips/fwh_lock.h +++ b/trunk/drivers/mtd/chips/fwh_lock.h @@ -98,7 +98,7 @@ static int fwh_unlock_varsize(struct mtd_info *mtd, loff_t ofs, uint64_t len) return ret; } -static void fixup_use_fwh_lock(struct mtd_info *mtd) +static void fixup_use_fwh_lock(struct mtd_info *mtd, void *param) { printk(KERN_NOTICE "using fwh lock/unlock method\n"); /* Setup for the chips with the fwh lock method */ diff --git a/trunk/drivers/mtd/devices/m25p80.c b/trunk/drivers/mtd/devices/m25p80.c index e4eba6cc1b2e..bf5a002209bd 100644 --- a/trunk/drivers/mtd/devices/m25p80.c +++ b/trunk/drivers/mtd/devices/m25p80.c @@ -51,10 +51,6 @@ #define OPCODE_WRDI 0x04 /* Write disable */ #define OPCODE_AAI_WP 0xad /* Auto address increment word program */ -/* Used for Macronix flashes only. */ -#define OPCODE_EN4B 0xb7 /* Enter 4-byte mode */ -#define OPCODE_EX4B 0xe9 /* Exit 4-byte mode */ - /* Status Register bits. */ #define SR_WIP 1 /* Write in progress */ #define SR_WEL 2 /* Write enable latch */ @@ -66,7 +62,7 @@ /* Define max times to check status register before we give up. */ #define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */ -#define MAX_CMD_SIZE 5 +#define MAX_CMD_SIZE 4 #ifdef CONFIG_M25PXX_USE_FAST_READ #define OPCODE_READ OPCODE_FAST_READ @@ -155,16 +151,6 @@ static inline int write_disable(struct m25p *flash) return spi_write_then_read(flash->spi, &code, 1, NULL, 0); } -/* - * Enable/disable 4-byte addressing mode. - */ -static inline int set_4byte(struct m25p *flash, int enable) -{ - u8 code = enable ? OPCODE_EN4B : OPCODE_EX4B; - - return spi_write_then_read(flash->spi, &code, 1, NULL, 0); -} - /* * Service routine to read status register until ready, or timeout occurs. * Returns non-zero if error. @@ -221,7 +207,6 @@ static void m25p_addr2cmd(struct m25p *flash, unsigned int addr, u8 *cmd) cmd[1] = addr >> (flash->addr_width * 8 - 8); cmd[2] = addr >> (flash->addr_width * 8 - 16); cmd[3] = addr >> (flash->addr_width * 8 - 24); - cmd[4] = addr >> (flash->addr_width * 8 - 32); } static int m25p_cmdsz(struct m25p *flash) @@ -497,10 +482,6 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, size_t actual; int cmd_sz, ret; - DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n", - dev_name(&flash->spi->dev), __func__, "to", - (u32)to, len); - *retlen = 0; /* sanity checks */ @@ -626,6 +607,7 @@ struct flash_info { .sector_size = (_sector_size), \ .n_sectors = (_n_sectors), \ .page_size = 256, \ + .addr_width = 3, \ .flags = (_flags), \ }) @@ -653,7 +635,7 @@ static const struct spi_device_id m25p_ids[] = { { "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8, SECT_4K) }, { "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, SECT_4K) }, { "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) }, - { "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) }, + { "at26df321", INFO(0x1f4701, 0, 64 * 1024, 64, SECT_4K) }, /* EON -- en25pxx */ { "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) }, @@ -671,8 +653,6 @@ static const struct spi_device_id m25p_ids[] = { { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, 0) }, { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, - { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) }, - { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, /* Spansion -- single (large) sector size only, at least * for the chips listed here (without boot sectors). @@ -784,7 +764,6 @@ static const struct spi_device_id *__devinit jedec_probe(struct spi_device *spi) return &m25p_ids[tmp]; } } - dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec); return ERR_PTR(-ENODEV); } @@ -904,17 +883,7 @@ static int __devinit m25p_probe(struct spi_device *spi) flash->mtd.dev.parent = &spi->dev; flash->page_size = info->page_size; - - if (info->addr_width) - flash->addr_width = info->addr_width; - else { - /* enable 4-byte addressing if the device exceeds 16MiB */ - if (flash->mtd.size > 0x1000000) { - flash->addr_width = 4; - set_4byte(flash, 1); - } else - flash->addr_width = 3; - } + flash->addr_width = info->addr_width; dev_info(&spi->dev, "%s (%lld Kbytes)\n", id->name, (long long)flash->mtd.size >> 10); diff --git a/trunk/drivers/mtd/devices/sst25l.c b/trunk/drivers/mtd/devices/sst25l.c index c163e619abc9..684247a8a5ed 100644 --- a/trunk/drivers/mtd/devices/sst25l.c +++ b/trunk/drivers/mtd/devices/sst25l.c @@ -335,7 +335,7 @@ static int sst25l_write(struct mtd_info *mtd, loff_t to, size_t len, return ret; } -static struct flash_info *__devinit sst25l_match_device(struct spi_device *spi) +static struct flash_info *__init sst25l_match_device(struct spi_device *spi) { struct flash_info *flash_info = NULL; struct spi_message m; @@ -375,7 +375,7 @@ static struct flash_info *__devinit sst25l_match_device(struct spi_device *spi) return flash_info; } -static int __devinit sst25l_probe(struct spi_device *spi) +static int __init sst25l_probe(struct spi_device *spi) { struct flash_info *flash_info; struct sst25l_flash *flash; diff --git a/trunk/drivers/mtd/maps/amd76xrom.c b/trunk/drivers/mtd/maps/amd76xrom.c index 77d64ce19e9f..19fe92db0c46 100644 --- a/trunk/drivers/mtd/maps/amd76xrom.c +++ b/trunk/drivers/mtd/maps/amd76xrom.c @@ -149,8 +149,11 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev, if (request_resource(&iomem_resource, &window->rsrc)) { window->rsrc.parent = NULL; printk(KERN_ERR MOD_NAME - " %s(): Unable to register resource %pR - kernel bug?\n", - __func__, &window->rsrc); + " %s(): Unable to register resource" + " 0x%.16llx-0x%.16llx - kernel bug?\n", + __func__, + (unsigned long long)window->rsrc.start, + (unsigned long long)window->rsrc.end); } diff --git a/trunk/drivers/mtd/maps/bcm963xx-flash.c b/trunk/drivers/mtd/maps/bcm963xx-flash.c index 1f3049590d9e..d175c120ee84 100644 --- a/trunk/drivers/mtd/maps/bcm963xx-flash.c +++ b/trunk/drivers/mtd/maps/bcm963xx-flash.c @@ -196,15 +196,10 @@ static int bcm963xx_probe(struct platform_device *pdev) bcm963xx_mtd_info = do_map_probe("cfi_probe", &bcm963xx_map); if (!bcm963xx_mtd_info) { dev_err(&pdev->dev, "failed to probe using CFI\n"); - bcm963xx_mtd_info = do_map_probe("jedec_probe", &bcm963xx_map); - if (bcm963xx_mtd_info) - goto probe_ok; - dev_err(&pdev->dev, "failed to probe using JEDEC\n"); err = -EIO; goto err_probe; } -probe_ok: bcm963xx_mtd_info->owner = THIS_MODULE; /* This is mutually exclusive */ diff --git a/trunk/drivers/mtd/maps/ck804xrom.c b/trunk/drivers/mtd/maps/ck804xrom.c index 5fdb7b26cea3..ddb462bea9b5 100644 --- a/trunk/drivers/mtd/maps/ck804xrom.c +++ b/trunk/drivers/mtd/maps/ck804xrom.c @@ -178,8 +178,11 @@ static int __devinit ck804xrom_init_one (struct pci_dev *pdev, if (request_resource(&iomem_resource, &window->rsrc)) { window->rsrc.parent = NULL; printk(KERN_ERR MOD_NAME - " %s(): Unable to register resource %pR - kernel bug?\n", - __func__, &window->rsrc); + " %s(): Unable to register resource" + " 0x%.016llx-0x%.016llx - kernel bug?\n", + __func__, + (unsigned long long)window->rsrc.start, + (unsigned long long)window->rsrc.end); } diff --git a/trunk/drivers/mtd/maps/esb2rom.c b/trunk/drivers/mtd/maps/esb2rom.c index 4feb7507ab7c..d12c93dc1aad 100644 --- a/trunk/drivers/mtd/maps/esb2rom.c +++ b/trunk/drivers/mtd/maps/esb2rom.c @@ -242,9 +242,12 @@ static int __devinit esb2rom_init_one(struct pci_dev *pdev, window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; if (request_resource(&iomem_resource, &window->rsrc)) { window->rsrc.parent = NULL; - printk(KERN_DEBUG MOD_NAME ": " - "%s(): Unable to register resource %pR - kernel bug?\n", - __func__, &window->rsrc); + printk(KERN_DEBUG MOD_NAME + ": %s(): Unable to register resource" + " 0x%.08llx-0x%.08llx - kernel bug?\n", + __func__, + (unsigned long long)window->rsrc.start, + (unsigned long long)window->rsrc.end); } /* Map the firmware hub into my address space. */ diff --git a/trunk/drivers/mtd/maps/ichxrom.c b/trunk/drivers/mtd/maps/ichxrom.c index 1337a4191a0c..f102bf243a74 100644 --- a/trunk/drivers/mtd/maps/ichxrom.c +++ b/trunk/drivers/mtd/maps/ichxrom.c @@ -175,9 +175,12 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev, window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; if (request_resource(&iomem_resource, &window->rsrc)) { window->rsrc.parent = NULL; - printk(KERN_DEBUG MOD_NAME ": " - "%s(): Unable to register resource %pR - kernel bug?\n", - __func__, &window->rsrc); + printk(KERN_DEBUG MOD_NAME + ": %s(): Unable to register resource" + " 0x%.16llx-0x%.16llx - kernel bug?\n", + __func__, + (unsigned long long)window->rsrc.start, + (unsigned long long)window->rsrc.end); } /* Map the firmware hub into my address space. */ diff --git a/trunk/drivers/mtd/maps/physmap_of.c b/trunk/drivers/mtd/maps/physmap_of.c index 8506578e6a35..9861814aa027 100644 --- a/trunk/drivers/mtd/maps/physmap_of.c +++ b/trunk/drivers/mtd/maps/physmap_of.c @@ -274,7 +274,9 @@ static int __devinit of_flash_probe(struct platform_device *dev, continue; } - dev_dbg(&dev->dev, "of_flash device: %pR\n", &res); + dev_dbg(&dev->dev, "of_flash device: %.8llx-%.8llx\n", + (unsigned long long)res.start, + (unsigned long long)res.end); err = -EBUSY; res_size = resource_size(&res); diff --git a/trunk/drivers/mtd/maps/scx200_docflash.c b/trunk/drivers/mtd/maps/scx200_docflash.c index 027e628a4f1d..b5391ebb736e 100644 --- a/trunk/drivers/mtd/maps/scx200_docflash.c +++ b/trunk/drivers/mtd/maps/scx200_docflash.c @@ -166,8 +166,9 @@ static int __init init_scx200_docflash(void) outl(pmr, scx200_cb_base + SCx200_PMR); } - printk(KERN_INFO NAME ": DOCCS mapped at %pR, width %d\n", - &docmem, width); + printk(KERN_INFO NAME ": DOCCS mapped at 0x%llx-0x%llx, width %d\n", + (unsigned long long)docmem.start, + (unsigned long long)docmem.end, width); scx200_docflash_map.size = size; if (width == 8) diff --git a/trunk/drivers/mtd/maps/tqm8xxl.c b/trunk/drivers/mtd/maps/tqm8xxl.c index c08e140d40ed..60146984f4be 100644 --- a/trunk/drivers/mtd/maps/tqm8xxl.c +++ b/trunk/drivers/mtd/maps/tqm8xxl.c @@ -139,7 +139,7 @@ static int __init init_tqm_mtd(void) goto error_mem; } - map_banks[idx]->name = kmalloc(16, GFP_KERNEL); + map_banks[idx]->name = (char *)kmalloc(16, GFP_KERNEL); if (!map_banks[idx]->name) { ret = -ENOMEM; diff --git a/trunk/drivers/mtd/mtdchar.c b/trunk/drivers/mtd/mtdchar.c index 145b3d0dc0db..ee4bb3330bdf 100644 --- a/trunk/drivers/mtd/mtdchar.c +++ b/trunk/drivers/mtd/mtdchar.c @@ -522,6 +522,10 @@ static int mtd_blkpg_ioctl(struct mtd_info *mtd, if (!capable(CAP_SYS_ADMIN)) return -EPERM; + /* Only master mtd device must be used to control partitions */ + if (!mtd_is_master(mtd)) + return -EINVAL; + if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg))) return -EFAULT; @@ -531,10 +535,6 @@ static int mtd_blkpg_ioctl(struct mtd_info *mtd, switch (a.op) { case BLKPG_ADD_PARTITION: - /* Only master mtd device must be used to add partitions */ - if (mtd_is_partition(mtd)) - return -EINVAL; - return mtd_add_partition(mtd, p.devname, p.start, p.length); case BLKPG_DEL_PARTITION: @@ -601,7 +601,6 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) } case MEMGETINFO: - memset(&info, 0, sizeof(info)); info.type = mtd->type; info.flags = mtd->flags; info.size = mtd->size; @@ -610,6 +609,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) info.oobsize = mtd->oobsize; /* The below fields are obsolete */ info.ecctype = -1; + info.eccsize = 0; if (copy_to_user(argp, &info, sizeof(struct mtd_info_user))) return -EFAULT; break; @@ -1201,7 +1201,7 @@ static int __init init_mtdchar(void) static void __exit cleanup_mtdchar(void) { unregister_mtd_user(&mtdchar_notifier); - mntput(mtd_inode_mnt); + mntput_long(mtd_inode_mnt); unregister_filesystem(&mtd_inodefs_type); __unregister_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS, "mtd"); } diff --git a/trunk/drivers/mtd/mtdconcat.c b/trunk/drivers/mtd/mtdconcat.c index 5f5777bd3f75..bf8de0943103 100644 --- a/trunk/drivers/mtd/mtdconcat.c +++ b/trunk/drivers/mtd/mtdconcat.c @@ -776,7 +776,6 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c concat->mtd.size = subdev[0]->size; concat->mtd.erasesize = subdev[0]->erasesize; concat->mtd.writesize = subdev[0]->writesize; - concat->mtd.writebufsize = subdev[0]->writebufsize; concat->mtd.subpage_sft = subdev[0]->subpage_sft; concat->mtd.oobsize = subdev[0]->oobsize; concat->mtd.oobavail = subdev[0]->oobavail; diff --git a/trunk/drivers/mtd/mtdoops.c b/trunk/drivers/mtd/mtdoops.c index e3e40f440323..c948150079be 100644 --- a/trunk/drivers/mtd/mtdoops.c +++ b/trunk/drivers/mtd/mtdoops.c @@ -401,8 +401,7 @@ static void mtdoops_notify_remove(struct mtd_info *mtd) printk(KERN_WARNING "mtdoops: could not unregister kmsg_dumper\n"); cxt->mtd = NULL; - flush_work_sync(&cxt->work_erase); - flush_work_sync(&cxt->work_write); + flush_scheduled_work(); } diff --git a/trunk/drivers/mtd/mtdpart.c b/trunk/drivers/mtd/mtdpart.c index 0a4760174782..79e3689f1e16 100644 --- a/trunk/drivers/mtd/mtdpart.c +++ b/trunk/drivers/mtd/mtdpart.c @@ -120,25 +120,8 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from, return -EINVAL; if (ops->datbuf && from + ops->len > mtd->size) return -EINVAL; - - /* - * If OOB is also requested, make sure that we do not read past the end - * of this partition. - */ - if (ops->oobbuf) { - size_t len, pages; - - if (ops->mode == MTD_OOB_AUTO) - len = mtd->oobavail; - else - len = mtd->oobsize; - pages = mtd_div_by_ws(mtd->size, mtd); - pages -= mtd_div_by_ws(from, mtd); - if (ops->ooboffs + ops->ooblen > pages * len) - return -EINVAL; - } - res = part->master->read_oob(part->master, from + part->offset, ops); + if (unlikely(res)) { if (res == -EUCLEAN) mtd->ecc_stats.corrected++; @@ -401,7 +384,6 @@ static struct mtd_part *allocate_partition(struct mtd_info *master, slave->mtd.flags = master->flags & ~part->mask_flags; slave->mtd.size = part->size; slave->mtd.writesize = master->writesize; - slave->mtd.writebufsize = master->writebufsize; slave->mtd.oobsize = master->oobsize; slave->mtd.oobavail = master->oobavail; slave->mtd.subpage_sft = master->subpage_sft; @@ -738,19 +720,19 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types, } EXPORT_SYMBOL_GPL(parse_mtd_partitions); -int mtd_is_partition(struct mtd_info *mtd) +int mtd_is_master(struct mtd_info *mtd) { struct mtd_part *part; - int ispart = 0; + int nopart = 0; mutex_lock(&mtd_partitions_mutex); list_for_each_entry(part, &mtd_partitions, list) if (&part->mtd == mtd) { - ispart = 1; + nopart = 1; break; } mutex_unlock(&mtd_partitions_mutex); - return ispart; + return nopart; } -EXPORT_SYMBOL_GPL(mtd_is_partition); +EXPORT_SYMBOL_GPL(mtd_is_master); diff --git a/trunk/drivers/mtd/nand/Kconfig b/trunk/drivers/mtd/nand/Kconfig index c89592239bc7..8229802b4346 100644 --- a/trunk/drivers/mtd/nand/Kconfig +++ b/trunk/drivers/mtd/nand/Kconfig @@ -96,7 +96,6 @@ config MTD_NAND_SPIA config MTD_NAND_AMS_DELTA tristate "NAND Flash device on Amstrad E3" depends on MACH_AMS_DELTA - default y help Support for NAND flash on Amstrad E3 (Delta). diff --git a/trunk/drivers/mtd/nand/ams-delta.c b/trunk/drivers/mtd/nand/ams-delta.c index a067d090cb31..2548e1065bf8 100644 --- a/trunk/drivers/mtd/nand/ams-delta.c +++ b/trunk/drivers/mtd/nand/ams-delta.c @@ -4,8 +4,6 @@ * Copyright (C) 2006 Jonathan McDowell * * Derived from drivers/mtd/toto.c - * Converted to platform driver by Janusz Krzysztofik - * Partially stolen from drivers/mtd/nand/plat_nand.c * * 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 @@ -64,10 +62,9 @@ static struct mtd_partition partition_info[] = { static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte) { struct nand_chip *this = mtd->priv; - void __iomem *io_base = this->priv; - writew(0, io_base + OMAP_MPUIO_IO_CNTL); - writew(byte, this->IO_ADDR_W); + omap_writew(0, (OMAP1_MPUIO_BASE + OMAP_MPUIO_IO_CNTL)); + omap_writew(byte, this->IO_ADDR_W); ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE, 0); ndelay(40); ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE, @@ -78,12 +75,11 @@ static u_char ams_delta_read_byte(struct mtd_info *mtd) { u_char res; struct nand_chip *this = mtd->priv; - void __iomem *io_base = this->priv; ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE, 0); ndelay(40); - writew(~0, io_base + OMAP_MPUIO_IO_CNTL); - res = readw(this->IO_ADDR_R); + omap_writew(~0, (OMAP1_MPUIO_BASE + OMAP_MPUIO_IO_CNTL)); + res = omap_readw(this->IO_ADDR_R); ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE, AMS_DELTA_LATCH2_NAND_NRE); @@ -155,16 +151,11 @@ static int ams_delta_nand_ready(struct mtd_info *mtd) /* * Main initialization routine */ -static int __devinit ams_delta_init(struct platform_device *pdev) +static int __init ams_delta_init(void) { struct nand_chip *this; - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - void __iomem *io_base; int err = 0; - if (!res) - return -ENXIO; - /* Allocate memory for MTD device structure and private data */ ams_delta_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); @@ -186,25 +177,9 @@ static int __devinit ams_delta_init(struct platform_device *pdev) /* Link the private data with the MTD structure */ ams_delta_mtd->priv = this; - if (!request_mem_region(res->start, resource_size(res), - dev_name(&pdev->dev))) { - dev_err(&pdev->dev, "request_mem_region failed\n"); - err = -EBUSY; - goto out_free; - } - - io_base = ioremap(res->start, resource_size(res)); - if (io_base == NULL) { - dev_err(&pdev->dev, "ioremap failed\n"); - err = -EIO; - goto out_release_io; - } - - this->priv = io_base; - /* Set address of NAND IO lines */ - this->IO_ADDR_R = io_base + OMAP_MPUIO_INPUT_LATCH; - this->IO_ADDR_W = io_base + OMAP_MPUIO_OUTPUT; + this->IO_ADDR_R = (OMAP1_MPUIO_BASE + OMAP_MPUIO_INPUT_LATCH); + this->IO_ADDR_W = (OMAP1_MPUIO_BASE + OMAP_MPUIO_OUTPUT); this->read_byte = ams_delta_read_byte; this->write_buf = ams_delta_write_buf; this->read_buf = ams_delta_read_buf; @@ -220,8 +195,6 @@ static int __devinit ams_delta_init(struct platform_device *pdev) this->chip_delay = 30; this->ecc.mode = NAND_ECC_SOFT; - platform_set_drvdata(pdev, io_base); - /* Set chip enabled, but */ ams_delta_latch2_write(NAND_MASK, AMS_DELTA_LATCH2_NAND_NRE | AMS_DELTA_LATCH2_NAND_NWE | @@ -241,56 +214,25 @@ static int __devinit ams_delta_init(struct platform_device *pdev) goto out; out_mtd: - platform_set_drvdata(pdev, NULL); - iounmap(io_base); -out_release_io: - release_mem_region(res->start, resource_size(res)); -out_free: kfree(ams_delta_mtd); out: return err; } +module_init(ams_delta_init); + /* * Clean up routine */ -static int __devexit ams_delta_cleanup(struct platform_device *pdev) +static void __exit ams_delta_cleanup(void) { - void __iomem *io_base = platform_get_drvdata(pdev); - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - /* Release resources, unregister device */ nand_release(ams_delta_mtd); - iounmap(io_base); - release_mem_region(res->start, resource_size(res)); - /* Free the MTD device structure */ kfree(ams_delta_mtd); - - return 0; -} - -static struct platform_driver ams_delta_nand_driver = { - .probe = ams_delta_init, - .remove = __devexit_p(ams_delta_cleanup), - .driver = { - .name = "ams-delta-nand", - .owner = THIS_MODULE, - }, -}; - -static int __init ams_delta_nand_init(void) -{ - return platform_driver_register(&ams_delta_nand_driver); -} -module_init(ams_delta_nand_init); - -static void __exit ams_delta_nand_exit(void) -{ - platform_driver_unregister(&ams_delta_nand_driver); } -module_exit(ams_delta_nand_exit); +module_exit(ams_delta_cleanup); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jonathan McDowell "); diff --git a/trunk/drivers/mtd/nand/fsl_elbc_nand.c b/trunk/drivers/mtd/nand/fsl_elbc_nand.c index 7a13d42cbabd..c141b07b25d1 100644 --- a/trunk/drivers/mtd/nand/fsl_elbc_nand.c +++ b/trunk/drivers/mtd/nand/fsl_elbc_nand.c @@ -388,8 +388,6 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, "page_addr: 0x%x, column: 0x%x.\n", page_addr, column); - elbc_fcm_ctrl->column = column; - elbc_fcm_ctrl->oob = 0; elbc_fcm_ctrl->use_mdr = 1; fcr = (NAND_CMD_STATUS << FCR_CMD1_SHIFT) | diff --git a/trunk/drivers/mtd/nand/fsmc_nand.c b/trunk/drivers/mtd/nand/fsmc_nand.c index 205b10b9f9b9..02edfba25b0c 100644 --- a/trunk/drivers/mtd/nand/fsmc_nand.c +++ b/trunk/drivers/mtd/nand/fsmc_nand.c @@ -31,7 +31,6 @@ #include #include #include -#include #include static struct nand_ecclayout fsmc_ecc1_layout = { @@ -120,36 +119,21 @@ static struct fsmc_eccplace fsmc_ecc4_sp_place = { } }; - -#ifdef CONFIG_MTD_PARTITIONS /* * Default partition tables to be used if the partition information not - * provided through platform data. - * + * provided through platform data + */ +#define PARTITION(n, off, sz) {.name = n, .offset = off, .size = sz} + +/* * Default partition layout for small page(= 512 bytes) devices * Size for "Root file system" is updated in driver based on actual device size */ static struct mtd_partition partition_info_16KB_blk[] = { - { - .name = "X-loader", - .offset = 0, - .size = 4*0x4000, - }, - { - .name = "U-Boot", - .offset = 0x10000, - .size = 20*0x4000, - }, - { - .name = "Kernel", - .offset = 0x60000, - .size = 256*0x4000, - }, - { - .name = "Root File System", - .offset = 0x460000, - .size = 0, - }, + PARTITION("X-loader", 0, 4 * 0x4000), + PARTITION("U-Boot", 0x10000, 20 * 0x4000), + PARTITION("Kernel", 0x60000, 256 * 0x4000), + PARTITION("Root File System", 0x460000, 0), }; /* @@ -157,37 +141,19 @@ static struct mtd_partition partition_info_16KB_blk[] = { * Size for "Root file system" is updated in driver based on actual device size */ static struct mtd_partition partition_info_128KB_blk[] = { - { - .name = "X-loader", - .offset = 0, - .size = 4*0x20000, - }, - { - .name = "U-Boot", - .offset = 0x80000, - .size = 12*0x20000, - }, - { - .name = "Kernel", - .offset = 0x200000, - .size = 48*0x20000, - }, - { - .name = "Root File System", - .offset = 0x800000, - .size = 0, - }, + PARTITION("X-loader", 0, 4 * 0x20000), + PARTITION("U-Boot", 0x80000, 12 * 0x20000), + PARTITION("Kernel", 0x200000, 48 * 0x20000), + PARTITION("Root File System", 0x800000, 0), }; #ifdef CONFIG_MTD_CMDLINE_PARTS const char *part_probes[] = { "cmdlinepart", NULL }; #endif -#endif /** - * struct fsmc_nand_data - structure for FSMC NAND device state + * struct fsmc_nand_data - atructure for FSMC NAND device state * - * @pid: Part ID on the AMBA PrimeCell format * @mtd: MTD info for a NAND flash. * @nand: Chip related info for a NAND flash. * @partitions: Partition info for a NAND Flash. @@ -203,7 +169,6 @@ const char *part_probes[] = { "cmdlinepart", NULL }; * @regs_va: FSMC regs base address. */ struct fsmc_nand_data { - u32 pid; struct mtd_info mtd; struct nand_chip nand; struct mtd_partition *partitions; @@ -543,9 +508,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) struct nand_chip *nand; struct fsmc_regs *regs; struct resource *res; - int ret = 0; - u32 pid; - int i; + int nr_parts, ret = 0; if (!pdata) { dev_err(&pdev->dev, "platform data is NULL\n"); @@ -635,18 +598,6 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) if (ret) goto err_probe1; - /* - * This device ID is actually a common AMBA ID as used on the - * AMBA PrimeCell bus. However it is not a PrimeCell. - */ - for (pid = 0, i = 0; i < 4; i++) - pid |= (readl(host->regs_va + resource_size(res) - 0x20 + 4 * i) & 255) << (i * 8); - host->pid = pid; - dev_info(&pdev->dev, "FSMC device partno %03x, manufacturer %02x, " - "revision %02x, config %02x\n", - AMBA_PART_BITS(pid), AMBA_MANF_BITS(pid), - AMBA_REV_BITS(pid), AMBA_CONFIG_BITS(pid)); - host->bank = pdata->bank; host->select_chip = pdata->select_bank; regs = host->regs_va; @@ -674,7 +625,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) fsmc_nand_setup(regs, host->bank, nand->options & NAND_BUSWIDTH_16); - if (AMBA_REV_BITS(host->pid) >= 8) { + if (get_fsmc_version(host->regs_va) == FSMC_VER8) { nand->ecc.read_page = fsmc_read_page_hwecc; nand->ecc.calculate = fsmc_read_hwecc_ecc4; nand->ecc.correct = fsmc_correct_data; @@ -694,7 +645,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) goto err_probe; } - if (AMBA_REV_BITS(host->pid) >= 8) { + if (get_fsmc_version(host->regs_va) == FSMC_VER8) { if (host->mtd.writesize == 512) { nand->ecc.layout = &fsmc_ecc4_sp_layout; host->ecc_place = &fsmc_ecc4_sp_place; @@ -725,9 +676,11 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) * Check if partition info passed via command line */ host->mtd.name = "nand"; - host->nr_partitions = parse_mtd_partitions(&host->mtd, part_probes, + nr_parts = parse_mtd_partitions(&host->mtd, part_probes, &host->partitions, 0); - if (host->nr_partitions <= 0) { + if (nr_parts > 0) { + host->nr_partitions = nr_parts; + } else { #endif /* * Check if partition info passed via command line diff --git a/trunk/drivers/mtd/nand/jz4740_nand.c b/trunk/drivers/mtd/nand/jz4740_nand.c index cea38a5d4ac5..67343fc31bd5 100644 --- a/trunk/drivers/mtd/nand/jz4740_nand.c +++ b/trunk/drivers/mtd/nand/jz4740_nand.c @@ -251,6 +251,58 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat, return 0; } + +/* Copy paste of nand_read_page_hwecc_oob_first except for different eccpos + * handling. The ecc area is for 4k chips 72 bytes long and thus does not fit + * into the eccpos array. */ +static int jz_nand_read_page_hwecc_oob_first(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, int page) +{ + int i, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + uint8_t *p = buf; + unsigned int ecc_offset = chip->page_shift; + + /* Read the OOB area first */ + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); + + for (i = ecc_offset; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + int stat; + + chip->ecc.hwctl(mtd, NAND_ECC_READ); + chip->read_buf(mtd, p, eccsize); + + stat = chip->ecc.correct(mtd, p, &chip->oob_poi[i], NULL); + if (stat < 0) + mtd->ecc_stats.failed++; + else + mtd->ecc_stats.corrected += stat; + } + return 0; +} + +/* Copy-and-paste of nand_write_page_hwecc with different eccpos handling. */ +static void jz_nand_write_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf) +{ + int i, eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + const uint8_t *p = buf; + unsigned int ecc_offset = chip->page_shift; + + for (i = ecc_offset; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { + chip->ecc.hwctl(mtd, NAND_ECC_WRITE); + chip->write_buf(mtd, p, eccsize); + chip->ecc.calculate(mtd, p, &chip->oob_poi[i]); + } + + chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); +} + #ifdef CONFIG_MTD_CMDLINE_PARTS static const char *part_probes[] = {"cmdline", NULL}; #endif @@ -341,6 +393,9 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) chip->ecc.size = 512; chip->ecc.bytes = 9; + chip->ecc.read_page = jz_nand_read_page_hwecc_oob_first; + chip->ecc.write_page = jz_nand_write_page_hwecc; + if (pdata) chip->ecc.layout = pdata->ecc_layout; @@ -434,7 +489,7 @@ static int __devexit jz_nand_remove(struct platform_device *pdev) return 0; } -static struct platform_driver jz_nand_driver = { +struct platform_driver jz_nand_driver = { .probe = jz_nand_probe, .remove = __devexit_p(jz_nand_remove), .driver = { diff --git a/trunk/drivers/mtd/nand/mxc_nand.c b/trunk/drivers/mtd/nand/mxc_nand.c index ef932ba55a0b..214b03afdd48 100644 --- a/trunk/drivers/mtd/nand/mxc_nand.c +++ b/trunk/drivers/mtd/nand/mxc_nand.c @@ -1009,7 +1009,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) struct mxc_nand_platform_data *pdata = pdev->dev.platform_data; struct mxc_nand_host *host; struct resource *res; - int err = 0, __maybe_unused nr_parts = 0; + int err = 0, nr_parts = 0; struct nand_ecclayout *oob_smallpage, *oob_largepage; /* Allocate memory for MTD device structure and private data */ diff --git a/trunk/drivers/mtd/nand/nand_base.c b/trunk/drivers/mtd/nand/nand_base.c index a9c6ce745767..31bf376b82a0 100644 --- a/trunk/drivers/mtd/nand/nand_base.c +++ b/trunk/drivers/mtd/nand/nand_base.c @@ -2865,24 +2865,20 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, /* check version */ val = le16_to_cpu(p->revision); - if (val & (1 << 5)) - chip->onfi_version = 23; - else if (val & (1 << 4)) + if (val == 1 || val > (1 << 4)) { + printk(KERN_INFO "%s: unsupported ONFI version: %d\n", + __func__, val); + return 0; + } + + if (val & (1 << 4)) chip->onfi_version = 22; else if (val & (1 << 3)) chip->onfi_version = 21; else if (val & (1 << 2)) chip->onfi_version = 20; - else if (val & (1 << 1)) - chip->onfi_version = 10; else - chip->onfi_version = 0; - - if (!chip->onfi_version) { - printk(KERN_INFO "%s: unsupported ONFI version: %d\n", - __func__, val); - return 0; - } + chip->onfi_version = 10; sanitize_string(p->manufacturer, sizeof(p->manufacturer)); sanitize_string(p->model, sizeof(p->model)); @@ -2891,7 +2887,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, mtd->writesize = le32_to_cpu(p->byte_per_page); mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize; mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); - chip->chipsize = (uint64_t)le32_to_cpu(p->blocks_per_lun) * mtd->erasesize; + chip->chipsize = le32_to_cpu(p->blocks_per_lun) * mtd->erasesize; busw = 0; if (le16_to_cpu(p->features) & 1) busw = NAND_BUSWIDTH_16; @@ -3161,7 +3157,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, printk(KERN_INFO "NAND device: Manufacturer ID:" " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id, nand_manuf_ids[maf_idx].name, - chip->onfi_version ? chip->onfi_params.model : type->name); + chip->onfi_version ? type->name : chip->onfi_params.model); return type; } @@ -3439,7 +3435,6 @@ int nand_scan_tail(struct mtd_info *mtd) mtd->resume = nand_resume; mtd->block_isbad = nand_block_isbad; mtd->block_markbad = nand_block_markbad; - mtd->writebufsize = mtd->writesize; /* propagate ecc.layout to mtd_info */ mtd->ecclayout = chip->ecc.layout; diff --git a/trunk/drivers/mtd/nand/nand_bbt.c b/trunk/drivers/mtd/nand/nand_bbt.c index 6ebd869993aa..586b981f0e61 100644 --- a/trunk/drivers/mtd/nand/nand_bbt.c +++ b/trunk/drivers/mtd/nand/nand_bbt.c @@ -1092,8 +1092,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) /** * verify_bbt_descr - verify the bad block description - * @mtd: MTD device structure - * @bd: the table to verify + * @bd: the table to verify * * This functions performs a few sanity checks on the bad block description * table. diff --git a/trunk/drivers/mtd/nand/nandsim.c b/trunk/drivers/mtd/nand/nandsim.c index a5aa99f014ba..a6a73aab1253 100644 --- a/trunk/drivers/mtd/nand/nandsim.c +++ b/trunk/drivers/mtd/nand/nandsim.c @@ -210,12 +210,12 @@ MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in d #define STATE_CMD_READ0 0x00000001 /* read data from the beginning of page */ #define STATE_CMD_READ1 0x00000002 /* read data from the second half of page */ #define STATE_CMD_READSTART 0x00000003 /* read data second command (large page devices) */ -#define STATE_CMD_PAGEPROG 0x00000004 /* start page program */ +#define STATE_CMD_PAGEPROG 0x00000004 /* start page programm */ #define STATE_CMD_READOOB 0x00000005 /* read OOB area */ #define STATE_CMD_ERASE1 0x00000006 /* sector erase first command */ #define STATE_CMD_STATUS 0x00000007 /* read status */ #define STATE_CMD_STATUS_M 0x00000008 /* read multi-plane status (isn't implemented) */ -#define STATE_CMD_SEQIN 0x00000009 /* sequential data input */ +#define STATE_CMD_SEQIN 0x00000009 /* sequential data imput */ #define STATE_CMD_READID 0x0000000A /* read ID */ #define STATE_CMD_ERASE2 0x0000000B /* sector erase second command */ #define STATE_CMD_RESET 0x0000000C /* reset */ @@ -230,7 +230,7 @@ MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in d #define STATE_ADDR_ZERO 0x00000040 /* one byte zero address was accepted */ #define STATE_ADDR_MASK 0x00000070 /* address states mask */ -/* During data input/output the simulator is in these states */ +/* Durind data input/output the simulator is in these states */ #define STATE_DATAIN 0x00000100 /* waiting for data input */ #define STATE_DATAIN_MASK 0x00000100 /* data input states mask */ @@ -248,7 +248,7 @@ MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in d /* Simulator's actions bit masks */ #define ACTION_CPY 0x00100000 /* copy page/OOB to the internal buffer */ -#define ACTION_PRGPAGE 0x00200000 /* program the internal buffer to flash */ +#define ACTION_PRGPAGE 0x00200000 /* programm the internal buffer to flash */ #define ACTION_SECERASE 0x00300000 /* erase sector */ #define ACTION_ZEROOFF 0x00400000 /* don't add any offset to address */ #define ACTION_HALFOFF 0x00500000 /* add to address half of page */ @@ -263,18 +263,18 @@ MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in d #define OPT_PAGE512 0x00000002 /* 512-byte page chips */ #define OPT_PAGE2048 0x00000008 /* 2048-byte page chips */ #define OPT_SMARTMEDIA 0x00000010 /* SmartMedia technology chips */ -#define OPT_AUTOINCR 0x00000020 /* page number auto incrementation is possible */ +#define OPT_AUTOINCR 0x00000020 /* page number auto inctimentation is possible */ #define OPT_PAGE512_8BIT 0x00000040 /* 512-byte page chips with 8-bit bus width */ #define OPT_PAGE4096 0x00000080 /* 4096-byte page chips */ #define OPT_LARGEPAGE (OPT_PAGE2048 | OPT_PAGE4096) /* 2048 & 4096-byte page chips */ #define OPT_SMALLPAGE (OPT_PAGE256 | OPT_PAGE512) /* 256 and 512-byte page chips */ -/* Remove action bits from state */ +/* Remove action bits ftom state */ #define NS_STATE(x) ((x) & ~ACTION_MASK) /* * Maximum previous states which need to be saved. Currently saving is - * only needed for page program operation with preceded read command + * only needed for page programm operation with preceeded read command * (which is only valid for 512-byte pages). */ #define NS_MAX_PREVSTATES 1 @@ -380,16 +380,16 @@ static struct nandsim_operations { /* Read OOB */ {OPT_SMALLPAGE, {STATE_CMD_READOOB | ACTION_OOBOFF, STATE_ADDR_PAGE | ACTION_CPY, STATE_DATAOUT, STATE_READY}}, - /* Program page starting from the beginning */ + /* Programm page starting from the beginning */ {OPT_ANY, {STATE_CMD_SEQIN, STATE_ADDR_PAGE, STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, - /* Program page starting from the beginning */ + /* Programm page starting from the beginning */ {OPT_SMALLPAGE, {STATE_CMD_READ0, STATE_CMD_SEQIN | ACTION_ZEROOFF, STATE_ADDR_PAGE, STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, - /* Program page starting from the second half */ + /* Programm page starting from the second half */ {OPT_PAGE512, {STATE_CMD_READ1, STATE_CMD_SEQIN | ACTION_HALFOFF, STATE_ADDR_PAGE, STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, - /* Program OOB */ + /* Programm OOB */ {OPT_SMALLPAGE, {STATE_CMD_READOOB, STATE_CMD_SEQIN | ACTION_OOBOFF, STATE_ADDR_PAGE, STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, /* Erase sector */ @@ -470,7 +470,7 @@ static int alloc_device(struct nandsim *ns) err = -EINVAL; goto err_close; } - ns->pages_written = vzalloc(ns->geom.pgnum); + ns->pages_written = vmalloc(ns->geom.pgnum); if (!ns->pages_written) { NS_ERR("alloc_device: unable to allocate pages written array\n"); err = -ENOMEM; @@ -483,6 +483,7 @@ static int alloc_device(struct nandsim *ns) goto err_free; } ns->cfile = cfile; + memset(ns->pages_written, 0, ns->geom.pgnum); return 0; } @@ -1170,9 +1171,9 @@ static inline void switch_to_ready_state(struct nandsim *ns, u_char status) * of supported operations. * * Operation can be unknown because of the following. - * 1. New command was accepted and this is the first call to find the + * 1. New command was accepted and this is the firs call to find the * correspondent states chain. In this case ns->npstates = 0; - * 2. There are several operations which begin with the same command(s) + * 2. There is several operations which begin with the same command(s) * (for example program from the second half and read from the * second half operations both begin with the READ1 command). In this * case the ns->pstates[] array contains previous states. @@ -1185,7 +1186,7 @@ static inline void switch_to_ready_state(struct nandsim *ns, u_char status) * ns->ops, ns->state, ns->nxstate are initialized, ns->npstate is * zeroed). * - * If there are several matches, the current state is pushed to the + * If there are several maches, the current state is pushed to the * ns->pstates. * * The operation can be unknown only while commands are input to the chip. @@ -1194,10 +1195,10 @@ static inline void switch_to_ready_state(struct nandsim *ns, u_char status) * operation is searched using the following pattern: * ns->pstates[0], ... ns->pstates[ns->npstates],
* - * It is supposed that this pattern must either match one operation or + * It is supposed that this pattern must either match one operation on * none. There can't be ambiguity in that case. * - * If no matches found, the function does the following: + * If no matches found, the functions does the following: * 1. if there are saved states present, try to ignore them and search * again only using the last command. If nothing was found, switch * to the STATE_READY state. @@ -1667,7 +1668,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action) case ACTION_PRGPAGE: /* - * Program page - move internal buffer data to the page. + * Programm page - move internal buffer data to the page. */ if (ns->lines.wp) { @@ -1932,7 +1933,7 @@ static u_char ns_nand_read_byte(struct mtd_info *mtd) NS_DBG("read_byte: all bytes were read\n"); /* - * The OPT_AUTOINCR allows to read next consecutive pages without + * The OPT_AUTOINCR allows to read next conseqitive pages without * new read operation cycle. */ if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) { diff --git a/trunk/drivers/mtd/nand/pasemi_nand.c b/trunk/drivers/mtd/nand/pasemi_nand.c index bb277a54986f..6ddb2461d740 100644 --- a/trunk/drivers/mtd/nand/pasemi_nand.c +++ b/trunk/drivers/mtd/nand/pasemi_nand.c @@ -107,7 +107,7 @@ static int __devinit pasemi_nand_probe(struct platform_device *ofdev, if (pasemi_nand_mtd) return -ENODEV; - pr_debug("pasemi_nand at %pR\n", &res); + pr_debug("pasemi_nand at %llx-%llx\n", res.start, res.end); /* Allocate memory for MTD device structure and private data */ pasemi_nand_mtd = kzalloc(sizeof(struct mtd_info) + diff --git a/trunk/drivers/mtd/nand/pxa3xx_nand.c b/trunk/drivers/mtd/nand/pxa3xx_nand.c index ea2c288df3f6..17f8518cc5eb 100644 --- a/trunk/drivers/mtd/nand/pxa3xx_nand.c +++ b/trunk/drivers/mtd/nand/pxa3xx_nand.c @@ -885,7 +885,6 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) /* set info fields needed to __readid */ info->read_id_bytes = (info->page_size == 2048) ? 4 : 2; info->reg_ndcr = ndcr; - info->cmdset = &default_cmdset; if (__readid(info, &id)) return -ENODEV; @@ -916,6 +915,7 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) info->ndtr0cs0 = nand_readl(info, NDTR0CS0); info->ndtr1cs0 = nand_readl(info, NDTR1CS0); + info->cmdset = &default_cmdset; return 0; } diff --git a/trunk/drivers/mtd/nand/txx9ndfmc.c b/trunk/drivers/mtd/nand/txx9ndfmc.c index ca270a4881a4..054a41c0ef4a 100644 --- a/trunk/drivers/mtd/nand/txx9ndfmc.c +++ b/trunk/drivers/mtd/nand/txx9ndfmc.c @@ -277,9 +277,8 @@ static int txx9ndfmc_nand_scan(struct mtd_info *mtd) ret = nand_scan_ident(mtd, 1, NULL); if (!ret) { if (mtd->writesize >= 512) { - /* Hardware ECC 6 byte ECC per 512 Byte data */ - chip->ecc.size = 512; - chip->ecc.bytes = 6; + chip->ecc.size = mtd->writesize; + chip->ecc.bytes = 3 * (mtd->writesize / 256); } ret = nand_scan_tail(mtd); } diff --git a/trunk/drivers/mtd/onenand/omap2.c b/trunk/drivers/mtd/onenand/omap2.c index ac31f461cc1c..d0894ca7798b 100644 --- a/trunk/drivers/mtd/onenand/omap2.c +++ b/trunk/drivers/mtd/onenand/omap2.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include @@ -64,13 +63,8 @@ struct omap2_onenand { int dma_channel; int freq; int (*setup)(void __iomem *base, int freq); - struct regulator *regulator; }; -#ifdef CONFIG_MTD_PARTITIONS -static const char *part_probes[] = { "cmdlinepart", NULL, }; -#endif - static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data) { struct omap2_onenand *c = data; @@ -114,9 +108,8 @@ static void wait_warn(char *msg, int state, unsigned int ctrl, static int omap2_onenand_wait(struct mtd_info *mtd, int state) { struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); - struct onenand_chip *this = mtd->priv; unsigned int intr = 0; - unsigned int ctrl, ctrl_mask; + unsigned int ctrl; unsigned long timeout; u32 syscfg; @@ -187,8 +180,7 @@ static int omap2_onenand_wait(struct mtd_info *mtd, int state) if (result == 0) { /* Timeout after 20ms */ ctrl = read_reg(c, ONENAND_REG_CTRL_STATUS); - if (ctrl & ONENAND_CTRL_ONGO && - !this->ongoing) { + if (ctrl & ONENAND_CTRL_ONGO) { /* * The operation seems to be still going * so give it some more time. @@ -277,11 +269,7 @@ static int omap2_onenand_wait(struct mtd_info *mtd, int state) return -EIO; } - ctrl_mask = 0xFE9F; - if (this->ongoing) - ctrl_mask &= ~0x8000; - - if (ctrl & ctrl_mask) + if (ctrl & 0xFE9F) wait_warn("unexpected controller status", state, ctrl, intr); return 0; @@ -603,30 +591,6 @@ static void omap2_onenand_shutdown(struct platform_device *pdev) memset((__force void *)c->onenand.base, 0, ONENAND_BUFRAM_SIZE); } -static int omap2_onenand_enable(struct mtd_info *mtd) -{ - int ret; - struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); - - ret = regulator_enable(c->regulator); - if (ret != 0) - dev_err(&c->pdev->dev, "cant enable regulator\n"); - - return ret; -} - -static int omap2_onenand_disable(struct mtd_info *mtd) -{ - int ret; - struct omap2_onenand *c = container_of(mtd, struct omap2_onenand, mtd); - - ret = regulator_disable(c->regulator); - if (ret != 0) - dev_err(&c->pdev->dev, "cant disable regulator\n"); - - return ret; -} - static int __devinit omap2_onenand_probe(struct platform_device *pdev) { struct omap_onenand_platform_data *pdata; @@ -741,18 +705,8 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) } } - if (pdata->regulator_can_sleep) { - c->regulator = regulator_get(&pdev->dev, "vonenand"); - if (IS_ERR(c->regulator)) { - dev_err(&pdev->dev, "Failed to get regulator\n"); - goto err_release_dma; - } - c->onenand.enable = omap2_onenand_enable; - c->onenand.disable = omap2_onenand_disable; - } - if ((r = onenand_scan(&c->mtd, 1)) < 0) - goto err_release_regulator; + goto err_release_dma; switch ((c->onenand.version_id >> 4) & 0xf) { case 0: @@ -773,15 +727,13 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) } #ifdef CONFIG_MTD_PARTITIONS - r = parse_mtd_partitions(&c->mtd, part_probes, &c->parts, 0); - if (r > 0) - r = add_mtd_partitions(&c->mtd, c->parts, r); - else if (pdata->parts != NULL) - r = add_mtd_partitions(&c->mtd, pdata->parts, pdata->nr_parts); + if (pdata->parts != NULL) + r = add_mtd_partitions(&c->mtd, pdata->parts, + pdata->nr_parts); else #endif r = add_mtd_device(&c->mtd); - if (r) + if (r < 0) goto err_release_onenand; platform_set_drvdata(pdev, c); @@ -790,8 +742,6 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) err_release_onenand: onenand_release(&c->mtd); -err_release_regulator: - regulator_put(c->regulator); err_release_dma: if (c->dma_channel != -1) omap_free_dma(c->dma_channel); @@ -807,7 +757,6 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) err_free_cs: gpmc_cs_free(c->gpmc_cs); err_kfree: - kfree(c->parts); kfree(c); return r; @@ -817,8 +766,18 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev) { struct omap2_onenand *c = dev_get_drvdata(&pdev->dev); + BUG_ON(c == NULL); + +#ifdef CONFIG_MTD_PARTITIONS + if (c->parts) + del_mtd_partitions(&c->mtd); + else + del_mtd_device(&c->mtd); +#else + del_mtd_device(&c->mtd); +#endif + onenand_release(&c->mtd); - regulator_put(c->regulator); if (c->dma_channel != -1) omap_free_dma(c->dma_channel); omap2_onenand_shutdown(pdev); @@ -830,7 +789,6 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev) iounmap(c->onenand.base); release_mem_region(c->phys_base, ONENAND_IO_SIZE); gpmc_cs_free(c->gpmc_cs); - kfree(c->parts); kfree(c); return 0; diff --git a/trunk/drivers/mtd/onenand/onenand_base.c b/trunk/drivers/mtd/onenand/onenand_base.c index bac41caa8df7..6b3a875647c9 100644 --- a/trunk/drivers/mtd/onenand/onenand_base.c +++ b/trunk/drivers/mtd/onenand/onenand_base.c @@ -400,7 +400,8 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le value = onenand_bufferram_address(this, block); this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); - if (ONENAND_IS_2PLANE(this) || ONENAND_IS_4KB_PAGE(this)) + if (ONENAND_IS_MLC(this) || ONENAND_IS_2PLANE(this) || + ONENAND_IS_4KB_PAGE(this)) /* It is always BufferRAM0 */ ONENAND_SET_BUFFERRAM0(this); else @@ -429,7 +430,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le case FLEXONENAND_CMD_RECOVER_LSB: case ONENAND_CMD_READ: case ONENAND_CMD_READOOB: - if (ONENAND_IS_4KB_PAGE(this)) + if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this)) /* It is always BufferRAM0 */ dataram = ONENAND_SET_BUFFERRAM0(this); else @@ -948,8 +949,6 @@ static int onenand_get_device(struct mtd_info *mtd, int new_state) if (this->state == FL_READY) { this->state = new_state; spin_unlock(&this->chip_lock); - if (new_state != FL_PM_SUSPENDED && this->enable) - this->enable(mtd); break; } if (new_state == FL_PM_SUSPENDED) { @@ -976,8 +975,6 @@ static void onenand_release_device(struct mtd_info *mtd) { struct onenand_chip *this = mtd->priv; - if (this->state != FL_PM_SUSPENDED && this->disable) - this->disable(mtd); /* Release the chip */ spin_lock(&this->chip_lock); this->state = FL_READY; @@ -1356,7 +1353,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, stats = mtd->ecc_stats; - readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; + readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; while (read < len) { cond_resched(); @@ -1432,7 +1429,7 @@ static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len, int ret; onenand_get_device(mtd, FL_READING); - ret = ONENAND_IS_4KB_PAGE(this) ? + ret = ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this) ? onenand_mlc_read_ops_nolock(mtd, from, &ops) : onenand_read_ops_nolock(mtd, from, &ops); onenand_release_device(mtd); @@ -1467,7 +1464,7 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from, onenand_get_device(mtd, FL_READING); if (ops->datbuf) - ret = ONENAND_IS_4KB_PAGE(this) ? + ret = ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this) ? onenand_mlc_read_ops_nolock(mtd, from, ops) : onenand_read_ops_nolock(mtd, from, ops); else @@ -1488,7 +1485,8 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state) { struct onenand_chip *this = mtd->priv; unsigned long timeout; - unsigned int interrupt, ctrl, ecc, addr1, addr8; + unsigned int interrupt; + unsigned int ctrl; /* The 20 msec is enough */ timeout = jiffies + msecs_to_jiffies(20); @@ -1500,28 +1498,25 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state) /* To get correct interrupt status in timeout case */ interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); - addr1 = this->read_word(this->base + ONENAND_REG_START_ADDRESS1); - addr8 = this->read_word(this->base + ONENAND_REG_START_ADDRESS8); if (interrupt & ONENAND_INT_READ) { - ecc = onenand_read_ecc(this); + int ecc = onenand_read_ecc(this); if (ecc & ONENAND_ECC_2BIT_ALL) { - printk(KERN_DEBUG "%s: ecc 0x%04x ctrl 0x%04x " - "intr 0x%04x addr1 %#x addr8 %#x\n", - __func__, ecc, ctrl, interrupt, addr1, addr8); + printk(KERN_WARNING "%s: ecc error = 0x%04x, " + "controller error 0x%04x\n", + __func__, ecc, ctrl); return ONENAND_BBT_READ_ECC_ERROR; } } else { - printk(KERN_ERR "%s: read timeout! ctrl 0x%04x " - "intr 0x%04x addr1 %#x addr8 %#x\n", - __func__, ctrl, interrupt, addr1, addr8); + printk(KERN_ERR "%s: read timeout! ctrl=0x%04x intr=0x%04x\n", + __func__, ctrl, interrupt); return ONENAND_BBT_READ_FATAL_ERROR; } /* Initial bad block case: 0x2400 or 0x0400 */ if (ctrl & ONENAND_CTRL_ERROR) { - printk(KERN_DEBUG "%s: ctrl 0x%04x intr 0x%04x addr1 %#x " - "addr8 %#x\n", __func__, ctrl, interrupt, addr1, addr8); + printk(KERN_DEBUG "%s: controller error = 0x%04x\n", + __func__, ctrl); return ONENAND_BBT_READ_ERROR; } @@ -1563,7 +1558,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, column = from & (mtd->oobsize - 1); - readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; + readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; while (read < len) { cond_resched(); @@ -1617,7 +1612,7 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to u_char *oob_buf = this->oob_buf; int status, i, readcmd; - readcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; + readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB; this->command(mtd, readcmd, to, mtd->oobsize); onenand_update_bufferram(mtd, to, 0); @@ -1850,7 +1845,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, const u_char *buf = ops->datbuf; const u_char *oob = ops->oobbuf; u_char *oobbuf; - int ret = 0, cmd; + int ret = 0; DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", __func__, (unsigned int) to, (int) len); @@ -1959,19 +1954,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, ONENAND_SET_NEXT_BUFFERRAM(this); } - this->ongoing = 0; - cmd = ONENAND_CMD_PROG; - - /* Exclude 1st OTP and OTP blocks for cache program feature */ - if (ONENAND_IS_CACHE_PROGRAM(this) && - likely(onenand_block(this, to) != 0) && - ONENAND_IS_4KB_PAGE(this) && - ((written + thislen) < len)) { - cmd = ONENAND_CMD_2X_CACHE_PROG; - this->ongoing = 1; - } - - this->command(mtd, cmd, to, mtd->writesize); + this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); /* * 2 PLANE, MLC, and Flex-OneNAND wait here @@ -2084,7 +2067,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, oobbuf = this->oob_buf; - oobcmd = ONENAND_IS_4KB_PAGE(this) ? ONENAND_CMD_PROG : ONENAND_CMD_PROGOOB; + oobcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_PROG : ONENAND_CMD_PROGOOB; /* Loop until all data write */ while (written < len) { @@ -2103,7 +2086,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, memcpy(oobbuf + column, buf, thislen); this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); - if (ONENAND_IS_4KB_PAGE(this)) { + if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this)) { /* Set main area of DataRAM to 0xff*/ memset(this->page_buf, 0xff, mtd->writesize); this->write_bufferram(mtd, ONENAND_DATARAM, @@ -2498,8 +2481,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) /* Grab the lock and see if the device is available */ onenand_get_device(mtd, FL_ERASING); - if (ONENAND_IS_4KB_PAGE(this) || region || - instr->len < MB_ERASE_MIN_BLK_COUNT * block_size) { + if (region || instr->len < MB_ERASE_MIN_BLK_COUNT * block_size) { /* region is set for Flex-OneNAND (no mb erase) */ ret = onenand_block_by_block_erase(mtd, instr, region, block_size); @@ -3047,7 +3029,7 @@ static int do_otp_read(struct mtd_info *mtd, loff_t from, size_t len, this->command(mtd, ONENAND_CMD_OTP_ACCESS, 0, 0); this->wait(mtd, FL_OTPING); - ret = ONENAND_IS_4KB_PAGE(this) ? + ret = ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this) ? onenand_mlc_read_ops_nolock(mtd, from, &ops) : onenand_read_ops_nolock(mtd, from, &ops); @@ -3395,10 +3377,8 @@ static void onenand_check_features(struct mtd_info *mtd) case ONENAND_DEVICE_DENSITY_4Gb: if (ONENAND_IS_DDP(this)) this->options |= ONENAND_HAS_2PLANE; - else if (numbufs == 1) { + else if (numbufs == 1) this->options |= ONENAND_HAS_4KB_PAGE; - this->options |= ONENAND_HAS_CACHE_PROGRAM; - } case ONENAND_DEVICE_DENSITY_2Gb: /* 2Gb DDP does not have 2 plane */ @@ -3419,11 +3399,7 @@ static void onenand_check_features(struct mtd_info *mtd) break; } - /* The MLC has 4KiB pagesize. */ - if (ONENAND_IS_MLC(this)) - this->options |= ONENAND_HAS_4KB_PAGE; - - if (ONENAND_IS_4KB_PAGE(this)) + if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this)) this->options &= ~ONENAND_HAS_2PLANE; if (FLEXONENAND(this)) { @@ -3439,8 +3415,6 @@ static void onenand_check_features(struct mtd_info *mtd) printk(KERN_DEBUG "Chip has 2 plane\n"); if (this->options & ONENAND_HAS_4KB_PAGE) printk(KERN_DEBUG "Chip has 4KiB pagesize\n"); - if (this->options & ONENAND_HAS_CACHE_PROGRAM) - printk(KERN_DEBUG "Chip has cache program feature\n"); } /** @@ -3857,7 +3831,7 @@ static int onenand_probe(struct mtd_info *mtd) /* The data buffer size is equal to page size */ mtd->writesize = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE); /* We use the full BufferRAM */ - if (ONENAND_IS_4KB_PAGE(this)) + if (ONENAND_IS_MLC(this) || ONENAND_IS_4KB_PAGE(this)) mtd->writesize <<= 1; mtd->oobsize = mtd->writesize >> 5; @@ -4080,7 +4054,6 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) mtd->block_isbad = onenand_block_isbad; mtd->block_markbad = onenand_block_markbad; mtd->owner = THIS_MODULE; - mtd->writebufsize = mtd->writesize; /* Unlock whole block */ this->unlock_all(mtd); diff --git a/trunk/drivers/mtd/onenand/onenand_bbt.c b/trunk/drivers/mtd/onenand/onenand_bbt.c index fc2c16a0fd1c..01ab5b3c453b 100644 --- a/trunk/drivers/mtd/onenand/onenand_bbt.c +++ b/trunk/drivers/mtd/onenand/onenand_bbt.c @@ -91,18 +91,16 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr for (j = 0; j < len; j++) { /* No need to read pages fully, * just read required OOB bytes */ - ret = onenand_bbt_read_oob(mtd, - from + j * this->writesize + bd->offs, &ops); + ret = onenand_bbt_read_oob(mtd, from + j * mtd->writesize + bd->offs, &ops); /* If it is a initial bad block, just ignore it */ if (ret == ONENAND_BBT_READ_FATAL_ERROR) return -EIO; - if (ret || check_short_pattern(&buf[j * scanlen], - scanlen, this->writesize, bd)) { + if (ret || check_short_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) { bbm->bbt[i >> 3] |= 0x03 << (i & 0x6); - printk(KERN_INFO "OneNAND eraseblock %d is an " - "initial bad block\n", i >> 1); + printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", + i >> 1, (unsigned int) from); mtd->ecc_stats.badblocks++; break; } diff --git a/trunk/drivers/mtd/onenand/samsung.c b/trunk/drivers/mtd/onenand/samsung.c index a4c74a9ba430..0de7a05e6de0 100644 --- a/trunk/drivers/mtd/onenand/samsung.c +++ b/trunk/drivers/mtd/onenand/samsung.c @@ -651,7 +651,7 @@ static int s5pc110_read_bufferram(struct mtd_info *mtd, int area, void __iomem *p; void *buf = (void *) buffer; dma_addr_t dma_src, dma_dst; - int err, ofs, page_dma = 0; + int err, page_dma = 0; struct device *dev = &onenand->pdev->dev; p = this->base + area; @@ -677,13 +677,10 @@ static int s5pc110_read_bufferram(struct mtd_info *mtd, int area, if (!page) goto normal; - /* Page offset */ - ofs = ((size_t) buf & ~PAGE_MASK); page_dma = 1; - /* DMA routine */ dma_src = onenand->phys_base + (p - this->base); - dma_dst = dma_map_page(dev, page, ofs, count, DMA_FROM_DEVICE); + dma_dst = dma_map_page(dev, page, 0, count, DMA_FROM_DEVICE); } else { /* DMA routine */ dma_src = onenand->phys_base + (p - this->base); diff --git a/trunk/drivers/mtd/ubi/build.c b/trunk/drivers/mtd/ubi/build.c index f49e49dc5928..5ebe280225d6 100644 --- a/trunk/drivers/mtd/ubi/build.c +++ b/trunk/drivers/mtd/ubi/build.c @@ -672,33 +672,7 @@ static int io_init(struct ubi_device *ubi) ubi->nor_flash = 1; } - /* - * Set UBI min. I/O size (@ubi->min_io_size). We use @mtd->writebufsize - * for these purposes, not @mtd->writesize. At the moment this does not - * matter for NAND, because currently @mtd->writebufsize is equivalent to - * @mtd->writesize for all NANDs. However, some CFI NOR flashes may - * have @mtd->writebufsize which is multiple of @mtd->writesize. - * - * The reason we use @mtd->writebufsize for @ubi->min_io_size is that - * UBI and UBIFS recovery algorithms rely on the fact that if there was - * an unclean power cut, then we can find offset of the last corrupted - * node, align the offset to @ubi->min_io_size, read the rest of the - * eraseblock starting from this offset, and check whether there are - * only 0xFF bytes. If yes, then we are probably dealing with a - * corruption caused by a power cut, if not, then this is probably some - * severe corruption. - * - * Thus, we have to use the maximum write unit size of the flash, which - * is @mtd->writebufsize, because @mtd->writesize is the minimum write - * size, not the maximum. - */ - if (ubi->mtd->type == MTD_NANDFLASH) - ubi_assert(ubi->mtd->writebufsize == ubi->mtd->writesize); - else if (ubi->mtd->type == MTD_NORFLASH) - ubi_assert(ubi->mtd->writebufsize % ubi->mtd->writesize == 0); - - ubi->min_io_size = ubi->mtd->writebufsize; - + ubi->min_io_size = ubi->mtd->writesize; ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft; /* diff --git a/trunk/drivers/mtd/ubi/vtbl.c b/trunk/drivers/mtd/ubi/vtbl.c index 0b8141fc5c26..fcdb7f65fe0b 100644 --- a/trunk/drivers/mtd/ubi/vtbl.c +++ b/trunk/drivers/mtd/ubi/vtbl.c @@ -425,11 +425,12 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi, /* Read both LEB 0 and LEB 1 into memory */ ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) { - leb[seb->lnum] = vzalloc(ubi->vtbl_size); + leb[seb->lnum] = vmalloc(ubi->vtbl_size); if (!leb[seb->lnum]) { err = -ENOMEM; goto out_free; } + memset(leb[seb->lnum], 0, ubi->vtbl_size); err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0, ubi->vtbl_size); @@ -515,9 +516,10 @@ static struct ubi_vtbl_record *create_empty_lvol(struct ubi_device *ubi, int i; struct ubi_vtbl_record *vtbl; - vtbl = vzalloc(ubi->vtbl_size); + vtbl = vmalloc(ubi->vtbl_size); if (!vtbl) return ERR_PTR(-ENOMEM); + memset(vtbl, 0, ubi->vtbl_size); for (i = 0; i < ubi->vtbl_slots; i++) memcpy(&vtbl[i], &empty_vtbl_record, UBI_VTBL_RECORD_SIZE); diff --git a/trunk/drivers/net/Kconfig b/trunk/drivers/net/Kconfig index 16fe4f9b719b..4c8bfc97fb4c 100644 --- a/trunk/drivers/net/Kconfig +++ b/trunk/drivers/net/Kconfig @@ -3389,7 +3389,8 @@ config NETCONSOLE config NETCONSOLE_DYNAMIC bool "Dynamic reconfiguration of logging targets" - depends on NETCONSOLE && SYSFS && CONFIGFS_FS + depends on NETCONSOLE && SYSFS + select CONFIGFS_FS help This option enables the ability to dynamically reconfigure target parameters (interface, IP addresses, port numbers, MAC addresses) diff --git a/trunk/drivers/nfc/pn544.c b/trunk/drivers/nfc/pn544.c index bae647264dd6..401c44b6eadb 100644 --- a/trunk/drivers/nfc/pn544.c +++ b/trunk/drivers/nfc/pn544.c @@ -69,7 +69,7 @@ struct pn544_info { struct mutex read_mutex; /* Serialize read_irq access */ struct mutex mutex; /* Serialize info struct access */ u8 *buf; - size_t buflen; + unsigned int buflen; }; static const char reg_vdd_io[] = "Vdd_IO"; diff --git a/trunk/drivers/of/fdt.c b/trunk/drivers/of/fdt.c index c787c3d95c60..af824e7e0367 100644 --- a/trunk/drivers/of/fdt.c +++ b/trunk/drivers/of/fdt.c @@ -692,12 +692,6 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, return 1; } -static void *__init early_device_tree_alloc(u64 size, u64 align) -{ - unsigned long mem = early_init_dt_alloc_memory_arch(size, align); - return __va(mem); -} - /** * unflatten_device_tree - create tree of device_nodes from flat blob * @@ -709,7 +703,7 @@ static void *__init early_device_tree_alloc(u64 size, u64 align) void __init unflatten_device_tree(void) { __unflatten_device_tree(initial_boot_params, &allnodes, - early_device_tree_alloc); + early_init_dt_alloc_memory_arch); /* Get pointer to OF "/chosen" node for use everywhere */ of_chosen = of_find_node_by_path("/chosen"); diff --git a/trunk/drivers/staging/autofs/dirhash.c b/trunk/drivers/staging/autofs/dirhash.c index a08bd7355035..d3f42c8325f7 100644 --- a/trunk/drivers/staging/autofs/dirhash.c +++ b/trunk/drivers/staging/autofs/dirhash.c @@ -88,13 +88,14 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb, } path.mnt = mnt; path_get(&path); - if (!follow_down_one(&path)) { + if (!follow_down(&path)) { path_put(&path); DPRINTK(("autofs: not expirable\ (not a mounted directory): %s\n", ent->name)); continue; } - follow_down(&path, false); // TODO: need to check error + while (d_mountpoint(path.dentry) && follow_down(&path)) + ; umount_ok = may_umount(path.mnt); path_put(&path); diff --git a/trunk/drivers/staging/smbfs/dir.c b/trunk/drivers/staging/smbfs/dir.c index f204d33910ec..87a3a9bd5842 100644 --- a/trunk/drivers/staging/smbfs/dir.c +++ b/trunk/drivers/staging/smbfs/dir.c @@ -283,7 +283,7 @@ static int smb_compare_dentry(const struct dentry *, unsigned int, const char *, const struct qstr *); static int smb_delete_dentry(const struct dentry *); -const struct dentry_operations smbfs_dentry_operations = +static const struct dentry_operations smbfs_dentry_operations = { .d_revalidate = smb_lookup_validate, .d_hash = smb_hash_dentry, @@ -291,7 +291,7 @@ const struct dentry_operations smbfs_dentry_operations = .d_delete = smb_delete_dentry, }; -const struct dentry_operations smbfs_dentry_operations_case = +static const struct dentry_operations smbfs_dentry_operations_case = { .d_revalidate = smb_lookup_validate, .d_delete = smb_delete_dentry, diff --git a/trunk/fs/Kconfig b/trunk/fs/Kconfig index 9a7921ae4763..771f457402d4 100644 --- a/trunk/fs/Kconfig +++ b/trunk/fs/Kconfig @@ -30,6 +30,15 @@ config FS_MBCACHE source "fs/reiserfs/Kconfig" source "fs/jfs/Kconfig" +config FS_POSIX_ACL +# Posix ACL utility routines (for now, only ext2/ext3/jfs/reiserfs/nfs4) +# +# NOTE: you can implement Posix ACLs without these helpers (XFS does). +# Never use this symbol for ifdefs. +# + bool + default n + source "fs/xfs/Kconfig" source "fs/gfs2/Kconfig" source "fs/ocfs2/Kconfig" @@ -38,14 +47,6 @@ source "fs/nilfs2/Kconfig" endif # BLOCK -# Posix ACL utility routines -# -# Note: Posix ACLs can be implemented without these helpers. Never use -# this symbol for ifdefs in core code. -# -config FS_POSIX_ACL - def_bool n - config EXPORTFS tristate diff --git a/trunk/fs/afs/dir.c b/trunk/fs/afs/dir.c index 20c106f24927..e6a4ab980e31 100644 --- a/trunk/fs/afs/dir.c +++ b/trunk/fs/afs/dir.c @@ -66,7 +66,6 @@ const struct dentry_operations afs_fs_dentry_operations = { .d_revalidate = afs_d_revalidate, .d_delete = afs_d_delete, .d_release = afs_d_release, - .d_automount = afs_d_automount, }; #define AFS_DIR_HASHTBL_SIZE 128 diff --git a/trunk/fs/afs/inode.c b/trunk/fs/afs/inode.c index db66c5201474..0747339011c3 100644 --- a/trunk/fs/afs/inode.c +++ b/trunk/fs/afs/inode.c @@ -184,8 +184,7 @@ struct inode *afs_iget_autocell(struct inode *dir, const char *dev_name, inode->i_generation = 0; set_bit(AFS_VNODE_PSEUDODIR, &vnode->flags); - set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags); - inode->i_flags |= S_AUTOMOUNT | S_NOATIME; + inode->i_flags |= S_NOATIME; unlock_new_inode(inode); _leave(" = %p", inode); return inode; diff --git a/trunk/fs/afs/internal.h b/trunk/fs/afs/internal.h index 5a9b6843bac1..58c633b80246 100644 --- a/trunk/fs/afs/internal.h +++ b/trunk/fs/afs/internal.h @@ -592,7 +592,6 @@ extern const struct inode_operations afs_mntpt_inode_operations; extern const struct inode_operations afs_autocell_inode_operations; extern const struct file_operations afs_mntpt_file_operations; -extern struct vfsmount *afs_d_automount(struct path *); extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *); extern void afs_mntpt_kill_timer(void); diff --git a/trunk/fs/afs/mntpt.c b/trunk/fs/afs/mntpt.c index aa59184151d0..e83c0336e7b5 100644 --- a/trunk/fs/afs/mntpt.c +++ b/trunk/fs/afs/mntpt.c @@ -24,6 +24,7 @@ static struct dentry *afs_mntpt_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd); static int afs_mntpt_open(struct inode *inode, struct file *file); +static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd); static void afs_mntpt_expiry_timed_out(struct work_struct *work); const struct file_operations afs_mntpt_file_operations = { @@ -33,11 +34,13 @@ const struct file_operations afs_mntpt_file_operations = { const struct inode_operations afs_mntpt_inode_operations = { .lookup = afs_mntpt_lookup, + .follow_link = afs_mntpt_follow_link, .readlink = page_readlink, .getattr = afs_getattr, }; const struct inode_operations afs_autocell_inode_operations = { + .follow_link = afs_mntpt_follow_link, .getattr = afs_getattr, }; @@ -85,7 +88,6 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key) _debug("symlink is a mountpoint"); spin_lock(&vnode->lock); set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags); - vnode->vfs_inode.i_flags |= S_AUTOMOUNT; spin_unlock(&vnode->lock); } @@ -236,24 +238,52 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) } /* - * handle an automount point + * follow a link from a mountpoint directory, thus causing it to be mounted */ -struct vfsmount *afs_d_automount(struct path *path) +static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd) { struct vfsmount *newmnt; + int err; - _enter("{%s,%s}", path->mnt->mnt_devname, path->dentry->d_name.name); + _enter("%p{%s},{%s:%p{%s},}", + dentry, + dentry->d_name.name, + nd->path.mnt->mnt_devname, + dentry, + nd->path.dentry->d_name.name); + + dput(nd->path.dentry); + nd->path.dentry = dget(dentry); + + newmnt = afs_mntpt_do_automount(nd->path.dentry); + if (IS_ERR(newmnt)) { + path_put(&nd->path); + return (void *)newmnt; + } - newmnt = afs_mntpt_do_automount(path->dentry); - if (IS_ERR(newmnt)) - return newmnt; + mntget(newmnt); + err = do_add_mount(newmnt, &nd->path, MNT_SHRINKABLE, &afs_vfsmounts); + switch (err) { + case 0: + path_put(&nd->path); + nd->path.mnt = newmnt; + nd->path.dentry = dget(newmnt->mnt_root); + queue_delayed_work(afs_wq, &afs_mntpt_expiry_timer, + afs_mntpt_expiry_timeout * HZ); + break; + case -EBUSY: + /* someone else made a mount here whilst we were busy */ + while (d_mountpoint(nd->path.dentry) && + follow_down(&nd->path)) + ; + err = 0; + default: + mntput(newmnt); + break; + } - mntget(newmnt); /* prevent immediate expiration */ - mnt_set_expiry(newmnt, &afs_vfsmounts); - queue_delayed_work(afs_wq, &afs_mntpt_expiry_timer, - afs_mntpt_expiry_timeout * HZ); - _leave(" = %p {%s}", newmnt, newmnt->mnt_devname); - return newmnt; + _leave(" = %d", err); + return ERR_PTR(err); } /* diff --git a/trunk/fs/aio.c b/trunk/fs/aio.c index fc557a3be0a9..5e00f15c54aa 100644 --- a/trunk/fs/aio.c +++ b/trunk/fs/aio.c @@ -87,7 +87,7 @@ static int __init aio_setup(void) aio_wq = create_workqueue("aio"); abe_pool = mempool_create_kmalloc_pool(1, sizeof(struct aio_batch_entry)); - BUG_ON(!aio_wq || !abe_pool); + BUG_ON(!abe_pool); pr_debug("aio_setup: sizeof(struct page) = %d\n", (int)sizeof(struct page)); diff --git a/trunk/fs/anon_inodes.c b/trunk/fs/anon_inodes.c index c5567cb78432..cbe57f3c4d89 100644 --- a/trunk/fs/anon_inodes.c +++ b/trunk/fs/anon_inodes.c @@ -233,7 +233,7 @@ static int __init anon_inode_init(void) return 0; err_mntput: - mntput(anon_inode_mnt); + mntput_long(anon_inode_mnt); err_unregister_filesystem: unregister_filesystem(&anon_inode_fs_type); err_exit: diff --git a/trunk/fs/autofs4/autofs_i.h b/trunk/fs/autofs4/autofs_i.h index 1f016bfb42d5..0fffe1c24cec 100644 --- a/trunk/fs/autofs4/autofs_i.h +++ b/trunk/fs/autofs4/autofs_i.h @@ -99,6 +99,7 @@ struct autofs_info { }; #define AUTOFS_INF_EXPIRING (1<<0) /* dentry is in the process of expiring */ +#define AUTOFS_INF_MOUNTPOINT (1<<1) /* mountpoint status for direct expire */ #define AUTOFS_INF_PENDING (1<<2) /* dentry pending mount */ struct autofs_wait_queue { @@ -175,6 +176,13 @@ static inline int autofs4_ispending(struct dentry *dentry) return 0; } +static inline void autofs4_copy_atime(struct file *src, struct file *dst) +{ + dst->f_path.dentry->d_inode->i_atime = + src->f_path.dentry->d_inode->i_atime; + return; +} + struct inode *autofs4_get_inode(struct super_block *, struct autofs_info *); void autofs4_free_ino(struct autofs_info *); @@ -204,83 +212,11 @@ void autofs_dev_ioctl_exit(void); extern const struct inode_operations autofs4_symlink_inode_operations; extern const struct inode_operations autofs4_dir_inode_operations; +extern const struct inode_operations autofs4_root_inode_operations; +extern const struct inode_operations autofs4_indirect_root_inode_operations; +extern const struct inode_operations autofs4_direct_root_inode_operations; extern const struct file_operations autofs4_dir_operations; extern const struct file_operations autofs4_root_operations; -extern const struct dentry_operations autofs4_dentry_operations; - -/* VFS automount flags management functions */ - -static inline void __managed_dentry_set_automount(struct dentry *dentry) -{ - dentry->d_flags |= DCACHE_NEED_AUTOMOUNT; -} - -static inline void managed_dentry_set_automount(struct dentry *dentry) -{ - spin_lock(&dentry->d_lock); - __managed_dentry_set_automount(dentry); - spin_unlock(&dentry->d_lock); -} - -static inline void __managed_dentry_clear_automount(struct dentry *dentry) -{ - dentry->d_flags &= ~DCACHE_NEED_AUTOMOUNT; -} - -static inline void managed_dentry_clear_automount(struct dentry *dentry) -{ - spin_lock(&dentry->d_lock); - __managed_dentry_clear_automount(dentry); - spin_unlock(&dentry->d_lock); -} - -static inline void __managed_dentry_set_transit(struct dentry *dentry) -{ - dentry->d_flags |= DCACHE_MANAGE_TRANSIT; -} - -static inline void managed_dentry_set_transit(struct dentry *dentry) -{ - spin_lock(&dentry->d_lock); - __managed_dentry_set_transit(dentry); - spin_unlock(&dentry->d_lock); -} - -static inline void __managed_dentry_clear_transit(struct dentry *dentry) -{ - dentry->d_flags &= ~DCACHE_MANAGE_TRANSIT; -} - -static inline void managed_dentry_clear_transit(struct dentry *dentry) -{ - spin_lock(&dentry->d_lock); - __managed_dentry_clear_transit(dentry); - spin_unlock(&dentry->d_lock); -} - -static inline void __managed_dentry_set_managed(struct dentry *dentry) -{ - dentry->d_flags |= (DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT); -} - -static inline void managed_dentry_set_managed(struct dentry *dentry) -{ - spin_lock(&dentry->d_lock); - __managed_dentry_set_managed(dentry); - spin_unlock(&dentry->d_lock); -} - -static inline void __managed_dentry_clear_managed(struct dentry *dentry) -{ - dentry->d_flags &= ~(DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT); -} - -static inline void managed_dentry_clear_managed(struct dentry *dentry) -{ - spin_lock(&dentry->d_lock); - __managed_dentry_clear_managed(dentry); - spin_unlock(&dentry->d_lock); -} /* Initializing function */ @@ -293,6 +229,19 @@ int autofs4_wait(struct autofs_sb_info *,struct dentry *, enum autofs_notify); int autofs4_wait_release(struct autofs_sb_info *,autofs_wqt_t,int); void autofs4_catatonic_mode(struct autofs_sb_info *); +static inline int autofs4_follow_mount(struct path *path) +{ + int res = 0; + + while (d_mountpoint(path->dentry)) { + int followed = follow_down(path); + if (!followed) + break; + res = 1; + } + return res; +} + static inline u32 autofs4_get_dev(struct autofs_sb_info *sbi) { return new_encode_dev(sbi->sb->s_dev); diff --git a/trunk/fs/autofs4/dev-ioctl.c b/trunk/fs/autofs4/dev-ioctl.c index 1442da4860e5..eff9a419469a 100644 --- a/trunk/fs/autofs4/dev-ioctl.c +++ b/trunk/fs/autofs4/dev-ioctl.c @@ -551,7 +551,7 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp, err = have_submounts(path.dentry); - if (follow_down_one(&path)) + if (follow_down(&path)) magic = path.mnt->mnt_sb->s_magic; } diff --git a/trunk/fs/autofs4/expire.c b/trunk/fs/autofs4/expire.c index 3ed79d76c233..cc1d01365905 100644 --- a/trunk/fs/autofs4/expire.c +++ b/trunk/fs/autofs4/expire.c @@ -26,6 +26,10 @@ static inline int autofs4_can_expire(struct dentry *dentry, if (ino == NULL) return 0; + /* No point expiring a pending mount */ + if (ino->flags & AUTOFS_INF_PENDING) + return 0; + if (!do_now) { /* Too young to die */ if (!timeout || time_after(ino->last_used + timeout, now)) @@ -52,7 +56,7 @@ static int autofs4_mount_busy(struct vfsmount *mnt, struct dentry *dentry) path_get(&path); - if (!follow_down_one(&path)) + if (!follow_down(&path)) goto done; if (is_autofs4_dentry(path.dentry)) { @@ -279,7 +283,6 @@ struct dentry *autofs4_expire_direct(struct super_block *sb, unsigned long timeout; struct dentry *root = dget(sb->s_root); int do_now = how & AUTOFS_EXP_IMMEDIATE; - struct autofs_info *ino; if (!root) return NULL; @@ -288,21 +291,19 @@ struct dentry *autofs4_expire_direct(struct super_block *sb, timeout = sbi->exp_timeout; spin_lock(&sbi->fs_lock); - ino = autofs4_dentry_ino(root); - /* No point expiring a pending mount */ - if (ino->flags & AUTOFS_INF_PENDING) { - spin_unlock(&sbi->fs_lock); - return NULL; - } - managed_dentry_set_transit(root); if (!autofs4_direct_busy(mnt, root, timeout, do_now)) { struct autofs_info *ino = autofs4_dentry_ino(root); + if (d_mountpoint(root)) { + ino->flags |= AUTOFS_INF_MOUNTPOINT; + spin_lock(&root->d_lock); + root->d_flags &= ~DCACHE_MOUNTED; + spin_unlock(&root->d_lock); + } ino->flags |= AUTOFS_INF_EXPIRING; init_completion(&ino->expire_complete); spin_unlock(&sbi->fs_lock); return root; } - managed_dentry_clear_transit(root); spin_unlock(&sbi->fs_lock); dput(root); @@ -339,10 +340,6 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, while ((dentry = get_next_positive_dentry(dentry, root))) { spin_lock(&sbi->fs_lock); ino = autofs4_dentry_ino(dentry); - /* No point expiring a pending mount */ - if (ino->flags & AUTOFS_INF_PENDING) - goto cont; - managed_dentry_set_transit(dentry); /* * Case 1: (i) indirect mount or top level pseudo direct mount @@ -402,8 +399,6 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, } } next: - managed_dentry_clear_transit(dentry); -cont: spin_unlock(&sbi->fs_lock); } return NULL; @@ -484,8 +479,6 @@ int autofs4_expire_run(struct super_block *sb, spin_lock(&sbi->fs_lock); ino = autofs4_dentry_ino(dentry); ino->flags &= ~AUTOFS_INF_EXPIRING; - if (!d_unhashed(dentry)) - managed_dentry_clear_transit(dentry); complete_all(&ino->expire_complete); spin_unlock(&sbi->fs_lock); @@ -511,18 +504,18 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt, ret = autofs4_wait(sbi, dentry, NFY_EXPIRE); spin_lock(&sbi->fs_lock); - ino->flags &= ~AUTOFS_INF_EXPIRING; - spin_lock(&dentry->d_lock); - if (ret) - __managed_dentry_clear_transit(dentry); - else { - if ((IS_ROOT(dentry) || - (autofs_type_indirect(sbi->type) && - IS_ROOT(dentry->d_parent))) && - !(dentry->d_flags & DCACHE_NEED_AUTOMOUNT)) - __managed_dentry_set_automount(dentry); + if (ino->flags & AUTOFS_INF_MOUNTPOINT) { + spin_lock(&sb->s_root->d_lock); + /* + * If we haven't been expired away, then reset + * mounted status. + */ + if (mnt->mnt_parent != mnt) + sb->s_root->d_flags |= DCACHE_MOUNTED; + spin_unlock(&sb->s_root->d_lock); + ino->flags &= ~AUTOFS_INF_MOUNTPOINT; } - spin_unlock(&dentry->d_lock); + ino->flags &= ~AUTOFS_INF_EXPIRING; complete_all(&ino->expire_complete); spin_unlock(&sbi->fs_lock); dput(dentry); diff --git a/trunk/fs/autofs4/inode.c b/trunk/fs/autofs4/inode.c index 9e1a9dad23e1..a7bdb9dcac84 100644 --- a/trunk/fs/autofs4/inode.c +++ b/trunk/fs/autofs4/inode.c @@ -45,6 +45,7 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino, if (!reinit) { ino->flags = 0; + ino->inode = NULL; ino->dentry = NULL; ino->size = 0; INIT_LIST_HEAD(&ino->active); @@ -75,8 +76,19 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino, void autofs4_free_ino(struct autofs_info *ino) { + struct autofs_info *p_ino; + if (ino->dentry) { ino->dentry->d_fsdata = NULL; + if (ino->dentry->d_inode) { + struct dentry *parent = ino->dentry->d_parent; + if (atomic_dec_and_test(&ino->count)) { + p_ino = autofs4_dentry_ino(parent); + if (p_ino && parent != ino->dentry) + atomic_dec(&p_ino->count); + } + dput(ino->dentry); + } ino->dentry = NULL; } if (ino->free) @@ -239,6 +251,10 @@ static struct autofs_info *autofs4_mkroot(struct autofs_sb_info *sbi) return ino; } +static const struct dentry_operations autofs4_sb_dentry_operations = { + .d_release = autofs4_dentry_release, +}; + int autofs4_fill_super(struct super_block *s, void *data, int silent) { struct inode * root_inode; @@ -276,7 +292,6 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) s->s_blocksize_bits = 10; s->s_magic = AUTOFS_SUPER_MAGIC; s->s_op = &autofs4_sops; - s->s_d_op = &autofs4_dentry_operations; s->s_time_gran = 1; /* @@ -294,6 +309,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) goto fail_iput; pipe = NULL; + d_set_d_op(root, &autofs4_sb_dentry_operations); root->d_fsdata = ino; /* Can this call block? */ @@ -304,11 +320,10 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) goto fail_dput; } - if (autofs_type_trigger(sbi->type)) - __managed_dentry_set_managed(root); - root_inode->i_fop = &autofs4_root_operations; - root_inode->i_op = &autofs4_dir_inode_operations; + root_inode->i_op = autofs_type_trigger(sbi->type) ? + &autofs4_direct_root_inode_operations : + &autofs4_indirect_root_inode_operations; /* Couldn't this be tested earlier? */ if (sbi->max_proto < AUTOFS_MIN_PROTO_VERSION || @@ -376,6 +391,7 @@ struct inode *autofs4_get_inode(struct super_block *sb, if (inode == NULL) return NULL; + inf->inode = inode; inode->i_mode = inf->mode; if (sb->s_root) { inode->i_uid = sb->s_root->d_inode->i_uid; diff --git a/trunk/fs/autofs4/root.c b/trunk/fs/autofs4/root.c index 1dba035fc376..651e4ef563b1 100644 --- a/trunk/fs/autofs4/root.c +++ b/trunk/fs/autofs4/root.c @@ -35,8 +35,10 @@ static long autofs4_root_compat_ioctl(struct file *,unsigned int,unsigned long); #endif static int autofs4_dir_open(struct inode *inode, struct file *file); static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *); -static struct vfsmount *autofs4_d_automount(struct path *); -static int autofs4_d_manage(struct dentry *, bool, bool); +static void *autofs4_follow_link(struct dentry *, struct nameidata *); + +#define TRIGGER_FLAGS (LOOKUP_CONTINUE | LOOKUP_DIRECTORY) +#define TRIGGER_INTENTS (LOOKUP_OPEN | LOOKUP_CREATE) const struct file_operations autofs4_root_operations = { .open = dcache_dir_open, @@ -58,7 +60,7 @@ const struct file_operations autofs4_dir_operations = { .llseek = dcache_dir_lseek, }; -const struct inode_operations autofs4_dir_inode_operations = { +const struct inode_operations autofs4_indirect_root_inode_operations = { .lookup = autofs4_lookup, .unlink = autofs4_dir_unlink, .symlink = autofs4_dir_symlink, @@ -66,10 +68,20 @@ const struct inode_operations autofs4_dir_inode_operations = { .rmdir = autofs4_dir_rmdir, }; -const struct dentry_operations autofs4_dentry_operations = { - .d_automount = autofs4_d_automount, - .d_manage = autofs4_d_manage, - .d_release = autofs4_dentry_release, +const struct inode_operations autofs4_direct_root_inode_operations = { + .lookup = autofs4_lookup, + .unlink = autofs4_dir_unlink, + .mkdir = autofs4_dir_mkdir, + .rmdir = autofs4_dir_rmdir, + .follow_link = autofs4_follow_link, +}; + +const struct inode_operations autofs4_dir_inode_operations = { + .lookup = autofs4_lookup, + .unlink = autofs4_dir_unlink, + .symlink = autofs4_dir_symlink, + .mkdir = autofs4_dir_mkdir, + .rmdir = autofs4_dir_rmdir, }; static void autofs4_add_active(struct dentry *dentry) @@ -104,6 +116,14 @@ static void autofs4_del_active(struct dentry *dentry) return; } +static unsigned int autofs4_need_mount(unsigned int flags) +{ + unsigned int res = 0; + if (flags & (TRIGGER_FLAGS | TRIGGER_INTENTS)) + res = 1; + return res; +} + static int autofs4_dir_open(struct inode *inode, struct file *file) { struct dentry *dentry = file->f_path.dentry; @@ -138,6 +158,239 @@ static int autofs4_dir_open(struct inode *inode, struct file *file) return dcache_dir_open(inode, file); } +static int try_to_fill_dentry(struct dentry *dentry, int flags) +{ + struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); + struct autofs_info *ino = autofs4_dentry_ino(dentry); + int status; + + DPRINTK("dentry=%p %.*s ino=%p", + dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode); + + /* + * Wait for a pending mount, triggering one if there + * isn't one already + */ + if (dentry->d_inode == NULL) { + DPRINTK("waiting for mount name=%.*s", + dentry->d_name.len, dentry->d_name.name); + + status = autofs4_wait(sbi, dentry, NFY_MOUNT); + + DPRINTK("mount done status=%d", status); + + /* Turn this into a real negative dentry? */ + if (status == -ENOENT) { + spin_lock(&sbi->fs_lock); + ino->flags &= ~AUTOFS_INF_PENDING; + spin_unlock(&sbi->fs_lock); + return status; + } else if (status) { + /* Return a negative dentry, but leave it "pending" */ + return status; + } + /* Trigger mount for path component or follow link */ + } else if (ino->flags & AUTOFS_INF_PENDING || + autofs4_need_mount(flags)) { + DPRINTK("waiting for mount name=%.*s", + dentry->d_name.len, dentry->d_name.name); + + spin_lock(&sbi->fs_lock); + ino->flags |= AUTOFS_INF_PENDING; + spin_unlock(&sbi->fs_lock); + status = autofs4_wait(sbi, dentry, NFY_MOUNT); + + DPRINTK("mount done status=%d", status); + + if (status) { + spin_lock(&sbi->fs_lock); + ino->flags &= ~AUTOFS_INF_PENDING; + spin_unlock(&sbi->fs_lock); + return status; + } + } + + /* Initialize expiry counter after successful mount */ + ino->last_used = jiffies; + + spin_lock(&sbi->fs_lock); + ino->flags &= ~AUTOFS_INF_PENDING; + spin_unlock(&sbi->fs_lock); + + return 0; +} + +/* For autofs direct mounts the follow link triggers the mount */ +static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) +{ + struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); + struct autofs_info *ino = autofs4_dentry_ino(dentry); + int oz_mode = autofs4_oz_mode(sbi); + unsigned int lookup_type; + int status; + + DPRINTK("dentry=%p %.*s oz_mode=%d nd->flags=%d", + dentry, dentry->d_name.len, dentry->d_name.name, oz_mode, + nd->flags); + /* + * For an expire of a covered direct or offset mount we need + * to break out of follow_down() at the autofs mount trigger + * (d_mounted--), so we can see the expiring flag, and manage + * the blocking and following here until the expire is completed. + */ + if (oz_mode) { + spin_lock(&sbi->fs_lock); + if (ino->flags & AUTOFS_INF_EXPIRING) { + spin_unlock(&sbi->fs_lock); + /* Follow down to our covering mount. */ + if (!follow_down(&nd->path)) + goto done; + goto follow; + } + spin_unlock(&sbi->fs_lock); + goto done; + } + + /* If an expire request is pending everyone must wait. */ + autofs4_expire_wait(dentry); + + /* We trigger a mount for almost all flags */ + lookup_type = autofs4_need_mount(nd->flags); + spin_lock(&sbi->fs_lock); + spin_lock(&autofs4_lock); + spin_lock(&dentry->d_lock); + if (!(lookup_type || ino->flags & AUTOFS_INF_PENDING)) { + spin_unlock(&dentry->d_lock); + spin_unlock(&autofs4_lock); + spin_unlock(&sbi->fs_lock); + goto follow; + } + + /* + * If the dentry contains directories then it is an autofs + * multi-mount with no root mount offset. So don't try to + * mount it again. + */ + if (ino->flags & AUTOFS_INF_PENDING || + (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs))) { + spin_unlock(&dentry->d_lock); + spin_unlock(&autofs4_lock); + spin_unlock(&sbi->fs_lock); + + status = try_to_fill_dentry(dentry, nd->flags); + if (status) + goto out_error; + + goto follow; + } + spin_unlock(&dentry->d_lock); + spin_unlock(&autofs4_lock); + spin_unlock(&sbi->fs_lock); +follow: + /* + * If there is no root mount it must be an autofs + * multi-mount with no root offset so we don't need + * to follow it. + */ + if (d_mountpoint(dentry)) { + if (!autofs4_follow_mount(&nd->path)) { + status = -ENOENT; + goto out_error; + } + } + +done: + return NULL; + +out_error: + path_put(&nd->path); + return ERR_PTR(status); +} + +/* + * Revalidate is called on every cache lookup. Some of those + * cache lookups may actually happen while the dentry is not + * yet completely filled in, and revalidate has to delay such + * lookups.. + */ +static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) +{ + struct inode *dir; + struct autofs_sb_info *sbi; + int oz_mode; + int flags = nd ? nd->flags : 0; + int status = 1; + + if (flags & LOOKUP_RCU) + return -ECHILD; + + dir = dentry->d_parent->d_inode; + sbi = autofs4_sbi(dir->i_sb); + oz_mode = autofs4_oz_mode(sbi); + + /* Pending dentry */ + spin_lock(&sbi->fs_lock); + if (autofs4_ispending(dentry)) { + /* The daemon never causes a mount to trigger */ + spin_unlock(&sbi->fs_lock); + + if (oz_mode) + return 1; + + /* + * If the directory has gone away due to an expire + * we have been called as ->d_revalidate() and so + * we need to return false and proceed to ->lookup(). + */ + if (autofs4_expire_wait(dentry) == -EAGAIN) + return 0; + + /* + * A zero status is success otherwise we have a + * negative error code. + */ + status = try_to_fill_dentry(dentry, flags); + if (status == 0) + return 1; + + return status; + } + spin_unlock(&sbi->fs_lock); + + /* Negative dentry.. invalidate if "old" */ + if (dentry->d_inode == NULL) + return 0; + + /* Check for a non-mountpoint directory with no contents */ + spin_lock(&autofs4_lock); + spin_lock(&dentry->d_lock); + if (S_ISDIR(dentry->d_inode->i_mode) && + !d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { + DPRINTK("dentry=%p %.*s, emptydir", + dentry, dentry->d_name.len, dentry->d_name.name); + spin_unlock(&dentry->d_lock); + spin_unlock(&autofs4_lock); + + /* The daemon never causes a mount to trigger */ + if (oz_mode) + return 1; + + /* + * A zero status is success otherwise we have a + * negative error code. + */ + status = try_to_fill_dentry(dentry, flags); + if (status == 0) + return 1; + + return status; + } + spin_unlock(&dentry->d_lock); + spin_unlock(&autofs4_lock); + + return 1; +} + void autofs4_dentry_release(struct dentry *de) { struct autofs_info *inf; @@ -145,8 +398,11 @@ void autofs4_dentry_release(struct dentry *de) DPRINTK("releasing %p", de); inf = autofs4_dentry_ino(de); + de->d_fsdata = NULL; + if (inf) { struct autofs_sb_info *sbi = autofs4_sbi(de->d_sb); + if (sbi) { spin_lock(&sbi->lookup_lock); if (!list_empty(&inf->active)) @@ -155,10 +411,26 @@ void autofs4_dentry_release(struct dentry *de) list_del(&inf->expiring); spin_unlock(&sbi->lookup_lock); } + + inf->dentry = NULL; + inf->inode = NULL; + autofs4_free_ino(inf); } } +/* For dentries of directories in the root dir */ +static const struct dentry_operations autofs4_root_dentry_operations = { + .d_revalidate = autofs4_revalidate, + .d_release = autofs4_dentry_release, +}; + +/* For other dentries */ +static const struct dentry_operations autofs4_dentry_operations = { + .d_revalidate = autofs4_revalidate, + .d_release = autofs4_dentry_release, +}; + static struct dentry *autofs4_lookup_active(struct dentry *dentry) { struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); @@ -269,244 +541,50 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry) return NULL; } -static int autofs4_mount_wait(struct dentry *dentry) -{ - struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); - struct autofs_info *ino = autofs4_dentry_ino(dentry); - int status; - - if (ino->flags & AUTOFS_INF_PENDING) { - DPRINTK("waiting for mount name=%.*s", - dentry->d_name.len, dentry->d_name.name); - status = autofs4_wait(sbi, dentry, NFY_MOUNT); - DPRINTK("mount wait done status=%d", status); - ino->last_used = jiffies; - return status; - } - return 0; -} - -static int do_expire_wait(struct dentry *dentry) -{ - struct dentry *expiring; - - expiring = autofs4_lookup_expiring(dentry); - if (!expiring) - return autofs4_expire_wait(dentry); - else { - /* - * If we are racing with expire the request might not - * be quite complete, but the directory has been removed - * so it must have been successful, just wait for it. - */ - autofs4_expire_wait(expiring); - autofs4_del_expiring(expiring); - dput(expiring); - } - return 0; -} - -static struct dentry *autofs4_mountpoint_changed(struct path *path) -{ - struct dentry *dentry = path->dentry; - struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); - - /* - * If this is an indirect mount the dentry could have gone away - * as a result of an expire and a new one created. - */ - if (autofs_type_indirect(sbi->type) && d_unhashed(dentry)) { - struct dentry *parent = dentry->d_parent; - struct dentry *new = d_lookup(parent, &dentry->d_name); - if (!new) - return NULL; - dput(path->dentry); - path->dentry = new; - } - return path->dentry; -} - -static struct vfsmount *autofs4_d_automount(struct path *path) -{ - struct dentry *dentry = path->dentry; - struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); - struct autofs_info *ino = autofs4_dentry_ino(dentry); - int status; - - DPRINTK("dentry=%p %.*s", - dentry, dentry->d_name.len, dentry->d_name.name); - - /* - * Someone may have manually umounted this or it was a submount - * that has gone away. - */ - spin_lock(&dentry->d_lock); - if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { - if (!(dentry->d_flags & DCACHE_MANAGE_TRANSIT) && - (dentry->d_flags & DCACHE_NEED_AUTOMOUNT)) - __managed_dentry_set_transit(path->dentry); - } - spin_unlock(&dentry->d_lock); - - /* The daemon never triggers a mount. */ - if (autofs4_oz_mode(sbi)) - return NULL; - - /* - * If an expire request is pending everyone must wait. - * If the expire fails we're still mounted so continue - * the follow and return. A return of -EAGAIN (which only - * happens with indirect mounts) means the expire completed - * and the directory was removed, so just go ahead and try - * the mount. - */ - status = do_expire_wait(dentry); - if (status && status != -EAGAIN) - return NULL; - - /* Callback to the daemon to perform the mount or wait */ - spin_lock(&sbi->fs_lock); - if (ino->flags & AUTOFS_INF_PENDING) { - spin_unlock(&sbi->fs_lock); - status = autofs4_mount_wait(dentry); - if (status) - return ERR_PTR(status); - spin_lock(&sbi->fs_lock); - goto done; - } - - /* - * If the dentry is a symlink it's equivalent to a directory - * having d_mountpoint() true, so there's no need to call back - * to the daemon. - */ - if (dentry->d_inode && S_ISLNK(dentry->d_inode->i_mode)) - goto done; - if (!d_mountpoint(dentry)) { - /* - * It's possible that user space hasn't removed directories - * after umounting a rootless multi-mount, although it - * should. For v5 have_submounts() is sufficient to handle - * this because the leaves of the directory tree under the - * mount never trigger mounts themselves (they have an autofs - * trigger mount mounted on them). But v4 pseudo direct mounts - * do need the leaves to to trigger mounts. In this case we - * have no choice but to use the list_empty() check and - * require user space behave. - */ - if (sbi->version > 4) { - if (have_submounts(dentry)) - goto done; - } else { - spin_lock(&dentry->d_lock); - if (!list_empty(&dentry->d_subdirs)) { - spin_unlock(&dentry->d_lock); - goto done; - } - spin_unlock(&dentry->d_lock); - } - ino->flags |= AUTOFS_INF_PENDING; - spin_unlock(&sbi->fs_lock); - status = autofs4_mount_wait(dentry); - if (status) - return ERR_PTR(status); - spin_lock(&sbi->fs_lock); - ino->flags &= ~AUTOFS_INF_PENDING; - } -done: - if (!(ino->flags & AUTOFS_INF_EXPIRING)) { - /* - * Any needed mounting has been completed and the path updated - * so turn this into a normal dentry so we don't continually - * call ->d_automount() and ->d_manage(). - */ - spin_lock(&dentry->d_lock); - __managed_dentry_clear_transit(dentry); - /* - * Only clear DMANAGED_AUTOMOUNT for rootless multi-mounts and - * symlinks as in all other cases the dentry will be covered by - * an actual mount so ->d_automount() won't be called during - * the follow. - */ - if ((!d_mountpoint(dentry) && - !list_empty(&dentry->d_subdirs)) || - (dentry->d_inode && S_ISLNK(dentry->d_inode->i_mode))) - __managed_dentry_clear_automount(dentry); - spin_unlock(&dentry->d_lock); - } - spin_unlock(&sbi->fs_lock); - - /* Mount succeeded, check if we ended up with a new dentry */ - dentry = autofs4_mountpoint_changed(path); - if (!dentry) - return ERR_PTR(-ENOENT); - - return NULL; -} - -int autofs4_d_manage(struct dentry *dentry, bool mounting_here, bool rcu_walk) -{ - struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); - - DPRINTK("dentry=%p %.*s", - dentry, dentry->d_name.len, dentry->d_name.name); - - /* The daemon never waits. */ - if (autofs4_oz_mode(sbi) || mounting_here) { - if (!d_mountpoint(dentry)) - return -EISDIR; - return 0; - } - - /* We need to sleep, so we need pathwalk to be in ref-mode */ - if (rcu_walk) - return -ECHILD; - - /* Wait for pending expires */ - do_expire_wait(dentry); - - /* - * This dentry may be under construction so wait on mount - * completion. - */ - return autofs4_mount_wait(dentry); -} - /* Lookups in the root directory */ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct autofs_sb_info *sbi; struct autofs_info *ino; - struct dentry *active; + struct dentry *expiring, *active; + int oz_mode; - DPRINTK("name = %.*s", dentry->d_name.len, dentry->d_name.name); + DPRINTK("name = %.*s", + dentry->d_name.len, dentry->d_name.name); /* File name too long to exist */ if (dentry->d_name.len > NAME_MAX) return ERR_PTR(-ENAMETOOLONG); sbi = autofs4_sbi(dir->i_sb); + oz_mode = autofs4_oz_mode(sbi); DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d", - current->pid, task_pgrp_nr(current), sbi->catatonic, oz_mode); + current->pid, task_pgrp_nr(current), sbi->catatonic, oz_mode); active = autofs4_lookup_active(dentry); if (active) { - return active; + dentry = active; + ino = autofs4_dentry_ino(dentry); } else { /* - * A dentry that is not within the root can never trigger a - * mount operation, unless the directory already exists, so we - * can return fail immediately. The daemon however does need - * to create directories within the file system. + * Mark the dentry incomplete but don't hash it. We do this + * to serialize our inode creation operations (symlink and + * mkdir) which prevents deadlock during the callback to + * the daemon. Subsequent user space lookups for the same + * dentry are placed on the wait queue while the daemon + * itself is allowed passage unresticted so the create + * operation itself can then hash the dentry. Finally, + * we check for the hashed dentry and return the newly + * hashed dentry. */ - if (!autofs4_oz_mode(sbi) && !IS_ROOT(dentry->d_parent)) - return ERR_PTR(-ENOENT); - - /* Mark entries in the root as mount triggers */ - if (autofs_type_indirect(sbi->type) && IS_ROOT(dentry->d_parent)) - __managed_dentry_set_managed(dentry); + d_set_d_op(dentry, &autofs4_root_dentry_operations); + /* + * And we need to ensure that the same dentry is used for + * all following lookup calls until it is hashed so that + * the dentry flags are persistent throughout the request. + */ ino = autofs4_init_ino(NULL, sbi, 0555); if (!ino) return ERR_PTR(-ENOMEM); @@ -518,6 +596,82 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s d_instantiate(dentry, NULL); } + + if (!oz_mode) { + mutex_unlock(&dir->i_mutex); + expiring = autofs4_lookup_expiring(dentry); + if (expiring) { + /* + * If we are racing with expire the request might not + * be quite complete but the directory has been removed + * so it must have been successful, so just wait for it. + */ + autofs4_expire_wait(expiring); + autofs4_del_expiring(expiring); + dput(expiring); + } + + spin_lock(&sbi->fs_lock); + ino->flags |= AUTOFS_INF_PENDING; + spin_unlock(&sbi->fs_lock); + if (dentry->d_op && dentry->d_op->d_revalidate) + (dentry->d_op->d_revalidate)(dentry, nd); + mutex_lock(&dir->i_mutex); + } + + /* + * If we are still pending, check if we had to handle + * a signal. If so we can force a restart.. + */ + if (ino->flags & AUTOFS_INF_PENDING) { + /* See if we were interrupted */ + if (signal_pending(current)) { + sigset_t *sigset = ¤t->pending.signal; + if (sigismember (sigset, SIGKILL) || + sigismember (sigset, SIGQUIT) || + sigismember (sigset, SIGINT)) { + if (active) + dput(active); + return ERR_PTR(-ERESTARTNOINTR); + } + } + if (!oz_mode) { + spin_lock(&sbi->fs_lock); + ino->flags &= ~AUTOFS_INF_PENDING; + spin_unlock(&sbi->fs_lock); + } + } + + /* + * If this dentry is unhashed, then we shouldn't honour this + * lookup. Returning ENOENT here doesn't do the right thing + * for all system calls, but it should be OK for the operations + * we permit from an autofs. + */ + if (!oz_mode && d_unhashed(dentry)) { + /* + * A user space application can (and has done in the past) + * remove and re-create this directory during the callback. + * This can leave us with an unhashed dentry, but a + * successful mount! So we need to perform another + * cached lookup in case the dentry now exists. + */ + struct dentry *parent = dentry->d_parent; + struct dentry *new = d_lookup(parent, &dentry->d_name); + if (new != NULL) + dentry = new; + else + dentry = ERR_PTR(-ENOENT); + + if (active) + dput(active); + + return dentry; + } + + if (active) + return active; + return NULL; } @@ -562,12 +716,18 @@ static int autofs4_dir_symlink(struct inode *dir, } d_add(dentry, inode); + if (dir == dir->i_sb->s_root->d_inode) + d_set_d_op(dentry, &autofs4_root_dentry_operations); + else + d_set_d_op(dentry, &autofs4_dentry_operations); + dentry->d_fsdata = ino; ino->dentry = dget(dentry); atomic_inc(&ino->count); p_ino = autofs4_dentry_ino(dentry->d_parent); if (p_ino && dentry->d_parent != dentry) atomic_inc(&p_ino->count); + ino->inode = inode; ino->u.symlink = cp; dir->i_mtime = CURRENT_TIME; @@ -622,58 +782,6 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry) return 0; } -/* - * Version 4 of autofs provides a pseudo direct mount implementation - * that relies on directories at the leaves of a directory tree under - * an indirect mount to trigger mounts. To allow for this we need to - * set the DMANAGED_AUTOMOUNT and DMANAGED_TRANSIT flags on the leaves - * of the directory tree. There is no need to clear the automount flag - * following a mount or restore it after an expire because these mounts - * are always covered. However, it is neccessary to ensure that these - * flags are clear on non-empty directories to avoid unnecessary calls - * during path walks. - */ -static void autofs_set_leaf_automount_flags(struct dentry *dentry) -{ - struct dentry *parent; - - /* root and dentrys in the root are already handled */ - if (IS_ROOT(dentry->d_parent)) - return; - - managed_dentry_set_managed(dentry); - - parent = dentry->d_parent; - /* only consider parents below dentrys in the root */ - if (IS_ROOT(parent->d_parent)) - return; - managed_dentry_clear_managed(parent); - return; -} - -static void autofs_clear_leaf_automount_flags(struct dentry *dentry) -{ - struct list_head *d_child; - struct dentry *parent; - - /* flags for dentrys in the root are handled elsewhere */ - if (IS_ROOT(dentry->d_parent)) - return; - - managed_dentry_clear_managed(dentry); - - parent = dentry->d_parent; - /* only consider parents below dentrys in the root */ - if (IS_ROOT(parent->d_parent)) - return; - d_child = &dentry->d_u.d_child; - /* Set parent managed if it's becoming empty */ - if (d_child->next == &parent->d_subdirs && - d_child->prev == &parent->d_subdirs) - managed_dentry_set_managed(parent); - return; -} - static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) { struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); @@ -701,9 +809,6 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) spin_unlock(&dentry->d_lock); spin_unlock(&autofs4_lock); - if (sbi->version < 5) - autofs_clear_leaf_automount_flags(dentry); - if (atomic_dec_and_test(&ino->count)) { p_ino = autofs4_dentry_ino(dentry->d_parent); if (p_ino && dentry->d_parent != dentry) @@ -746,8 +851,10 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode) } d_add(dentry, inode); - if (sbi->version < 5) - autofs_set_leaf_automount_flags(dentry); + if (dir == dir->i_sb->s_root->d_inode) + d_set_d_op(dentry, &autofs4_root_dentry_operations); + else + d_set_d_op(dentry, &autofs4_dentry_operations); dentry->d_fsdata = ino; ino->dentry = dget(dentry); @@ -755,6 +862,7 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode) p_ino = autofs4_dentry_ino(dentry->d_parent); if (p_ino && dentry->d_parent != dentry) atomic_inc(&p_ino->count); + ino->inode = inode; inc_nlink(dir); dir->i_mtime = CURRENT_TIME; @@ -836,7 +944,8 @@ static inline int autofs4_ask_umount(struct vfsmount *mnt, int __user *p) int is_autofs4_dentry(struct dentry *dentry) { return dentry && dentry->d_inode && - dentry->d_op == &autofs4_dentry_operations && + (dentry->d_op == &autofs4_root_dentry_operations || + dentry->d_op == &autofs4_dentry_operations) && dentry->d_fsdata != NULL; } diff --git a/trunk/fs/autofs4/waitq.c b/trunk/fs/autofs4/waitq.c index 56010056b2e6..c5f8459c905e 100644 --- a/trunk/fs/autofs4/waitq.c +++ b/trunk/fs/autofs4/waitq.c @@ -309,9 +309,6 @@ static int validate_request(struct autofs_wait_queue **wait, * completed while we waited on the mutex ... */ if (notify == NFY_MOUNT) { - struct dentry *new = NULL; - int valid = 1; - /* * If the dentry was successfully mounted while we slept * on the wait queue mutex we can return success. If it @@ -319,20 +316,8 @@ static int validate_request(struct autofs_wait_queue **wait, * a multi-mount with no mount at it's base) we can * continue on and create a new request. */ - if (!IS_ROOT(dentry)) { - if (dentry->d_inode && d_unhashed(dentry)) { - struct dentry *parent = dentry->d_parent; - new = d_lookup(parent, &dentry->d_name); - if (new) - dentry = new; - } - } if (have_submounts(dentry)) - valid = 0; - - if (new) - dput(new); - return valid; + return 0; } return 1; diff --git a/trunk/fs/btrfs/ctree.h b/trunk/fs/btrfs/ctree.h index b875d445ea81..a142d204b526 100644 --- a/trunk/fs/btrfs/ctree.h +++ b/trunk/fs/btrfs/ctree.h @@ -27,7 +27,6 @@ #include #include #include -#include #include #include "extent_io.h" #include "extent_map.h" diff --git a/trunk/fs/btrfs/file.c b/trunk/fs/btrfs/file.c index a9e0a4eaf3d9..66836d85763b 100644 --- a/trunk/fs/btrfs/file.c +++ b/trunk/fs/btrfs/file.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -1238,117 +1237,6 @@ static int btrfs_file_mmap(struct file *filp, struct vm_area_struct *vma) return 0; } -static long btrfs_fallocate(struct file *file, int mode, - loff_t offset, loff_t len) -{ - struct inode *inode = file->f_path.dentry->d_inode; - struct extent_state *cached_state = NULL; - u64 cur_offset; - u64 last_byte; - u64 alloc_start; - u64 alloc_end; - u64 alloc_hint = 0; - u64 locked_end; - u64 mask = BTRFS_I(inode)->root->sectorsize - 1; - struct extent_map *em; - int ret; - - alloc_start = offset & ~mask; - alloc_end = (offset + len + mask) & ~mask; - - /* We only support the FALLOC_FL_KEEP_SIZE mode */ - if (mode & ~FALLOC_FL_KEEP_SIZE) - return -EOPNOTSUPP; - - /* - * wait for ordered IO before we have any locks. We'll loop again - * below with the locks held. - */ - btrfs_wait_ordered_range(inode, alloc_start, alloc_end - alloc_start); - - mutex_lock(&inode->i_mutex); - ret = inode_newsize_ok(inode, alloc_end); - if (ret) - goto out; - - if (alloc_start > inode->i_size) { - ret = btrfs_cont_expand(inode, alloc_start); - if (ret) - goto out; - } - - ret = btrfs_check_data_free_space(inode, alloc_end - alloc_start); - if (ret) - goto out; - - locked_end = alloc_end - 1; - while (1) { - struct btrfs_ordered_extent *ordered; - - /* the extent lock is ordered inside the running - * transaction - */ - lock_extent_bits(&BTRFS_I(inode)->io_tree, alloc_start, - locked_end, 0, &cached_state, GFP_NOFS); - ordered = btrfs_lookup_first_ordered_extent(inode, - alloc_end - 1); - if (ordered && - ordered->file_offset + ordered->len > alloc_start && - ordered->file_offset < alloc_end) { - btrfs_put_ordered_extent(ordered); - unlock_extent_cached(&BTRFS_I(inode)->io_tree, - alloc_start, locked_end, - &cached_state, GFP_NOFS); - /* - * we can't wait on the range with the transaction - * running or with the extent lock held - */ - btrfs_wait_ordered_range(inode, alloc_start, - alloc_end - alloc_start); - } else { - if (ordered) - btrfs_put_ordered_extent(ordered); - break; - } - } - - cur_offset = alloc_start; - while (1) { - em = btrfs_get_extent(inode, NULL, 0, cur_offset, - alloc_end - cur_offset, 0); - BUG_ON(IS_ERR(em) || !em); - last_byte = min(extent_map_end(em), alloc_end); - last_byte = (last_byte + mask) & ~mask; - if (em->block_start == EXTENT_MAP_HOLE || - (cur_offset >= inode->i_size && - !test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) { - ret = btrfs_prealloc_file_range(inode, mode, cur_offset, - last_byte - cur_offset, - 1 << inode->i_blkbits, - offset + len, - &alloc_hint); - if (ret < 0) { - free_extent_map(em); - break; - } - } - free_extent_map(em); - - cur_offset = last_byte; - if (cur_offset >= alloc_end) { - ret = 0; - break; - } - } - unlock_extent_cached(&BTRFS_I(inode)->io_tree, alloc_start, locked_end, - &cached_state, GFP_NOFS); - - btrfs_free_reserved_data_space(inode, alloc_end - alloc_start); -out: - mutex_unlock(&inode->i_mutex); - return ret; -} - const struct file_operations btrfs_file_operations = { .llseek = generic_file_llseek, .read = do_sync_read, @@ -1360,7 +1248,6 @@ const struct file_operations btrfs_file_operations = { .open = generic_file_open, .release = btrfs_release_file, .fsync = btrfs_sync_file, - .fallocate = btrfs_fallocate, .unlocked_ioctl = btrfs_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = btrfs_ioctl, diff --git a/trunk/fs/btrfs/inode.c b/trunk/fs/btrfs/inode.c index 902afbf50811..a3798a3aa0d2 100644 --- a/trunk/fs/btrfs/inode.c +++ b/trunk/fs/btrfs/inode.c @@ -7098,6 +7098,116 @@ int btrfs_prealloc_file_range_trans(struct inode *inode, min_size, actual_len, alloc_hint, trans); } +static long btrfs_fallocate(struct inode *inode, int mode, + loff_t offset, loff_t len) +{ + struct extent_state *cached_state = NULL; + u64 cur_offset; + u64 last_byte; + u64 alloc_start; + u64 alloc_end; + u64 alloc_hint = 0; + u64 locked_end; + u64 mask = BTRFS_I(inode)->root->sectorsize - 1; + struct extent_map *em; + int ret; + + alloc_start = offset & ~mask; + alloc_end = (offset + len + mask) & ~mask; + + /* We only support the FALLOC_FL_KEEP_SIZE mode */ + if (mode && (mode != FALLOC_FL_KEEP_SIZE)) + return -EOPNOTSUPP; + + /* + * wait for ordered IO before we have any locks. We'll loop again + * below with the locks held. + */ + btrfs_wait_ordered_range(inode, alloc_start, alloc_end - alloc_start); + + mutex_lock(&inode->i_mutex); + ret = inode_newsize_ok(inode, alloc_end); + if (ret) + goto out; + + if (alloc_start > inode->i_size) { + ret = btrfs_cont_expand(inode, alloc_start); + if (ret) + goto out; + } + + ret = btrfs_check_data_free_space(inode, alloc_end - alloc_start); + if (ret) + goto out; + + locked_end = alloc_end - 1; + while (1) { + struct btrfs_ordered_extent *ordered; + + /* the extent lock is ordered inside the running + * transaction + */ + lock_extent_bits(&BTRFS_I(inode)->io_tree, alloc_start, + locked_end, 0, &cached_state, GFP_NOFS); + ordered = btrfs_lookup_first_ordered_extent(inode, + alloc_end - 1); + if (ordered && + ordered->file_offset + ordered->len > alloc_start && + ordered->file_offset < alloc_end) { + btrfs_put_ordered_extent(ordered); + unlock_extent_cached(&BTRFS_I(inode)->io_tree, + alloc_start, locked_end, + &cached_state, GFP_NOFS); + /* + * we can't wait on the range with the transaction + * running or with the extent lock held + */ + btrfs_wait_ordered_range(inode, alloc_start, + alloc_end - alloc_start); + } else { + if (ordered) + btrfs_put_ordered_extent(ordered); + break; + } + } + + cur_offset = alloc_start; + while (1) { + em = btrfs_get_extent(inode, NULL, 0, cur_offset, + alloc_end - cur_offset, 0); + BUG_ON(IS_ERR(em) || !em); + last_byte = min(extent_map_end(em), alloc_end); + last_byte = (last_byte + mask) & ~mask; + if (em->block_start == EXTENT_MAP_HOLE || + (cur_offset >= inode->i_size && + !test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) { + ret = btrfs_prealloc_file_range(inode, mode, cur_offset, + last_byte - cur_offset, + 1 << inode->i_blkbits, + offset + len, + &alloc_hint); + if (ret < 0) { + free_extent_map(em); + break; + } + } + free_extent_map(em); + + cur_offset = last_byte; + if (cur_offset >= alloc_end) { + ret = 0; + break; + } + } + unlock_extent_cached(&BTRFS_I(inode)->io_tree, alloc_start, locked_end, + &cached_state, GFP_NOFS); + + btrfs_free_reserved_data_space(inode, alloc_end - alloc_start); +out: + mutex_unlock(&inode->i_mutex); + return ret; +} + static int btrfs_set_page_dirty(struct page *page) { return __set_page_dirty_nobuffers(page); @@ -7200,6 +7310,7 @@ static const struct inode_operations btrfs_file_inode_operations = { .listxattr = btrfs_listxattr, .removexattr = btrfs_removexattr, .permission = btrfs_permission, + .fallocate = btrfs_fallocate, .fiemap = btrfs_fiemap, }; static const struct inode_operations btrfs_special_inode_operations = { diff --git a/trunk/fs/cifs/cifs_dfs_ref.c b/trunk/fs/cifs/cifs_dfs_ref.c index 7ed36536e754..c68a056f27fd 100644 --- a/trunk/fs/cifs/cifs_dfs_ref.c +++ b/trunk/fs/cifs/cifs_dfs_ref.c @@ -255,6 +255,35 @@ static struct vfsmount *cifs_dfs_do_refmount(struct cifs_sb_info *cifs_sb, } +static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd, + struct list_head *mntlist) +{ + /* stolen from afs code */ + int err; + + mntget(newmnt); + err = do_add_mount(newmnt, &nd->path, nd->path.mnt->mnt_flags | MNT_SHRINKABLE, mntlist); + switch (err) { + case 0: + path_put(&nd->path); + nd->path.mnt = newmnt; + nd->path.dentry = dget(newmnt->mnt_root); + schedule_delayed_work(&cifs_dfs_automount_task, + cifs_dfs_mountpoint_expiry_timeout); + break; + case -EBUSY: + /* someone else made a mount here whilst we were busy */ + while (d_mountpoint(nd->path.dentry) && + follow_down(&nd->path)) + ; + err = 0; + default: + mntput(newmnt); + break; + } + return err; +} + static void dump_referral(const struct dfs_info3_param *ref) { cFYI(1, "DFS: ref path: %s", ref->path_name); @@ -264,43 +293,45 @@ static void dump_referral(const struct dfs_info3_param *ref) ref->path_consumed); } -/* - * Create a vfsmount that we can automount - */ -static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt) + +static void* +cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) { struct dfs_info3_param *referrals = NULL; unsigned int num_referrals = 0; struct cifs_sb_info *cifs_sb; struct cifsSesInfo *ses; - char *full_path; + char *full_path = NULL; int xid, i; - int rc; - struct vfsmount *mnt; + int rc = 0; + struct vfsmount *mnt = ERR_PTR(-ENOENT); struct tcon_link *tlink; cFYI(1, "in %s", __func__); - BUG_ON(IS_ROOT(mntpt)); + BUG_ON(IS_ROOT(dentry)); xid = GetXid(); + dput(nd->path.dentry); + nd->path.dentry = dget(dentry); + /* * The MSDFS spec states that paths in DFS referral requests and * responses must be prefixed by a single '\' character instead of * the double backslashes usually used in the UNC. This function * gives us the latter, so we must adjust the result. */ - mnt = ERR_PTR(-ENOMEM); - full_path = build_path_from_dentry(mntpt); - if (full_path == NULL) - goto free_xid; + full_path = build_path_from_dentry(dentry); + if (full_path == NULL) { + rc = -ENOMEM; + goto out_err; + } - cifs_sb = CIFS_SB(mntpt->d_inode->i_sb); + cifs_sb = CIFS_SB(dentry->d_inode->i_sb); tlink = cifs_sb_tlink(cifs_sb); - mnt = ERR_PTR(-EINVAL); if (IS_ERR(tlink)) { - mnt = ERR_CAST(tlink); - goto free_full_path; + rc = PTR_ERR(tlink); + goto out_err; } ses = tlink_tcon(tlink)->ses; @@ -310,63 +341,46 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt) cifs_put_tlink(tlink); - mnt = ERR_PTR(-ENOENT); for (i = 0; i < num_referrals; i++) { int len; - dump_referral(referrals + i); + dump_referral(referrals+i); /* connect to a node */ len = strlen(referrals[i].node_name); if (len < 2) { cERROR(1, "%s: Net Address path too short: %s", __func__, referrals[i].node_name); - mnt = ERR_PTR(-EINVAL); - break; + rc = -EINVAL; + goto out_err; } mnt = cifs_dfs_do_refmount(cifs_sb, full_path, referrals + i); cFYI(1, "%s: cifs_dfs_do_refmount:%s , mnt:%p", __func__, referrals[i].node_name, mnt); + + /* complete mount procedure if we accured submount */ if (!IS_ERR(mnt)) - goto success; + break; } - /* no valid submounts were found; return error from get_dfs_path() by - * preference */ - if (rc != 0) - mnt = ERR_PTR(rc); + /* we need it cause for() above could exit without valid submount */ + rc = PTR_ERR(mnt); + if (IS_ERR(mnt)) + goto out_err; + + rc = add_mount_helper(mnt, nd, &cifs_dfs_automount_list); -success: +out: + FreeXid(xid); free_dfs_info_array(referrals, num_referrals); -free_full_path: kfree(full_path); -free_xid: - FreeXid(xid); cFYI(1, "leaving %s" , __func__); - return mnt; -} - -/* - * Attempt to automount the referral - */ -struct vfsmount *cifs_dfs_d_automount(struct path *path) -{ - struct vfsmount *newmnt; - - cFYI(1, "in %s", __func__); - - newmnt = cifs_dfs_do_automount(path->dentry); - if (IS_ERR(newmnt)) { - cFYI(1, "leaving %s [automount failed]" , __func__); - return newmnt; - } - - mntget(newmnt); /* prevent immediate expiration */ - mnt_set_expiry(newmnt, &cifs_dfs_automount_list); - schedule_delayed_work(&cifs_dfs_automount_task, - cifs_dfs_mountpoint_expiry_timeout); - cFYI(1, "leaving %s [ok]" , __func__); - return newmnt; + return ERR_PTR(rc); +out_err: + path_put(&nd->path); + goto out; } const struct inode_operations cifs_dfs_referral_inode_operations = { + .follow_link = cifs_dfs_follow_mountpoint, }; + diff --git a/trunk/fs/cifs/cifsfs.h b/trunk/fs/cifs/cifsfs.h index 851030f74939..897b2b2b28b5 100644 --- a/trunk/fs/cifs/cifsfs.h +++ b/trunk/fs/cifs/cifsfs.h @@ -93,12 +93,6 @@ extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir); extern const struct dentry_operations cifs_dentry_ops; extern const struct dentry_operations cifs_ci_dentry_ops; -#ifdef CONFIG_CIFS_DFS_UPCALL -extern struct vfsmount *cifs_dfs_d_automount(struct path *path); -#else -#define cifs_dfs_d_automount NULL -#endif - /* Functions related to symlinks */ extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd); extern void cifs_put_link(struct dentry *direntry, diff --git a/trunk/fs/cifs/connect.c b/trunk/fs/cifs/connect.c index 9f59887badd2..a65d311d163a 100644 --- a/trunk/fs/cifs/connect.c +++ b/trunk/fs/cifs/connect.c @@ -1113,8 +1113,6 @@ cifs_parse_mount_options(char *options, const char *devname, } else if (!strnicmp(data, "uid", 3) && value && *value) { vol->linux_uid = simple_strtoul(value, &value, 0); uid_specified = true; - } else if (!strnicmp(data, "cruid", 5) && value && *value) { - vol->cred_uid = simple_strtoul(value, &value, 0); } else if (!strnicmp(data, "forceuid", 8)) { override_uid = 1; } else if (!strnicmp(data, "noforceuid", 10)) { diff --git a/trunk/fs/cifs/dir.c b/trunk/fs/cifs/dir.c index dd5f22918c33..1e95dd635632 100644 --- a/trunk/fs/cifs/dir.c +++ b/trunk/fs/cifs/dir.c @@ -675,7 +675,6 @@ cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) const struct dentry_operations cifs_dentry_ops = { .d_revalidate = cifs_d_revalidate, - .d_automount = cifs_dfs_d_automount, /* d_delete: cifs_d_delete, */ /* not needed except for debugging */ }; @@ -712,5 +711,4 @@ const struct dentry_operations cifs_ci_dentry_ops = { .d_revalidate = cifs_d_revalidate, .d_hash = cifs_ci_hash, .d_compare = cifs_ci_compare, - .d_automount = cifs_dfs_d_automount, }; diff --git a/trunk/fs/cifs/inode.c b/trunk/fs/cifs/inode.c index 6c9ee8014ff0..b06b60620240 100644 --- a/trunk/fs/cifs/inode.c +++ b/trunk/fs/cifs/inode.c @@ -32,7 +32,7 @@ #include "fscache.h" -static void cifs_set_ops(struct inode *inode) +static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral) { struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); @@ -60,7 +60,7 @@ static void cifs_set_ops(struct inode *inode) break; case S_IFDIR: #ifdef CONFIG_CIFS_DFS_UPCALL - if (IS_AUTOMOUNT(inode)) { + if (is_dfs_referral) { inode->i_op = &cifs_dfs_referral_inode_operations; } else { #else /* NO DFS support, treat as a directory */ @@ -167,9 +167,7 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) } spin_unlock(&inode->i_lock); - if (fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL) - inode->i_flags |= S_AUTOMOUNT; - cifs_set_ops(inode); + cifs_set_ops(inode, fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL); } void diff --git a/trunk/fs/cifs/netmisc.c b/trunk/fs/cifs/netmisc.c index 6783ce6cdc89..9aad47a2d62f 100644 --- a/trunk/fs/cifs/netmisc.c +++ b/trunk/fs/cifs/netmisc.c @@ -899,8 +899,8 @@ map_smb_to_linux_error(struct smb_hdr *smb, int logErr) } /* else ERRHRD class errors or junk - return EIO */ - cFYI(1, "Mapping smb error code 0x%x to POSIX err %d", - le32_to_cpu(smb->Status.CifsError), rc); + cFYI(1, "Mapping smb error code %d to POSIX err %d", + smberrcode, rc); /* generic corrective action e.g. reconnect SMB session on * ERRbaduid could be added */ diff --git a/trunk/fs/compat.c b/trunk/fs/compat.c index f6fd0a00e6cc..eb1740ac8c0a 100644 --- a/trunk/fs/compat.c +++ b/trunk/fs/compat.c @@ -257,7 +257,7 @@ static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs * } /* - * The following statfs calls are copies of code from fs/statfs.c and + * The following statfs calls are copies of code from fs/open.c and * should be checked against those from time to time */ asmlinkage long compat_sys_statfs(const char __user *pathname, struct compat_statfs __user *buf) @@ -320,9 +320,7 @@ static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstat __put_user(kbuf->f_namelen, &ubuf->f_namelen) || __put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) || __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) || - __put_user(kbuf->f_frsize, &ubuf->f_frsize) || - __put_user(kbuf->f_flags, &ubuf->f_flags) || - __clear_user(ubuf->f_spare, sizeof(ubuf->f_spare))) + __put_user(kbuf->f_frsize, &ubuf->f_frsize)) return -EFAULT; return 0; } @@ -599,8 +597,10 @@ ssize_t compat_rw_copy_check_uvector(int type, if (nr_segs > fast_segs) { ret = -ENOMEM; iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL); - if (iov == NULL) + if (iov == NULL) { + *ret_pointer = fast_pointer; goto out; + } } *ret_pointer = iov; diff --git a/trunk/fs/configfs/Kconfig b/trunk/fs/configfs/Kconfig index 9febcdefdfdc..13587cc97a0b 100644 --- a/trunk/fs/configfs/Kconfig +++ b/trunk/fs/configfs/Kconfig @@ -1,8 +1,8 @@ config CONFIGFS_FS tristate "Userspace-driven configuration filesystem" - select SYSFS + depends on SYSFS help - configfs is a RAM-based filesystem that provides the converse + configfs is a ram-based filesystem that provides the converse of sysfs's functionality. Where sysfs is a filesystem-based view of kernel objects, configfs is a filesystem-based manager of kernel objects, or config_items. diff --git a/trunk/fs/dcache.c b/trunk/fs/dcache.c index 9f493ee4dcba..274a22250380 100644 --- a/trunk/fs/dcache.c +++ b/trunk/fs/dcache.c @@ -1380,11 +1380,8 @@ EXPORT_SYMBOL(d_set_d_op); static void __d_instantiate(struct dentry *dentry, struct inode *inode) { spin_lock(&dentry->d_lock); - if (inode) { - if (unlikely(IS_AUTOMOUNT(inode))) - dentry->d_flags |= DCACHE_NEED_AUTOMOUNT; + if (inode) list_add(&dentry->d_alias, &inode->i_dentry); - } dentry->d_inode = inode; dentry_rcuwalk_barrier(dentry); spin_unlock(&dentry->d_lock); diff --git a/trunk/fs/dlm/Kconfig b/trunk/fs/dlm/Kconfig index 1897eb1b4b6a..2dbb422e8116 100644 --- a/trunk/fs/dlm/Kconfig +++ b/trunk/fs/dlm/Kconfig @@ -1,7 +1,8 @@ menuconfig DLM tristate "Distributed Lock Manager (DLM)" depends on EXPERIMENTAL && INET - depends on SYSFS && CONFIGFS_FS && (IPV6 || IPV6=n) + depends on SYSFS && (IPV6 || IPV6=n) + select CONFIGFS_FS select IP_SCTP help A general purpose distributed lock manager for kernel or userspace diff --git a/trunk/fs/ext4/ext4.h b/trunk/fs/ext4/ext4.h index 0c8d97b56f34..1de65f572033 100644 --- a/trunk/fs/ext4/ext4.h +++ b/trunk/fs/ext4/ext4.h @@ -2065,7 +2065,7 @@ extern int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, extern void ext4_ext_truncate(struct inode *); extern void ext4_ext_init(struct super_block *); extern void ext4_ext_release(struct super_block *); -extern long ext4_fallocate(struct file *file, int mode, loff_t offset, +extern long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len); extern int ext4_convert_unwritten_extents(struct inode *inode, loff_t offset, ssize_t len); diff --git a/trunk/fs/ext4/extents.c b/trunk/fs/ext4/extents.c index 63a75810b7c3..c4068f6abf03 100644 --- a/trunk/fs/ext4/extents.c +++ b/trunk/fs/ext4/extents.c @@ -3627,15 +3627,14 @@ static void ext4_falloc_update_inode(struct inode *inode, } /* - * preallocate space for a file. This implements ext4's fallocate file + * preallocate space for a file. This implements ext4's fallocate inode * operation, which gets called from sys_fallocate system call. * For block-mapped files, posix_fallocate should fall back to the method * of writing zeroes to the required new blocks (the same behavior which is * expected for file systems which do not support fallocate() system call). */ -long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) +long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len) { - struct inode *inode = file->f_path.dentry->d_inode; handle_t *handle; loff_t new_size; unsigned int max_blocks; @@ -3646,7 +3645,7 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) unsigned int credits, blkbits = inode->i_blkbits; /* We only support the FALLOC_FL_KEEP_SIZE mode */ - if (mode & ~FALLOC_FL_KEEP_SIZE) + if (mode && (mode != FALLOC_FL_KEEP_SIZE)) return -EOPNOTSUPP; /* @@ -3656,6 +3655,10 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) return -EOPNOTSUPP; + /* preallocation to directories is currently not supported */ + if (S_ISDIR(inode->i_mode)) + return -ENODEV; + map.m_lblk = offset >> blkbits; /* * We can't just convert len to max_blocks because diff --git a/trunk/fs/ext4/file.c b/trunk/fs/ext4/file.c index 2e8322c8aa88..bb003dc9ffff 100644 --- a/trunk/fs/ext4/file.c +++ b/trunk/fs/ext4/file.c @@ -210,7 +210,6 @@ const struct file_operations ext4_file_operations = { .fsync = ext4_sync_file, .splice_read = generic_file_splice_read, .splice_write = generic_file_splice_write, - .fallocate = ext4_fallocate, }; const struct inode_operations ext4_file_inode_operations = { @@ -224,6 +223,7 @@ const struct inode_operations ext4_file_inode_operations = { .removexattr = generic_removexattr, #endif .check_acl = ext4_check_acl, + .fallocate = ext4_fallocate, .fiemap = ext4_fiemap, }; diff --git a/trunk/fs/file_table.c b/trunk/fs/file_table.c index c3e89adf53c0..c3dee381f1b4 100644 --- a/trunk/fs/file_table.c +++ b/trunk/fs/file_table.c @@ -311,7 +311,7 @@ struct file *fget_light(unsigned int fd, int *fput_needed) struct files_struct *files = current->files; *fput_needed = 0; - if (atomic_read(&files->count) == 1) { + if (likely((atomic_read(&files->count) == 1))) { file = fcheck_files(files, fd); } else { rcu_read_lock(); diff --git a/trunk/fs/fs_struct.c b/trunk/fs/fs_struct.c index 78b519c13536..68ca487bedb1 100644 --- a/trunk/fs/fs_struct.c +++ b/trunk/fs/fs_struct.c @@ -4,19 +4,6 @@ #include #include #include -#include "internal.h" - -static inline void path_get_longterm(struct path *path) -{ - path_get(path); - mnt_make_longterm(path->mnt); -} - -static inline void path_put_longterm(struct path *path) -{ - mnt_make_shortterm(path->mnt); - path_put(path); -} /* * Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values. @@ -30,11 +17,11 @@ void set_fs_root(struct fs_struct *fs, struct path *path) write_seqcount_begin(&fs->seq); old_root = fs->root; fs->root = *path; - path_get_longterm(path); + path_get_long(path); write_seqcount_end(&fs->seq); spin_unlock(&fs->lock); if (old_root.dentry) - path_put_longterm(&old_root); + path_put_long(&old_root); } /* @@ -49,12 +36,12 @@ void set_fs_pwd(struct fs_struct *fs, struct path *path) write_seqcount_begin(&fs->seq); old_pwd = fs->pwd; fs->pwd = *path; - path_get_longterm(path); + path_get_long(path); write_seqcount_end(&fs->seq); spin_unlock(&fs->lock); if (old_pwd.dentry) - path_put_longterm(&old_pwd); + path_put_long(&old_pwd); } void chroot_fs_refs(struct path *old_root, struct path *new_root) @@ -72,13 +59,13 @@ void chroot_fs_refs(struct path *old_root, struct path *new_root) write_seqcount_begin(&fs->seq); if (fs->root.dentry == old_root->dentry && fs->root.mnt == old_root->mnt) { - path_get_longterm(new_root); + path_get_long(new_root); fs->root = *new_root; count++; } if (fs->pwd.dentry == old_root->dentry && fs->pwd.mnt == old_root->mnt) { - path_get_longterm(new_root); + path_get_long(new_root); fs->pwd = *new_root; count++; } @@ -89,13 +76,13 @@ void chroot_fs_refs(struct path *old_root, struct path *new_root) } while_each_thread(g, p); read_unlock(&tasklist_lock); while (count--) - path_put_longterm(old_root); + path_put_long(old_root); } void free_fs_struct(struct fs_struct *fs) { - path_put_longterm(&fs->root); - path_put_longterm(&fs->pwd); + path_put_long(&fs->root); + path_put_long(&fs->pwd); kmem_cache_free(fs_cachep, fs); } @@ -131,9 +118,9 @@ struct fs_struct *copy_fs_struct(struct fs_struct *old) spin_lock(&old->lock); fs->root = old->root; - path_get_longterm(&fs->root); + path_get_long(&fs->root); fs->pwd = old->pwd; - path_get_longterm(&fs->pwd); + path_get_long(&fs->pwd); spin_unlock(&old->lock); } return fs; diff --git a/trunk/fs/gfs2/file.c b/trunk/fs/gfs2/file.c index 7cfdcb913363..fca6689e12e6 100644 --- a/trunk/fs/gfs2/file.c +++ b/trunk/fs/gfs2/file.c @@ -19,8 +19,6 @@ #include #include #include -#include -#include #include #include #include @@ -612,260 +610,6 @@ static ssize_t gfs2_file_aio_write(struct kiocb *iocb, const struct iovec *iov, return generic_file_aio_write(iocb, iov, nr_segs, pos); } -static void empty_write_end(struct page *page, unsigned from, - unsigned to) -{ - struct gfs2_inode *ip = GFS2_I(page->mapping->host); - - page_zero_new_buffers(page, from, to); - flush_dcache_page(page); - mark_page_accessed(page); - - if (!gfs2_is_writeback(ip)) - gfs2_page_add_databufs(ip, page, from, to); - - block_commit_write(page, from, to); -} - -static int write_empty_blocks(struct page *page, unsigned from, unsigned to) -{ - unsigned start, end, next; - struct buffer_head *bh, *head; - int error; - - if (!page_has_buffers(page)) { - error = __block_write_begin(page, from, to - from, gfs2_block_map); - if (unlikely(error)) - return error; - - empty_write_end(page, from, to); - return 0; - } - - bh = head = page_buffers(page); - next = end = 0; - while (next < from) { - next += bh->b_size; - bh = bh->b_this_page; - } - start = next; - do { - next += bh->b_size; - if (buffer_mapped(bh)) { - if (end) { - error = __block_write_begin(page, start, end - start, - gfs2_block_map); - if (unlikely(error)) - return error; - empty_write_end(page, start, end); - end = 0; - } - start = next; - } - else - end = next; - bh = bh->b_this_page; - } while (next < to); - - if (end) { - error = __block_write_begin(page, start, end - start, gfs2_block_map); - if (unlikely(error)) - return error; - empty_write_end(page, start, end); - } - - return 0; -} - -static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len, - int mode) -{ - struct gfs2_inode *ip = GFS2_I(inode); - struct buffer_head *dibh; - int error; - u64 start = offset >> PAGE_CACHE_SHIFT; - unsigned int start_offset = offset & ~PAGE_CACHE_MASK; - u64 end = (offset + len - 1) >> PAGE_CACHE_SHIFT; - pgoff_t curr; - struct page *page; - unsigned int end_offset = (offset + len) & ~PAGE_CACHE_MASK; - unsigned int from, to; - - if (!end_offset) - end_offset = PAGE_CACHE_SIZE; - - error = gfs2_meta_inode_buffer(ip, &dibh); - if (unlikely(error)) - goto out; - - gfs2_trans_add_bh(ip->i_gl, dibh, 1); - - if (gfs2_is_stuffed(ip)) { - error = gfs2_unstuff_dinode(ip, NULL); - if (unlikely(error)) - goto out; - } - - curr = start; - offset = start << PAGE_CACHE_SHIFT; - from = start_offset; - to = PAGE_CACHE_SIZE; - while (curr <= end) { - page = grab_cache_page_write_begin(inode->i_mapping, curr, - AOP_FLAG_NOFS); - if (unlikely(!page)) { - error = -ENOMEM; - goto out; - } - - if (curr == end) - to = end_offset; - error = write_empty_blocks(page, from, to); - if (!error && offset + to > inode->i_size && - !(mode & FALLOC_FL_KEEP_SIZE)) { - i_size_write(inode, offset + to); - } - unlock_page(page); - page_cache_release(page); - if (error) - goto out; - curr++; - offset += PAGE_CACHE_SIZE; - from = 0; - } - - gfs2_dinode_out(ip, dibh->b_data); - mark_inode_dirty(inode); - - brelse(dibh); - -out: - return error; -} - -static void calc_max_reserv(struct gfs2_inode *ip, loff_t max, loff_t *len, - unsigned int *data_blocks, unsigned int *ind_blocks) -{ - const struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); - unsigned int max_blocks = ip->i_alloc->al_rgd->rd_free_clone; - unsigned int tmp, max_data = max_blocks - 3 * (sdp->sd_max_height - 1); - - for (tmp = max_data; tmp > sdp->sd_diptrs;) { - tmp = DIV_ROUND_UP(tmp, sdp->sd_inptrs); - max_data -= tmp; - } - /* This calculation isn't the exact reverse of gfs2_write_calc_reserve, - so it might end up with fewer data blocks */ - if (max_data <= *data_blocks) - return; - *data_blocks = max_data; - *ind_blocks = max_blocks - max_data; - *len = ((loff_t)max_data - 3) << sdp->sd_sb.sb_bsize_shift; - if (*len > max) { - *len = max; - gfs2_write_calc_reserv(ip, max, data_blocks, ind_blocks); - } -} - -static long gfs2_fallocate(struct file *file, int mode, loff_t offset, - loff_t len) -{ - struct inode *inode = file->f_path.dentry->d_inode; - struct gfs2_sbd *sdp = GFS2_SB(inode); - struct gfs2_inode *ip = GFS2_I(inode); - unsigned int data_blocks = 0, ind_blocks = 0, rblocks; - loff_t bytes, max_bytes; - struct gfs2_alloc *al; - int error; - loff_t next = (offset + len - 1) >> sdp->sd_sb.sb_bsize_shift; - next = (next + 1) << sdp->sd_sb.sb_bsize_shift; - - /* We only support the FALLOC_FL_KEEP_SIZE mode */ - if (mode & ~FALLOC_FL_KEEP_SIZE) - return -EOPNOTSUPP; - - offset = (offset >> sdp->sd_sb.sb_bsize_shift) << - sdp->sd_sb.sb_bsize_shift; - - len = next - offset; - bytes = sdp->sd_max_rg_data * sdp->sd_sb.sb_bsize / 2; - if (!bytes) - bytes = UINT_MAX; - - gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ip->i_gh); - error = gfs2_glock_nq(&ip->i_gh); - if (unlikely(error)) - goto out_uninit; - - if (!gfs2_write_alloc_required(ip, offset, len)) - goto out_unlock; - - while (len > 0) { - if (len < bytes) - bytes = len; - al = gfs2_alloc_get(ip); - if (!al) { - error = -ENOMEM; - goto out_unlock; - } - - error = gfs2_quota_lock_check(ip); - if (error) - goto out_alloc_put; - -retry: - gfs2_write_calc_reserv(ip, bytes, &data_blocks, &ind_blocks); - - al->al_requested = data_blocks + ind_blocks; - error = gfs2_inplace_reserve(ip); - if (error) { - if (error == -ENOSPC && bytes > sdp->sd_sb.sb_bsize) { - bytes >>= 1; - goto retry; - } - goto out_qunlock; - } - max_bytes = bytes; - calc_max_reserv(ip, len, &max_bytes, &data_blocks, &ind_blocks); - al->al_requested = data_blocks + ind_blocks; - - rblocks = RES_DINODE + ind_blocks + RES_STATFS + RES_QUOTA + - RES_RG_HDR + gfs2_rg_blocks(al); - if (gfs2_is_jdata(ip)) - rblocks += data_blocks ? data_blocks : 1; - - error = gfs2_trans_begin(sdp, rblocks, - PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize); - if (error) - goto out_trans_fail; - - error = fallocate_chunk(inode, offset, max_bytes, mode); - gfs2_trans_end(sdp); - - if (error) - goto out_trans_fail; - - len -= max_bytes; - offset += max_bytes; - gfs2_inplace_release(ip); - gfs2_quota_unlock(ip); - gfs2_alloc_put(ip); - } - goto out_unlock; - -out_trans_fail: - gfs2_inplace_release(ip); -out_qunlock: - gfs2_quota_unlock(ip); -out_alloc_put: - gfs2_alloc_put(ip); -out_unlock: - gfs2_glock_dq(&ip->i_gh); -out_uninit: - gfs2_holder_uninit(&ip->i_gh); - return error; -} - #ifdef CONFIG_GFS2_FS_LOCKING_DLM /** @@ -1021,7 +765,6 @@ const struct file_operations gfs2_file_fops = { .splice_read = generic_file_splice_read, .splice_write = generic_file_splice_write, .setlease = gfs2_setlease, - .fallocate = gfs2_fallocate, }; const struct file_operations gfs2_dir_fops = { @@ -1051,7 +794,6 @@ const struct file_operations gfs2_file_fops_nolock = { .splice_read = generic_file_splice_read, .splice_write = generic_file_splice_write, .setlease = generic_setlease, - .fallocate = gfs2_fallocate, }; const struct file_operations gfs2_dir_fops_nolock = { diff --git a/trunk/fs/gfs2/ops_inode.c b/trunk/fs/gfs2/ops_inode.c index d8b26ac2e20b..040b5a2e6556 100644 --- a/trunk/fs/gfs2/ops_inode.c +++ b/trunk/fs/gfs2/ops_inode.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include "gfs2.h" @@ -1255,6 +1257,261 @@ static int gfs2_removexattr(struct dentry *dentry, const char *name) return ret; } +static void empty_write_end(struct page *page, unsigned from, + unsigned to) +{ + struct gfs2_inode *ip = GFS2_I(page->mapping->host); + + page_zero_new_buffers(page, from, to); + flush_dcache_page(page); + mark_page_accessed(page); + + if (!gfs2_is_writeback(ip)) + gfs2_page_add_databufs(ip, page, from, to); + + block_commit_write(page, from, to); +} + + +static int write_empty_blocks(struct page *page, unsigned from, unsigned to) +{ + unsigned start, end, next; + struct buffer_head *bh, *head; + int error; + + if (!page_has_buffers(page)) { + error = __block_write_begin(page, from, to - from, gfs2_block_map); + if (unlikely(error)) + return error; + + empty_write_end(page, from, to); + return 0; + } + + bh = head = page_buffers(page); + next = end = 0; + while (next < from) { + next += bh->b_size; + bh = bh->b_this_page; + } + start = next; + do { + next += bh->b_size; + if (buffer_mapped(bh)) { + if (end) { + error = __block_write_begin(page, start, end - start, + gfs2_block_map); + if (unlikely(error)) + return error; + empty_write_end(page, start, end); + end = 0; + } + start = next; + } + else + end = next; + bh = bh->b_this_page; + } while (next < to); + + if (end) { + error = __block_write_begin(page, start, end - start, gfs2_block_map); + if (unlikely(error)) + return error; + empty_write_end(page, start, end); + } + + return 0; +} + +static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len, + int mode) +{ + struct gfs2_inode *ip = GFS2_I(inode); + struct buffer_head *dibh; + int error; + u64 start = offset >> PAGE_CACHE_SHIFT; + unsigned int start_offset = offset & ~PAGE_CACHE_MASK; + u64 end = (offset + len - 1) >> PAGE_CACHE_SHIFT; + pgoff_t curr; + struct page *page; + unsigned int end_offset = (offset + len) & ~PAGE_CACHE_MASK; + unsigned int from, to; + + if (!end_offset) + end_offset = PAGE_CACHE_SIZE; + + error = gfs2_meta_inode_buffer(ip, &dibh); + if (unlikely(error)) + goto out; + + gfs2_trans_add_bh(ip->i_gl, dibh, 1); + + if (gfs2_is_stuffed(ip)) { + error = gfs2_unstuff_dinode(ip, NULL); + if (unlikely(error)) + goto out; + } + + curr = start; + offset = start << PAGE_CACHE_SHIFT; + from = start_offset; + to = PAGE_CACHE_SIZE; + while (curr <= end) { + page = grab_cache_page_write_begin(inode->i_mapping, curr, + AOP_FLAG_NOFS); + if (unlikely(!page)) { + error = -ENOMEM; + goto out; + } + + if (curr == end) + to = end_offset; + error = write_empty_blocks(page, from, to); + if (!error && offset + to > inode->i_size && + !(mode & FALLOC_FL_KEEP_SIZE)) { + i_size_write(inode, offset + to); + } + unlock_page(page); + page_cache_release(page); + if (error) + goto out; + curr++; + offset += PAGE_CACHE_SIZE; + from = 0; + } + + gfs2_dinode_out(ip, dibh->b_data); + mark_inode_dirty(inode); + + brelse(dibh); + +out: + return error; +} + +static void calc_max_reserv(struct gfs2_inode *ip, loff_t max, loff_t *len, + unsigned int *data_blocks, unsigned int *ind_blocks) +{ + const struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); + unsigned int max_blocks = ip->i_alloc->al_rgd->rd_free_clone; + unsigned int tmp, max_data = max_blocks - 3 * (sdp->sd_max_height - 1); + + for (tmp = max_data; tmp > sdp->sd_diptrs;) { + tmp = DIV_ROUND_UP(tmp, sdp->sd_inptrs); + max_data -= tmp; + } + /* This calculation isn't the exact reverse of gfs2_write_calc_reserve, + so it might end up with fewer data blocks */ + if (max_data <= *data_blocks) + return; + *data_blocks = max_data; + *ind_blocks = max_blocks - max_data; + *len = ((loff_t)max_data - 3) << sdp->sd_sb.sb_bsize_shift; + if (*len > max) { + *len = max; + gfs2_write_calc_reserv(ip, max, data_blocks, ind_blocks); + } +} + +static long gfs2_fallocate(struct inode *inode, int mode, loff_t offset, + loff_t len) +{ + struct gfs2_sbd *sdp = GFS2_SB(inode); + struct gfs2_inode *ip = GFS2_I(inode); + unsigned int data_blocks = 0, ind_blocks = 0, rblocks; + loff_t bytes, max_bytes; + struct gfs2_alloc *al; + int error; + loff_t next = (offset + len - 1) >> sdp->sd_sb.sb_bsize_shift; + next = (next + 1) << sdp->sd_sb.sb_bsize_shift; + + /* We only support the FALLOC_FL_KEEP_SIZE mode */ + if (mode && (mode != FALLOC_FL_KEEP_SIZE)) + return -EOPNOTSUPP; + + offset = (offset >> sdp->sd_sb.sb_bsize_shift) << + sdp->sd_sb.sb_bsize_shift; + + len = next - offset; + bytes = sdp->sd_max_rg_data * sdp->sd_sb.sb_bsize / 2; + if (!bytes) + bytes = UINT_MAX; + + gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ip->i_gh); + error = gfs2_glock_nq(&ip->i_gh); + if (unlikely(error)) + goto out_uninit; + + if (!gfs2_write_alloc_required(ip, offset, len)) + goto out_unlock; + + while (len > 0) { + if (len < bytes) + bytes = len; + al = gfs2_alloc_get(ip); + if (!al) { + error = -ENOMEM; + goto out_unlock; + } + + error = gfs2_quota_lock_check(ip); + if (error) + goto out_alloc_put; + +retry: + gfs2_write_calc_reserv(ip, bytes, &data_blocks, &ind_blocks); + + al->al_requested = data_blocks + ind_blocks; + error = gfs2_inplace_reserve(ip); + if (error) { + if (error == -ENOSPC && bytes > sdp->sd_sb.sb_bsize) { + bytes >>= 1; + goto retry; + } + goto out_qunlock; + } + max_bytes = bytes; + calc_max_reserv(ip, len, &max_bytes, &data_blocks, &ind_blocks); + al->al_requested = data_blocks + ind_blocks; + + rblocks = RES_DINODE + ind_blocks + RES_STATFS + RES_QUOTA + + RES_RG_HDR + gfs2_rg_blocks(al); + if (gfs2_is_jdata(ip)) + rblocks += data_blocks ? data_blocks : 1; + + error = gfs2_trans_begin(sdp, rblocks, + PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize); + if (error) + goto out_trans_fail; + + error = fallocate_chunk(inode, offset, max_bytes, mode); + gfs2_trans_end(sdp); + + if (error) + goto out_trans_fail; + + len -= max_bytes; + offset += max_bytes; + gfs2_inplace_release(ip); + gfs2_quota_unlock(ip); + gfs2_alloc_put(ip); + } + goto out_unlock; + +out_trans_fail: + gfs2_inplace_release(ip); +out_qunlock: + gfs2_quota_unlock(ip); +out_alloc_put: + gfs2_alloc_put(ip); +out_unlock: + gfs2_glock_dq(&ip->i_gh); +out_uninit: + gfs2_holder_uninit(&ip->i_gh); + return error; +} + + static int gfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, u64 start, u64 len) { @@ -1305,6 +1562,7 @@ const struct inode_operations gfs2_file_iops = { .getxattr = gfs2_getxattr, .listxattr = gfs2_listxattr, .removexattr = gfs2_removexattr, + .fallocate = gfs2_fallocate, .fiemap = gfs2_fiemap, }; diff --git a/trunk/fs/hpfs/inode.c b/trunk/fs/hpfs/inode.c index 1ae35baa539e..56f0da1cfd10 100644 --- a/trunk/fs/hpfs/inode.c +++ b/trunk/fs/hpfs/inode.c @@ -281,7 +281,7 @@ int hpfs_setattr(struct dentry *dentry, struct iattr *attr) attr->ia_size != i_size_read(inode)) { error = vmtruncate(inode, attr->ia_size); if (error) - goto out_unlock; + return error; } setattr_copy(inode, attr); diff --git a/trunk/fs/internal.h b/trunk/fs/internal.h index 0663568b1247..9687c2ee2735 100644 --- a/trunk/fs/internal.h +++ b/trunk/fs/internal.h @@ -70,10 +70,6 @@ extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *, extern void release_mounts(struct list_head *); extern void umount_tree(struct vfsmount *, int, struct list_head *); extern struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int); -extern int finish_automount(struct vfsmount *, struct path *); - -extern void mnt_make_longterm(struct vfsmount *); -extern void mnt_make_shortterm(struct vfsmount *); extern void __init mnt_init(void); diff --git a/trunk/fs/ioctl.c b/trunk/fs/ioctl.c index a59635e295fa..d6cc16476620 100644 --- a/trunk/fs/ioctl.c +++ b/trunk/fs/ioctl.c @@ -86,7 +86,7 @@ int fiemap_fill_next_extent(struct fiemap_extent_info *fieinfo, u64 logical, u64 phys, u64 len, u32 flags) { struct fiemap_extent extent; - struct fiemap_extent __user *dest = fieinfo->fi_extents_start; + struct fiemap_extent *dest = fieinfo->fi_extents_start; /* only count the extents */ if (fieinfo->fi_extents_max == 0) { @@ -173,7 +173,6 @@ static int fiemap_check_ranges(struct super_block *sb, static int ioctl_fiemap(struct file *filp, unsigned long arg) { struct fiemap fiemap; - struct fiemap __user *ufiemap = (struct fiemap __user *) arg; struct fiemap_extent_info fieinfo = { 0, }; struct inode *inode = filp->f_path.dentry->d_inode; struct super_block *sb = inode->i_sb; @@ -183,7 +182,8 @@ static int ioctl_fiemap(struct file *filp, unsigned long arg) if (!inode->i_op->fiemap) return -EOPNOTSUPP; - if (copy_from_user(&fiemap, ufiemap, sizeof(fiemap))) + if (copy_from_user(&fiemap, (struct fiemap __user *)arg, + sizeof(struct fiemap))) return -EFAULT; if (fiemap.fm_extent_count > FIEMAP_MAX_EXTENTS) @@ -196,7 +196,7 @@ static int ioctl_fiemap(struct file *filp, unsigned long arg) fieinfo.fi_flags = fiemap.fm_flags; fieinfo.fi_extents_max = fiemap.fm_extent_count; - fieinfo.fi_extents_start = ufiemap->fm_extents; + fieinfo.fi_extents_start = (struct fiemap_extent *)(arg + sizeof(fiemap)); if (fiemap.fm_extent_count != 0 && !access_ok(VERIFY_WRITE, fieinfo.fi_extents_start, @@ -209,7 +209,7 @@ static int ioctl_fiemap(struct file *filp, unsigned long arg) error = inode->i_op->fiemap(inode, &fieinfo, fiemap.fm_start, len); fiemap.fm_flags = fieinfo.fi_flags; fiemap.fm_mapped_extents = fieinfo.fi_extents_mapped; - if (copy_to_user(ufiemap, &fiemap, sizeof(fiemap))) + if (copy_to_user((char *)arg, &fiemap, sizeof(fiemap))) error = -EFAULT; return error; diff --git a/trunk/fs/jffs2/build.c b/trunk/fs/jffs2/build.c index 3005ec4520ad..85c6be2db02f 100644 --- a/trunk/fs/jffs2/build.c +++ b/trunk/fs/jffs2/build.c @@ -336,13 +336,14 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c) size = sizeof(struct jffs2_eraseblock) * c->nr_blocks; #ifndef __ECOS if (jffs2_blocks_use_vmalloc(c)) - c->blocks = vzalloc(size); + c->blocks = vmalloc(size); else #endif - c->blocks = kzalloc(size, GFP_KERNEL); + c->blocks = kmalloc(size, GFP_KERNEL); if (!c->blocks) return -ENOMEM; + memset(c->blocks, 0, size); for (i=0; inr_blocks; i++) { INIT_LIST_HEAD(&c->blocks[i].list); c->blocks[i].offset = i * c->sector_size; diff --git a/trunk/fs/jffs2/jffs2_fs_sb.h b/trunk/fs/jffs2/jffs2_fs_sb.h index 0bc6a6c80a56..f864005de64c 100644 --- a/trunk/fs/jffs2/jffs2_fs_sb.h +++ b/trunk/fs/jffs2/jffs2_fs_sb.h @@ -144,4 +144,4 @@ struct jffs2_sb_info { void *os_priv; }; -#endif /* _JFFS2_FS_SB */ +#endif /* _JFFS2_FB_SB */ diff --git a/trunk/fs/jffs2/xattr.c b/trunk/fs/jffs2/xattr.c index 4f9cc0482949..9b572ca40a49 100644 --- a/trunk/fs/jffs2/xattr.c +++ b/trunk/fs/jffs2/xattr.c @@ -151,7 +151,7 @@ static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_dat JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n", offset, je32_to_cpu(rx.hdr_crc), crc); xd->flags |= JFFS2_XFLAGS_INVALID; - return -EIO; + return EIO; } totlen = PAD(sizeof(rx) + rx.name_len + 1 + je16_to_cpu(rx.value_len)); if (je16_to_cpu(rx.magic) != JFFS2_MAGIC_BITMASK @@ -167,7 +167,7 @@ static int do_verify_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_dat je32_to_cpu(rx.xid), xd->xid, je32_to_cpu(rx.version), xd->version); xd->flags |= JFFS2_XFLAGS_INVALID; - return -EIO; + return EIO; } xd->xprefix = rx.xprefix; xd->name_len = rx.name_len; @@ -230,7 +230,7 @@ static int do_load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum ref_offset(xd->node), xd->data_crc, crc); kfree(data); xd->flags |= JFFS2_XFLAGS_INVALID; - return -EIO; + return EIO; } xd->flags |= JFFS2_XFLAGS_HOT; @@ -268,7 +268,7 @@ static int load_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *x if (xd->xname) return 0; if (xd->flags & JFFS2_XFLAGS_INVALID) - return -EIO; + return EIO; if (unlikely(is_xattr_datum_unchecked(c, xd))) rc = do_verify_xattr_datum(c, xd); if (!rc) @@ -460,7 +460,7 @@ static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref if (crc != je32_to_cpu(rr.node_crc)) { JFFS2_ERROR("node CRC failed at %#08x, read=%#08x, calc=%#08x\n", offset, je32_to_cpu(rr.node_crc), crc); - return -EIO; + return EIO; } if (je16_to_cpu(rr.magic) != JFFS2_MAGIC_BITMASK || je16_to_cpu(rr.nodetype) != JFFS2_NODETYPE_XREF @@ -470,7 +470,7 @@ static int verify_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *ref offset, je16_to_cpu(rr.magic), JFFS2_MAGIC_BITMASK, je16_to_cpu(rr.nodetype), JFFS2_NODETYPE_XREF, je32_to_cpu(rr.totlen), PAD(sizeof(rr))); - return -EIO; + return EIO; } ref->ino = je32_to_cpu(rr.ino); ref->xid = je32_to_cpu(rr.xid); diff --git a/trunk/fs/namei.c b/trunk/fs/namei.c index b753192d8c3f..8df7a78ace58 100644 --- a/trunk/fs/namei.c +++ b/trunk/fs/namei.c @@ -367,6 +367,18 @@ void path_get(struct path *path) } EXPORT_SYMBOL(path_get); +/** + * path_get_long - get a long reference to a path + * @path: path to get the reference to + * + * Given a path increment the reference count to the dentry and the vfsmount. + */ +void path_get_long(struct path *path) +{ + mntget_long(path->mnt); + dget(path->dentry); +} + /** * path_put - put a reference to a path * @path: path to put the reference to @@ -380,6 +392,18 @@ void path_put(struct path *path) } EXPORT_SYMBOL(path_put); +/** + * path_put_long - put a long reference to a path + * @path: path to put the reference to + * + * Given a path decrement the reference count to the dentry and the vfsmount. + */ +void path_put_long(struct path *path) +{ + dput(path->dentry); + mntput_long(path->mnt); +} + /** * nameidata_drop_rcu - drop this nameidata out of rcu-walk * @nd: nameidata pathwalk data to drop @@ -776,8 +800,12 @@ __do_follow_link(const struct path *link, struct nameidata *nd, void **p) touch_atime(link->mnt, dentry); nd_set_link(nd, NULL); - if (link->mnt == nd->path.mnt) - mntget(link->mnt); + if (link->mnt != nd->path.mnt) { + path_to_nameidata(link, nd); + nd->inode = nd->path.dentry->d_inode; + dget(dentry); + } + mntget(link->mnt); nd->last_type = LAST_BIND; *p = dentry->d_inode->i_op->follow_link(dentry, nd); @@ -868,148 +896,54 @@ int follow_up(struct path *path) } /* - * Perform an automount - * - return -EISDIR to tell follow_managed() to stop and return the path we - * were called with. + * serialization is taken care of in namespace.c */ -static int follow_automount(struct path *path, unsigned flags, - bool *need_mntput) +static void __follow_mount_rcu(struct nameidata *nd, struct path *path, + struct inode **inode) { - struct vfsmount *mnt; - int err; - - if (!path->dentry->d_op || !path->dentry->d_op->d_automount) - return -EREMOTE; - - /* We don't want to mount if someone supplied AT_NO_AUTOMOUNT - * and this is the terminal part of the path. - */ - if ((flags & LOOKUP_NO_AUTOMOUNT) && !(flags & LOOKUP_CONTINUE)) - return -EISDIR; /* we actually want to stop here */ - - /* We want to mount if someone is trying to open/create a file of any - * type under the mountpoint, wants to traverse through the mountpoint - * or wants to open the mounted directory. - * - * We don't want to mount if someone's just doing a stat and they've - * set AT_SYMLINK_NOFOLLOW - unless they're stat'ing a directory and - * appended a '/' to the name. - */ - if (!(flags & LOOKUP_FOLLOW) && - !(flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY | - LOOKUP_OPEN | LOOKUP_CREATE))) - return -EISDIR; - - current->total_link_count++; - if (current->total_link_count >= 40) - return -ELOOP; - - mnt = path->dentry->d_op->d_automount(path); - if (IS_ERR(mnt)) { - /* - * The filesystem is allowed to return -EISDIR here to indicate - * it doesn't want to automount. For instance, autofs would do - * this so that its userspace daemon can mount on this dentry. - * - * However, we can only permit this if it's a terminal point in - * the path being looked up; if it wasn't then the remainder of - * the path is inaccessible and we should say so. - */ - if (PTR_ERR(mnt) == -EISDIR && (flags & LOOKUP_CONTINUE)) - return -EREMOTE; - return PTR_ERR(mnt); + while (d_mountpoint(path->dentry)) { + struct vfsmount *mounted; + mounted = __lookup_mnt(path->mnt, path->dentry, 1); + if (!mounted) + return; + path->mnt = mounted; + path->dentry = mounted->mnt_root; + nd->seq = read_seqcount_begin(&path->dentry->d_seq); + *inode = path->dentry->d_inode; } +} - if (!mnt) /* mount collision */ - return 0; - - err = finish_automount(mnt, path); - - switch (err) { - case -EBUSY: - /* Someone else made a mount here whilst we were busy */ - return 0; - case 0: +static int __follow_mount(struct path *path) +{ + int res = 0; + while (d_mountpoint(path->dentry)) { + struct vfsmount *mounted = lookup_mnt(path); + if (!mounted) + break; dput(path->dentry); - if (*need_mntput) + if (res) mntput(path->mnt); - path->mnt = mnt; - path->dentry = dget(mnt->mnt_root); - *need_mntput = true; - return 0; - default: - return err; + path->mnt = mounted; + path->dentry = dget(mounted->mnt_root); + res = 1; } - + return res; } -/* - * Handle a dentry that is managed in some way. - * - Flagged for transit management (autofs) - * - Flagged as mountpoint - * - Flagged as automount point - * - * This may only be called in refwalk mode. - * - * Serialization is taken care of in namespace.c - */ -static int follow_managed(struct path *path, unsigned flags) +static void follow_mount(struct path *path) { - unsigned managed; - bool need_mntput = false; - int ret; - - /* Given that we're not holding a lock here, we retain the value in a - * local variable for each dentry as we look at it so that we don't see - * the components of that value change under us */ - while (managed = ACCESS_ONCE(path->dentry->d_flags), - managed &= DCACHE_MANAGED_DENTRY, - unlikely(managed != 0)) { - /* Allow the filesystem to manage the transit without i_mutex - * being held. */ - if (managed & DCACHE_MANAGE_TRANSIT) { - BUG_ON(!path->dentry->d_op); - BUG_ON(!path->dentry->d_op->d_manage); - ret = path->dentry->d_op->d_manage(path->dentry, - false, false); - if (ret < 0) - return ret == -EISDIR ? 0 : ret; - } - - /* Transit to a mounted filesystem. */ - if (managed & DCACHE_MOUNTED) { - struct vfsmount *mounted = lookup_mnt(path); - if (mounted) { - dput(path->dentry); - if (need_mntput) - mntput(path->mnt); - path->mnt = mounted; - path->dentry = dget(mounted->mnt_root); - need_mntput = true; - continue; - } - - /* Something is mounted on this dentry in another - * namespace and/or whatever was mounted there in this - * namespace got unmounted before we managed to get the - * vfsmount_lock */ - } - - /* Handle an automount point */ - if (managed & DCACHE_NEED_AUTOMOUNT) { - ret = follow_automount(path, flags, &need_mntput); - if (ret < 0) - return ret == -EISDIR ? 0 : ret; - continue; - } - - /* We didn't change the current path point */ - break; + while (d_mountpoint(path->dentry)) { + struct vfsmount *mounted = lookup_mnt(path); + if (!mounted) + break; + dput(path->dentry); + mntput(path->mnt); + path->mnt = mounted; + path->dentry = dget(mounted->mnt_root); } - return 0; } -int follow_down_one(struct path *path) +int follow_down(struct path *path) { struct vfsmount *mounted; @@ -1024,41 +958,13 @@ int follow_down_one(struct path *path) return 0; } -/* - * Skip to top of mountpoint pile in rcuwalk mode. We abort the rcu-walk if we - * meet a managed dentry and we're not walking to "..". True is returned to - * continue, false to abort. - */ -static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, - struct inode **inode, bool reverse_transit) -{ - while (d_mountpoint(path->dentry)) { - struct vfsmount *mounted; - if (unlikely(path->dentry->d_flags & DCACHE_MANAGE_TRANSIT) && - !reverse_transit && - path->dentry->d_op->d_manage(path->dentry, false, true) < 0) - return false; - mounted = __lookup_mnt(path->mnt, path->dentry, 1); - if (!mounted) - break; - path->mnt = mounted; - path->dentry = mounted->mnt_root; - nd->seq = read_seqcount_begin(&path->dentry->d_seq); - *inode = path->dentry->d_inode; - } - - if (unlikely(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT)) - return reverse_transit; - return true; -} - static int follow_dotdot_rcu(struct nameidata *nd) { struct inode *inode = nd->inode; set_root_rcu(nd); - while (1) { + while(1) { if (nd->path.dentry == nd->root.dentry && nd->path.mnt == nd->root.mnt) { break; @@ -1081,80 +987,12 @@ static int follow_dotdot_rcu(struct nameidata *nd) nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); inode = nd->path.dentry->d_inode; } - __follow_mount_rcu(nd, &nd->path, &inode, true); + __follow_mount_rcu(nd, &nd->path, &inode); nd->inode = inode; return 0; } -/* - * Follow down to the covering mount currently visible to userspace. At each - * point, the filesystem owning that dentry may be queried as to whether the - * caller is permitted to proceed or not. - * - * Care must be taken as namespace_sem may be held (indicated by mounting_here - * being true). - */ -int follow_down(struct path *path, bool mounting_here) -{ - unsigned managed; - int ret; - - while (managed = ACCESS_ONCE(path->dentry->d_flags), - unlikely(managed & DCACHE_MANAGED_DENTRY)) { - /* Allow the filesystem to manage the transit without i_mutex - * being held. - * - * We indicate to the filesystem if someone is trying to mount - * something here. This gives autofs the chance to deny anyone - * other than its daemon the right to mount on its - * superstructure. - * - * The filesystem may sleep at this point. - */ - if (managed & DCACHE_MANAGE_TRANSIT) { - BUG_ON(!path->dentry->d_op); - BUG_ON(!path->dentry->d_op->d_manage); - ret = path->dentry->d_op->d_manage( - path->dentry, mounting_here, false); - if (ret < 0) - return ret == -EISDIR ? 0 : ret; - } - - /* Transit to a mounted filesystem. */ - if (managed & DCACHE_MOUNTED) { - struct vfsmount *mounted = lookup_mnt(path); - if (!mounted) - break; - dput(path->dentry); - mntput(path->mnt); - path->mnt = mounted; - path->dentry = dget(mounted->mnt_root); - continue; - } - - /* Don't handle automount points here */ - break; - } - return 0; -} - -/* - * Skip to top of mountpoint pile in refwalk mode for follow_dotdot() - */ -static void follow_mount(struct path *path) -{ - while (d_mountpoint(path->dentry)) { - struct vfsmount *mounted = lookup_mnt(path); - if (!mounted) - break; - dput(path->dentry); - mntput(path->mnt); - path->mnt = mounted; - path->dentry = dget(mounted->mnt_root); - } -} - static void follow_dotdot(struct nameidata *nd) { set_root(nd); @@ -1219,14 +1057,12 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, struct vfsmount *mnt = nd->path.mnt; struct dentry *dentry, *parent = nd->path.dentry; struct inode *dir; - int err; - /* * See if the low-level filesystem might want * to use its own hash.. */ if (unlikely(parent->d_flags & DCACHE_OP_HASH)) { - err = parent->d_op->d_hash(parent, nd->inode, name); + int err = parent->d_op->d_hash(parent, nd->inode, name); if (err < 0) return err; } @@ -1253,28 +1089,22 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, nd->seq = seq; if (dentry->d_flags & DCACHE_OP_REVALIDATE) goto need_revalidate; -done2: path->mnt = mnt; path->dentry = dentry; - if (likely(__follow_mount_rcu(nd, path, inode, false))) - return 0; - if (nameidata_drop_rcu(nd)) - return -ECHILD; - /* fallthru */ - } - dentry = __d_lookup(parent, name); - if (!dentry) - goto need_lookup; + __follow_mount_rcu(nd, path, inode); + } else { + dentry = __d_lookup(parent, name); + if (!dentry) + goto need_lookup; found: - if (dentry->d_flags & DCACHE_OP_REVALIDATE) - goto need_revalidate; + if (dentry->d_flags & DCACHE_OP_REVALIDATE) + goto need_revalidate; done: - path->mnt = mnt; - path->dentry = dentry; - err = follow_managed(path, nd->flags); - if (unlikely(err < 0)) - return err; - *inode = path->dentry->d_inode; + path->mnt = mnt; + path->dentry = dentry; + __follow_mount(path); + *inode = path->dentry->d_inode; + } return 0; need_lookup: @@ -1313,14 +1143,23 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, goto need_lookup; if (IS_ERR(dentry)) goto fail; - if (nd->flags & LOOKUP_RCU) - goto done2; goto done; fail: return PTR_ERR(dentry); } +/* + * This is a temporary kludge to deal with "automount" symlinks; proper + * solution is to trigger them on follow_mount(), so that do_lookup() + * would DTRT. To be killed before 2.6.34-final. + */ +static inline int follow_on_final(struct inode *inode, unsigned lookup_flags) +{ + return inode && unlikely(inode->i_op->follow_link) && + ((lookup_flags & LOOKUP_FOLLOW) || S_ISDIR(inode->i_mode)); +} + /* * Name resolution. * This is the basic name resolution function, turning a pathname into @@ -1459,8 +1298,7 @@ static int link_path_walk(const char *name, struct nameidata *nd) err = do_lookup(nd, &this, &next, &inode); if (err) break; - if (inode && unlikely(inode->i_op->follow_link) && - (lookup_flags & LOOKUP_FOLLOW)) { + if (follow_on_final(inode, lookup_flags)) { if (nameidata_dentry_drop_rcu_maybe(nd, next.dentry)) return -ECHILD; BUG_ON(inode != next.dentry->d_inode); @@ -2362,9 +2200,11 @@ static struct file *do_last(struct nameidata *nd, struct path *path, if (open_flag & O_EXCL) goto exit_dput; - error = follow_managed(path, nd->flags); - if (error < 0) - goto exit_dput; + if (__follow_mount(path)) { + error = -ELOOP; + if (open_flag & O_NOFOLLOW) + goto exit_dput; + } error = -ENOENT; if (!path->dentry->d_inode) @@ -2513,7 +2353,8 @@ struct file *do_filp_open(int dfd, const char *pathname, struct inode *linki = link.dentry->d_inode; void *cookie; error = -ELOOP; - if (!(nd.flags & LOOKUP_FOLLOW)) + /* S_ISDIR part is a temporary automount kludge */ + if (!(nd.flags & LOOKUP_FOLLOW) && !S_ISDIR(linki->i_mode)) goto exit_dput; if (count++ == 32) goto exit_dput; @@ -3572,7 +3413,6 @@ const struct inode_operations page_symlink_inode_operations = { }; EXPORT_SYMBOL(user_path_at); -EXPORT_SYMBOL(follow_down_one); EXPORT_SYMBOL(follow_down); EXPORT_SYMBOL(follow_up); EXPORT_SYMBOL(get_write_access); /* binfmt_aout */ diff --git a/trunk/fs/namespace.c b/trunk/fs/namespace.c index 7b0b95371696..3ddfd9046c44 100644 --- a/trunk/fs/namespace.c +++ b/trunk/fs/namespace.c @@ -183,7 +183,7 @@ static inline void mnt_dec_count(struct vfsmount *mnt) unsigned int mnt_get_count(struct vfsmount *mnt) { #ifdef CONFIG_SMP - unsigned int count = 0; + unsigned int count = atomic_read(&mnt->mnt_longrefs); int cpu; for_each_possible_cpu(cpu) { @@ -217,7 +217,7 @@ struct vfsmount *alloc_vfsmnt(const char *name) if (!mnt->mnt_pcp) goto out_free_devname; - this_cpu_add(mnt->mnt_pcp->mnt_count, 1); + atomic_set(&mnt->mnt_longrefs, 1); #else mnt->mnt_count = 1; mnt->mnt_writers = 0; @@ -611,21 +611,6 @@ static void attach_mnt(struct vfsmount *mnt, struct path *path) list_add_tail(&mnt->mnt_child, &path->mnt->mnt_mounts); } -static inline void __mnt_make_longterm(struct vfsmount *mnt) -{ -#ifdef CONFIG_SMP - atomic_inc(&mnt->mnt_longterm); -#endif -} - -/* needs vfsmount lock for write */ -static inline void __mnt_make_shortterm(struct vfsmount *mnt) -{ -#ifdef CONFIG_SMP - atomic_dec(&mnt->mnt_longterm); -#endif -} - /* * vfsmount lock must be held for write */ @@ -639,11 +624,8 @@ static void commit_tree(struct vfsmount *mnt) BUG_ON(parent == mnt); list_add_tail(&head, &mnt->mnt_list); - list_for_each_entry(m, &head, mnt_list) { + list_for_each_entry(m, &head, mnt_list) m->mnt_ns = n; - __mnt_make_longterm(m); - } - list_splice(&head, n->list.prev); list_add_tail(&mnt->mnt_hash, mount_hashtable + @@ -752,30 +734,51 @@ static inline void mntfree(struct vfsmount *mnt) deactivate_super(sb); } -static void mntput_no_expire(struct vfsmount *mnt) +#ifdef CONFIG_SMP +static inline void __mntput(struct vfsmount *mnt, int longrefs) { + if (!longrefs) { put_again: -#ifdef CONFIG_SMP - br_read_lock(vfsmount_lock); - if (likely(atomic_read(&mnt->mnt_longterm))) { - mnt_dec_count(mnt); + br_read_lock(vfsmount_lock); + if (likely(atomic_read(&mnt->mnt_longrefs))) { + mnt_dec_count(mnt); + br_read_unlock(vfsmount_lock); + return; + } br_read_unlock(vfsmount_lock); - return; + } else { + BUG_ON(!atomic_read(&mnt->mnt_longrefs)); + if (atomic_add_unless(&mnt->mnt_longrefs, -1, 1)) + return; } - br_read_unlock(vfsmount_lock); br_write_lock(vfsmount_lock); - mnt_dec_count(mnt); + if (!longrefs) + mnt_dec_count(mnt); + else + atomic_dec(&mnt->mnt_longrefs); if (mnt_get_count(mnt)) { br_write_unlock(vfsmount_lock); return; } + if (unlikely(mnt->mnt_pinned)) { + mnt_add_count(mnt, mnt->mnt_pinned + 1); + mnt->mnt_pinned = 0; + br_write_unlock(vfsmount_lock); + acct_auto_close_mnt(mnt); + goto put_again; + } + br_write_unlock(vfsmount_lock); + mntfree(mnt); +} #else +static inline void __mntput(struct vfsmount *mnt, int longrefs) +{ +put_again: mnt_dec_count(mnt); if (likely(mnt_get_count(mnt))) return; br_write_lock(vfsmount_lock); -#endif if (unlikely(mnt->mnt_pinned)) { mnt_add_count(mnt, mnt->mnt_pinned + 1); mnt->mnt_pinned = 0; @@ -786,6 +789,12 @@ static void mntput_no_expire(struct vfsmount *mnt) br_write_unlock(vfsmount_lock); mntfree(mnt); } +#endif + +static void mntput_no_expire(struct vfsmount *mnt) +{ + __mntput(mnt, 0); +} void mntput(struct vfsmount *mnt) { @@ -793,7 +802,7 @@ void mntput(struct vfsmount *mnt) /* avoid cacheline pingpong, hope gcc doesn't get "smart" */ if (unlikely(mnt->mnt_expiry_mark)) mnt->mnt_expiry_mark = 0; - mntput_no_expire(mnt); + __mntput(mnt, 0); } } EXPORT_SYMBOL(mntput); @@ -806,6 +815,33 @@ struct vfsmount *mntget(struct vfsmount *mnt) } EXPORT_SYMBOL(mntget); +void mntput_long(struct vfsmount *mnt) +{ +#ifdef CONFIG_SMP + if (mnt) { + /* avoid cacheline pingpong, hope gcc doesn't get "smart" */ + if (unlikely(mnt->mnt_expiry_mark)) + mnt->mnt_expiry_mark = 0; + __mntput(mnt, 1); + } +#else + mntput(mnt); +#endif +} +EXPORT_SYMBOL(mntput_long); + +struct vfsmount *mntget_long(struct vfsmount *mnt) +{ +#ifdef CONFIG_SMP + if (mnt) + atomic_inc(&mnt->mnt_longrefs); + return mnt; +#else + return mntget(mnt); +#endif +} +EXPORT_SYMBOL(mntget_long); + void mnt_pin(struct vfsmount *mnt) { br_write_lock(vfsmount_lock); @@ -1180,7 +1216,7 @@ void release_mounts(struct list_head *head) dput(dentry); mntput(m); } - mntput(mnt); + mntput_long(mnt); } } @@ -1190,21 +1226,19 @@ void release_mounts(struct list_head *head) */ void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) { - LIST_HEAD(tmp_list); struct vfsmount *p; for (p = mnt; p; p = next_mnt(p, mnt)) - list_move(&p->mnt_hash, &tmp_list); + list_move(&p->mnt_hash, kill); if (propagate) - propagate_umount(&tmp_list); + propagate_umount(kill); - list_for_each_entry(p, &tmp_list, mnt_hash) { + list_for_each_entry(p, kill, mnt_hash) { list_del_init(&p->mnt_expire); list_del_init(&p->mnt_list); __touch_mnt_namespace(p->mnt_ns); p->mnt_ns = NULL; - __mnt_make_shortterm(p); list_del_init(&p->mnt_child); if (p->mnt_parent != p) { p->mnt_parent->mnt_ghosts++; @@ -1212,7 +1246,6 @@ void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) } change_mnt_propagation(p, MS_PRIVATE); } - list_splice(&tmp_list, kill); } static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts); @@ -1811,10 +1844,9 @@ static int do_move_mount(struct path *path, char *old_name) return err; down_write(&namespace_sem); - err = follow_down(path, true); - if (err < 0) - goto out; - + while (d_mountpoint(path->dentry) && + follow_down(path)) + ; err = -EINVAL; if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt)) goto out; @@ -1872,8 +1904,6 @@ static int do_move_mount(struct path *path, char *old_name) return err; } -static int do_add_mount(struct vfsmount *, struct path *, int); - /* * create a new mount for userspace and request it to be added into the * namespace's tree @@ -1882,7 +1912,6 @@ static int do_new_mount(struct path *path, char *type, int flags, int mnt_flags, char *name, void *data) { struct vfsmount *mnt; - int err; if (!type) return -EINVAL; @@ -1895,47 +1924,15 @@ static int do_new_mount(struct path *path, char *type, int flags, if (IS_ERR(mnt)) return PTR_ERR(mnt); - err = do_add_mount(mnt, path, mnt_flags); - if (err) - mntput(mnt); - return err; -} - -int finish_automount(struct vfsmount *m, struct path *path) -{ - int err; - /* The new mount record should have at least 2 refs to prevent it being - * expired before we get a chance to add it - */ - BUG_ON(mnt_get_count(m) < 2); - - if (m->mnt_sb == path->mnt->mnt_sb && - m->mnt_root == path->dentry) { - err = -ELOOP; - goto fail; - } - - err = do_add_mount(m, path, path->mnt->mnt_flags | MNT_SHRINKABLE); - if (!err) - return 0; -fail: - /* remove m from any expiration list it may be on */ - if (!list_empty(&m->mnt_expire)) { - down_write(&namespace_sem); - br_write_lock(vfsmount_lock); - list_del_init(&m->mnt_expire); - br_write_unlock(vfsmount_lock); - up_write(&namespace_sem); - } - mntput(m); - mntput(m); - return err; + return do_add_mount(mnt, path, mnt_flags, NULL); } /* * add a mount into a namespace's mount tree + * - provide the option of adding the new mount to an expiration list */ -static int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flags) +int do_add_mount(struct vfsmount *newmnt, struct path *path, + int mnt_flags, struct list_head *fslist) { int err; @@ -1943,10 +1940,9 @@ static int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flag down_write(&namespace_sem); /* Something was mounted here while we slept */ - err = follow_down(path, true); - if (err < 0) - goto unlock; - + while (d_mountpoint(path->dentry) && + follow_down(path)) + ; err = -EINVAL; if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt)) goto unlock; @@ -1962,29 +1958,22 @@ static int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flag goto unlock; newmnt->mnt_flags = mnt_flags; - err = graft_tree(newmnt, path); + if ((err = graft_tree(newmnt, path))) + goto unlock; + + if (fslist) /* add to the specified expiration list */ + list_add_tail(&newmnt->mnt_expire, fslist); + + up_write(&namespace_sem); + return 0; unlock: up_write(&namespace_sem); + mntput_long(newmnt); return err; } -/** - * mnt_set_expiry - Put a mount on an expiration list - * @mnt: The mount to list. - * @expiry_list: The list to add the mount to. - */ -void mnt_set_expiry(struct vfsmount *mnt, struct list_head *expiry_list) -{ - down_write(&namespace_sem); - br_write_lock(vfsmount_lock); - - list_add_tail(&mnt->mnt_expire, expiry_list); - - br_write_unlock(vfsmount_lock); - up_write(&namespace_sem); -} -EXPORT_SYMBOL(mnt_set_expiry); +EXPORT_SYMBOL_GPL(do_add_mount); /* * process a list of expirable mountpoints with the intent of discarding any @@ -2273,22 +2262,6 @@ static struct mnt_namespace *alloc_mnt_ns(void) return new_ns; } -void mnt_make_longterm(struct vfsmount *mnt) -{ - __mnt_make_longterm(mnt); -} - -void mnt_make_shortterm(struct vfsmount *mnt) -{ -#ifdef CONFIG_SMP - if (atomic_add_unless(&mnt->mnt_longterm, -1, 1)) - return; - br_write_lock(vfsmount_lock); - atomic_dec(&mnt->mnt_longterm); - br_write_unlock(vfsmount_lock); -#endif -} - /* * Allocate a new namespace structure and populate it with contents * copied from the namespace of the passed in task structure. @@ -2326,19 +2299,14 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, q = new_ns->root; while (p) { q->mnt_ns = new_ns; - __mnt_make_longterm(q); if (fs) { if (p == fs->root.mnt) { - fs->root.mnt = mntget(q); - __mnt_make_longterm(q); - mnt_make_shortterm(p); rootmnt = p; + fs->root.mnt = mntget_long(q); } if (p == fs->pwd.mnt) { - fs->pwd.mnt = mntget(q); - __mnt_make_longterm(q); - mnt_make_shortterm(p); pwdmnt = p; + fs->pwd.mnt = mntget_long(q); } } p = next_mnt(p, mnt_ns->root); @@ -2347,9 +2315,9 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, up_write(&namespace_sem); if (rootmnt) - mntput(rootmnt); + mntput_long(rootmnt); if (pwdmnt) - mntput(pwdmnt); + mntput_long(pwdmnt); return new_ns; } @@ -2382,7 +2350,6 @@ struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt) new_ns = alloc_mnt_ns(); if (!IS_ERR(new_ns)) { mnt->mnt_ns = new_ns; - __mnt_make_longterm(mnt); new_ns->root = mnt; list_add(&new_ns->list, &new_ns->root->mnt_list); } diff --git a/trunk/fs/nfs/dir.c b/trunk/fs/nfs/dir.c index 2c3eb33b904d..df8c03a02161 100644 --- a/trunk/fs/nfs/dir.c +++ b/trunk/fs/nfs/dir.c @@ -970,7 +970,7 @@ int nfs_lookup_verify_inode(struct inode *inode, struct nameidata *nd) { struct nfs_server *server = NFS_SERVER(inode); - if (IS_AUTOMOUNT(inode)) + if (test_bit(NFS_INO_MOUNTPOINT, &NFS_I(inode)->flags)) return 0; if (nd != NULL) { /* VFS wants an on-the-wire revalidation */ @@ -1173,7 +1173,6 @@ const struct dentry_operations nfs_dentry_operations = { .d_revalidate = nfs_lookup_revalidate, .d_delete = nfs_dentry_delete, .d_iput = nfs_dentry_iput, - .d_automount = nfs_d_automount, }; static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) @@ -1247,7 +1246,6 @@ const struct dentry_operations nfs4_dentry_operations = { .d_revalidate = nfs_open_revalidate, .d_delete = nfs_dentry_delete, .d_iput = nfs_dentry_iput, - .d_automount = nfs_d_automount, }; /* diff --git a/trunk/fs/nfs/inode.c b/trunk/fs/nfs/inode.c index d8512423ba72..ce00b704452c 100644 --- a/trunk/fs/nfs/inode.c +++ b/trunk/fs/nfs/inode.c @@ -300,7 +300,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) else inode->i_op = &nfs_mountpoint_inode_operations; inode->i_fop = NULL; - inode->i_flags |= S_AUTOMOUNT; + set_bit(NFS_INO_MOUNTPOINT, &nfsi->flags); } } else if (S_ISLNK(inode->i_mode)) inode->i_op = &nfs_symlink_inode_operations; @@ -1208,7 +1208,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) /* Update the fsid? */ if (S_ISDIR(inode->i_mode) && (fattr->valid & NFS_ATTR_FATTR_FSID) && !nfs_fsid_equal(&server->fsid, &fattr->fsid) && - !IS_AUTOMOUNT(inode)) + !test_bit(NFS_INO_MOUNTPOINT, &nfsi->flags)) server->fsid = fattr->fsid; /* diff --git a/trunk/fs/nfs/internal.h b/trunk/fs/nfs/internal.h index 4644f04b4b46..bfa3a34af801 100644 --- a/trunk/fs/nfs/internal.h +++ b/trunk/fs/nfs/internal.h @@ -252,7 +252,6 @@ extern char *nfs_path(const char *base, const struct dentry *droot, const struct dentry *dentry, char *buffer, ssize_t buflen); -extern struct vfsmount *nfs_d_automount(struct path *path); /* getroot.c */ extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *); diff --git a/trunk/fs/nfs/namespace.c b/trunk/fs/nfs/namespace.c index f32b8603dca8..74aaf3963c10 100644 --- a/trunk/fs/nfs/namespace.c +++ b/trunk/fs/nfs/namespace.c @@ -97,8 +97,9 @@ char *nfs_path(const char *base, } /* - * nfs_d_automount - Handle crossing a mountpoint on the server - * @path - The mountpoint + * nfs_follow_mountpoint - handle crossing a mountpoint on the server + * @dentry - dentry of mountpoint + * @nd - nameidata info * * When we encounter a mountpoint on the server, we want to set up * a mountpoint on the client too, to prevent inode numbers from @@ -108,65 +109,87 @@ char *nfs_path(const char *base, * situation, and that different filesystems may want to use * different security flavours. */ -struct vfsmount *nfs_d_automount(struct path *path) +static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) { struct vfsmount *mnt; - struct nfs_server *server = NFS_SERVER(path->dentry->d_inode); + struct nfs_server *server = NFS_SERVER(dentry->d_inode); struct dentry *parent; struct nfs_fh *fh = NULL; struct nfs_fattr *fattr = NULL; int err; - dprintk("--> nfs_d_automount()\n"); + dprintk("--> nfs_follow_mountpoint()\n"); - mnt = ERR_PTR(-ESTALE); - if (IS_ROOT(path->dentry)) - goto out_nofree; + err = -ESTALE; + if (IS_ROOT(dentry)) + goto out_err; - mnt = ERR_PTR(-ENOMEM); + err = -ENOMEM; fh = nfs_alloc_fhandle(); fattr = nfs_alloc_fattr(); if (fh == NULL || fattr == NULL) - goto out; + goto out_err; dprintk("%s: enter\n", __func__); + dput(nd->path.dentry); + nd->path.dentry = dget(dentry); - /* Look it up again to get its attributes */ - parent = dget_parent(path->dentry); + /* Look it up again */ + parent = dget_parent(nd->path.dentry); err = server->nfs_client->rpc_ops->lookup(parent->d_inode, - &path->dentry->d_name, + &nd->path.dentry->d_name, fh, fattr); dput(parent); - if (err != 0) { - mnt = ERR_PTR(err); - goto out; - } + if (err != 0) + goto out_err; if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) - mnt = nfs_do_refmount(path->mnt, path->dentry); + mnt = nfs_do_refmount(nd->path.mnt, nd->path.dentry); else - mnt = nfs_do_submount(path->mnt, path->dentry, fh, fattr); + mnt = nfs_do_submount(nd->path.mnt, nd->path.dentry, fh, + fattr); + err = PTR_ERR(mnt); if (IS_ERR(mnt)) - goto out; + goto out_err; - dprintk("%s: done, success\n", __func__); - mntget(mnt); /* prevent immediate expiration */ - mnt_set_expiry(mnt, &nfs_automount_list); + mntget(mnt); + err = do_add_mount(mnt, &nd->path, nd->path.mnt->mnt_flags|MNT_SHRINKABLE, + &nfs_automount_list); + if (err < 0) { + mntput(mnt); + if (err == -EBUSY) + goto out_follow; + goto out_err; + } + path_put(&nd->path); + nd->path.mnt = mnt; + nd->path.dentry = dget(mnt->mnt_root); schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); - out: nfs_free_fattr(fattr); nfs_free_fhandle(fh); -out_nofree: - dprintk("<-- nfs_follow_mountpoint() = %p\n", mnt); - return mnt; + dprintk("%s: done, returned %d\n", __func__, err); + + dprintk("<-- nfs_follow_mountpoint() = %d\n", err); + return ERR_PTR(err); +out_err: + path_put(&nd->path); + goto out; +out_follow: + while (d_mountpoint(nd->path.dentry) && + follow_down(&nd->path)) + ; + err = 0; + goto out; } const struct inode_operations nfs_mountpoint_inode_operations = { + .follow_link = nfs_follow_mountpoint, .getattr = nfs_getattr, }; const struct inode_operations nfs_referral_inode_operations = { + .follow_link = nfs_follow_mountpoint, }; static void nfs_expire_automounts(struct work_struct *work) diff --git a/trunk/fs/nfsd/vfs.c b/trunk/fs/nfsd/vfs.c index 641117f2188d..a3c7f701395a 100644 --- a/trunk/fs/nfsd/vfs.c +++ b/trunk/fs/nfsd/vfs.c @@ -87,9 +87,8 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, .dentry = dget(dentry)}; int err = 0; - err = follow_down(&path, false); - if (err < 0) - goto out; + while (d_mountpoint(path.dentry) && follow_down(&path)) + ; exp2 = rqst_exp_get_by_name(rqstp, &path); if (IS_ERR(exp2)) { diff --git a/trunk/fs/ocfs2/Kconfig b/trunk/fs/ocfs2/Kconfig index 77a8de5f7119..ab152c00cd3a 100644 --- a/trunk/fs/ocfs2/Kconfig +++ b/trunk/fs/ocfs2/Kconfig @@ -1,6 +1,7 @@ config OCFS2_FS tristate "OCFS2 file system support" - depends on NET && SYSFS && CONFIGFS_FS + depends on NET && SYSFS + select CONFIGFS_FS select JBD2 select CRC32 select QUOTA diff --git a/trunk/fs/ocfs2/file.c b/trunk/fs/ocfs2/file.c index a6651956482e..63e3fca266e0 100644 --- a/trunk/fs/ocfs2/file.c +++ b/trunk/fs/ocfs2/file.c @@ -1989,20 +1989,20 @@ int ocfs2_change_file_space(struct file *file, unsigned int cmd, return __ocfs2_change_file_space(file, inode, file->f_pos, cmd, sr, 0); } -static long ocfs2_fallocate(struct file *file, int mode, loff_t offset, +static long ocfs2_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len) { - struct inode *inode = file->f_path.dentry->d_inode; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); struct ocfs2_space_resv sr; int change_size = 1; int cmd = OCFS2_IOC_RESVSP64; - if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) - return -EOPNOTSUPP; if (!ocfs2_writes_unwritten_extents(osb)) return -EOPNOTSUPP; + if (S_ISDIR(inode->i_mode)) + return -ENODEV; + if (mode & FALLOC_FL_KEEP_SIZE) change_size = 0; @@ -2610,6 +2610,7 @@ const struct inode_operations ocfs2_file_iops = { .getxattr = generic_getxattr, .listxattr = ocfs2_listxattr, .removexattr = generic_removexattr, + .fallocate = ocfs2_fallocate, .fiemap = ocfs2_fiemap, }; @@ -2641,7 +2642,6 @@ const struct file_operations ocfs2_fops = { .flock = ocfs2_flock, .splice_read = ocfs2_file_splice_read, .splice_write = ocfs2_file_splice_write, - .fallocate = ocfs2_fallocate, }; const struct file_operations ocfs2_dops = { diff --git a/trunk/fs/open.c b/trunk/fs/open.c index e52389e1f05b..5b6ef7e2859e 100644 --- a/trunk/fs/open.c +++ b/trunk/fs/open.c @@ -255,10 +255,10 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len) if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0)) return -EFBIG; - if (!file->f_op->fallocate) + if (!inode->i_op->fallocate) return -EOPNOTSUPP; - return file->f_op->fallocate(file, mode, offset, len); + return inode->i_op->fallocate(inode, mode, offset, len); } SYSCALL_DEFINE(fallocate)(int fd, int mode, loff_t offset, loff_t len) diff --git a/trunk/fs/pipe.c b/trunk/fs/pipe.c index 89e9e19b1b2e..e2e95fb46a1e 100644 --- a/trunk/fs/pipe.c +++ b/trunk/fs/pipe.c @@ -1292,7 +1292,7 @@ static int __init init_pipe_fs(void) static void __exit exit_pipe_fs(void) { unregister_filesystem(&pipe_fs_type); - mntput(pipe_mnt); + mntput_long(pipe_mnt); } fs_initcall(init_pipe_fs); diff --git a/trunk/fs/squashfs/Kconfig b/trunk/fs/squashfs/Kconfig index aa68a8a31518..e5f63da64d04 100644 --- a/trunk/fs/squashfs/Kconfig +++ b/trunk/fs/squashfs/Kconfig @@ -29,6 +29,7 @@ config SQUASHFS config SQUASHFS_XATTR bool "Squashfs XATTR support" depends on SQUASHFS + default n help Saying Y here includes support for extended attributes (xattrs). Xattrs are name:value pairs associated with inodes by @@ -39,6 +40,7 @@ config SQUASHFS_XATTR config SQUASHFS_LZO bool "Include support for LZO compressed file systems" depends on SQUASHFS + default n select LZO_DECOMPRESS help Saying Y here includes support for reading Squashfs file systems @@ -51,24 +53,10 @@ config SQUASHFS_LZO If unsure, say N. -config SQUASHFS_XZ - bool "Include support for XZ compressed file systems" - depends on SQUASHFS - select XZ_DEC - help - Saying Y here includes support for reading Squashfs file systems - compressed with XZ compresssion. XZ gives better compression than - the default zlib compression, at the expense of greater CPU and - memory overhead. - - XZ is not the standard compression used in Squashfs and so most - file systems will be readable without selecting this option. - - If unsure, say N. - config SQUASHFS_EMBEDDED bool "Additional option for memory-constrained systems" depends on SQUASHFS + default n help Saying Y here allows you to specify cache size. diff --git a/trunk/fs/squashfs/Makefile b/trunk/fs/squashfs/Makefile index cecf2bea07af..7672bac8d328 100644 --- a/trunk/fs/squashfs/Makefile +++ b/trunk/fs/squashfs/Makefile @@ -7,4 +7,3 @@ squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o squashfs-$(CONFIG_SQUASHFS_XATTR) += xattr.o xattr_id.o squashfs-$(CONFIG_SQUASHFS_LZO) += lzo_wrapper.o -squashfs-$(CONFIG_SQUASHFS_XZ) += xz_wrapper.o diff --git a/trunk/fs/squashfs/block.c b/trunk/fs/squashfs/block.c index 2fb2882f0fa7..653c030eb840 100644 --- a/trunk/fs/squashfs/block.c +++ b/trunk/fs/squashfs/block.c @@ -34,6 +34,7 @@ #include "squashfs_fs.h" #include "squashfs_fs_sb.h" +#include "squashfs_fs_i.h" #include "squashfs.h" #include "decompressor.h" diff --git a/trunk/fs/squashfs/cache.c b/trunk/fs/squashfs/cache.c index 26b15ae34d6f..57314bee9059 100644 --- a/trunk/fs/squashfs/cache.c +++ b/trunk/fs/squashfs/cache.c @@ -55,6 +55,7 @@ #include "squashfs_fs.h" #include "squashfs_fs_sb.h" +#include "squashfs_fs_i.h" #include "squashfs.h" /* diff --git a/trunk/fs/squashfs/decompressor.c b/trunk/fs/squashfs/decompressor.c index a5940e54c4dd..24af9ce9722f 100644 --- a/trunk/fs/squashfs/decompressor.c +++ b/trunk/fs/squashfs/decompressor.c @@ -27,6 +27,7 @@ #include "squashfs_fs.h" #include "squashfs_fs_sb.h" +#include "squashfs_fs_i.h" #include "decompressor.h" #include "squashfs.h" @@ -40,26 +41,23 @@ static const struct squashfs_decompressor squashfs_lzma_unsupported_comp_ops = { }; #ifndef CONFIG_SQUASHFS_LZO -static const struct squashfs_decompressor squashfs_lzo_comp_ops = { +static const struct squashfs_decompressor squashfs_lzo_unsupported_comp_ops = { NULL, NULL, NULL, LZO_COMPRESSION, "lzo", 0 }; #endif -#ifndef CONFIG_SQUASHFS_XZ -static const struct squashfs_decompressor squashfs_xz_comp_ops = { - NULL, NULL, NULL, XZ_COMPRESSION, "xz", 0 -}; -#endif - static const struct squashfs_decompressor squashfs_unknown_comp_ops = { NULL, NULL, NULL, 0, "unknown", 0 }; static const struct squashfs_decompressor *decompressor[] = { &squashfs_zlib_comp_ops, - &squashfs_lzo_comp_ops, - &squashfs_xz_comp_ops, &squashfs_lzma_unsupported_comp_ops, +#ifdef CONFIG_SQUASHFS_LZO + &squashfs_lzo_comp_ops, +#else + &squashfs_lzo_unsupported_comp_ops, +#endif &squashfs_unknown_comp_ops }; diff --git a/trunk/fs/squashfs/decompressor.h b/trunk/fs/squashfs/decompressor.h index 3b305a70f7aa..7425f80783f6 100644 --- a/trunk/fs/squashfs/decompressor.h +++ b/trunk/fs/squashfs/decompressor.h @@ -52,13 +52,4 @@ static inline int squashfs_decompress(struct squashfs_sb_info *msblk, return msblk->decompressor->decompress(msblk, buffer, bh, b, offset, length, srclength, pages); } - -#ifdef CONFIG_SQUASHFS_XZ -extern const struct squashfs_decompressor squashfs_xz_comp_ops; -#endif - -#ifdef CONFIG_SQUASHFS_LZO -extern const struct squashfs_decompressor squashfs_lzo_comp_ops; -#endif - #endif diff --git a/trunk/fs/squashfs/fragment.c b/trunk/fs/squashfs/fragment.c index 7eef571443c6..7c90bbd6879d 100644 --- a/trunk/fs/squashfs/fragment.c +++ b/trunk/fs/squashfs/fragment.c @@ -39,6 +39,7 @@ #include "squashfs_fs.h" #include "squashfs_fs_sb.h" +#include "squashfs_fs_i.h" #include "squashfs.h" /* diff --git a/trunk/fs/squashfs/id.c b/trunk/fs/squashfs/id.c index d8f32452638e..b7f64bcd2b70 100644 --- a/trunk/fs/squashfs/id.c +++ b/trunk/fs/squashfs/id.c @@ -37,6 +37,7 @@ #include "squashfs_fs.h" #include "squashfs_fs_sb.h" +#include "squashfs_fs_i.h" #include "squashfs.h" /* diff --git a/trunk/fs/squashfs/lzo_wrapper.c b/trunk/fs/squashfs/lzo_wrapper.c index 7da759e34c52..5d87789bf1c1 100644 --- a/trunk/fs/squashfs/lzo_wrapper.c +++ b/trunk/fs/squashfs/lzo_wrapper.c @@ -29,6 +29,7 @@ #include "squashfs_fs.h" #include "squashfs_fs_sb.h" +#include "squashfs_fs_i.h" #include "squashfs.h" #include "decompressor.h" diff --git a/trunk/fs/squashfs/squashfs.h b/trunk/fs/squashfs/squashfs.h index ba729d808876..5d45569d5f72 100644 --- a/trunk/fs/squashfs/squashfs.h +++ b/trunk/fs/squashfs/squashfs.h @@ -27,6 +27,11 @@ #define WARNING(s, args...) pr_warning("SQUASHFS: "s, ## args) +static inline struct squashfs_inode_info *squashfs_i(struct inode *inode) +{ + return list_entry(inode, struct squashfs_inode_info, vfs_inode); +} + /* block.c */ extern int squashfs_read_data(struct super_block *, void **, u64, int, u64 *, int, int); @@ -99,3 +104,6 @@ extern const struct xattr_handler *squashfs_xattr_handlers[]; /* zlib_wrapper.c */ extern const struct squashfs_decompressor squashfs_zlib_comp_ops; + +/* lzo_wrapper.c */ +extern const struct squashfs_decompressor squashfs_lzo_comp_ops; diff --git a/trunk/fs/squashfs/squashfs_fs.h b/trunk/fs/squashfs/squashfs_fs.h index 39533feffd6d..c5137fc9ab11 100644 --- a/trunk/fs/squashfs/squashfs_fs.h +++ b/trunk/fs/squashfs/squashfs_fs.h @@ -238,7 +238,6 @@ struct meta_index { #define ZLIB_COMPRESSION 1 #define LZMA_COMPRESSION 2 #define LZO_COMPRESSION 3 -#define XZ_COMPRESSION 4 struct squashfs_super_block { __le32 s_magic; diff --git a/trunk/fs/squashfs/squashfs_fs_i.h b/trunk/fs/squashfs/squashfs_fs_i.h index 359baefc01fc..d3e3a37f28a1 100644 --- a/trunk/fs/squashfs/squashfs_fs_i.h +++ b/trunk/fs/squashfs/squashfs_fs_i.h @@ -45,10 +45,4 @@ struct squashfs_inode_info { }; struct inode vfs_inode; }; - - -static inline struct squashfs_inode_info *squashfs_i(struct inode *inode) -{ - return list_entry(inode, struct squashfs_inode_info, vfs_inode); -} #endif diff --git a/trunk/fs/squashfs/xattr_id.c b/trunk/fs/squashfs/xattr_id.c index 05385dbe1465..d33be5dd6c32 100644 --- a/trunk/fs/squashfs/xattr_id.c +++ b/trunk/fs/squashfs/xattr_id.c @@ -32,6 +32,7 @@ #include "squashfs_fs.h" #include "squashfs_fs_sb.h" +#include "squashfs_fs_i.h" #include "squashfs.h" #include "xattr.h" diff --git a/trunk/fs/squashfs/xz_wrapper.c b/trunk/fs/squashfs/xz_wrapper.c deleted file mode 100644 index 856756ca5ee4..000000000000 --- a/trunk/fs/squashfs/xz_wrapper.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Squashfs - a compressed read only filesystem for Linux - * - * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 - * Phillip Lougher - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2, - * or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * xz_wrapper.c - */ - - -#include -#include -#include -#include - -#include "squashfs_fs.h" -#include "squashfs_fs_sb.h" -#include "squashfs_fs_i.h" -#include "squashfs.h" -#include "decompressor.h" - -struct squashfs_xz { - struct xz_dec *state; - struct xz_buf buf; -}; - -static void *squashfs_xz_init(struct squashfs_sb_info *msblk) -{ - int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE); - - struct squashfs_xz *stream = kmalloc(sizeof(*stream), GFP_KERNEL); - if (stream == NULL) - goto failed; - - stream->state = xz_dec_init(XZ_PREALLOC, block_size); - if (stream->state == NULL) - goto failed; - - return stream; - -failed: - ERROR("Failed to allocate xz workspace\n"); - kfree(stream); - return NULL; -} - - -static void squashfs_xz_free(void *strm) -{ - struct squashfs_xz *stream = strm; - - if (stream) { - xz_dec_end(stream->state); - kfree(stream); - } -} - - -static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void **buffer, - struct buffer_head **bh, int b, int offset, int length, int srclength, - int pages) -{ - enum xz_ret xz_err; - int avail, total = 0, k = 0, page = 0; - struct squashfs_xz *stream = msblk->stream; - - mutex_lock(&msblk->read_data_mutex); - - xz_dec_reset(stream->state); - stream->buf.in_pos = 0; - stream->buf.in_size = 0; - stream->buf.out_pos = 0; - stream->buf.out_size = PAGE_CACHE_SIZE; - stream->buf.out = buffer[page++]; - - do { - if (stream->buf.in_pos == stream->buf.in_size && k < b) { - avail = min(length, msblk->devblksize - offset); - length -= avail; - wait_on_buffer(bh[k]); - if (!buffer_uptodate(bh[k])) - goto release_mutex; - - if (avail == 0) { - offset = 0; - put_bh(bh[k++]); - continue; - } - - stream->buf.in = bh[k]->b_data + offset; - stream->buf.in_size = avail; - stream->buf.in_pos = 0; - offset = 0; - } - - if (stream->buf.out_pos == stream->buf.out_size - && page < pages) { - stream->buf.out = buffer[page++]; - stream->buf.out_pos = 0; - total += PAGE_CACHE_SIZE; - } - - xz_err = xz_dec_run(stream->state, &stream->buf); - - if (stream->buf.in_pos == stream->buf.in_size && k < b) - put_bh(bh[k++]); - } while (xz_err == XZ_OK); - - if (xz_err != XZ_STREAM_END) { - ERROR("xz_dec_run error, data probably corrupt\n"); - goto release_mutex; - } - - if (k < b) { - ERROR("xz_uncompress error, input remaining\n"); - goto release_mutex; - } - - total += stream->buf.out_pos; - mutex_unlock(&msblk->read_data_mutex); - return total; - -release_mutex: - mutex_unlock(&msblk->read_data_mutex); - - for (; k < b; k++) - put_bh(bh[k]); - - return -EIO; -} - -const struct squashfs_decompressor squashfs_xz_comp_ops = { - .init = squashfs_xz_init, - .free = squashfs_xz_free, - .decompress = squashfs_xz_uncompress, - .id = XZ_COMPRESSION, - .name = "xz", - .supported = 1 -}; diff --git a/trunk/fs/squashfs/zlib_wrapper.c b/trunk/fs/squashfs/zlib_wrapper.c index 818a5e063faf..7a603874e483 100644 --- a/trunk/fs/squashfs/zlib_wrapper.c +++ b/trunk/fs/squashfs/zlib_wrapper.c @@ -29,6 +29,7 @@ #include "squashfs_fs.h" #include "squashfs_fs_sb.h" +#include "squashfs_fs_i.h" #include "squashfs.h" #include "decompressor.h" @@ -65,8 +66,8 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer, struct buffer_head **bh, int b, int offset, int length, int srclength, int pages) { - int zlib_err, zlib_init = 0; - int k = 0, page = 0; + int zlib_err = 0, zlib_init = 0; + int avail, bytes, k = 0, page = 0; z_stream *stream = msblk->stream; mutex_lock(&msblk->read_data_mutex); @@ -74,10 +75,11 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer, stream->avail_out = 0; stream->avail_in = 0; + bytes = length; do { if (stream->avail_in == 0 && k < b) { - int avail = min(length, msblk->devblksize - offset); - length -= avail; + avail = min(bytes, msblk->devblksize - offset); + bytes -= avail; wait_on_buffer(bh[k]); if (!buffer_uptodate(bh[k])) goto release_mutex; @@ -126,11 +128,6 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer, goto release_mutex; } - if (k < b) { - ERROR("zlib_uncompress error, data remaining\n"); - goto release_mutex; - } - length = stream->total_out; mutex_unlock(&msblk->read_data_mutex); return length; diff --git a/trunk/fs/stat.c b/trunk/fs/stat.c index d5c61cf2b703..12e90e213900 100644 --- a/trunk/fs/stat.c +++ b/trunk/fs/stat.c @@ -75,13 +75,11 @@ int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat, int error = -EINVAL; int lookup_flags = 0; - if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT)) != 0) + if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0) goto out; if (!(flag & AT_SYMLINK_NOFOLLOW)) lookup_flags |= LOOKUP_FOLLOW; - if (flag & AT_NO_AUTOMOUNT) - lookup_flags |= LOOKUP_NO_AUTOMOUNT; error = user_path_at(dfd, filename, lookup_flags, &path); if (error) diff --git a/trunk/fs/super.c b/trunk/fs/super.c index 74e149efed81..4f6a3571a634 100644 --- a/trunk/fs/super.c +++ b/trunk/fs/super.c @@ -1141,7 +1141,7 @@ static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype) return mnt; err: - mntput(mnt); + mntput_long(mnt); return ERR_PTR(err); } diff --git a/trunk/fs/xfs/linux-2.6/xfs_file.c b/trunk/fs/xfs/linux-2.6/xfs_file.c index a55c1b46b219..ef51eb43e137 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_file.c +++ b/trunk/fs/xfs/linux-2.6/xfs_file.c @@ -37,7 +37,6 @@ #include "xfs_trace.h" #include -#include static const struct vm_operations_struct xfs_file_vm_ops; @@ -883,60 +882,6 @@ xfs_file_aio_write( return ret; } -STATIC long -xfs_file_fallocate( - struct file *file, - int mode, - loff_t offset, - loff_t len) -{ - struct inode *inode = file->f_path.dentry->d_inode; - long error; - loff_t new_size = 0; - xfs_flock64_t bf; - xfs_inode_t *ip = XFS_I(inode); - int cmd = XFS_IOC_RESVSP; - - if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) - return -EOPNOTSUPP; - - bf.l_whence = 0; - bf.l_start = offset; - bf.l_len = len; - - xfs_ilock(ip, XFS_IOLOCK_EXCL); - - if (mode & FALLOC_FL_PUNCH_HOLE) - cmd = XFS_IOC_UNRESVSP; - - /* check the new inode size is valid before allocating */ - if (!(mode & FALLOC_FL_KEEP_SIZE) && - offset + len > i_size_read(inode)) { - new_size = offset + len; - error = inode_newsize_ok(inode, new_size); - if (error) - goto out_unlock; - } - - error = -xfs_change_file_space(ip, cmd, &bf, 0, XFS_ATTR_NOLOCK); - if (error) - goto out_unlock; - - /* Change file size if needed */ - if (new_size) { - struct iattr iattr; - - iattr.ia_valid = ATTR_SIZE; - iattr.ia_size = new_size; - error = -xfs_setattr(ip, &iattr, XFS_ATTR_NOLOCK); - } - -out_unlock: - xfs_iunlock(ip, XFS_IOLOCK_EXCL); - return error; -} - - STATIC int xfs_file_open( struct inode *inode, @@ -1055,7 +1000,6 @@ const struct file_operations xfs_file_operations = { .open = xfs_file_open, .release = xfs_file_release, .fsync = xfs_file_fsync, - .fallocate = xfs_file_fallocate, }; const struct file_operations xfs_dir_file_operations = { diff --git a/trunk/fs/xfs/linux-2.6/xfs_iops.c b/trunk/fs/xfs/linux-2.6/xfs_iops.c index bd5727852fd6..da54403633b6 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_iops.c +++ b/trunk/fs/xfs/linux-2.6/xfs_iops.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -504,6 +505,61 @@ xfs_vn_setattr( return -xfs_setattr(XFS_I(dentry->d_inode), iattr, 0); } +STATIC long +xfs_vn_fallocate( + struct inode *inode, + int mode, + loff_t offset, + loff_t len) +{ + long error; + loff_t new_size = 0; + xfs_flock64_t bf; + xfs_inode_t *ip = XFS_I(inode); + int cmd = XFS_IOC_RESVSP; + + /* preallocation on directories not yet supported */ + error = -ENODEV; + if (S_ISDIR(inode->i_mode)) + goto out_error; + + bf.l_whence = 0; + bf.l_start = offset; + bf.l_len = len; + + xfs_ilock(ip, XFS_IOLOCK_EXCL); + + if (mode & FALLOC_FL_PUNCH_HOLE) + cmd = XFS_IOC_UNRESVSP; + + /* check the new inode size is valid before allocating */ + if (!(mode & FALLOC_FL_KEEP_SIZE) && + offset + len > i_size_read(inode)) { + new_size = offset + len; + error = inode_newsize_ok(inode, new_size); + if (error) + goto out_unlock; + } + + error = -xfs_change_file_space(ip, cmd, &bf, 0, XFS_ATTR_NOLOCK); + if (error) + goto out_unlock; + + /* Change file size if needed */ + if (new_size) { + struct iattr iattr; + + iattr.ia_valid = ATTR_SIZE; + iattr.ia_size = new_size; + error = -xfs_setattr(ip, &iattr, XFS_ATTR_NOLOCK); + } + +out_unlock: + xfs_iunlock(ip, XFS_IOLOCK_EXCL); +out_error: + return error; +} + #define XFS_FIEMAP_FLAGS (FIEMAP_FLAG_SYNC|FIEMAP_FLAG_XATTR) /* @@ -597,6 +653,7 @@ static const struct inode_operations xfs_inode_operations = { .getxattr = generic_getxattr, .removexattr = generic_removexattr, .listxattr = xfs_vn_listxattr, + .fallocate = xfs_vn_fallocate, .fiemap = xfs_vn_fiemap, }; diff --git a/trunk/include/asm-generic/pgtable.h b/trunk/include/asm-generic/pgtable.h index 31b6188df221..f1eddf71dd0c 100644 --- a/trunk/include/asm-generic/pgtable.h +++ b/trunk/include/asm-generic/pgtable.h @@ -87,6 +87,14 @@ static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm, pmd_clear(mm, address, pmdp); return pmd; }) +#else /* CONFIG_TRANSPARENT_HUGEPAGE */ +static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm, + unsigned long address, + pmd_t *pmdp) +{ + BUG(); + return __pmd(0); +} #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ #endif @@ -155,9 +163,9 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm, #endif #ifndef __HAVE_ARCH_PMDP_SPLITTING_FLUSH -extern pmd_t pmdp_splitting_flush(struct vm_area_struct *vma, - unsigned long address, - pmd_t *pmdp); +extern pmd_t pmdp_clear_flush(struct vm_area_struct *vma, + unsigned long address, + pmd_t *pmdp); #endif #ifndef __HAVE_ARCH_PTE_SAME diff --git a/trunk/include/linux/amba/pl08x.h b/trunk/include/linux/amba/pl08x.h index 3111385b8ca7..521a0f8974ac 100644 --- a/trunk/include/linux/amba/pl08x.h +++ b/trunk/include/linux/amba/pl08x.h @@ -12,6 +12,7 @@ * * Please credit ARM.com * Documentation: ARM DDI 0196D + * */ #ifndef AMBA_PL08X_H @@ -21,15 +22,6 @@ #include #include -struct pl08x_lli; -struct pl08x_driver_data; - -/* Bitmasks for selecting AHB ports for DMA transfers */ -enum { - PL08X_AHB1 = (1 << 0), - PL08X_AHB2 = (1 << 1) -}; - /** * struct pl08x_channel_data - data structure to pass info between * platform and PL08x driver regarding channel configuration @@ -54,10 +46,8 @@ enum { * @circular_buffer: whether the buffer passed in is circular and * shall simply be looped round round (like a record baby round * round round round) - * @single: the device connected to this channel will request single DMA - * transfers, not bursts. (Bursts are default.) - * @periph_buses: the device connected to this channel is accessible via - * these buses (use PL08X_AHB1 | PL08X_AHB2). + * @single: the device connected to this channel will request single + * DMA transfers, not bursts. (Bursts are default.) */ struct pl08x_channel_data { char *bus_id; @@ -65,10 +55,10 @@ struct pl08x_channel_data { int max_signal; u32 muxval; u32 cctl; + u32 ccfg; dma_addr_t addr; bool circular_buffer; bool single; - u8 periph_buses; }; /** @@ -77,23 +67,24 @@ struct pl08x_channel_data { * @addr: current address * @maxwidth: the maximum width of a transfer on this bus * @buswidth: the width of this bus in bytes: 1, 2 or 4 - * @fill_bytes: bytes required to fill to the next bus memory boundary + * @fill_bytes: bytes required to fill to the next bus memory + * boundary */ struct pl08x_bus_data { dma_addr_t addr; u8 maxwidth; u8 buswidth; - size_t fill_bytes; + u32 fill_bytes; }; /** * struct pl08x_phy_chan - holder for the physical channels * @id: physical index to this channel * @lock: a lock to use when altering an instance of this struct - * @signal: the physical signal (aka channel) serving this physical channel - * right now - * @serving: the virtual channel currently being served by this physical - * channel + * @signal: the physical signal (aka channel) serving this + * physical channel right now + * @serving: the virtual channel currently being served by this + * physical channel */ struct pl08x_phy_chan { unsigned int id; @@ -101,6 +92,11 @@ struct pl08x_phy_chan { spinlock_t lock; int signal; struct pl08x_dma_chan *serving; + u32 csrc; + u32 cdst; + u32 clli; + u32 cctl; + u32 ccfg; }; /** @@ -112,23 +108,26 @@ struct pl08x_txd { struct dma_async_tx_descriptor tx; struct list_head node; enum dma_data_direction direction; - dma_addr_t src_addr; - dma_addr_t dst_addr; - size_t len; + struct pl08x_bus_data srcbus; + struct pl08x_bus_data dstbus; + int len; dma_addr_t llis_bus; - struct pl08x_lli *llis_va; - /* Default cctl value for LLIs */ - u32 cctl; + void *llis_va; + struct pl08x_channel_data *cd; + bool active; /* * Settings to be put into the physical channel when we - * trigger this txd. Other registers are in llis_va[0]. + * trigger this txd */ - u32 ccfg; + u32 csrc; + u32 cdst; + u32 clli; + u32 cctl; }; /** - * struct pl08x_dma_chan_state - holds the PL08x specific virtual channel - * states + * struct pl08x_dma_chan_state - holds the PL08x specific virtual + * channel states * @PL08X_CHAN_IDLE: the channel is idle * @PL08X_CHAN_RUNNING: the channel has allocated a physical transport * channel and is running a transfer on it @@ -148,8 +147,6 @@ enum pl08x_dma_chan_state { * struct pl08x_dma_chan - this structure wraps a DMA ENGINE channel * @chan: wrappped abstract channel * @phychan: the physical channel utilized by this channel, if there is one - * @phychan_hold: if non-zero, hold on to the physical channel even if we - * have no pending entries * @tasklet: tasklet scheduled by the IRQ to handle actual work etc * @name: name of channel * @cd: channel platform data @@ -157,49 +154,53 @@ enum pl08x_dma_chan_state { * @runtime_direction: current direction of this channel according to * runtime config * @lc: last completed transaction on this channel - * @pend_list: queued transactions pending on this channel + * @desc_list: queued transactions pending on this channel * @at: active transaction on this channel + * @lockflags: sometimes we let a lock last between two function calls, + * especially prep/submit, and then we need to store the IRQ flags + * in the channel state, here * @lock: a lock for this channel data * @host: a pointer to the host (internal use) * @state: whether the channel is idle, paused, running etc * @slave: whether this channel is a device (slave) or for memcpy - * @waiting: a TX descriptor on this channel which is waiting for a physical - * channel to become available + * @waiting: a TX descriptor on this channel which is waiting for + * a physical channel to become available */ struct pl08x_dma_chan { struct dma_chan chan; struct pl08x_phy_chan *phychan; - int phychan_hold; struct tasklet_struct tasklet; char *name; struct pl08x_channel_data *cd; dma_addr_t runtime_addr; enum dma_data_direction runtime_direction; + atomic_t last_issued; dma_cookie_t lc; - struct list_head pend_list; + struct list_head desc_list; struct pl08x_txd *at; + unsigned long lockflags; spinlock_t lock; - struct pl08x_driver_data *host; + void *host; enum pl08x_dma_chan_state state; bool slave; struct pl08x_txd *waiting; }; /** - * struct pl08x_platform_data - the platform configuration for the PL08x - * PrimeCells. + * struct pl08x_platform_data - the platform configuration for the + * PL08x PrimeCells. * @slave_channels: the channels defined for the different devices on the * platform, all inclusive, including multiplexed channels. The available - * physical channels will be multiplexed around these signals as they are - * requested, just enumerate all possible channels. - * @get_signal: request a physical signal to be used for a DMA transfer - * immediately: if there is some multiplexing or similar blocking the use - * of the channel the transfer can be denied by returning less than zero, - * else it returns the allocated signal number + * physical channels will be multiplexed around these signals as they + * are requested, just enumerate all possible channels. + * @get_signal: request a physical signal to be used for a DMA + * transfer immediately: if there is some multiplexing or similar blocking + * the use of the channel the transfer can be denied by returning + * less than zero, else it returns the allocated signal number * @put_signal: indicate to the platform that this physical signal is not * running any DMA transfer and multiplexing can be recycled - * @lli_buses: buses which LLIs can be fetched from: PL08X_AHB1 | PL08X_AHB2 - * @mem_buses: buses which memory can be accessed from: PL08X_AHB1 | PL08X_AHB2 + * @bus_bit_lli: Bit[0] of the address indicated which AHB bus master the + * LLI addresses are on 0/1 Master 1/2. */ struct pl08x_platform_data { struct pl08x_channel_data *slave_channels; @@ -207,8 +208,6 @@ struct pl08x_platform_data { struct pl08x_channel_data memcpy_channel; int (*get_signal)(struct pl08x_dma_chan *); void (*put_signal)(struct pl08x_dma_chan *); - u8 lli_buses; - u8 mem_buses; }; #ifdef CONFIG_AMBA_PL08X diff --git a/trunk/include/linux/auto_fs4.h b/trunk/include/linux/auto_fs4.h index e02982fa2953..8b49ac48a5b7 100644 --- a/trunk/include/linux/auto_fs4.h +++ b/trunk/include/linux/auto_fs4.h @@ -24,7 +24,7 @@ #define AUTOFS_MIN_PROTO_VERSION 3 #define AUTOFS_MAX_PROTO_VERSION 5 -#define AUTOFS_PROTO_SUBVERSION 2 +#define AUTOFS_PROTO_SUBVERSION 1 /* Mask for expire behaviour */ #define AUTOFS_EXP_IMMEDIATE 1 diff --git a/trunk/include/linux/dcache.h b/trunk/include/linux/dcache.h index f958c19e3ca5..59fcd24b1468 100644 --- a/trunk/include/linux/dcache.h +++ b/trunk/include/linux/dcache.h @@ -167,8 +167,6 @@ struct dentry_operations { void (*d_release)(struct dentry *); void (*d_iput)(struct dentry *, struct inode *); char *(*d_dname)(struct dentry *, char *, int); - struct vfsmount *(*d_automount)(struct path *); - int (*d_manage)(struct dentry *, bool, bool); } ____cacheline_aligned; /* @@ -207,18 +205,13 @@ struct dentry_operations { #define DCACHE_CANT_MOUNT 0x0100 #define DCACHE_GENOCIDE 0x0200 +#define DCACHE_MOUNTED 0x0400 /* is a mountpoint */ #define DCACHE_OP_HASH 0x1000 #define DCACHE_OP_COMPARE 0x2000 #define DCACHE_OP_REVALIDATE 0x4000 #define DCACHE_OP_DELETE 0x8000 -#define DCACHE_MOUNTED 0x10000 /* is a mountpoint */ -#define DCACHE_NEED_AUTOMOUNT 0x20000 /* handle automount on this dir */ -#define DCACHE_MANAGE_TRANSIT 0x40000 /* manage transit from this dirent */ -#define DCACHE_MANAGED_DENTRY \ - (DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT) - extern seqlock_t rename_lock; static inline int dname_external(struct dentry *dentry) @@ -406,12 +399,7 @@ static inline void dont_mount(struct dentry *dentry) extern void dput(struct dentry *); -static inline bool d_managed(struct dentry *dentry) -{ - return dentry->d_flags & DCACHE_MANAGED_DENTRY; -} - -static inline bool d_mountpoint(struct dentry *dentry) +static inline int d_mountpoint(struct dentry *dentry) { return dentry->d_flags & DCACHE_MOUNTED; } diff --git a/trunk/include/linux/dmaengine.h b/trunk/include/linux/dmaengine.h index 9bebd7f16ef1..8cd00ad98d37 100644 --- a/trunk/include/linux/dmaengine.h +++ b/trunk/include/linux/dmaengine.h @@ -532,7 +532,7 @@ static inline int dmaengine_resume(struct dma_chan *chan) return dmaengine_device_control(chan, DMA_RESUME, 0); } -static inline dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc) +static inline int dmaengine_submit(struct dma_async_tx_descriptor *desc) { return desc->tx_submit(desc); } diff --git a/trunk/include/linux/fcntl.h b/trunk/include/linux/fcntl.h index a562fa5fb4e3..afc00af3229b 100644 --- a/trunk/include/linux/fcntl.h +++ b/trunk/include/linux/fcntl.h @@ -45,7 +45,6 @@ #define AT_REMOVEDIR 0x200 /* Remove directory instead of unlinking file. */ #define AT_SYMLINK_FOLLOW 0x400 /* Follow symbolic links. */ -#define AT_NO_AUTOMOUNT 0x800 /* Suppress terminal automount traversal */ #ifdef __KERNEL__ diff --git a/trunk/include/linux/file.h b/trunk/include/linux/file.h index e85baebf6279..b1e12970f617 100644 --- a/trunk/include/linux/file.h +++ b/trunk/include/linux/file.h @@ -23,7 +23,7 @@ extern struct file *alloc_file(struct path *, fmode_t mode, static inline void fput_light(struct file *file, int fput_needed) { - if (fput_needed) + if (unlikely(fput_needed)) fput(file); } diff --git a/trunk/include/linux/fs.h b/trunk/include/linux/fs.h index 32b38cd829d3..08824e0ef381 100644 --- a/trunk/include/linux/fs.h +++ b/trunk/include/linux/fs.h @@ -242,7 +242,6 @@ struct inodes_stat_t { #define S_SWAPFILE 256 /* Do not truncate: swapon got its bmaps */ #define S_PRIVATE 512 /* Inode is fs-internal */ #define S_IMA 1024 /* Inode has an associated IMA struct */ -#define S_AUTOMOUNT 2048 /* Automount/referral quasi-directory */ /* * Note that nosuid etc flags are inode-specific: setting some file-system @@ -278,7 +277,6 @@ struct inodes_stat_t { #define IS_SWAPFILE(inode) ((inode)->i_flags & S_SWAPFILE) #define IS_PRIVATE(inode) ((inode)->i_flags & S_PRIVATE) #define IS_IMA(inode) ((inode)->i_flags & S_IMA) -#define IS_AUTOMOUNT(inode) ((inode)->i_flags & S_AUTOMOUNT) /* the read-only stuff doesn't really belong here, but any other place is probably as bad and I don't want to create yet another include file. */ @@ -1483,8 +1481,8 @@ struct fiemap_extent_info { unsigned int fi_flags; /* Flags as passed from user */ unsigned int fi_extents_mapped; /* Number of mapped extents */ unsigned int fi_extents_max; /* Size of fiemap_extent array */ - struct fiemap_extent __user *fi_extents_start; /* Start of - fiemap_extent array */ + struct fiemap_extent *fi_extents_start; /* Start of fiemap_extent + * array */ }; int fiemap_fill_next_extent(struct fiemap_extent_info *info, u64 logical, u64 phys, u64 len, u32 flags); @@ -1552,8 +1550,6 @@ struct file_operations { ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); int (*setlease)(struct file *, long, struct file_lock **); - long (*fallocate)(struct file *file, int mode, loff_t offset, - loff_t len); }; #define IPERM_FLAG_RCU 0x0001 @@ -1584,6 +1580,8 @@ struct inode_operations { ssize_t (*listxattr) (struct dentry *, char *, size_t); int (*removexattr) (struct dentry *, const char *); void (*truncate_range)(struct inode *, loff_t, loff_t); + long (*fallocate)(struct inode *inode, int mode, loff_t offset, + loff_t len); int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len); } ____cacheline_aligned; diff --git a/trunk/include/linux/mount.h b/trunk/include/linux/mount.h index 604f122a2326..1869ea24a739 100644 --- a/trunk/include/linux/mount.h +++ b/trunk/include/linux/mount.h @@ -60,7 +60,7 @@ struct vfsmount { struct super_block *mnt_sb; /* pointer to superblock */ #ifdef CONFIG_SMP struct mnt_pcp __percpu *mnt_pcp; - atomic_t mnt_longterm; /* how many of the refs are longterm */ + atomic_t mnt_longrefs; #else int mnt_count; int mnt_writers; @@ -96,6 +96,8 @@ extern int mnt_clone_write(struct vfsmount *mnt); extern void mnt_drop_write(struct vfsmount *mnt); extern void mntput(struct vfsmount *mnt); extern struct vfsmount *mntget(struct vfsmount *mnt); +extern void mntput_long(struct vfsmount *mnt); +extern struct vfsmount *mntget_long(struct vfsmount *mnt); extern void mnt_pin(struct vfsmount *mnt); extern void mnt_unpin(struct vfsmount *mnt); extern int __mnt_is_readonly(struct vfsmount *mnt); @@ -108,7 +110,12 @@ extern struct vfsmount *vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data); -extern void mnt_set_expiry(struct vfsmount *mnt, struct list_head *expiry_list); +struct nameidata; + +struct path; +extern int do_add_mount(struct vfsmount *newmnt, struct path *path, + int mnt_flags, struct list_head *fslist); + extern void mark_mounts_for_expiry(struct list_head *mounts); extern dev_t name_to_dev_t(char *name); diff --git a/trunk/include/linux/mtd/cfi.h b/trunk/include/linux/mtd/cfi.h index a9baee6864af..4dd0c2cd7659 100644 --- a/trunk/include/linux/mtd/cfi.h +++ b/trunk/include/linux/mtd/cfi.h @@ -527,7 +527,8 @@ struct cfi_extquery *cfi_read_pri(struct map_info *map, uint16_t adr, uint16_t s struct cfi_fixup { uint16_t mfr; uint16_t id; - void (*fixup)(struct mtd_info *mtd); + void (*fixup)(struct mtd_info *mtd, void* param); + void* param; }; #define CFI_MFR_ANY 0xFFFF diff --git a/trunk/include/linux/mtd/fsmc.h b/trunk/include/linux/mtd/fsmc.h index 6987995ad3cf..5d2556700ec2 100644 --- a/trunk/include/linux/mtd/fsmc.h +++ b/trunk/include/linux/mtd/fsmc.h @@ -16,7 +16,6 @@ #ifndef __MTD_FSMC_H #define __MTD_FSMC_H -#include #include #include #include @@ -28,7 +27,7 @@ /* * The placement of the Command Latch Enable (CLE) and - * Address Latch Enable (ALE) is twisted around in the + * Address Latch Enable (ALE) is twised around in the * SPEAR310 implementation. */ #if defined(CONFIG_MACH_SPEAR310) @@ -63,7 +62,7 @@ struct fsmc_nor_bank_regs { /* ctrl_tim register definitions */ -struct fsmc_nand_bank_regs { +struct fsms_nand_bank_regs { uint32_t pc; uint32_t sts; uint32_t comm; @@ -79,7 +78,7 @@ struct fsmc_nand_bank_regs { struct fsmc_regs { struct fsmc_nor_bank_regs nor_bank_regs[FSMC_MAX_NOR_BANKS]; uint8_t reserved_1[0x40 - 0x20]; - struct fsmc_nand_bank_regs bank_regs[FSMC_MAX_NAND_BANKS]; + struct fsms_nand_bank_regs bank_regs[FSMC_MAX_NAND_BANKS]; uint8_t reserved_2[0xfe0 - 0xc0]; uint32_t peripid0; /* 0xfe0 */ uint32_t peripid1; /* 0xfe4 */ @@ -115,6 +114,25 @@ struct fsmc_regs { #define FSMC_THOLD_4 (4 << 16) #define FSMC_THIZ_1 (1 << 24) +/* peripid2 register definitions */ +#define FSMC_REVISION_MSK (0xf) +#define FSMC_REVISION_SHFT (0x4) + +#define FSMC_VER1 1 +#define FSMC_VER2 2 +#define FSMC_VER3 3 +#define FSMC_VER4 4 +#define FSMC_VER5 5 +#define FSMC_VER6 6 +#define FSMC_VER7 7 +#define FSMC_VER8 8 + +static inline uint32_t get_fsmc_version(struct fsmc_regs *regs) +{ + return (readl(®s->peripid2) >> FSMC_REVISION_SHFT) & + FSMC_REVISION_MSK; +} + /* * There are 13 bytes of ecc for every 512 byte block in FSMC version 8 * and it has to be read consecutively and immediately after the 512 diff --git a/trunk/include/linux/mtd/mtd.h b/trunk/include/linux/mtd/mtd.h index 9d5306bad117..fe8d77ebec13 100644 --- a/trunk/include/linux/mtd/mtd.h +++ b/trunk/include/linux/mtd/mtd.h @@ -144,17 +144,6 @@ struct mtd_info { */ uint32_t writesize; - /* - * Size of the write buffer used by the MTD. MTD devices having a write - * buffer can write multiple writesize chunks at a time. E.g. while - * writing 4 * writesize bytes to a device with 2 * writesize bytes - * buffer the MTD driver can (but doesn't have to) do 2 writesize - * operations, but not 4. Currently, all NANDs have writebufsize - * equivalent to writesize (NAND page size). Some NOR flashes do have - * writebufsize greater than writesize. - */ - uint32_t writebufsize; - uint32_t oobsize; // Amount of OOB data per block (e.g. 16) uint32_t oobavail; // Available OOB bytes per block diff --git a/trunk/include/linux/mtd/nand.h b/trunk/include/linux/mtd/nand.h index 1f489b247a29..63e17d01fde9 100644 --- a/trunk/include/linux/mtd/nand.h +++ b/trunk/include/linux/mtd/nand.h @@ -448,8 +448,6 @@ struct nand_buffers { * See the defines for further explanation. * @badblockpos: [INTERN] position of the bad block marker in the oob * area. - * @badblockbits: [INTERN] number of bits to left-shift the bad block - * number * @cellinfo: [INTERN] MLC/multichip data from chip ident * @numchips: [INTERN] number of physical chips * @chipsize: [INTERN] the size of one chip for multichip arrays diff --git a/trunk/include/linux/mtd/onenand.h b/trunk/include/linux/mtd/onenand.h index ae418e41d8f5..0c8815bfae1c 100644 --- a/trunk/include/linux/mtd/onenand.h +++ b/trunk/include/linux/mtd/onenand.h @@ -118,8 +118,6 @@ struct onenand_chip { int (*chip_probe)(struct mtd_info *mtd); int (*block_markbad)(struct mtd_info *mtd, loff_t ofs); int (*scan_bbt)(struct mtd_info *mtd); - int (*enable)(struct mtd_info *mtd); - int (*disable)(struct mtd_info *mtd); struct completion complete; int irq; @@ -139,14 +137,6 @@ struct onenand_chip { void *bbm; void *priv; - - /* - * Shows that the current operation is composed - * of sequence of commands. For example, cache program. - * Such command status OnGo bit is checked at the end of - * sequence. - */ - unsigned int ongoing; }; /* @@ -181,9 +171,6 @@ struct onenand_chip { #define ONENAND_IS_2PLANE(this) (0) #endif -#define ONENAND_IS_CACHE_PROGRAM(this) \ - (this->options & ONENAND_HAS_CACHE_PROGRAM) - /* Check byte access in OneNAND */ #define ONENAND_CHECK_BYTE_ACCESS(addr) (addr & 0x1) @@ -194,7 +181,6 @@ struct onenand_chip { #define ONENAND_HAS_UNLOCK_ALL (0x0002) #define ONENAND_HAS_2PLANE (0x0004) #define ONENAND_HAS_4KB_PAGE (0x0008) -#define ONENAND_HAS_CACHE_PROGRAM (0x0010) #define ONENAND_SKIP_UNLOCK_CHECK (0x0100) #define ONENAND_PAGEBUF_ALLOC (0x1000) #define ONENAND_OOBBUF_ALLOC (0x2000) diff --git a/trunk/include/linux/mtd/partitions.h b/trunk/include/linux/mtd/partitions.h index 4a0a8ba90a72..2b54316591d2 100644 --- a/trunk/include/linux/mtd/partitions.h +++ b/trunk/include/linux/mtd/partitions.h @@ -89,7 +89,7 @@ static inline int mtd_has_cmdlinepart(void) { return 1; } static inline int mtd_has_cmdlinepart(void) { return 0; } #endif -int mtd_is_partition(struct mtd_info *mtd); +int mtd_is_master(struct mtd_info *mtd); int mtd_add_partition(struct mtd_info *master, char *name, long long offset, long long length); int mtd_del_partition(struct mtd_info *master, int partno); diff --git a/trunk/include/linux/namei.h b/trunk/include/linux/namei.h index f276d4fa01fc..18d06add0a40 100644 --- a/trunk/include/linux/namei.h +++ b/trunk/include/linux/namei.h @@ -45,7 +45,6 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; * - ending slashes ok even for nonexistent files * - internal "there are more path components" flag * - dentry cache is untrusted; force a real lookup - * - suppress terminal automount */ #define LOOKUP_FOLLOW 0x0001 #define LOOKUP_DIRECTORY 0x0002 @@ -54,7 +53,6 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; #define LOOKUP_PARENT 0x0010 #define LOOKUP_REVAL 0x0020 #define LOOKUP_RCU 0x0040 -#define LOOKUP_NO_AUTOMOUNT 0x0080 /* * Intent data */ @@ -81,8 +79,7 @@ extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry extern struct dentry *lookup_one_len(const char *, struct dentry *, int); -extern int follow_down_one(struct path *); -extern int follow_down(struct path *, bool); +extern int follow_down(struct path *); extern int follow_up(struct path *); extern struct dentry *lock_rename(struct dentry *, struct dentry *); diff --git a/trunk/include/linux/nfs_fs.h b/trunk/include/linux/nfs_fs.h index 6023efa9f5d9..0779bb8f95be 100644 --- a/trunk/include/linux/nfs_fs.h +++ b/trunk/include/linux/nfs_fs.h @@ -215,6 +215,7 @@ struct nfs_inode { #define NFS_INO_ADVISE_RDPLUS (0) /* advise readdirplus */ #define NFS_INO_STALE (1) /* possible stale inode */ #define NFS_INO_ACL_LRU_SET (2) /* Inode is on the LRU list */ +#define NFS_INO_MOUNTPOINT (3) /* inode is remote mountpoint */ #define NFS_INO_FLUSHING (4) /* inode is flushing out data */ #define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */ #define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */ diff --git a/trunk/include/linux/of_fdt.h b/trunk/include/linux/of_fdt.h index 0ef22a1f129e..c84d900fbbb3 100644 --- a/trunk/include/linux/of_fdt.h +++ b/trunk/include/linux/of_fdt.h @@ -97,7 +97,7 @@ extern void early_init_dt_check_for_initrd(unsigned long node); extern int early_init_dt_scan_memory(unsigned long node, const char *uname, int depth, void *data); extern void early_init_dt_add_memory_arch(u64 base, u64 size); -extern u64 early_init_dt_alloc_memory_arch(u64 size, u64 align); +extern void * early_init_dt_alloc_memory_arch(u64 size, u64 align); extern u64 dt_mem_next_cell(int s, __be32 **cellp); /* diff --git a/trunk/include/linux/path.h b/trunk/include/linux/path.h index edc98dec6266..a581e8c06533 100644 --- a/trunk/include/linux/path.h +++ b/trunk/include/linux/path.h @@ -10,7 +10,9 @@ struct path { }; extern void path_get(struct path *); +extern void path_get_long(struct path *); extern void path_put(struct path *); +extern void path_put_long(struct path *); static inline int path_equal(const struct path *path1, const struct path *path2) { diff --git a/trunk/include/linux/pci-acpi.h b/trunk/include/linux/pci-acpi.h index 44623500f419..479d9bb88e11 100644 --- a/trunk/include/linux/pci-acpi.h +++ b/trunk/include/linux/pci-acpi.h @@ -35,6 +35,9 @@ static inline acpi_handle acpi_pci_get_bridge_handle(struct pci_bus *pbus) return acpi_get_pci_rootbridge_handle(pci_domain_nr(pbus), pbus->number); } +#else +static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev) +{ return NULL; } #endif #ifdef CONFIG_ACPI_APEI diff --git a/trunk/mm/pgtable-generic.c b/trunk/mm/pgtable-generic.c index 0369f5b3ba1b..d030548047e2 100644 --- a/trunk/mm/pgtable-generic.c +++ b/trunk/mm/pgtable-generic.c @@ -92,29 +92,32 @@ pte_t ptep_clear_flush(struct vm_area_struct *vma, unsigned long address, #endif #ifndef __HAVE_ARCH_PMDP_CLEAR_FLUSH -#ifdef CONFIG_TRANSPARENT_HUGEPAGE pmd_t pmdp_clear_flush(struct vm_area_struct *vma, unsigned long address, pmd_t *pmdp) { pmd_t pmd; +#ifndef CONFIG_TRANSPARENT_HUGEPAGE + BUG(); +#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ VM_BUG_ON(address & ~HPAGE_PMD_MASK); pmd = pmdp_get_and_clear(vma->vm_mm, address, pmdp); flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE); return pmd; } -#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ #endif #ifndef __HAVE_ARCH_PMDP_SPLITTING_FLUSH -#ifdef CONFIG_TRANSPARENT_HUGEPAGE pmd_t pmdp_splitting_flush(struct vm_area_struct *vma, unsigned long address, pmd_t *pmdp) { +#ifdef CONFIG_TRANSPARENT_HUGEPAGE pmd_t pmd = pmd_mksplitting(*pmdp); VM_BUG_ON(address & ~HPAGE_PMD_MASK); set_pmd_at(vma->vm_mm, address, pmdp, pmd); /* tlb flush only to serialize against gup-fast */ flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE); -} +#else /* CONFIG_TRANSPARENT_HUGEPAGE */ + BUG(); #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ +} #endif