diff --git a/[refs] b/[refs] index 84b89d537b37..be4de3bf014b 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: aa891f6b3f440402c6879ad1ecf332d318137422 +refs/heads/master: a1181caac965c660be2bd350a9deb763e6f4b738 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/mach-s5p6442/mach-smdk6442.c b/trunk/arch/arm/mach-s5p6442/mach-smdk6442.c index eaf6b9c489ff..e69f137b0a39 100644 --- a/trunk/arch/arm/mach-s5p6442/mach-smdk6442.c +++ b/trunk/arch/arm/mach-s5p6442/mach-smdk6442.c @@ -68,7 +68,6 @@ static struct s3c2410_uartcfg smdk6442_uartcfgs[] __initdata = { static struct platform_device *smdk6442_devices[] __initdata = { &s3c_device_i2c0, - &samsung_asoc_dma, &s5p6442_device_iis0, &s3c_device_wdt, }; diff --git a/trunk/arch/arm/mach-s5p64x0/mach-smdk6440.c b/trunk/arch/arm/mach-s5p64x0/mach-smdk6440.c index e5beb84e2393..e9802755daeb 100644 --- a/trunk/arch/arm/mach-s5p64x0/mach-smdk6440.c +++ b/trunk/arch/arm/mach-s5p64x0/mach-smdk6440.c @@ -95,7 +95,6 @@ static struct platform_device *smdk6440_devices[] __initdata = { &s3c_device_i2c1, &s3c_device_ts, &s3c_device_wdt, - &samsung_asoc_dma, &s5p6440_device_iis, }; diff --git a/trunk/arch/arm/mach-s5p64x0/mach-smdk6450.c b/trunk/arch/arm/mach-s5p64x0/mach-smdk6450.c index 3a20de0a9264..b78f56292780 100644 --- a/trunk/arch/arm/mach-s5p64x0/mach-smdk6450.c +++ b/trunk/arch/arm/mach-s5p64x0/mach-smdk6450.c @@ -113,7 +113,6 @@ static struct platform_device *smdk6450_devices[] __initdata = { &s3c_device_i2c1, &s3c_device_ts, &s3c_device_wdt, - &samsung_asoc_dma, &s5p6450_device_iis0, /* s5p6450_device_spi0 will be added */ }; diff --git a/trunk/arch/arm/mach-s5pv210/mach-smdkc110.c b/trunk/arch/arm/mach-s5pv210/mach-smdkc110.c index ce11a02eabf3..bb20a14da100 100644 --- a/trunk/arch/arm/mach-s5pv210/mach-smdkc110.c +++ b/trunk/arch/arm/mach-s5pv210/mach-smdkc110.c @@ -81,7 +81,6 @@ static struct s3c_ide_platdata smdkc110_ide_pdata __initdata = { }; static struct platform_device *smdkc110_devices[] __initdata = { - &samsung_asoc_dma, &s5pv210_device_iis0, &s5pv210_device_ac97, &s5pv210_device_spdif, diff --git a/trunk/arch/arm/mach-s5pv210/mach-smdkv210.c b/trunk/arch/arm/mach-s5pv210/mach-smdkv210.c index bc9fdb52a020..88e45223c8af 100644 --- a/trunk/arch/arm/mach-s5pv210/mach-smdkv210.c +++ b/trunk/arch/arm/mach-s5pv210/mach-smdkv210.c @@ -225,7 +225,6 @@ static struct platform_device *smdkv210_devices[] __initdata = { &s5pv210_device_ac97, &s5pv210_device_iis0, &s5pv210_device_spdif, - &samsung_asoc_dma, &samsung_device_keypad, &smdkv210_dm9000, &smdkv210_lcd_lte480wv, diff --git a/trunk/arch/arm/mach-s5pv310/mach-smdkc210.c b/trunk/arch/arm/mach-s5pv310/mach-smdkc210.c index d9cab02e23ca..2d49273c0a26 100644 --- a/trunk/arch/arm/mach-s5pv310/mach-smdkc210.c +++ b/trunk/arch/arm/mach-s5pv310/mach-smdkc210.c @@ -163,9 +163,8 @@ static struct platform_device *smdkc210_devices[] __initdata = { &s5pv310_device_pd[PD_CAM], &s5pv310_device_pd[PD_TV], &s5pv310_device_pd[PD_GPS], - &s5pv310_device_sysmmu, - &samsung_asoc_dma, &smdkc210_smsc911x, + &s5pv310_device_sysmmu, }; static void __init smdkc210_smsc911x_init(void) diff --git a/trunk/arch/arm/mach-s5pv310/mach-smdkv310.c b/trunk/arch/arm/mach-s5pv310/mach-smdkv310.c index b1cddbf3c616..28680cf9a72c 100644 --- a/trunk/arch/arm/mach-s5pv310/mach-smdkv310.c +++ b/trunk/arch/arm/mach-s5pv310/mach-smdkv310.c @@ -163,9 +163,8 @@ static struct platform_device *smdkv310_devices[] __initdata = { &s5pv310_device_pd[PD_CAM], &s5pv310_device_pd[PD_TV], &s5pv310_device_pd[PD_GPS], - &s5pv310_device_sysmmu, - &samsung_asoc_dma, &smdkv310_smsc911x, + &s5pv310_device_sysmmu, }; static void __init smdkv310_smsc911x_init(void) 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/m68k/include/asm/cacheflush_no.h b/trunk/arch/m68k/include/asm/cacheflush_no.h index cb88aa96c4f1..7085bd51668b 100644 --- a/trunk/arch/m68k/include/asm/cacheflush_no.h +++ b/trunk/arch/m68k/include/asm/cacheflush_no.h @@ -2,22 +2,21 @@ #define _M68KNOMMU_CACHEFLUSH_H /* - * (C) Copyright 2000-2010, Greg Ungerer + * (C) Copyright 2000-2004, Greg Ungerer */ #include -#include #define flush_cache_all() __flush_cache_all() #define flush_cache_mm(mm) do { } while (0) #define flush_cache_dup_mm(mm) do { } while (0) -#define flush_cache_range(vma, start, end) do { } while (0) +#define flush_cache_range(vma, start, end) __flush_cache_all() #define flush_cache_page(vma, vmaddr) do { } while (0) -#define flush_dcache_range(start, len) __flush_dcache_all() +#define flush_dcache_range(start,len) __flush_cache_all() #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0 #define flush_dcache_page(page) do { } while (0) #define flush_dcache_mmap_lock(mapping) do { } while (0) #define flush_dcache_mmap_unlock(mapping) do { } while (0) -#define flush_icache_range(start, len) __flush_icache_all() +#define flush_icache_range(start,len) __flush_cache_all() #define flush_icache_page(vma,pg) do { } while (0) #define flush_icache_user_range(vma,pg,adr,len) do { } while (0) #define flush_cache_vmap(start, end) do { } while (0) @@ -28,52 +27,66 @@ #define copy_from_user_page(vma, page, vaddr, dst, src, len) \ memcpy(dst, src, len) -void mcf_cache_push(void); - static inline void __flush_cache_all(void) { -#ifdef CACHE_PUSH - mcf_cache_push(); -#endif -#ifdef CACHE_INVALIDATE +#if defined(CONFIG_M5407) || defined(CONFIG_M548x) + /* + * Use cpushl to push and invalidate all cache lines. + * Gas doesn't seem to know how to generate the ColdFire + * cpushl instruction... Oh well, bit stuff it for now. + */ + __asm__ __volatile__ ( + "nop\n\t" + "clrl %%d0\n\t" + "1:\n\t" + "movel %%d0,%%a0\n\t" + "2:\n\t" + ".word 0xf468\n\t" + "addl #0x10,%%a0\n\t" + "cmpl #0x00000800,%%a0\n\t" + "blt 2b\n\t" + "addql #1,%%d0\n\t" + "cmpil #4,%%d0\n\t" + "bne 1b\n\t" + "movel #0xb6088500,%%d0\n\t" + "movec %%d0,%%CACR\n\t" + : : : "d0", "a0" ); +#endif /* CONFIG_M5407 */ +#if defined(CONFIG_M523x) || defined(CONFIG_M527x) __asm__ __volatile__ ( - "movel %0, %%d0\n\t" + "movel #0x81400100, %%d0\n\t" "movec %%d0, %%CACR\n\t" "nop\n\t" - : : "i" (CACHE_INVALIDATE) : "d0" ); -#endif -} - -/* - * Some ColdFire parts implement separate instruction and data caches, - * on those we should just flush the appropriate cache. If we don't need - * to do any specific flushing then this will be optimized away. - */ -static inline void __flush_icache_all(void) -{ -#ifdef CACHE_INVALIDATEI + : : : "d0" ); +#endif /* CONFIG_M523x || CONFIG_M527x */ +#if defined(CONFIG_M528x) __asm__ __volatile__ ( - "movel %0, %%d0\n\t" + "movel #0x81000200, %%d0\n\t" "movec %%d0, %%CACR\n\t" "nop\n\t" - : : "i" (CACHE_INVALIDATEI) : "d0" ); -#endif -} - -static inline void __flush_dcache_all(void) -{ -#ifdef CACHE_PUSH - mcf_cache_push(); -#endif -#ifdef CACHE_INVALIDATED + : : : "d0" ); +#endif /* CONFIG_M528x */ +#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || defined(CONFIG_M5272) + __asm__ __volatile__ ( + "movel #0x81000100, %%d0\n\t" + "movec %%d0, %%CACR\n\t" + "nop\n\t" + : : : "d0" ); +#endif /* CONFIG_M5206 || CONFIG_M5206e || CONFIG_M5272 */ +#ifdef CONFIG_M5249 __asm__ __volatile__ ( - "movel %0, %%d0\n\t" + "movel #0xa1000200, %%d0\n\t" "movec %%d0, %%CACR\n\t" "nop\n\t" - : : "i" (CACHE_INVALIDATED) : "d0" ); -#else - /* Flush the wrtite buffer */ - __asm__ __volatile__ ( "nop" ); -#endif + : : : "d0" ); +#endif /* CONFIG_M5249 */ +#ifdef CONFIG_M532x + __asm__ __volatile__ ( + "movel #0x81000200, %%d0\n\t" + "movec %%d0, %%CACR\n\t" + "nop\n\t" + : : : "d0" ); +#endif /* CONFIG_M532x */ } + #endif /* _M68KNOMMU_CACHEFLUSH_H */ diff --git a/trunk/arch/m68k/include/asm/coldfire.h b/trunk/arch/m68k/include/asm/coldfire.h index 213028cbe110..3b0a34d0fe33 100644 --- a/trunk/arch/m68k/include/asm/coldfire.h +++ b/trunk/arch/m68k/include/asm/coldfire.h @@ -32,7 +32,7 @@ */ #define MCF_MBAR 0x10000000 #define MCF_MBAR2 0x80000000 -#if defined(CONFIG_M54xx) +#if defined(CONFIG_M548x) #define MCF_IPSBAR MCF_MBAR #elif defined(CONFIG_M520x) #define MCF_IPSBAR 0xFC000000 diff --git a/trunk/arch/m68k/include/asm/entry_no.h b/trunk/arch/m68k/include/asm/entry_no.h index 627d69bacc58..26be277394f9 100644 --- a/trunk/arch/m68k/include/asm/entry_no.h +++ b/trunk/arch/m68k/include/asm/entry_no.h @@ -42,16 +42,12 @@ */ #ifdef CONFIG_COLDFIRE -#ifdef CONFIG_COLDFIRE_SW_A7 /* - * This is made a little more tricky on older ColdFires. There is no - * separate supervisor and user stack pointers. Need to artificially + * This is made a little more tricky on the ColdFire. There is no + * separate kernel and user stack pointers. Need to artificially * construct a usp in software... When doing this we need to disable - * interrupts, otherwise bad things will happen. + * interrupts, otherwise bad things could happen. */ -.globl sw_usp -.globl sw_ksp - .macro SAVE_ALL move #0x2700,%sr /* disable intrs */ btst #5,%sp@(2) /* from user? */ @@ -78,7 +74,9 @@ 7: .endm -.macro RESTORE_USER +.macro RESTORE_ALL + btst #5,%sp@(PT_SR) /* going user? */ + bnes 8f /* no, skip */ move #0x2700,%sr /* disable intrs */ movel sw_usp,%a0 /* get usp */ movel %sp@(PT_OFF_PC),%a0@- /* copy exception program counter */ @@ -93,22 +91,19 @@ subql #8,sw_usp /* set exception */ movel sw_usp,%sp /* restore usp */ rte + 8: + moveml %sp@,%d1-%d5/%a0-%a2 + lea %sp@(32),%sp /* space for 8 regs */ + movel %sp@+,%d0 + addql #4,%sp /* orig d0 */ + addl %sp@+,%sp /* stkadj */ + rte .endm -.macro RDUSP - movel sw_usp,%a2 -.endm - -.macro WRUSP - movel %a0,sw_usp -.endm - -#else /* !CONFIG_COLDFIRE_SW_A7 */ /* - * Modern ColdFire parts have separate supervisor and user stack - * pointers. Simple load and restore macros for this case. + * Quick exception save, use current stack only. */ -.macro SAVE_ALL +.macro SAVE_LOCAL move #0x2700,%sr /* disable intrs */ clrl %sp@- /* stkadj */ movel %d0,%sp@- /* orig d0 */ @@ -117,7 +112,7 @@ moveml %d1-%d5/%a0-%a2,%sp@ .endm -.macro RESTORE_USER +.macro RESTORE_LOCAL moveml %sp@,%d1-%d5/%a0-%a2 lea %sp@(32),%sp /* space for 8 regs */ movel %sp@+,%d0 @@ -126,18 +121,6 @@ rte .endm -.macro RDUSP - /*move %usp,%a2*/ - .word 0x4e6a -.endm - -.macro WRUSP - /*move %a0,%usp*/ - .word 0x4e60 -.endm - -#endif /* !CONFIG_COLDFIRE_SW_A7 */ - .macro SAVE_SWITCH_STACK lea %sp@(-24),%sp /* 6 regs */ moveml %a3-%a6/%d6-%d7,%sp@ @@ -148,6 +131,14 @@ lea %sp@(24),%sp /* 6 regs */ .endm +/* + * Software copy of the user and kernel stack pointers... Ugh... + * Need these to get around ColdFire not having separate kernel + * and user stack pointers. + */ +.globl sw_usp +.globl sw_ksp + #else /* !CONFIG_COLDFIRE */ /* @@ -176,6 +167,6 @@ moveml %sp@+,%a3-%a6/%d6-%d7 .endm -#endif /* !COLDFIRE_SW_A7 */ +#endif /* !CONFIG_COLDFIRE */ #endif /* __ASSEMBLY__ */ #endif /* __M68KNOMMU_ENTRY_H */ diff --git a/trunk/arch/m68k/include/asm/gpio.h b/trunk/arch/m68k/include/asm/gpio.h index c64c7b74cf86..1b57adbafad5 100644 --- a/trunk/arch/m68k/include/asm/gpio.h +++ b/trunk/arch/m68k/include/asm/gpio.h @@ -37,7 +37,7 @@ #if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \ defined(CONFIG_M520x) || defined(CONFIG_M523x) || \ defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ - defined(CONFIG_M532x) || defined(CONFIG_M54xx) + defined(CONFIG_M532x) || defined(CONFIG_M548x) /* These parts have GPIO organized by 8 bit ports */ diff --git a/trunk/arch/m68k/include/asm/io_no.h b/trunk/arch/m68k/include/asm/io_no.h index cf20f3097af6..6e2413e518cb 100644 --- a/trunk/arch/m68k/include/asm/io_no.h +++ b/trunk/arch/m68k/include/asm/io_no.h @@ -145,6 +145,7 @@ static inline void io_insl(unsigned int addr, void *buf, int len) #define IOMAP_WRITETHROUGH 3 extern void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag); +extern void __iounmap(void *addr, unsigned long size); static inline void *ioremap(unsigned long physaddr, unsigned long size) { diff --git a/trunk/arch/m68k/include/asm/m5206sim.h b/trunk/arch/m68k/include/asm/m5206sim.h index 561b03b5ddf8..9c384e294af9 100644 --- a/trunk/arch/m68k/include/asm/m5206sim.h +++ b/trunk/arch/m68k/include/asm/m5206sim.h @@ -12,10 +12,6 @@ #define m5206sim_h /****************************************************************************/ -#define CPU_NAME "COLDFIRE(m5206)" -#define CPU_INSTR_PER_JIFFY 3 - -#include /* * Define the 5206 SIM register set addresses. @@ -92,14 +88,6 @@ #define MCFSIM_PADDR (MCF_MBAR + 0x1c5) /* Parallel Direction (r/w) */ #define MCFSIM_PADAT (MCF_MBAR + 0x1c9) /* Parallel Port Value (r/w) */ -#if defined(CONFIG_NETtel) -#define MCFUART_BASE1 0x180 /* Base address of UART1 */ -#define MCFUART_BASE2 0x140 /* Base address of UART2 */ -#else -#define MCFUART_BASE1 0x140 /* Base address of UART1 */ -#define MCFUART_BASE2 0x180 /* Base address of UART2 */ -#endif - /* * Define system peripheral IRQ usage. */ @@ -107,7 +95,7 @@ #define MCF_IRQ_PROFILER 31 /* Timer1, Level 7 */ /* - * Generic GPIO + * Generic GPIO */ #define MCFGPIO_PIN_MAX 8 #define MCFGPIO_IRQ_VECBASE -1 diff --git a/trunk/arch/m68k/include/asm/m520xsim.h b/trunk/arch/m68k/include/asm/m520xsim.h index 88ed8239fe4e..db824a4b136e 100644 --- a/trunk/arch/m68k/include/asm/m520xsim.h +++ b/trunk/arch/m68k/include/asm/m520xsim.h @@ -11,11 +11,6 @@ #define m520xsim_h /****************************************************************************/ -#define CPU_NAME "COLDFIRE(m520x)" -#define CPU_INSTR_PER_JIFFY 3 - -#include - /* * Define the 520x SIM register set addresses. */ @@ -59,9 +54,6 @@ #define MCFSIM_SDCS0 0x000a8110 /* SDRAM Chip Select 0 Configuration */ #define MCFSIM_SDCS1 0x000a8114 /* SDRAM Chip Select 1 Configuration */ -/* - * EPORT and GPIO registers. - */ #define MCFEPORT_EPDDR 0xFC088002 #define MCFEPORT_EPDR 0xFC088004 #define MCFEPORT_EPPDR 0xFC088005 @@ -105,7 +97,6 @@ #define MCFGPIO_PCLRR_UART 0xFC0A402A #define MCFGPIO_PCLRR_FECH 0xFC0A402B #define MCFGPIO_PCLRR_FECL 0xFC0A402C - /* * Generic GPIO support */ @@ -118,6 +109,7 @@ #define MCFGPIO_PIN_MAX 80 #define MCFGPIO_IRQ_MAX 8 #define MCFGPIO_IRQ_VECBASE MCFINT_VECBASE +/****************************************************************************/ #define MCF_GPIO_PAR_UART (0xA4036) #define MCF_GPIO_PAR_FECI2C (0xA4033) @@ -133,13 +125,6 @@ #define MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2 (0x02) #define MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2 (0x04) -/* - * UART module. - */ -#define MCFUART_BASE1 0x60000 /* Base address of UART1 */ -#define MCFUART_BASE2 0x64000 /* Base address of UART2 */ -#define MCFUART_BASE3 0x68000 /* Base address of UART2 */ - /* * Reset Controll Unit. */ diff --git a/trunk/arch/m68k/include/asm/m523xsim.h b/trunk/arch/m68k/include/asm/m523xsim.h index 4ad7a00257a8..e8d06b24a48e 100644 --- a/trunk/arch/m68k/include/asm/m523xsim.h +++ b/trunk/arch/m68k/include/asm/m523xsim.h @@ -11,10 +11,6 @@ #define m523xsim_h /****************************************************************************/ -#define CPU_NAME "COLDFIRE(m523x)" -#define CPU_INSTR_PER_JIFFY 3 - -#include /* * Define the 523x SIM register set addresses. @@ -54,13 +50,6 @@ #define MCF_RCR_SWRESET 0x80 /* Software reset bit */ #define MCF_RCR_FRCSTOUT 0x40 /* Force external reset */ -/* - * UART module. - */ -#define MCFUART_BASE1 0x200 /* Base address of UART1 */ -#define MCFUART_BASE2 0x240 /* Base address of UART2 */ -#define MCFUART_BASE3 0x280 /* Base address of UART3 */ - #define MCFGPIO_PODR_ADDR (MCF_IPSBAR + 0x100000) #define MCFGPIO_PODR_DATAH (MCF_IPSBAR + 0x100001) #define MCFGPIO_PODR_DATAL (MCF_IPSBAR + 0x100002) diff --git a/trunk/arch/m68k/include/asm/m5249sim.h b/trunk/arch/m68k/include/asm/m5249sim.h index 4908b118f2fd..79b7b402f3c9 100644 --- a/trunk/arch/m68k/include/asm/m5249sim.h +++ b/trunk/arch/m68k/include/asm/m5249sim.h @@ -11,11 +11,6 @@ #define m5249sim_h /****************************************************************************/ -#define CPU_NAME "COLDFIRE(m5249)" -#define CPU_INSTR_PER_JIFFY 3 - -#include - /* * Define the 5249 SIM register set addresses. */ @@ -61,11 +56,6 @@ #define MCFSIM_DACR1 0x110 /* DRAM 1 Addr and Ctrl (r/w) */ #define MCFSIM_DMR1 0x114 /* DRAM 1 Mask reg (r/w) */ -/* - * UART module. - */ -#define MCFUART_BASE1 0x1c0 /* Base address of UART1 */ -#define MCFUART_BASE2 0x200 /* Base address of UART2 */ /* * Some symbol defines for the above... diff --git a/trunk/arch/m68k/include/asm/m5272sim.h b/trunk/arch/m68k/include/asm/m5272sim.h index b7cc50abc831..df3332c2317d 100644 --- a/trunk/arch/m68k/include/asm/m5272sim.h +++ b/trunk/arch/m68k/include/asm/m5272sim.h @@ -12,11 +12,6 @@ #define m5272sim_h /****************************************************************************/ -#define CPU_NAME "COLDFIRE(m5272)" -#define CPU_INSTR_PER_JIFFY 3 - -#include - /* * Define the 5272 SIM register set addresses. */ @@ -67,9 +62,6 @@ #define MCFSIM_DCMR1 0x5c /* DRAM 1 Mask reg (r/w) */ #define MCFSIM_DCCR1 0x63 /* DRAM 1 Control reg (r/w) */ -#define MCFUART_BASE1 0x100 /* Base address of UART1 */ -#define MCFUART_BASE2 0x140 /* Base address of UART2 */ - #define MCFSIM_PACNT (MCF_MBAR + 0x80) /* Port A Control (r/w) */ #define MCFSIM_PADDR (MCF_MBAR + 0x84) /* Port A Direction (r/w) */ #define MCFSIM_PADAT (MCF_MBAR + 0x86) /* Port A Data (r/w) */ diff --git a/trunk/arch/m68k/include/asm/m527xsim.h b/trunk/arch/m68k/include/asm/m527xsim.h index e8042e8bc003..1feb46f108ce 100644 --- a/trunk/arch/m68k/include/asm/m527xsim.h +++ b/trunk/arch/m68k/include/asm/m527xsim.h @@ -11,10 +11,6 @@ #define m527xsim_h /****************************************************************************/ -#define CPU_NAME "COLDFIRE(m527x)" -#define CPU_INSTR_PER_JIFFY 3 - -#include /* * Define the 5270/5271 SIM register set addresses. @@ -59,12 +55,6 @@ #define MCFSIM_DMR1 0x5c /* SDRAM address mask 1 */ #endif -/* - * UART module. - */ -#define MCFUART_BASE1 0x200 /* Base address of UART1 */ -#define MCFUART_BASE2 0x240 /* Base address of UART2 */ -#define MCFUART_BASE3 0x280 /* Base address of UART3 */ #ifdef CONFIG_M5271 #define MCFGPIO_PODR_ADDR (MCF_IPSBAR + 0x100000) diff --git a/trunk/arch/m68k/include/asm/m528xsim.h b/trunk/arch/m68k/include/asm/m528xsim.h index a6d2f4d9aaa0..891cbedad972 100644 --- a/trunk/arch/m68k/include/asm/m528xsim.h +++ b/trunk/arch/m68k/include/asm/m528xsim.h @@ -11,10 +11,6 @@ #define m528xsim_h /****************************************************************************/ -#define CPU_NAME "COLDFIRE(m528x)" -#define CPU_INSTR_PER_JIFFY 3 - -#include /* * Define the 5280/5282 SIM register set addresses. @@ -45,13 +41,6 @@ #define MCFSIM_DACR1 0x50 /* SDRAM base address 1 */ #define MCFSIM_DMR1 0x54 /* SDRAM address mask 1 */ -/* - * UART module. - */ -#define MCFUART_BASE1 0x200 /* Base address of UART1 */ -#define MCFUART_BASE2 0x240 /* Base address of UART2 */ -#define MCFUART_BASE3 0x280 /* Base address of UART3 */ - /* * GPIO registers */ diff --git a/trunk/arch/m68k/include/asm/m52xxacr.h b/trunk/arch/m68k/include/asm/m52xxacr.h deleted file mode 100644 index abc391a9ae8d..000000000000 --- a/trunk/arch/m68k/include/asm/m52xxacr.h +++ /dev/null @@ -1,94 +0,0 @@ -/****************************************************************************/ - -/* - * m52xxacr.h -- ColdFire version 2 core cache support - * - * (C) Copyright 2010, Greg Ungerer - */ - -/****************************************************************************/ -#ifndef m52xxacr_h -#define m52xxacr_h -/****************************************************************************/ - -/* - * All varients of the ColdFire using version 2 cores have a similar - * cache setup. Although not absolutely identical the cache register - * definitions are compatible for all of them. Mostly they support a - * configurable cache memory that can be instruction only, data only, - * or split instruction and data. The exception is the very old version 2 - * core based parts, like the 5206(e), 5249 and 5272, which are instruction - * cache only. Cache size varies from 2k up to 16k. - */ - -/* - * Define the Cache Control register flags. - */ -#define CACR_CENB 0x80000000 /* Enable cache */ -#define CACR_CDPI 0x10000000 /* Disable invalidation by CPUSHL */ -#define CACR_CFRZ 0x08000000 /* Cache freeze mode */ -#define CACR_CINV 0x01000000 /* Invalidate cache */ -#define CACR_DISI 0x00800000 /* Disable instruction cache */ -#define CACR_DISD 0x00400000 /* Disable data cache */ -#define CACR_INVI 0x00200000 /* Invalidate instruction cache */ -#define CACR_INVD 0x00100000 /* Invalidate data cache */ -#define CACR_CEIB 0x00000400 /* Non-cachable instruction burst */ -#define CACR_DCM 0x00000200 /* Default cache mode */ -#define CACR_DBWE 0x00000100 /* Buffered write enable */ -#define CACR_DWP 0x00000020 /* Write protection */ -#define CACR_EUSP 0x00000010 /* Enable separate user a7 */ - -/* - * Define the Access Control register flags. - */ -#define ACR_BASE_POS 24 /* Address Base (upper 8 bits) */ -#define ACR_MASK_POS 16 /* Address Mask (next 8 bits) */ -#define ACR_ENABLE 0x00008000 /* Enable this ACR */ -#define ACR_USER 0x00000000 /* Allow only user accesses */ -#define ACR_SUPER 0x00002000 /* Allow supervisor access only */ -#define ACR_ANY 0x00004000 /* Allow any access type */ -#define ACR_CENB 0x00000000 /* Caching of region enabled */ -#define ACR_CDIS 0x00000040 /* Caching of region disabled */ -#define ACR_BWE 0x00000020 /* Write buffer enabled */ -#define ACR_WPROTECT 0x00000004 /* Write protect region */ - -/* - * Set the cache controller settings we will use. On the cores that support - * a split cache configuration we allow all the combinations at Kconfig - * time. For those cores that only have an instruction cache we just set - * that as on. - */ -#if defined(CONFIG_CACHE_I) -#define CACHE_TYPE (CACR_DISD + CACR_EUSP) -#define CACHE_INVTYPEI 0 -#elif defined(CONFIG_CACHE_D) -#define CACHE_TYPE (CACR_DISI + CACR_EUSP) -#define CACHE_INVTYPED 0 -#elif defined(CONFIG_CACHE_BOTH) -#define CACHE_TYPE CACR_EUSP -#define CACHE_INVTYPEI CACR_INVI -#define CACHE_INVTYPED CACR_INVD -#else -/* This is the instruction cache only devices (no split cache, no eusp) */ -#define CACHE_TYPE 0 -#define CACHE_INVTYPEI 0 -#endif - -#define CACHE_INIT (CACR_CINV + CACHE_TYPE) -#define CACHE_MODE (CACR_CENB + CACHE_TYPE + CACR_DCM) - -#define CACHE_INVALIDATE (CACHE_MODE + CACR_CINV) -#if defined(CACHE_INVTYPEI) -#define CACHE_INVALIDATEI (CACHE_MODE + CACR_CINV + CACHE_INVTYPEI) -#endif -#if defined(CACHE_INVTYPED) -#define CACHE_INVALIDATED (CACHE_MODE + CACR_CINV + CACHE_INVTYPED) -#endif - -#define ACR0_MODE ((CONFIG_RAMBASE & 0xff000000) + \ - (0x000f0000) + \ - (ACR_ENABLE + ACR_ANY + ACR_CENB + ACR_BWE)) -#define ACR1_MODE 0 - -/****************************************************************************/ -#endif /* m52xxsim_h */ diff --git a/trunk/arch/m68k/include/asm/m5307sim.h b/trunk/arch/m68k/include/asm/m5307sim.h index 0bf57397e7a9..c6830e5b54ce 100644 --- a/trunk/arch/m68k/include/asm/m5307sim.h +++ b/trunk/arch/m68k/include/asm/m5307sim.h @@ -14,11 +14,6 @@ #define m5307sim_h /****************************************************************************/ -#define CPU_NAME "COLDFIRE(m5307)" -#define CPU_INSTR_PER_JIFFY 3 - -#include - /* * Define the 5307 SIM register set addresses. */ @@ -98,17 +93,6 @@ #define MCFSIM_PADDR (MCF_MBAR + 0x244) #define MCFSIM_PADAT (MCF_MBAR + 0x248) -/* - * UART module. - */ -#if defined(CONFIG_NETtel) || defined(CONFIG_SECUREEDGEMP3) -#define MCFUART_BASE1 0x200 /* Base address of UART1 */ -#define MCFUART_BASE2 0x1c0 /* Base address of UART2 */ -#else -#define MCFUART_BASE1 0x1c0 /* Base address of UART1 */ -#define MCFUART_BASE2 0x200 /* Base address of UART2 */ -#endif - /* * Generic GPIO support */ @@ -162,5 +146,32 @@ #define MCF_IRQ_TIMER 30 /* Timer0, Level 6 */ #define MCF_IRQ_PROFILER 31 /* Timer1, Level 7 */ +/* + * Define the Cache register flags. + */ +#define CACR_EC (1<<31) +#define CACR_ESB (1<<29) +#define CACR_DPI (1<<28) +#define CACR_HLCK (1<<27) +#define CACR_CINVA (1<<24) +#define CACR_DNFB (1<<10) +#define CACR_DCM_WTHRU (0<<8) +#define CACR_DCM_WBACK (1<<8) +#define CACR_DCM_OFF_PRE (2<<8) +#define CACR_DCM_OFF_IMP (3<<8) +#define CACR_DW (1<<5) + +#define ACR_BASE_POS 24 +#define ACR_MASK_POS 16 +#define ACR_ENABLE (1<<15) +#define ACR_USER (0<<13) +#define ACR_SUPER (1<<13) +#define ACR_ANY (2<<13) +#define ACR_CM_WTHRU (0<<5) +#define ACR_CM_WBACK (1<<5) +#define ACR_CM_OFF_PRE (2<<5) +#define ACR_CM_OFF_IMP (3<<5) +#define ACR_WPROTECT (1<<2) + /****************************************************************************/ #endif /* m5307sim_h */ diff --git a/trunk/arch/m68k/include/asm/m532xsim.h b/trunk/arch/m68k/include/asm/m532xsim.h index e6470f8ca324..c4bf1c81e3cf 100644 --- a/trunk/arch/m68k/include/asm/m532xsim.h +++ b/trunk/arch/m68k/include/asm/m532xsim.h @@ -9,11 +9,6 @@ #define m532xsim_h /****************************************************************************/ -#define CPU_NAME "COLDFIRE(m532x)" -#define CPU_INSTR_PER_JIFFY 3 - -#include - #define MCF_REG32(x) (*(volatile unsigned long *)(x)) #define MCF_REG16(x) (*(volatile unsigned short *)(x)) #define MCF_REG08(x) (*(volatile unsigned char *)(x)) @@ -79,11 +74,31 @@ #define MCF_IRQ_PROFILER (64 + 33) /* Timer1 */ /* - * UART module. + * Define the Cache register flags. */ -#define MCFUART_BASE1 0xFC060000 /* Base address of UART1 */ -#define MCFUART_BASE2 0xFC064000 /* Base address of UART2 */ -#define MCFUART_BASE3 0xFC068000 /* Base address of UART3 */ +#define CACR_EC (1<<31) +#define CACR_ESB (1<<29) +#define CACR_DPI (1<<28) +#define CACR_HLCK (1<<27) +#define CACR_CINVA (1<<24) +#define CACR_DNFB (1<<10) +#define CACR_DCM_WTHRU (0<<8) +#define CACR_DCM_WBACK (1<<8) +#define CACR_DCM_OFF_PRE (2<<8) +#define CACR_DCM_OFF_IMP (3<<8) +#define CACR_DW (1<<5) + +#define ACR_BASE_POS 24 +#define ACR_MASK_POS 16 +#define ACR_ENABLE (1<<15) +#define ACR_USER (0<<13) +#define ACR_SUPER (1<<13) +#define ACR_ANY (2<<13) +#define ACR_CM_WTHRU (0<<5) +#define ACR_CM_WBACK (1<<5) +#define ACR_CM_OFF_PRE (2<<5) +#define ACR_CM_OFF_IMP (3<<5) +#define ACR_WPROTECT (1<<2) /********************************************************************* * diff --git a/trunk/arch/m68k/include/asm/m53xxacr.h b/trunk/arch/m68k/include/asm/m53xxacr.h deleted file mode 100644 index cd952b0a8bd3..000000000000 --- a/trunk/arch/m68k/include/asm/m53xxacr.h +++ /dev/null @@ -1,101 +0,0 @@ -/****************************************************************************/ - -/* - * m53xxacr.h -- ColdFire version 3 core cache support - * - * (C) Copyright 2010, Greg Ungerer - */ - -/****************************************************************************/ -#ifndef m53xxacr_h -#define m53xxacr_h -/****************************************************************************/ - -/* - * All varients of the ColdFire using version 3 cores have a similar - * cache setup. They have a unified instruction and data cache, with - * configurable write-through or copy-back operation. - */ - -/* - * Define the Cache Control register flags. - */ -#define CACR_EC 0x80000000 /* Enable cache */ -#define CACR_ESB 0x20000000 /* Enable store buffer */ -#define CACR_DPI 0x10000000 /* Disable invalidation by CPUSHL */ -#define CACR_HLCK 0x08000000 /* Half cache lock mode */ -#define CACR_CINVA 0x01000000 /* Invalidate cache */ -#define CACR_DNFB 0x00000400 /* Inhibited fill buffer */ -#define CACR_DCM_WT 0x00000000 /* Cacheable write-through */ -#define CACR_DCM_CB 0x00000100 /* Cacheable copy-back */ -#define CACR_DCM_PRE 0x00000200 /* Cache inhibited, precise */ -#define CACR_DCM_IMPRE 0x00000300 /* Cache inhibited, imprecise */ -#define CACR_WPROTECT 0x00000020 /* Write protect*/ -#define CACR_EUSP 0x00000010 /* Eanble separate user a7 */ - -/* - * Define the Access Control register flags. - */ -#define ACR_BASE_POS 24 /* Address Base (upper 8 bits) */ -#define ACR_MASK_POS 16 /* Address Mask (next 8 bits) */ -#define ACR_ENABLE 0x00008000 /* Enable this ACR */ -#define ACR_USER 0x00000000 /* Allow only user accesses */ -#define ACR_SUPER 0x00002000 /* Allow supervisor access only */ -#define ACR_ANY 0x00004000 /* Allow any access type */ -#define ACR_CM_WT 0x00000000 /* Cacheable, write-through */ -#define ACR_CM_CB 0x00000020 /* Cacheable, copy-back */ -#define ACR_CM_PRE 0x00000040 /* Cache inhibited, precise */ -#define ACR_CM_IMPRE 0x00000060 /* Cache inhibited, imprecise */ -#define ACR_WPROTECT 0x00000004 /* Write protect region */ - -/* - * Define the cache type and arrangement (needed for pushes). - */ -#if defined(CONFIG_M5307) -#define CACHE_SIZE 0x2000 /* 8k of unified cache */ -#define ICACHE_SIZE CACHE_SIZE -#define DCACHE_SIZE CACHE_SIZE -#elif defined(CONFIG_M532x) -#define CACHE_SIZE 0x4000 /* 32k of unified cache */ -#define ICACHE_SIZE CACHE_SIZE -#define DCACHE_SIZE CACHE_SIZE -#endif - -#define CACHE_LINE_SIZE 16 /* 16 byte line size */ -#define CACHE_WAYS 4 /* 4 ways - set associative */ - -/* - * Set the cache controller settings we will use. This default in the - * CACR is cache inhibited, we use the ACR register to set cacheing - * enabled on the regions we want (eg RAM). - */ -#if defined(CONFIG_CACHE_COPYBACK) -#define CACHE_TYPE ACR_CM_CB -#define CACHE_PUSH -#else -#define CACHE_TYPE ACR_CM_WT -#endif - -#ifdef CONFIG_COLDFIRE_SW_A7 -#define CACHE_MODE (CACR_EC + CACR_ESB + CACR_DCM_PRE) -#else -#define CACHE_MODE (CACR_EC + CACR_ESB + CACR_DCM_PRE + CACR_EUSP) -#endif - -/* - * Unified cache means we will never need to flush for coherency of - * instruction fetch. We will need to flush to maintain memory/DMA - * coherency though in all cases. And for copyback caches we will need - * to push cached data as well. - */ -#define CACHE_INIT CACR_CINVA -#define CACHE_INVALIDATE CACR_CINVA -#define CACHE_INVALIDATED CACR_CINVA - -#define ACR0_MODE ((CONFIG_RAMBASE & 0xff000000) + \ - (0x000f0000) + \ - (ACR_ENABLE + ACR_ANY + CACHE_TYPE)) -#define ACR1_MODE 0 - -/****************************************************************************/ -#endif /* m53xxsim_h */ diff --git a/trunk/arch/m68k/include/asm/m5407sim.h b/trunk/arch/m68k/include/asm/m5407sim.h index 75f5c28a551d..c399abbf953c 100644 --- a/trunk/arch/m68k/include/asm/m5407sim.h +++ b/trunk/arch/m68k/include/asm/m5407sim.h @@ -14,11 +14,6 @@ #define m5407sim_h /****************************************************************************/ -#define CPU_NAME "COLDFIRE(m5407)" -#define CPU_INSTR_PER_JIFFY 3 - -#include - /* * Define the 5407 SIM register set addresses. */ @@ -78,9 +73,6 @@ #define MCFSIM_DACR1 0x110 /* DRAM 1 Addr and Ctrl (r/w) */ #define MCFSIM_DMR1 0x114 /* DRAM 1 Mask reg (r/w) */ -#define MCFUART_BASE1 0x1c0 /* Base address of UART1 */ -#define MCFUART_BASE2 0x200 /* Base address of UART2 */ - #define MCFSIM_PADDR (MCF_MBAR + 0x244) #define MCFSIM_PADAT (MCF_MBAR + 0x248) @@ -125,5 +117,39 @@ #define MCF_IRQ_TIMER 30 /* Timer0, Level 6 */ #define MCF_IRQ_PROFILER 31 /* Timer1, Level 7 */ +/* + * Define the Cache register flags. + */ +#define CACR_DEC 0x80000000 /* Enable data cache */ +#define CACR_DWP 0x40000000 /* Data write protection */ +#define CACR_DESB 0x20000000 /* Enable data store buffer */ +#define CACR_DDPI 0x10000000 /* Disable CPUSHL */ +#define CACR_DHCLK 0x08000000 /* Half data cache lock mode */ +#define CACR_DDCM_WT 0x00000000 /* Write through cache*/ +#define CACR_DDCM_CP 0x02000000 /* Copyback cache */ +#define CACR_DDCM_P 0x04000000 /* No cache, precise */ +#define CACR_DDCM_IMP 0x06000000 /* No cache, imprecise */ +#define CACR_DCINVA 0x01000000 /* Invalidate data cache */ +#define CACR_BEC 0x00080000 /* Enable branch cache */ +#define CACR_BCINVA 0x00040000 /* Invalidate branch cache */ +#define CACR_IEC 0x00008000 /* Enable instruction cache */ +#define CACR_DNFB 0x00002000 /* Inhibited fill buffer */ +#define CACR_IDPI 0x00001000 /* Disable CPUSHL */ +#define CACR_IHLCK 0x00000800 /* Intruction cache half lock */ +#define CACR_IDCM 0x00000400 /* Intruction cache inhibit */ +#define CACR_ICINVA 0x00000100 /* Invalidate instr cache */ + +#define ACR_BASE_POS 24 /* Address Base */ +#define ACR_MASK_POS 16 /* Address Mask */ +#define ACR_ENABLE 0x00008000 /* Enable address */ +#define ACR_USER 0x00000000 /* User mode access only */ +#define ACR_SUPER 0x00002000 /* Supervisor mode only */ +#define ACR_ANY 0x00004000 /* Match any access mode */ +#define ACR_CM_WT 0x00000000 /* Write through mode */ +#define ACR_CM_CP 0x00000020 /* Copyback mode */ +#define ACR_CM_OFF_PRE 0x00000040 /* No cache, precise */ +#define ACR_CM_OFF_IMP 0x00000060 /* No cache, imprecise */ +#define ACR_WPROTECT 0x00000004 /* Write protect */ + /****************************************************************************/ #endif /* m5407sim_h */ diff --git a/trunk/arch/m68k/include/asm/m54xxgpt.h b/trunk/arch/m68k/include/asm/m548xgpt.h similarity index 95% rename from trunk/arch/m68k/include/asm/m54xxgpt.h rename to trunk/arch/m68k/include/asm/m548xgpt.h index df75dd87ae7a..33b2eef90f0a 100644 --- a/trunk/arch/m68k/include/asm/m54xxgpt.h +++ b/trunk/arch/m68k/include/asm/m548xgpt.h @@ -1,13 +1,13 @@ /* - * File: m54xxgpt.h - * Purpose: Register and bit definitions for the MCF54XX + * File: m548xgpt.h + * Purpose: Register and bit definitions for the MCF548X * * Notes: * */ -#ifndef m54xxgpt_h -#define m54xxgpt_h +#ifndef m548xgpt_h +#define m548xgpt_h /********************************************************************* * @@ -87,4 +87,4 @@ /********************************************************************/ -#endif /* m54xxgpt_h */ +#endif /* m548xgpt_h */ diff --git a/trunk/arch/m68k/include/asm/m54xxsim.h b/trunk/arch/m68k/include/asm/m548xsim.h similarity index 73% rename from trunk/arch/m68k/include/asm/m54xxsim.h rename to trunk/arch/m68k/include/asm/m548xsim.h index 462ae5328441..149135ef30d2 100644 --- a/trunk/arch/m68k/include/asm/m54xxsim.h +++ b/trunk/arch/m68k/include/asm/m548xsim.h @@ -1,16 +1,11 @@ /* - * m54xxsim.h -- ColdFire 547x/548x System Integration Unit support. + * m548xsim.h -- ColdFire 547x/548x System Integration Unit support. */ -#ifndef m54xxsim_h -#define m54xxsim_h +#ifndef m548xsim_h +#define m548xsim_h -#define CPU_NAME "COLDFIRE(m54xx)" -#define CPU_INSTR_PER_JIFFY 2 - -#include - -#define MCFINT_VECBASE 64 +#define MCFINT_VECBASE 64 /* * Interrupt Controller Registers @@ -26,14 +21,6 @@ #define MCFINTC_IACKL 0x19 /* */ #define MCFINTC_ICR0 0x40 /* Base ICR register */ -/* - * UART module. - */ -#define MCFUART_BASE1 0x8600 /* Base address of UART1 */ -#define MCFUART_BASE2 0x8700 /* Base address of UART2 */ -#define MCFUART_BASE3 0x8800 /* Base address of UART3 */ -#define MCFUART_BASE4 0x8900 /* Base address of UART4 */ - /* * Define system peripheral IRQ usage. */ @@ -65,4 +52,4 @@ #define MCF_PAR_PSC_RTS_RTS (0x30) #define MCF_PAR_PSC_CANRX (0x40) -#endif /* m54xxsim_h */ +#endif /* m548xsim_h */ diff --git a/trunk/arch/m68k/include/asm/m54xxacr.h b/trunk/arch/m68k/include/asm/m54xxacr.h deleted file mode 100644 index 16a1835f9b2a..000000000000 --- a/trunk/arch/m68k/include/asm/m54xxacr.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Bit definitions for the MCF54xx ACR and CACR registers. - */ - -#ifndef m54xxacr_h -#define m54xxacr_h - -/* - * Define the Cache register flags. - */ -#define CACR_DEC 0x80000000 /* Enable data cache */ -#define CACR_DWP 0x40000000 /* Data write protection */ -#define CACR_DESB 0x20000000 /* Enable data store buffer */ -#define CACR_DDPI 0x10000000 /* Disable invalidation by CPUSHL */ -#define CACR_DHCLK 0x08000000 /* Half data cache lock mode */ -#define CACR_DDCM_WT 0x00000000 /* Write through cache*/ -#define CACR_DDCM_CP 0x02000000 /* Copyback cache */ -#define CACR_DDCM_P 0x04000000 /* No cache, precise */ -#define CACR_DDCM_IMP 0x06000000 /* No cache, imprecise */ -#define CACR_DCINVA 0x01000000 /* Invalidate data cache */ -#define CACR_BEC 0x00080000 /* Enable branch cache */ -#define CACR_BCINVA 0x00040000 /* Invalidate branch cache */ -#define CACR_IEC 0x00008000 /* Enable instruction cache */ -#define CACR_DNFB 0x00002000 /* Inhibited fill buffer */ -#define CACR_IDPI 0x00001000 /* Disable CPUSHL */ -#define CACR_IHLCK 0x00000800 /* Intruction cache half lock */ -#define CACR_IDCM 0x00000400 /* Intruction cache inhibit */ -#define CACR_ICINVA 0x00000100 /* Invalidate instr cache */ -#define CACR_EUSP 0x00000020 /* Enable separate user a7 */ - -#define ACR_BASE_POS 24 /* Address Base */ -#define ACR_MASK_POS 16 /* Address Mask */ -#define ACR_ENABLE 0x00008000 /* Enable address */ -#define ACR_USER 0x00000000 /* User mode access only */ -#define ACR_SUPER 0x00002000 /* Supervisor mode only */ -#define ACR_ANY 0x00004000 /* Match any access mode */ -#define ACR_CM_WT 0x00000000 /* Write through mode */ -#define ACR_CM_CP 0x00000020 /* Copyback mode */ -#define ACR_CM_OFF_PRE 0x00000040 /* No cache, precise */ -#define ACR_CM_OFF_IMP 0x00000060 /* No cache, imprecise */ -#define ACR_CM 0x00000060 /* Cache mode mask */ -#define ACR_WPROTECT 0x00000004 /* Write protect */ - -#if defined(CONFIG_M5407) - -#define ICACHE_SIZE 0x4000 /* instruction - 16k */ -#define DCACHE_SIZE 0x2000 /* data - 8k */ - -#elif defined(CONFIG_M54xx) - -#define ICACHE_SIZE 0x8000 /* instruction - 32k */ -#define DCACHE_SIZE 0x8000 /* data - 32k */ - -#endif - -#define CACHE_LINE_SIZE 0x0010 /* 16 bytes */ -#define CACHE_WAYS 4 /* 4 ways */ - -/* - * Version 4 cores have a true harvard style separate instruction - * and data cache. Enable data and instruction caches, also enable write - * buffers and branch accelerator. - */ -/* attention : enabling CACR_DESB requires a "nop" to flush the store buffer */ -/* use '+' instead of '|' for assembler's sake */ - - /* Enable data cache */ - /* Enable data store buffer */ - /* outside ACRs : No cache, precise */ - /* Enable instruction+branch caches */ -#if defined(CONFIG_M5407) -#define CACHE_MODE (CACR_DEC+CACR_DESB+CACR_DDCM_P+CACR_BEC+CACR_IEC) -#else -#define CACHE_MODE (CACR_DEC+CACR_DESB+CACR_DDCM_P+CACR_BEC+CACR_IEC+CACR_EUSP) -#endif -#if defined(CONFIG_CACHE_COPYBACK) -#define DATA_CACHE_MODE (ACR_ENABLE+ACR_ANY+ACR_CM_CP) -#else -#define DATA_CACHE_MODE (ACR_ENABLE+ACR_ANY+ACR_CM_WT) -#endif -#define INSN_CACHE_MODE (ACR_ENABLE+ACR_ANY) - -#define CACHE_INIT (CACR_DCINVA+CACR_BCINVA+CACR_ICINVA) -#define CACHE_INVALIDATE (CACHE_MODE+CACR_DCINVA+CACR_BCINVA+CACR_ICINVA) -#define CACHE_INVALIDATEI (CACHE_MODE+CACR_BCINVA+CACR_ICINVA) -#define CACHE_INVALIDATED (CACHE_MODE+CACR_DCINVA) -#define ACR0_MODE (0x000f0000+DATA_CACHE_MODE) -#define ACR1_MODE 0 -#define ACR2_MODE (0x000f0000+INSN_CACHE_MODE) -#define ACR3_MODE 0 - -#if ((DATA_CACHE_MODE & ACR_CM) == ACR_CM_CP) -/* Copyback cache mode must push dirty cache lines first */ -#define CACHE_PUSH -#endif - -#endif /* m54xxacr_h */ diff --git a/trunk/arch/m68k/include/asm/mcfcache.h b/trunk/arch/m68k/include/asm/mcfcache.h new file mode 100644 index 000000000000..f49dfc09f70a --- /dev/null +++ b/trunk/arch/m68k/include/asm/mcfcache.h @@ -0,0 +1,150 @@ +/****************************************************************************/ + +/* + * mcfcache.h -- ColdFire CPU cache support code + * + * (C) Copyright 2004, Greg Ungerer + */ + +/****************************************************************************/ +#ifndef __M68KNOMMU_MCFCACHE_H +#define __M68KNOMMU_MCFCACHE_H +/****************************************************************************/ + + +/* + * The different ColdFire families have different cache arrangments. + * Everything from a small instruction only cache, to configurable + * data and/or instruction cache, to unified instruction/data, to + * harvard style separate instruction and data caches. + */ + +#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || defined(CONFIG_M5272) +/* + * Simple version 2 core cache. These have instruction cache only, + * we just need to invalidate it and enable it. + */ +.macro CACHE_ENABLE + movel #0x01000000,%d0 /* invalidate cache cmd */ + movec %d0,%CACR /* do invalidate cache */ + movel #0x80000100,%d0 /* setup cache mask */ + movec %d0,%CACR /* enable cache */ +.endm +#endif /* CONFIG_M5206 || CONFIG_M5206e || CONFIG_M5272 */ + +#if defined(CONFIG_M523x) || defined(CONFIG_M527x) +/* + * New version 2 cores have a configurable split cache arrangement. + * For now I am just enabling instruction cache - but ultimately I + * think a split instruction/data cache would be better. + */ +.macro CACHE_ENABLE + movel #0x01400000,%d0 + movec %d0,%CACR /* invalidate cache */ + nop + movel #0x0000c000,%d0 /* set SDRAM cached only */ + movec %d0,%ACR0 + movel #0x00000000,%d0 /* no other regions cached */ + movec %d0,%ACR1 + movel #0x80400100,%d0 /* configure cache */ + movec %d0,%CACR /* enable cache */ + nop +.endm +#endif /* CONFIG_M523x || CONFIG_M527x */ + +#if defined(CONFIG_M528x) +.macro CACHE_ENABLE + nop + movel #0x01000000, %d0 + movec %d0, %CACR /* Invalidate cache */ + nop + movel #0x0000c020, %d0 /* Set SDRAM cached only */ + movec %d0, %ACR0 + movel #0x00000000, %d0 /* No other regions cached */ + movec %d0, %ACR1 + movel #0x80000200, %d0 /* Setup cache mask */ + movec %d0, %CACR /* Enable cache */ + nop +.endm +#endif /* CONFIG_M528x */ + +#if defined(CONFIG_M5249) || defined(CONFIG_M5307) +/* + * The version 3 core cache. Oddly enough the version 2 core 5249 + * has the same SDRAM and cache setup as the version 3 cores. + * This is a single unified instruction/data cache. + */ +.macro CACHE_ENABLE + movel #0x01000000,%d0 /* invalidate whole cache */ + movec %d0,%CACR + nop +#if defined(DEBUGGER_COMPATIBLE_CACHE) || defined(CONFIG_SECUREEDGEMP3) + movel #0x0000c000,%d0 /* set SDRAM cached (write-thru) */ +#else + movel #0x0000c020,%d0 /* set SDRAM cached (copyback) */ +#endif + movec %d0,%ACR0 + movel #0x00000000,%d0 /* no other regions cached */ + movec %d0,%ACR1 + movel #0xa0000200,%d0 /* enable cache */ + movec %d0,%CACR + nop +.endm +#endif /* CONFIG_M5249 || CONFIG_M5307 */ + +#if defined(CONFIG_M532x) +.macro CACHE_ENABLE + movel #0x01000000,%d0 /* invalidate cache cmd */ + movec %d0,%CACR /* do invalidate cache */ + nop + movel #0x4001C000,%d0 /* set SDRAM cached (write-thru) */ + movec %d0,%ACR0 + movel #0x00000000,%d0 /* no other regions cached */ + movec %d0,%ACR1 + movel #0x80000200,%d0 /* setup cache mask */ + movec %d0,%CACR /* enable cache */ + nop +.endm +#endif /* CONFIG_M532x */ + +#if defined(CONFIG_M5407) || defined(CONFIG_M548x) +/* + * Version 4 cores have a true harvard style separate instruction + * and data cache. Invalidate and enable cache, also enable write + * buffers and branch accelerator. + */ +.macro CACHE_ENABLE + movel #0x01040100,%d0 /* invalidate whole cache */ + movec %d0,%CACR + nop + movel #0x000fc000,%d0 /* set SDRAM cached only */ + movec %d0, %ACR0 + movel #0x00000000,%d0 /* no other regions cached */ + movec %d0, %ACR1 + movel #0x000fc000,%d0 /* set SDRAM cached only */ + movec %d0, %ACR2 + movel #0x00000000,%d0 /* no other regions cached */ + movec %d0, %ACR3 + movel #0xb6088400,%d0 /* enable caches */ + movec %d0,%CACR + nop +.endm +#endif /* CONFIG_M5407 */ + +#if defined(CONFIG_M520x) +.macro CACHE_ENABLE + move.l #0x01000000,%d0 /* invalidate whole cache */ + movec %d0,%CACR + nop + move.l #0x0000c000,%d0 /* set SDRAM cached (write-thru) */ + movec %d0,%ACR0 + move.l #0x00000000,%d0 /* no other regions cached */ + movec %d0,%ACR1 + move.l #0x80400000,%d0 /* enable 8K instruction cache */ + movec %d0,%CACR + nop +.endm +#endif /* CONFIG_M520x */ + +/****************************************************************************/ +#endif /* __M68KNOMMU_MCFCACHE_H */ diff --git a/trunk/arch/m68k/include/asm/mcfsim.h b/trunk/arch/m68k/include/asm/mcfsim.h index ebd0304054ad..6901fd68165b 100644 --- a/trunk/arch/m68k/include/asm/mcfsim.h +++ b/trunk/arch/m68k/include/asm/mcfsim.h @@ -41,8 +41,8 @@ #elif defined(CONFIG_M5407) #include #include -#elif defined(CONFIG_M54xx) -#include +#elif defined(CONFIG_M548x) +#include #endif /****************************************************************************/ diff --git a/trunk/arch/m68k/include/asm/mcfuart.h b/trunk/arch/m68k/include/asm/mcfuart.h index 2abedff0a694..db72e2b889ca 100644 --- a/trunk/arch/m68k/include/asm/mcfuart.h +++ b/trunk/arch/m68k/include/asm/mcfuart.h @@ -12,6 +12,49 @@ #define mcfuart_h /****************************************************************************/ +/* + * Define the base address of the UARTS within the MBAR address + * space. + */ +#if defined(CONFIG_M5272) +#define MCFUART_BASE1 0x100 /* Base address of UART1 */ +#define MCFUART_BASE2 0x140 /* Base address of UART2 */ +#elif defined(CONFIG_M5206) || defined(CONFIG_M5206e) +#if defined(CONFIG_NETtel) +#define MCFUART_BASE1 0x180 /* Base address of UART1 */ +#define MCFUART_BASE2 0x140 /* Base address of UART2 */ +#else +#define MCFUART_BASE1 0x140 /* Base address of UART1 */ +#define MCFUART_BASE2 0x180 /* Base address of UART2 */ +#endif +#elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) +#define MCFUART_BASE1 0x200 /* Base address of UART1 */ +#define MCFUART_BASE2 0x240 /* Base address of UART2 */ +#define MCFUART_BASE3 0x280 /* Base address of UART3 */ +#elif defined(CONFIG_M5249) || defined(CONFIG_M5307) || defined(CONFIG_M5407) +#if defined(CONFIG_NETtel) || defined(CONFIG_SECUREEDGEMP3) +#define MCFUART_BASE1 0x200 /* Base address of UART1 */ +#define MCFUART_BASE2 0x1c0 /* Base address of UART2 */ +#else +#define MCFUART_BASE1 0x1c0 /* Base address of UART1 */ +#define MCFUART_BASE2 0x200 /* Base address of UART2 */ +#endif +#elif defined(CONFIG_M520x) +#define MCFUART_BASE1 0x60000 /* Base address of UART1 */ +#define MCFUART_BASE2 0x64000 /* Base address of UART2 */ +#define MCFUART_BASE3 0x68000 /* Base address of UART2 */ +#elif defined(CONFIG_M532x) +#define MCFUART_BASE1 0xfc060000 /* Base address of UART1 */ +#define MCFUART_BASE2 0xfc064000 /* Base address of UART2 */ +#define MCFUART_BASE3 0xfc068000 /* Base address of UART3 */ +#elif defined(CONFIG_M548x) +#define MCFUART_BASE1 0x8600 /* on M548x */ +#define MCFUART_BASE2 0x8700 /* on M548x */ +#define MCFUART_BASE3 0x8800 /* on M548x */ +#define MCFUART_BASE4 0x8900 /* on M548x */ +#endif + + #include #include @@ -174,7 +217,7 @@ struct mcf_platform_uart { #define MCFUART_URF_RXS 0xc0 /* Receiver status */ #endif -#if defined(CONFIG_M54xx) +#if defined(CONFIG_M548x) #define MCFUART_TXFIFOSIZE 512 #elif defined(CONFIG_M5272) #define MCFUART_TXFIFOSIZE 25 diff --git a/trunk/arch/m68k/include/asm/processor.h b/trunk/arch/m68k/include/asm/processor.h index 278c69bad57a..7a6a7590cc02 100644 --- a/trunk/arch/m68k/include/asm/processor.h +++ b/trunk/arch/m68k/include/asm/processor.h @@ -20,26 +20,23 @@ static inline unsigned long rdusp(void) { -#ifdef CONFIG_COLDFIRE_SW_A7 +#ifdef CONFIG_COLDFIRE extern unsigned int sw_usp; return sw_usp; #else - register unsigned long usp __asm__("a0"); - /* move %usp,%a0 */ - __asm__ __volatile__(".word 0x4e68" : "=a" (usp)); + unsigned long usp; + __asm__ __volatile__("move %/usp,%0" : "=a" (usp)); return usp; #endif } static inline void wrusp(unsigned long usp) { -#ifdef CONFIG_COLDFIRE_SW_A7 +#ifdef CONFIG_COLDFIRE extern unsigned int sw_usp; sw_usp = usp; #else - register unsigned long a0 __asm__("a0") = usp; - /* move %a0,%usp */ - __asm__ __volatile__(".word 0x4e60" : : "a" (a0) ); + __asm__ __volatile__("move %0,%/usp" : : "a" (usp)); #endif } diff --git a/trunk/arch/m68knommu/Kconfig b/trunk/arch/m68knommu/Kconfig index 704e7b92334c..fa9f746cf4ae 100644 --- a/trunk/arch/m68knommu/Kconfig +++ b/trunk/arch/m68knommu/Kconfig @@ -75,16 +75,6 @@ config GENERIC_CLOCKEVENTS config NO_IOPORT def_bool y -config COLDFIRE_SW_A7 - bool - default n - -config HAVE_CACHE_SPLIT - bool - -config HAVE_CACHE_CB - bool - source "init/Kconfig" source "kernel/Kconfig.freezer" @@ -117,90 +107,69 @@ config M68360 config M5206 bool "MCF5206" - select COLDFIRE_SW_A7 help Motorola ColdFire 5206 processor support. config M5206e bool "MCF5206e" - select COLDFIRE_SW_A7 help Motorola ColdFire 5206e processor support. config M520x bool "MCF520x" select GENERIC_CLOCKEVENTS - select HAVE_CACHE_SPLIT help Freescale Coldfire 5207/5208 processor support. config M523x bool "MCF523x" select GENERIC_CLOCKEVENTS - select HAVE_CACHE_SPLIT help Freescale Coldfire 5230/1/2/4/5 processor support config M5249 bool "MCF5249" - select COLDFIRE_SW_A7 help Motorola ColdFire 5249 processor support. config M5271 bool "MCF5271" - select HAVE_CACHE_SPLIT help Freescale (Motorola) ColdFire 5270/5271 processor support. config M5272 bool "MCF5272" - select COLDFIRE_SW_A7 help Motorola ColdFire 5272 processor support. config M5275 bool "MCF5275" - select HAVE_CACHE_SPLIT help Freescale (Motorola) ColdFire 5274/5275 processor support. config M528x bool "MCF528x" select GENERIC_CLOCKEVENTS - select HAVE_CACHE_SPLIT help Motorola ColdFire 5280/5282 processor support. config M5307 bool "MCF5307" - select COLDFIRE_SW_A7 - select HAVE_CACHE_CB help Motorola ColdFire 5307 processor support. config M532x bool "MCF532x" - select HAVE_CACHE_CB help Freescale (Motorola) ColdFire 532x processor support. config M5407 bool "MCF5407" - select COLDFIRE_SW_A7 - select HAVE_CACHE_CB help Motorola ColdFire 5407 processor support. -config M547x - bool "MCF547x" - select HAVE_CACHE_CB - help - Freescale ColdFire 5470/5471/5472/5473/5474/5475 processor support. - config M548x bool "MCF548x" - select HAVE_CACHE_CB help Freescale ColdFire 5480/5481/5482/5483/5484/5485 processor support. @@ -212,14 +181,9 @@ config M527x select GENERIC_CLOCKEVENTS default y -config M54xx - bool - depends on (M548x || M547x) - default y - config COLDFIRE bool - depends on (M5206 || M5206e || M520x || M523x || M5249 || M527x || M5272 || M528x || M5307 || M532x || M5407 || M54xx) + depends on (M5206 || M5206e || M520x || M523x || M5249 || M527x || M5272 || M528x || M5307 || M532x || M5407 || M548x) select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB default y @@ -266,46 +230,6 @@ config OLDMASK Build support for the older revision ColdFire 5307 silicon. Specifically this is the 1H55J mask revision. -if HAVE_CACHE_SPLIT -choice - prompt "Split Cache Configuration" - default CACHE_I - -config CACHE_I - bool "Instruction" - help - Use all of the ColdFire CPU cache memory as an instruction cache. - -config CACHE_D - bool "Data" - help - Use all of the ColdFire CPU cache memory as a data cache. - -config CACHE_BOTH - bool "Both" - help - Split the ColdFire CPU cache, and use half as an instruction cache - and half as a data cache. -endchoice -endif - -if HAVE_CACHE_CB -choice - prompt "Data cache mode" - default CACHE_WRITETHRU - -config CACHE_WRITETHRU - bool "Write-through" - help - The ColdFire CPU cache is set into Write-through mode. - -config CACHE_COPYBACK - bool "Copy-back" - help - The ColdFire CPU cache is set into Copy-back mode. -endchoice -endif - comment "Platform" config PILOT3 @@ -321,16 +245,16 @@ config XCOPILOT_BUGS Support the bugs of Xcopilot. config UC5272 - bool 'Arcturus Networks uC5272 dimm board support' - depends on M5272 - help - Support for the Arcturus Networks uC5272 dimm board. + bool 'Arcturus Networks uC5272 dimm board support' + depends on M5272 + help + Support for the Arcturus Networks uC5272 dimm board. config UC5282 - bool "Arcturus Networks uC5282 board support" - depends on M528x - help - Support for the Arcturus Networks uC5282 dimm board. + bool "Arcturus Networks uC5282 board support" + depends on M528x + help + Support for the Arcturus Networks uC5282 dimm board. config UCSIMM bool "uCsimm module support" @@ -355,7 +279,7 @@ config DIRECT_IO_ACCESS depends on (UCSIMM || UCDIMM || DRAGEN2) help Disable the CPU internal registers protection in user mode, - to allow a user application to read/write them. + to allow a user application to read/write them. config INIT_LCD bool "Initialize LCD" @@ -593,7 +517,7 @@ config EMAC_INC depends on (SOM5282EM) config SNEHA - bool + bool default y depends on CPU16B diff --git a/trunk/arch/m68knommu/Makefile b/trunk/arch/m68knommu/Makefile index 589613fed31d..026ef16fa68e 100644 --- a/trunk/arch/m68knommu/Makefile +++ b/trunk/arch/m68knommu/Makefile @@ -25,7 +25,7 @@ platform-$(CONFIG_M528x) := 528x platform-$(CONFIG_M5307) := 5307 platform-$(CONFIG_M532x) := 532x platform-$(CONFIG_M5407) := 5407 -platform-$(CONFIG_M54xx) := 54xx +platform-$(CONFIG_M548x) := 548x PLATFORM := $(platform-y) board-$(CONFIG_PILOT) := pilot @@ -74,7 +74,7 @@ cpuclass-$(CONFIG_M528x) := coldfire cpuclass-$(CONFIG_M5307) := coldfire cpuclass-$(CONFIG_M532x) := coldfire cpuclass-$(CONFIG_M5407) := coldfire -cpuclass-$(CONFIG_M54xx) := coldfire +cpuclass-$(CONFIG_M548x) := coldfire cpuclass-$(CONFIG_M68328) := 68328 cpuclass-$(CONFIG_M68EZ328) := 68328 cpuclass-$(CONFIG_M68VZ328) := 68328 @@ -91,18 +91,18 @@ export PLATFORM BOARD MODEL CPUCLASS # Some CFLAG additions based on specific CPU type. # cflags-$(CONFIG_M5206) := $(call cc-option,-mcpu=5206,-m5200) -cflags-$(CONFIG_M5206e) := $(call cc-option,-mcpu=5206e,-m5200) +cflags-$(CONFIG_M5206e) := $(call cc-option,-m5206e,-m5200) cflags-$(CONFIG_M520x) := $(call cc-option,-mcpu=5208,-m5200) cflags-$(CONFIG_M523x) := $(call cc-option,-mcpu=523x,-m5307) cflags-$(CONFIG_M5249) := $(call cc-option,-mcpu=5249,-m5200) cflags-$(CONFIG_M5271) := $(call cc-option,-mcpu=5271,-m5307) cflags-$(CONFIG_M5272) := $(call cc-option,-mcpu=5272,-m5307) cflags-$(CONFIG_M5275) := $(call cc-option,-mcpu=5275,-m5307) -cflags-$(CONFIG_M528x) := $(call cc-option,-mcpu=528x,-m5307) -cflags-$(CONFIG_M5307) := $(call cc-option,-mcpu=5307,-m5200) +cflags-$(CONFIG_M528x) := $(call cc-option,-m528x,-m5307) +cflags-$(CONFIG_M5307) := $(call cc-option,-m5307,-m5200) cflags-$(CONFIG_M532x) := $(call cc-option,-mcpu=532x,-m5307) -cflags-$(CONFIG_M5407) := $(call cc-option,-mcpu=5407,-m5200) -cflags-$(CONFIG_M54xx) := $(call cc-option,-mcpu=5475,-m5200) +cflags-$(CONFIG_M5407) := $(call cc-option,-m5407,-m5200) +cflags-$(CONFIG_M548x) := $(call cc-option,-m5407,-m5200) cflags-$(CONFIG_M68328) := -m68000 cflags-$(CONFIG_M68EZ328) := -m68000 cflags-$(CONFIG_M68VZ328) := -m68000 diff --git a/trunk/arch/m68knommu/kernel/setup.c b/trunk/arch/m68knommu/kernel/setup.c index 16b2de7f5101..c684adf5dc40 100644 --- a/trunk/arch/m68knommu/kernel/setup.c +++ b/trunk/arch/m68knommu/kernel/setup.c @@ -55,29 +55,55 @@ void (*mach_halt)(void); void (*mach_power_off)(void); #ifdef CONFIG_M68328 -#define CPU_NAME "MC68328" + #define CPU "MC68328" #endif #ifdef CONFIG_M68EZ328 -#define CPU_NAME "MC68EZ328" + #define CPU "MC68EZ328" #endif #ifdef CONFIG_M68VZ328 -#define CPU_NAME "MC68VZ328" + #define CPU "MC68VZ328" #endif #ifdef CONFIG_M68360 -#define CPU_NAME "MC68360" + #define CPU "MC68360" #endif -#ifndef CPU_NAME -#define CPU_NAME "UNKNOWN" +#if defined(CONFIG_M5206) + #define CPU "COLDFIRE(m5206)" #endif - -/* - * Different cores have different instruction execution timings. - * The old/traditional 68000 cores are basically all the same, at 16. - * The ColdFire cores vary a little, their values are defined in their - * headers. We default to the standard 68000 value here. - */ -#ifndef CPU_INSTR_PER_JIFFY -#define CPU_INSTR_PER_JIFFY 16 +#if defined(CONFIG_M5206e) + #define CPU "COLDFIRE(m5206e)" +#endif +#if defined(CONFIG_M520x) + #define CPU "COLDFIRE(m520x)" +#endif +#if defined(CONFIG_M523x) + #define CPU "COLDFIRE(m523x)" +#endif +#if defined(CONFIG_M5249) + #define CPU "COLDFIRE(m5249)" +#endif +#if defined(CONFIG_M5271) + #define CPU "COLDFIRE(m5270/5271)" +#endif +#if defined(CONFIG_M5272) + #define CPU "COLDFIRE(m5272)" +#endif +#if defined(CONFIG_M5275) + #define CPU "COLDFIRE(m5274/5275)" +#endif +#if defined(CONFIG_M528x) + #define CPU "COLDFIRE(m5280/5282)" +#endif +#if defined(CONFIG_M5307) + #define CPU "COLDFIRE(m5307)" +#endif +#if defined(CONFIG_M532x) + #define CPU "COLDFIRE(m532x)" +#endif +#if defined(CONFIG_M5407) + #define CPU "COLDFIRE(m5407)" +#endif +#ifndef CPU + #define CPU "UNKNOWN" #endif extern int _stext, _etext, _sdata, _edata, _sbss, _ebss, _end; @@ -182,7 +208,7 @@ void __init setup_arch(char **cmdline_p) command_line[sizeof(command_line) - 1] = 0; #endif /* CONFIG_UBOOT */ - printk(KERN_INFO "\x0F\r\n\nuClinux/" CPU_NAME "\n"); + printk(KERN_INFO "\x0F\r\n\nuClinux/" CPU "\n"); #ifdef CONFIG_UCDIMM printk(KERN_INFO "uCdimm by Lineo, Inc. \n"); @@ -231,6 +257,11 @@ void __init setup_arch(char **cmdline_p) memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); boot_command_line[COMMAND_LINE_SIZE-1] = 0; +#ifdef DEBUG + if (strlen(*cmdline_p)) + printk(KERN_DEBUG "Command line: '%s'\n", *cmdline_p); +#endif + #if defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_DUMMY_CONSOLE) conswitchp = &dummy_con; #endif @@ -272,10 +303,15 @@ static int show_cpuinfo(struct seq_file *m, void *v) char *cpu, *mmu, *fpu; u_long clockfreq; - cpu = CPU_NAME; + cpu = CPU; mmu = "none"; fpu = "none"; - clockfreq = (loops_per_jiffy * HZ) * CPU_INSTR_PER_JIFFY; + +#ifdef CONFIG_COLDFIRE + clockfreq = (loops_per_jiffy * HZ) * 3; +#else + clockfreq = (loops_per_jiffy * HZ) * 16; +#endif seq_printf(m, "CPU:\t\t%s\n" "MMU:\t\t%s\n" diff --git a/trunk/arch/m68knommu/mm/Makefile b/trunk/arch/m68knommu/mm/Makefile index b54ab6b4b523..fc91f254f51b 100644 --- a/trunk/arch/m68knommu/mm/Makefile +++ b/trunk/arch/m68knommu/mm/Makefile @@ -2,4 +2,4 @@ # Makefile for the linux m68knommu specific parts of the memory manager. # -obj-y += init.o kmap.o +obj-y += init.o fault.o memory.o kmap.o diff --git a/trunk/arch/m68knommu/mm/fault.c b/trunk/arch/m68knommu/mm/fault.c new file mode 100644 index 000000000000..bc05cf74d9c0 --- /dev/null +++ b/trunk/arch/m68knommu/mm/fault.c @@ -0,0 +1,57 @@ +/* + * linux/arch/m68knommu/mm/fault.c + * + * Copyright (C) 1998 D. Jeff Dionne , + * Copyright (C) 2000 Lineo, Inc. (www.lineo.com) + * + * Based on: + * + * linux/arch/m68k/mm/fault.c + * + * Copyright (C) 1995 Hamish Macdonald + */ + +#include +#include +#include +#include + +#include +#include + +extern void die_if_kernel(char *, struct pt_regs *, long); + +/* + * This routine handles page faults. It determines the problem, and + * then passes it off to one of the appropriate routines. + * + * error_code: + * bit 0 == 0 means no page found, 1 means protection fault + * bit 1 == 0 means read, 1 means write + * + * If this routine detects a bad access, it returns 1, otherwise it + * returns 0. + */ +asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, + unsigned long error_code) +{ +#ifdef DEBUG + printk(KERN_DEBUG "regs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld\n", + regs->sr, regs->pc, address, error_code); +#endif + + /* + * Oops. The kernel tried to access some bad page. We'll have to + * terminate things with extreme prejudice. + */ + if ((unsigned long) address < PAGE_SIZE) + printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); + else + printk(KERN_ALERT "Unable to handle kernel access"); + printk(KERN_ALERT " at virtual address %08lx\n", address); + die_if_kernel("Oops", regs, error_code); + do_exit(SIGKILL); + + return 1; +} + diff --git a/trunk/arch/m68knommu/mm/kmap.c b/trunk/arch/m68knommu/mm/kmap.c index ece8d5ad4e6c..902c1dfda9e5 100644 --- a/trunk/arch/m68knommu/mm/kmap.c +++ b/trunk/arch/m68knommu/mm/kmap.c @@ -35,6 +35,15 @@ void iounmap(void *addr) { } +/* + * __iounmap unmaps nearly everything, so be careful + * it doesn't free currently pointer/page tables anymore but it + * wans't used anyway and might be added later. + */ +void __iounmap(void *addr, unsigned long size) +{ +} + /* * Set new cache mode for some kernel address space. * The caller must push data for that range itself, if such data may already diff --git a/trunk/arch/m68knommu/mm/memory.c b/trunk/arch/m68knommu/mm/memory.c new file mode 100644 index 000000000000..8f7949e786d4 --- /dev/null +++ b/trunk/arch/m68knommu/mm/memory.c @@ -0,0 +1,33 @@ +/* + * linux/arch/m68knommu/mm/memory.c + * + * Copyright (C) 1998 Kenneth Albanowski , + * Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com) + * + * Based on: + * + * linux/arch/m68k/mm/memory.c + * + * Copyright (C) 1995 Hamish Macdonald + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * Map some physical address range into the kernel address space. + */ + +unsigned long kernel_map(unsigned long paddr, unsigned long size, + int nocacheflag, unsigned long *memavailp ) +{ + return paddr; +} + diff --git a/trunk/arch/m68knommu/platform/54xx/Makefile b/trunk/arch/m68knommu/platform/548x/Makefile similarity index 100% rename from trunk/arch/m68knommu/platform/54xx/Makefile rename to trunk/arch/m68knommu/platform/548x/Makefile diff --git a/trunk/arch/m68knommu/platform/54xx/config.c b/trunk/arch/m68knommu/platform/548x/config.c similarity index 74% rename from trunk/arch/m68knommu/platform/54xx/config.c rename to trunk/arch/m68knommu/platform/548x/config.c index 78130984db95..9888846bd1cf 100644 --- a/trunk/arch/m68knommu/platform/54xx/config.c +++ b/trunk/arch/m68knommu/platform/548x/config.c @@ -1,7 +1,7 @@ /***************************************************************************/ /* - * linux/arch/m68knommu/platform/54xx/config.c + * linux/arch/m68knommu/platform/548x/config.c * * Copyright (C) 2010, Philippe De Muyter */ @@ -15,13 +15,13 @@ #include #include #include -#include +#include #include -#include +#include /***************************************************************************/ -static struct mcf_platform_uart m54xx_uart_platform[] = { +static struct mcf_platform_uart m548x_uart_platform[] = { { .mapbase = MCF_MBAR + MCFUART_BASE1, .irq = 64 + 35, @@ -40,20 +40,20 @@ static struct mcf_platform_uart m54xx_uart_platform[] = { }, }; -static struct platform_device m54xx_uart = { +static struct platform_device m548x_uart = { .name = "mcfuart", .id = 0, - .dev.platform_data = m54xx_uart_platform, + .dev.platform_data = m548x_uart_platform, }; -static struct platform_device *m54xx_devices[] __initdata = { - &m54xx_uart, +static struct platform_device *m548x_devices[] __initdata = { + &m548x_uart, }; /***************************************************************************/ -static void __init m54xx_uart_init_line(int line, int irq) +static void __init m548x_uart_init_line(int line, int irq) { int rts_cts; @@ -72,18 +72,18 @@ static void __init m54xx_uart_init_line(int line, int irq) MCF_MBAR + MCF_PAR_PSC(line)); } -static void __init m54xx_uarts_init(void) +static void __init m548x_uarts_init(void) { - const int nrlines = ARRAY_SIZE(m54xx_uart_platform); + const int nrlines = ARRAY_SIZE(m548x_uart_platform); int line; for (line = 0; (line < nrlines); line++) - m54xx_uart_init_line(line, m54xx_uart_platform[line].irq); + m548x_uart_init_line(line, m548x_uart_platform[line].irq); } /***************************************************************************/ -static void mcf54xx_reset(void) +static void mcf548x_reset(void) { /* disable interrupts and enable the watchdog */ asm("movew #0x2700, %sr\n"); @@ -97,8 +97,8 @@ static void mcf54xx_reset(void) void __init config_BSP(char *commandp, int size) { - mach_reset = mcf54xx_reset; - m54xx_uarts_init(); + mach_reset = mcf548x_reset; + m548x_uarts_init(); } /***************************************************************************/ @@ -106,7 +106,7 @@ void __init config_BSP(char *commandp, int size) static int __init init_BSP(void) { - platform_add_devices(m54xx_devices, ARRAY_SIZE(m54xx_devices)); + platform_add_devices(m548x_devices, ARRAY_SIZE(m548x_devices)); return 0; } diff --git a/trunk/arch/m68knommu/platform/68328/ints.c b/trunk/arch/m68knommu/platform/68328/ints.c index 2a3af193ccd3..865852806a17 100644 --- a/trunk/arch/m68knommu/platform/68328/ints.c +++ b/trunk/arch/m68knommu/platform/68328/ints.c @@ -179,8 +179,8 @@ void __init init_IRQ(void) IMR = ~0; for (i = 0; (i < NR_IRQS); i++) { - set_irq_chip(i, &intc_irq_chip); - set_irq_handler(i, handle_level_irq); + set_irq_chip(irq, &intc_irq_chip); + set_irq_handler(irq, handle_level_irq); } } diff --git a/trunk/arch/m68knommu/platform/coldfire/Makefile b/trunk/arch/m68knommu/platform/coldfire/Makefile index a8967baabd72..45f501fa4525 100644 --- a/trunk/arch/m68knommu/platform/coldfire/Makefile +++ b/trunk/arch/m68knommu/platform/coldfire/Makefile @@ -14,7 +14,7 @@ asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 -obj-$(CONFIG_COLDFIRE) += cache.o clk.o dma.o entry.o vectors.o +obj-$(CONFIG_COLDFIRE) += clk.o dma.o entry.o vectors.o obj-$(CONFIG_M5206) += timers.o intc.o obj-$(CONFIG_M5206e) += timers.o intc.o obj-$(CONFIG_M520x) += pit.o intc-simr.o @@ -26,7 +26,7 @@ obj-$(CONFIG_M528x) += pit.o intc-2.o obj-$(CONFIG_M5307) += timers.o intc.o obj-$(CONFIG_M532x) += timers.o intc-simr.o obj-$(CONFIG_M5407) += timers.o intc.o -obj-$(CONFIG_M54xx) += sltimers.o intc-2.o +obj-$(CONFIG_M548x) += sltimers.o intc-2.o obj-y += pinmux.o gpio.o extra-y := head.o diff --git a/trunk/arch/m68knommu/platform/coldfire/cache.c b/trunk/arch/m68knommu/platform/coldfire/cache.c deleted file mode 100644 index 235d3c4f4f0f..000000000000 --- a/trunk/arch/m68knommu/platform/coldfire/cache.c +++ /dev/null @@ -1,48 +0,0 @@ -/***************************************************************************/ - -/* - * cache.c -- general ColdFire Cache maintainence code - * - * Copyright (C) 2010, Greg Ungerer (gerg@snapgear.com) - */ - -/***************************************************************************/ - -#include -#include -#include - -/***************************************************************************/ -#ifdef CACHE_PUSH -/***************************************************************************/ - -/* - * Use cpushl to push all dirty cache lines back to memory. - * Older versions of GAS don't seem to know how to generate the - * ColdFire cpushl instruction... Oh well, bit stuff it for now. - */ - -void mcf_cache_push(void) -{ - __asm__ __volatile__ ( - "clrl %%d0\n\t" - "1:\n\t" - "movel %%d0,%%a0\n\t" - "2:\n\t" - ".word 0xf468\n\t" - "addl %0,%%a0\n\t" - "cmpl %1,%%a0\n\t" - "blt 2b\n\t" - "addql #1,%%d0\n\t" - "cmpil %2,%%d0\n\t" - "bne 1b\n\t" - : /* No output */ - : "i" (CACHE_LINE_SIZE), - "i" (DCACHE_SIZE / CACHE_WAYS), - "i" (CACHE_WAYS) - : "d0", "a0" ); -} - -/***************************************************************************/ -#endif /* CACHE_PUSH */ -/***************************************************************************/ diff --git a/trunk/arch/m68knommu/platform/coldfire/entry.S b/trunk/arch/m68knommu/platform/coldfire/entry.S index 4ddfc3da70d8..e1debc8285ef 100644 --- a/trunk/arch/m68knommu/platform/coldfire/entry.S +++ b/trunk/arch/m68knommu/platform/coldfire/entry.S @@ -36,16 +36,13 @@ #include #include -#ifdef CONFIG_COLDFIRE_SW_A7 -/* - * Define software copies of the supervisor and user stack pointers. - */ .bss + sw_ksp: .long 0 + sw_usp: .long 0 -#endif /* CONFIG_COLDFIRE_SW_A7 */ .text @@ -54,6 +51,7 @@ sw_usp: .globl ret_from_exception .globl ret_from_signal .globl sys_call_table +.globl ret_from_interrupt .globl inthandler .globl fasthandler @@ -142,7 +140,20 @@ Luser_return: jne Lwork_to_do /* still work to do */ Lreturn: - RESTORE_USER + move #0x2700,%sr /* disable intrs */ + movel sw_usp,%a0 /* get usp */ + movel %sp@(PT_OFF_PC),%a0@- /* copy exception program counter */ + movel %sp@(PT_OFF_FORMATVEC),%a0@- /* copy exception format/vector/sr */ + moveml %sp@,%d1-%d5/%a0-%a2 + lea %sp@(32),%sp /* space for 8 regs */ + movel %sp@+,%d0 + addql #4,%sp /* orig d0 */ + addl %sp@+,%sp /* stk adj */ + addql #8,%sp /* remove exception */ + movel %sp,sw_ksp /* save ksp */ + subql #8,sw_usp /* set exception */ + movel sw_usp,%sp /* restore usp */ + rte Lwork_to_do: movel %a0@(TI_FLAGS),%d1 /* get thread_info->flags */ @@ -180,7 +191,31 @@ ENTRY(inthandler) jbsr do_IRQ /* call high level irq handler */ lea %sp@(8),%sp /* pop args off stack */ - bra ret_from_exception + bra ret_from_interrupt /* this was fallthrough */ + +/* + * This is the fast interrupt handler (for certain hardware interrupt + * sources). Unlike the normal interrupt handler it just uses the + * current stack (doesn't care if it is user or kernel). It also + * doesn't bother doing the bottom half handlers. + */ +ENTRY(fasthandler) + SAVE_LOCAL + + movew %sp@(PT_OFF_FORMATVEC),%d0 + andl #0x03fc,%d0 /* mask out vector only */ + + movel %sp,%sp@- /* push regs arg */ + lsrl #2,%d0 /* calculate real vector # */ + movel %d0,%sp@- /* push vector number */ + jbsr do_IRQ /* call high level irq handler */ + lea %sp@(8),%sp /* pop args off stack */ + + RESTORE_LOCAL + +ENTRY(ret_from_interrupt) + /* the fasthandler is confusing me, haven't seen any user */ + jmp ret_from_exception /* * Beware - when entering resume, prev (the current task) is @@ -191,8 +226,9 @@ ENTRY(inthandler) */ ENTRY(resume) movel %a0, %d1 /* get prev thread in d1 */ - RDUSP - movel %a2,%a0@(TASK_THREAD+THREAD_USP) + + movel sw_usp,%d0 /* save usp */ + movel %d0,%a0@(TASK_THREAD+THREAD_USP) SAVE_SWITCH_STACK movel %sp,%a0@(TASK_THREAD+THREAD_KSP) /* save kernel stack pointer */ @@ -200,5 +236,5 @@ ENTRY(resume) RESTORE_SWITCH_STACK movel %a1@(TASK_THREAD+THREAD_USP),%a0 /* restore thread user stack */ - WRUSP + movel %a0, sw_usp rts diff --git a/trunk/arch/m68knommu/platform/coldfire/head.S b/trunk/arch/m68knommu/platform/coldfire/head.S index d5977909ae5f..0b2d7c7adf79 100644 --- a/trunk/arch/m68knommu/platform/coldfire/head.S +++ b/trunk/arch/m68knommu/platform/coldfire/head.S @@ -3,7 +3,7 @@ /* * head.S -- common startup code for ColdFire CPUs. * - * (C) Copyright 1999-2010, Greg Ungerer . + * (C) Copyright 1999-2006, Greg Ungerer . */ /*****************************************************************************/ @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -172,27 +173,10 @@ _start: /* * Now that we know what the memory is, lets enable cache - * and get things moving. This is Coldfire CPU specific. Not - * all version cores have identical cache register setup. But - * it is very similar. Define the exact settings in the headers - * then the code here is the same for all. + * and get things moving. This is Coldfire CPU specific. */ - movel #CACHE_INIT,%d0 /* invalidate whole cache */ - movec %d0,%CACR - nop - movel #ACR0_MODE,%d0 /* set RAM region for caching */ - movec %d0,%ACR0 - movel #ACR1_MODE,%d0 /* anything else to cache? */ - movec %d0,%ACR1 -#ifdef ACR2_MODE - movel #ACR2_MODE,%d0 - movec %d0,%ACR2 - movel #ACR3_MODE,%d0 - movec %d0,%ACR3 -#endif - movel #CACHE_MODE,%d0 /* enable cache */ - movec %d0,%CACR - nop + CACHE_ENABLE /* enable CPU cache */ + #ifdef CONFIG_ROMFS_FS /* diff --git a/trunk/arch/microblaze/include/asm/pgtable.h b/trunk/arch/microblaze/include/asm/pgtable.h index b23f68075879..cae268c22ba2 100644 --- a/trunk/arch/microblaze/include/asm/pgtable.h +++ b/trunk/arch/microblaze/include/asm/pgtable.h @@ -444,9 +444,8 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, *ptep = pte; } -#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG -static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, - unsigned long address, pte_t *ptep) +static inline int ptep_test_and_clear_young(struct mm_struct *mm, + unsigned long addr, pte_t *ptep) { return (pte_update(ptep, _PAGE_ACCESSED, 0) & _PAGE_ACCESSED) != 0; } @@ -458,7 +457,6 @@ static inline int ptep_test_and_clear_dirty(struct mm_struct *mm, (_PAGE_DIRTY | _PAGE_HWWRITE), 0) & _PAGE_DIRTY) != 0; } -#define __HAVE_ARCH_PTEP_GET_AND_CLEAR static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { diff --git a/trunk/arch/microblaze/include/asm/tlb.h b/trunk/arch/microblaze/include/asm/tlb.h index 8aa97817cc8c..e8abd4a0349c 100644 --- a/trunk/arch/microblaze/include/asm/tlb.h +++ b/trunk/arch/microblaze/include/asm/tlb.h @@ -13,7 +13,6 @@ #define tlb_flush(tlb) flush_tlb_mm((tlb)->mm) -#include #include #ifdef CONFIG_MMU diff --git a/trunk/arch/microblaze/kernel/prom.c b/trunk/arch/microblaze/kernel/prom.c index bceaa5543e39..c881393f07fd 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); } -void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) +u64 __init early_init_dt_alloc_memory_arch(u64 size, u64 align) { - return __va(memblock_alloc(size, align)); + return 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 a19811e98a41..9dbe58368953 100644 --- a/trunk/arch/mips/kernel/prom.c +++ b/trunk/arch/mips/kernel/prom.c @@ -45,9 +45,11 @@ void __init free_mem_mach(unsigned long addr, unsigned long size) return free_bootmem(addr, size); } -void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) +u64 __init early_init_dt_alloc_memory_arch(u64 size, u64 align) { - return __alloc_bootmem(size, align, __pa(MAX_DMA_ADDRESS)); + return virt_to_phys( + __alloc_bootmem(size, align, __pa(MAX_DMA_ADDRESS)) + ); } #ifdef CONFIG_BLK_DEV_INITRD diff --git a/trunk/arch/mips/sibyte/common/sb_tbprof.c b/trunk/arch/mips/sibyte/common/sb_tbprof.c index 87ccdb4b5ac9..48853ab5bcf0 100644 --- a/trunk/arch/mips/sibyte/common/sb_tbprof.c +++ b/trunk/arch/mips/sibyte/common/sb_tbprof.c @@ -410,14 +410,13 @@ static int sbprof_tb_open(struct inode *inode, struct file *filp) return -EBUSY; memset(&sbp, 0, sizeof(struct sbprof_tb)); - sbp.sbprof_tbbuf = vmalloc(MAX_TBSAMPLE_BYTES); + sbp.sbprof_tbbuf = vzalloc(MAX_TBSAMPLE_BYTES); if (!sbp.sbprof_tbbuf) { sbp.open = SB_CLOSED; wmb(); return -ENOMEM; } - memset(sbp.sbprof_tbbuf, 0, MAX_TBSAMPLE_BYTES); init_waitqueue_head(&sbp.tb_sync); init_waitqueue_head(&sbp.tb_read); mutex_init(&sbp.lock); 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/parisc/kernel/firmware.c b/trunk/arch/parisc/kernel/firmware.c index 4896ed090585..df971fa0c32f 100644 --- a/trunk/arch/parisc/kernel/firmware.c +++ b/trunk/arch/parisc/kernel/firmware.c @@ -1126,13 +1126,15 @@ int pdc_iodc_print(const unsigned char *str, unsigned count) unsigned int i; unsigned long flags; - for (i = 0; i < count;) { + for (i = 0; i < count && i < 79;) { switch(str[i]) { case '\n': iodc_dbuf[i+0] = '\r'; iodc_dbuf[i+1] = '\n'; i += 2; goto print; + case '\b': /* BS */ + i--; /* overwrite last */ default: iodc_dbuf[i] = str[i]; i++; @@ -1140,6 +1142,15 @@ int pdc_iodc_print(const unsigned char *str, unsigned count) } } + /* if we're at the end of line, and not already inserting a newline, + * insert one anyway. iodc console doesn't claim to support >79 char + * lines. don't account for this in the return value. + */ + if (i == 79 && iodc_dbuf[i-1] != '\n') { + iodc_dbuf[i+0] = '\r'; + iodc_dbuf[i+1] = '\n'; + } + print: spin_lock_irqsave(&pdc_lock, flags); real32_call(PAGE0->mem_cons.iodc_io, diff --git a/trunk/arch/powerpc/kernel/perf_event.c b/trunk/arch/powerpc/kernel/perf_event.c index ab6f6beadb57..567480705789 100644 --- a/trunk/arch/powerpc/kernel/perf_event.c +++ b/trunk/arch/powerpc/kernel/perf_event.c @@ -1212,7 +1212,6 @@ static void record_and_restart(struct perf_event *event, unsigned long val, if (left <= 0) left = period; record = 1; - event->hw.last_period = event->hw.sample_period; } if (left < 0x80000000LL) val = 0x80000000LL - left; diff --git a/trunk/arch/powerpc/kernel/prom.c b/trunk/arch/powerpc/kernel/prom.c index 7185f0da7dc3..9e3132db718b 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); } -void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) +u64 __init early_init_dt_alloc_memory_arch(u64 size, u64 align) { - return __va(memblock_alloc(size, align)); + return 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/infiniband/core/cache.c b/trunk/drivers/infiniband/core/cache.c index f9ba7d74dfc0..68883565b725 100644 --- a/trunk/drivers/infiniband/core/cache.c +++ b/trunk/drivers/infiniband/core/cache.c @@ -308,7 +308,7 @@ static void ib_cache_event(struct ib_event_handler *handler, INIT_WORK(&work->work, ib_cache_task); work->device = event->device; work->port_num = event->element.port_num; - queue_work(ib_wq, &work->work); + schedule_work(&work->work); } } } @@ -368,7 +368,7 @@ static void ib_cache_cleanup_one(struct ib_device *device) int p; ib_unregister_event_handler(&device->cache.event_handler); - flush_workqueue(ib_wq); + flush_scheduled_work(); for (p = 0; p <= end_port(device) - start_port(device); ++p) { kfree(device->cache.pkey_cache[p]); diff --git a/trunk/drivers/infiniband/core/device.c b/trunk/drivers/infiniband/core/device.c index f793bf2f5da7..a19effad0811 100644 --- a/trunk/drivers/infiniband/core/device.c +++ b/trunk/drivers/infiniband/core/device.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "core_priv.h" @@ -51,9 +52,6 @@ struct ib_client_data { void * data; }; -struct workqueue_struct *ib_wq; -EXPORT_SYMBOL_GPL(ib_wq); - static LIST_HEAD(device_list); static LIST_HEAD(client_list); @@ -720,10 +718,6 @@ static int __init ib_core_init(void) { int ret; - ib_wq = alloc_workqueue("infiniband", 0, 0); - if (!ib_wq) - return -ENOMEM; - ret = ib_sysfs_setup(); if (ret) printk(KERN_WARNING "Couldn't create InfiniBand device class\n"); @@ -732,7 +726,6 @@ static int __init ib_core_init(void) if (ret) { printk(KERN_WARNING "Couldn't set up InfiniBand P_Key/GID cache\n"); ib_sysfs_cleanup(); - destroy_workqueue(ib_wq); } return ret; @@ -743,7 +736,7 @@ static void __exit ib_core_cleanup(void) ib_cache_cleanup(); ib_sysfs_cleanup(); /* Make sure that any pending umem accounting work is done. */ - destroy_workqueue(ib_wq); + flush_scheduled_work(); } module_init(ib_core_init); diff --git a/trunk/drivers/infiniband/core/sa_query.c b/trunk/drivers/infiniband/core/sa_query.c index e38be1bcc01c..91a660310b7c 100644 --- a/trunk/drivers/infiniband/core/sa_query.c +++ b/trunk/drivers/infiniband/core/sa_query.c @@ -425,7 +425,7 @@ static void ib_sa_event(struct ib_event_handler *handler, struct ib_event *event port->sm_ah = NULL; spin_unlock_irqrestore(&port->ah_lock, flags); - queue_work(ib_wq, &sa_dev->port[event->element.port_num - + schedule_work(&sa_dev->port[event->element.port_num - sa_dev->start_port].update_task); } } diff --git a/trunk/drivers/infiniband/core/umem.c b/trunk/drivers/infiniband/core/umem.c index b645e558876f..415e186eee32 100644 --- a/trunk/drivers/infiniband/core/umem.c +++ b/trunk/drivers/infiniband/core/umem.c @@ -262,7 +262,7 @@ void ib_umem_release(struct ib_umem *umem) umem->mm = mm; umem->diff = diff; - queue_work(ib_wq, &umem->work); + schedule_work(&umem->work); return; } } else diff --git a/trunk/drivers/infiniband/hw/amso1100/c2_rnic.c b/trunk/drivers/infiniband/hw/amso1100/c2_rnic.c index 8c81992fa6db..85cfae4cad71 100644 --- a/trunk/drivers/infiniband/hw/amso1100/c2_rnic.c +++ b/trunk/drivers/infiniband/hw/amso1100/c2_rnic.c @@ -459,12 +459,13 @@ int __devinit c2_rnic_init(struct c2_dev *c2dev) IB_DEVICE_MEM_WINDOW); /* Allocate the qptr_array */ - c2dev->qptr_array = vzalloc(C2_MAX_CQS * sizeof(void *)); + c2dev->qptr_array = vmalloc(C2_MAX_CQS * sizeof(void *)); if (!c2dev->qptr_array) { return -ENOMEM; } - /* Initialize the qptr_array */ + /* Inialize the qptr_array */ + memset(c2dev->qptr_array, 0, C2_MAX_CQS * sizeof(void *)); c2dev->qptr_array[0] = (void *) &c2dev->req_vq; c2dev->qptr_array[1] = (void *) &c2dev->rep_vq; c2dev->qptr_array[2] = (void *) &c2dev->aeq; diff --git a/trunk/drivers/infiniband/hw/ehca/ipz_pt_fn.c b/trunk/drivers/infiniband/hw/ehca/ipz_pt_fn.c index 1898d6e7cce5..1596e3085344 100644 --- a/trunk/drivers/infiniband/hw/ehca/ipz_pt_fn.c +++ b/trunk/drivers/infiniband/hw/ehca/ipz_pt_fn.c @@ -222,14 +222,15 @@ int ipz_queue_ctor(struct ehca_pd *pd, struct ipz_queue *queue, queue->small_page = NULL; /* allocate queue page pointers */ - queue->queue_pages = kzalloc(nr_of_pages * sizeof(void *), GFP_KERNEL); + queue->queue_pages = kmalloc(nr_of_pages * sizeof(void *), GFP_KERNEL); if (!queue->queue_pages) { - queue->queue_pages = vzalloc(nr_of_pages * sizeof(void *)); + queue->queue_pages = vmalloc(nr_of_pages * sizeof(void *)); if (!queue->queue_pages) { ehca_gen_err("Couldn't allocate queue page list"); return 0; } } + memset(queue->queue_pages, 0, nr_of_pages * sizeof(void *)); /* allocate actual queue pages */ if (is_small) { diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_driver.c b/trunk/drivers/infiniband/hw/ipath/ipath_driver.c index 47db4bf34628..b33f0457a1ff 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_driver.c @@ -199,11 +199,12 @@ static struct ipath_devdata *ipath_alloc_devdata(struct pci_dev *pdev) goto bail; } - dd = vzalloc(sizeof(*dd)); + dd = vmalloc(sizeof(*dd)); if (!dd) { dd = ERR_PTR(-ENOMEM); goto bail; } + memset(dd, 0, sizeof(*dd)); dd->ipath_unit = -1; spin_lock_irqsave(&ipath_devs_lock, flags); @@ -755,7 +756,7 @@ static void __devexit ipath_remove_one(struct pci_dev *pdev) */ ipath_shutdown_device(dd); - flush_workqueue(ib_wq); + flush_scheduled_work(); if (dd->verbs_dev) ipath_unregister_ib_device(dd->verbs_dev); diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_file_ops.c b/trunk/drivers/infiniband/hw/ipath/ipath_file_ops.c index 6d4b29c4cd89..9292a15ad7c4 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_file_ops.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_file_ops.c @@ -1530,7 +1530,7 @@ static int init_subports(struct ipath_devdata *dd, } num_subports = uinfo->spu_subport_cnt; - pd->subport_uregbase = vzalloc(PAGE_SIZE * num_subports); + pd->subport_uregbase = vmalloc(PAGE_SIZE * num_subports); if (!pd->subport_uregbase) { ret = -ENOMEM; goto bail; @@ -1538,13 +1538,13 @@ static int init_subports(struct ipath_devdata *dd, /* Note: pd->port_rcvhdrq_size isn't initialized yet. */ size = ALIGN(dd->ipath_rcvhdrcnt * dd->ipath_rcvhdrentsize * sizeof(u32), PAGE_SIZE) * num_subports; - pd->subport_rcvhdr_base = vzalloc(size); + pd->subport_rcvhdr_base = vmalloc(size); if (!pd->subport_rcvhdr_base) { ret = -ENOMEM; goto bail_ureg; } - pd->subport_rcvegrbuf = vzalloc(pd->port_rcvegrbuf_chunks * + pd->subport_rcvegrbuf = vmalloc(pd->port_rcvegrbuf_chunks * pd->port_rcvegrbuf_size * num_subports); if (!pd->subport_rcvegrbuf) { @@ -1556,6 +1556,11 @@ static int init_subports(struct ipath_devdata *dd, pd->port_subport_id = uinfo->spu_subport_id; pd->active_slaves = 1; set_bit(IPATH_PORT_MASTER_UNINIT, &pd->port_flag); + memset(pd->subport_uregbase, 0, PAGE_SIZE * num_subports); + memset(pd->subport_rcvhdr_base, 0, size); + memset(pd->subport_rcvegrbuf, 0, pd->port_rcvegrbuf_chunks * + pd->port_rcvegrbuf_size * + num_subports); goto bail; bail_rhdr: diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_init_chip.c b/trunk/drivers/infiniband/hw/ipath/ipath_init_chip.c index fef0f4201257..776938299e4c 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_init_chip.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_init_chip.c @@ -442,7 +442,7 @@ static void init_shadow_tids(struct ipath_devdata *dd) struct page **pages; dma_addr_t *addrs; - pages = vzalloc(dd->ipath_cfgports * dd->ipath_rcvtidcnt * + pages = vmalloc(dd->ipath_cfgports * dd->ipath_rcvtidcnt * sizeof(struct page *)); if (!pages) { ipath_dev_err(dd, "failed to allocate shadow page * " @@ -461,6 +461,9 @@ static void init_shadow_tids(struct ipath_devdata *dd) return; } + memset(pages, 0, dd->ipath_cfgports * dd->ipath_rcvtidcnt * + sizeof(struct page *)); + dd->ipath_pageshadow = pages; dd->ipath_physshadow = addrs; } diff --git a/trunk/drivers/infiniband/hw/ipath/ipath_user_pages.c b/trunk/drivers/infiniband/hw/ipath/ipath_user_pages.c index bab9f74c0665..5e86d73eba2a 100644 --- a/trunk/drivers/infiniband/hw/ipath/ipath_user_pages.c +++ b/trunk/drivers/infiniband/hw/ipath/ipath_user_pages.c @@ -220,7 +220,7 @@ void ipath_release_user_pages_on_close(struct page **p, size_t num_pages) work->mm = mm; work->num_pages = num_pages; - queue_work(ib_wq, &work->work); + schedule_work(&work->work); return; bail_mm: diff --git a/trunk/drivers/infiniband/hw/mlx4/main.c b/trunk/drivers/infiniband/hw/mlx4/main.c index c7a6213c6996..4c85224aeaa7 100644 --- a/trunk/drivers/infiniband/hw/mlx4/main.c +++ b/trunk/drivers/infiniband/hw/mlx4/main.c @@ -623,9 +623,8 @@ static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) struct mlx4_ib_dev *mdev = to_mdev(ibqp->device); struct mlx4_ib_qp *mqp = to_mqp(ibqp); - err = mlx4_multicast_attach(mdev->dev, &mqp->mqp, gid->raw, - !!(mqp->flags & MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK), - MLX4_PROTOCOL_IB); + err = mlx4_multicast_attach(mdev->dev, &mqp->mqp, gid->raw, !!(mqp->flags & + MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK)); if (err) return err; @@ -636,7 +635,7 @@ static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) return 0; err_add: - mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw, MLX4_PROTOCOL_IB); + mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw); return err; } @@ -666,7 +665,7 @@ static int mlx4_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) struct mlx4_ib_gid_entry *ge; err = mlx4_multicast_detach(mdev->dev, - &mqp->mqp, gid->raw, MLX4_PROTOCOL_IB); + &mqp->mqp, gid->raw); if (err) return err; @@ -1006,8 +1005,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) if (mlx4_uar_alloc(dev, &ibdev->priv_uar)) goto err_pd; - ibdev->uar_map = ioremap((phys_addr_t) ibdev->priv_uar.pfn << PAGE_SHIFT, - PAGE_SIZE); + ibdev->uar_map = ioremap(ibdev->priv_uar.pfn << PAGE_SHIFT, PAGE_SIZE); if (!ibdev->uar_map) goto err_uar; MLX4_INIT_DOORBELL_LOCK(&ibdev->uar_lock); diff --git a/trunk/drivers/infiniband/hw/mthca/mthca_catas.c b/trunk/drivers/infiniband/hw/mthca/mthca_catas.c index e4a08c2819e4..0aa0110e4b6c 100644 --- a/trunk/drivers/infiniband/hw/mthca/mthca_catas.c +++ b/trunk/drivers/infiniband/hw/mthca/mthca_catas.c @@ -146,7 +146,7 @@ static void poll_catas(unsigned long dev_ptr) void mthca_start_catas_poll(struct mthca_dev *dev) { - phys_addr_t addr; + unsigned long addr; init_timer(&dev->catas_err.timer); dev->catas_err.map = NULL; @@ -158,8 +158,7 @@ void mthca_start_catas_poll(struct mthca_dev *dev) dev->catas_err.map = ioremap(addr, dev->catas_err.size * 4); if (!dev->catas_err.map) { mthca_warn(dev, "couldn't map catastrophic error region " - "at 0x%llx/0x%x\n", (unsigned long long) addr, - dev->catas_err.size * 4); + "at 0x%lx/0x%x\n", addr, dev->catas_err.size * 4); return; } diff --git a/trunk/drivers/infiniband/hw/mthca/mthca_cmd.c b/trunk/drivers/infiniband/hw/mthca/mthca_cmd.c index 7bfa2a164955..f4ceecd9684b 100644 --- a/trunk/drivers/infiniband/hw/mthca/mthca_cmd.c +++ b/trunk/drivers/infiniband/hw/mthca/mthca_cmd.c @@ -713,7 +713,7 @@ int mthca_RUN_FW(struct mthca_dev *dev, u8 *status) static void mthca_setup_cmd_doorbells(struct mthca_dev *dev, u64 base) { - phys_addr_t addr; + unsigned long addr; u16 max_off = 0; int i; diff --git a/trunk/drivers/infiniband/hw/mthca/mthca_eq.c b/trunk/drivers/infiniband/hw/mthca/mthca_eq.c index 76785c653c13..8e8c728aff88 100644 --- a/trunk/drivers/infiniband/hw/mthca/mthca_eq.c +++ b/trunk/drivers/infiniband/hw/mthca/mthca_eq.c @@ -653,7 +653,7 @@ static int mthca_map_reg(struct mthca_dev *dev, unsigned long offset, unsigned long size, void __iomem **map) { - phys_addr_t base = pci_resource_start(dev->pdev, 0); + unsigned long base = pci_resource_start(dev->pdev, 0); *map = ioremap(base + offset, size); if (!*map) diff --git a/trunk/drivers/infiniband/hw/mthca/mthca_main.c b/trunk/drivers/infiniband/hw/mthca/mthca_main.c index 8a40cd539ab1..5eee6665919a 100644 --- a/trunk/drivers/infiniband/hw/mthca/mthca_main.c +++ b/trunk/drivers/infiniband/hw/mthca/mthca_main.c @@ -790,7 +790,7 @@ static int mthca_setup_hca(struct mthca_dev *dev) goto err_uar_table_free; } - dev->kar = ioremap((phys_addr_t) dev->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE); + dev->kar = ioremap(dev->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE); if (!dev->kar) { mthca_err(dev, "Couldn't map kernel access region, " "aborting.\n"); diff --git a/trunk/drivers/infiniband/hw/mthca/mthca_mr.c b/trunk/drivers/infiniband/hw/mthca/mthca_mr.c index 44045c8846db..065b20899876 100644 --- a/trunk/drivers/infiniband/hw/mthca/mthca_mr.c +++ b/trunk/drivers/infiniband/hw/mthca/mthca_mr.c @@ -853,7 +853,7 @@ void mthca_arbel_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr) int mthca_init_mr_table(struct mthca_dev *dev) { - phys_addr_t addr; + unsigned long addr; int mpts, mtts, err, i; err = mthca_alloc_init(&dev->mr_table.mpt_alloc, diff --git a/trunk/drivers/infiniband/hw/nes/nes.c b/trunk/drivers/infiniband/hw/nes/nes.c index 3b4ec3238ceb..0c9f0aa5d4ea 100644 --- a/trunk/drivers/infiniband/hw/nes/nes.c +++ b/trunk/drivers/infiniband/hw/nes/nes.c @@ -144,7 +144,6 @@ static int nes_inetaddr_event(struct notifier_block *notifier, struct nes_device *nesdev; struct net_device *netdev; struct nes_vnic *nesvnic; - unsigned int is_bonded; nes_debug(NES_DBG_NETDEV, "nes_inetaddr_event: ip address %pI4, netmask %pI4.\n", &ifa->ifa_address, &ifa->ifa_mask); @@ -153,8 +152,7 @@ static int nes_inetaddr_event(struct notifier_block *notifier, nesdev, nesdev->netdev[0]->name); netdev = nesdev->netdev[0]; nesvnic = netdev_priv(netdev); - is_bonded = (netdev->master == event_netdev); - if ((netdev == event_netdev) || is_bonded) { + if (netdev == event_netdev) { if (nesvnic->rdma_enabled == 0) { nes_debug(NES_DBG_NETDEV, "Returning without processing event for %s since" " RDMA is not enabled.\n", @@ -171,10 +169,7 @@ static int nes_inetaddr_event(struct notifier_block *notifier, nes_manage_arp_cache(netdev, netdev->dev_addr, ntohl(nesvnic->local_ipaddr), NES_ARP_DELETE); nesvnic->local_ipaddr = 0; - if (is_bonded) - continue; - else - return NOTIFY_OK; + return NOTIFY_OK; break; case NETDEV_UP: nes_debug(NES_DBG_NETDEV, "event:UP\n"); @@ -183,24 +178,15 @@ static int nes_inetaddr_event(struct notifier_block *notifier, nes_debug(NES_DBG_NETDEV, "Interface already has local_ipaddr\n"); return NOTIFY_OK; } - /* fall through */ - case NETDEV_CHANGEADDR: /* Add the address to the IP table */ - if (netdev->master) - nesvnic->local_ipaddr = - ((struct in_device *)netdev->master->ip_ptr)->ifa_list->ifa_address; - else - nesvnic->local_ipaddr = ifa->ifa_address; + nesvnic->local_ipaddr = ifa->ifa_address; nes_write_indexed(nesdev, NES_IDX_DST_IP_ADDR+(0x10*PCI_FUNC(nesdev->pcidev->devfn)), - ntohl(nesvnic->local_ipaddr)); + ntohl(ifa->ifa_address)); nes_manage_arp_cache(netdev, netdev->dev_addr, ntohl(nesvnic->local_ipaddr), NES_ARP_ADD); - if (is_bonded) - continue; - else - return NOTIFY_OK; + return NOTIFY_OK; break; default: break; @@ -674,8 +660,6 @@ static int __devinit nes_probe(struct pci_dev *pcidev, const struct pci_device_i } nes_notifiers_registered++; - INIT_DELAYED_WORK(&nesdev->work, nes_recheck_link_status); - /* Initialize network devices */ if ((netdev = nes_netdev_init(nesdev, mmio_regs)) == NULL) goto bail7; @@ -758,7 +742,6 @@ static void __devexit nes_remove(struct pci_dev *pcidev) struct nes_device *nesdev = pci_get_drvdata(pcidev); struct net_device *netdev; int netdev_index = 0; - unsigned long flags; if (nesdev->netdev_count) { netdev = nesdev->netdev[netdev_index]; @@ -785,14 +768,6 @@ static void __devexit nes_remove(struct pci_dev *pcidev) free_irq(pcidev->irq, nesdev); tasklet_kill(&nesdev->dpc_tasklet); - spin_lock_irqsave(&nesdev->nesadapter->phy_lock, flags); - if (nesdev->link_recheck) { - spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags); - cancel_delayed_work_sync(&nesdev->work); - } else { - spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags); - } - /* Deallocate the Adapter Structure */ nes_destroy_adapter(nesdev->nesadapter); diff --git a/trunk/drivers/infiniband/hw/nes/nes.h b/trunk/drivers/infiniband/hw/nes/nes.h index 6fe79876009e..b3d145e82b4c 100644 --- a/trunk/drivers/infiniband/hw/nes/nes.h +++ b/trunk/drivers/infiniband/hw/nes/nes.h @@ -268,9 +268,6 @@ struct nes_device { u8 napi_isr_ran; u8 disable_rx_flow_control; u8 disable_tx_flow_control; - - struct delayed_work work; - u8 link_recheck; }; @@ -510,7 +507,6 @@ void nes_nic_ce_handler(struct nes_device *, struct nes_hw_nic_cq *); void nes_iwarp_ce_handler(struct nes_device *, struct nes_hw_cq *); int nes_destroy_cqp(struct nes_device *); int nes_nic_cm_xmit(struct sk_buff *, struct net_device *); -void nes_recheck_link_status(struct work_struct *work); /* nes_nic.c */ struct net_device *nes_netdev_init(struct nes_device *, void __iomem *); diff --git a/trunk/drivers/infiniband/hw/nes/nes_cm.c b/trunk/drivers/infiniband/hw/nes/nes_cm.c index 009ec814d517..25ad0f9944c0 100644 --- a/trunk/drivers/infiniband/hw/nes/nes_cm.c +++ b/trunk/drivers/infiniband/hw/nes/nes_cm.c @@ -1107,7 +1107,6 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpi struct flowi fl; struct neighbour *neigh; int rc = arpindex; - struct net_device *netdev; struct nes_adapter *nesadapter = nesvnic->nesdev->nesadapter; memset(&fl, 0, sizeof fl); @@ -1118,12 +1117,7 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpi return rc; } - if (nesvnic->netdev->master) - netdev = nesvnic->netdev->master; - else - netdev = nesvnic->netdev; - - neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, netdev); + neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, nesvnic->netdev); if (neigh) { if (neigh->nud_state & NUD_VALID) { nes_debug(NES_DBG_CM, "Neighbor MAC address for 0x%08X" diff --git a/trunk/drivers/infiniband/hw/nes/nes_hw.c b/trunk/drivers/infiniband/hw/nes/nes_hw.c index 8b606fd64022..1980a461c499 100644 --- a/trunk/drivers/infiniband/hw/nes/nes_hw.c +++ b/trunk/drivers/infiniband/hw/nes/nes_hw.c @@ -2608,13 +2608,6 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) netif_start_queue(nesvnic->netdev); nesvnic->linkup = 1; netif_carrier_on(nesvnic->netdev); - - spin_lock(&nesvnic->port_ibevent_lock); - if (nesdev->iw_status == 0) { - nesdev->iw_status = 1; - nes_port_ibevent(nesvnic); - } - spin_unlock(&nesvnic->port_ibevent_lock); } } } else { @@ -2640,23 +2633,9 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) netif_stop_queue(nesvnic->netdev); nesvnic->linkup = 0; netif_carrier_off(nesvnic->netdev); - - spin_lock(&nesvnic->port_ibevent_lock); - if (nesdev->iw_status == 1) { - nesdev->iw_status = 0; - nes_port_ibevent(nesvnic); - } - spin_unlock(&nesvnic->port_ibevent_lock); } } } - if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_SFP_D) { - if (nesdev->link_recheck) - cancel_delayed_work(&nesdev->work); - nesdev->link_recheck = 1; - schedule_delayed_work(&nesdev->work, - NES_LINK_RECHECK_DELAY); - } } spin_unlock_irqrestore(&nesadapter->phy_lock, flags); @@ -2664,80 +2643,6 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) nesadapter->mac_sw_state[mac_number] = NES_MAC_SW_IDLE; } -void nes_recheck_link_status(struct work_struct *work) -{ - unsigned long flags; - struct nes_device *nesdev = container_of(work, struct nes_device, work.work); - struct nes_adapter *nesadapter = nesdev->nesadapter; - struct nes_vnic *nesvnic; - u32 mac_index = nesdev->mac_index; - u16 phy_data; - u16 temp_phy_data; - - spin_lock_irqsave(&nesadapter->phy_lock, flags); - - /* check link status */ - nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9003); - temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); - - nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 3, 0x0021); - nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); - nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 3, 0x0021); - phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); - - phy_data = (!temp_phy_data && (phy_data == 0x8000)) ? 0x4 : 0x0; - - nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n", - __func__, phy_data, - nesadapter->mac_link_down[mac_index] ? "DOWN" : "UP"); - - if (phy_data & 0x0004) { - nesadapter->mac_link_down[mac_index] = 0; - list_for_each_entry(nesvnic, &nesadapter->nesvnic_list[mac_index], list) { - if (nesvnic->linkup == 0) { - printk(PFX "The Link is now up for port %s, netdev %p.\n", - nesvnic->netdev->name, nesvnic->netdev); - if (netif_queue_stopped(nesvnic->netdev)) - netif_start_queue(nesvnic->netdev); - nesvnic->linkup = 1; - netif_carrier_on(nesvnic->netdev); - - spin_lock(&nesvnic->port_ibevent_lock); - if (nesdev->iw_status == 0) { - nesdev->iw_status = 1; - nes_port_ibevent(nesvnic); - } - spin_unlock(&nesvnic->port_ibevent_lock); - } - } - - } else { - nesadapter->mac_link_down[mac_index] = 1; - list_for_each_entry(nesvnic, &nesadapter->nesvnic_list[mac_index], list) { - if (nesvnic->linkup == 1) { - printk(PFX "The Link is now down for port %s, netdev %p.\n", - nesvnic->netdev->name, nesvnic->netdev); - if (!(netif_queue_stopped(nesvnic->netdev))) - netif_stop_queue(nesvnic->netdev); - nesvnic->linkup = 0; - netif_carrier_off(nesvnic->netdev); - - spin_lock(&nesvnic->port_ibevent_lock); - if (nesdev->iw_status == 1) { - nesdev->iw_status = 0; - nes_port_ibevent(nesvnic); - } - spin_unlock(&nesvnic->port_ibevent_lock); - } - } - } - if (nesdev->link_recheck++ < NES_LINK_RECHECK_MAX) - schedule_delayed_work(&nesdev->work, NES_LINK_RECHECK_DELAY); - else - nesdev->link_recheck = 0; - - spin_unlock_irqrestore(&nesadapter->phy_lock, flags); -} static void nes_nic_napi_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) diff --git a/trunk/drivers/infiniband/hw/nes/nes_hw.h b/trunk/drivers/infiniband/hw/nes/nes_hw.h index d2abe07133a5..1204c3432b63 100644 --- a/trunk/drivers/infiniband/hw/nes/nes_hw.h +++ b/trunk/drivers/infiniband/hw/nes/nes_hw.h @@ -1193,8 +1193,6 @@ struct nes_listener { struct nes_ib_device; -#define NES_EVENT_DELAY msecs_to_jiffies(100) - struct nes_vnic { struct nes_ib_device *nesibdev; u64 sq_full; @@ -1249,10 +1247,6 @@ struct nes_vnic { u32 lro_max_aggr; struct net_lro_mgr lro_mgr; struct net_lro_desc lro_desc[NES_MAX_LRO_DESCRIPTORS]; - struct timer_list event_timer; - enum ib_event_type delayed_event; - enum ib_event_type last_dispatched_event; - spinlock_t port_ibevent_lock; }; struct nes_ib_device { @@ -1354,10 +1348,6 @@ struct nes_terminate_hdr { #define BAD_FRAME_OFFSET 64 #define CQE_MAJOR_DRV 0x8000 -/* Used for link status recheck after interrupt processing */ -#define NES_LINK_RECHECK_DELAY msecs_to_jiffies(50) -#define NES_LINK_RECHECK_MAX 60 - #define nes_vlan_rx vlan_hwaccel_receive_skb #define nes_netif_rx netif_receive_skb diff --git a/trunk/drivers/infiniband/hw/nes/nes_nic.c b/trunk/drivers/infiniband/hw/nes/nes_nic.c index 2c9c1933bbe3..5a4c36484722 100644 --- a/trunk/drivers/infiniband/hw/nes/nes_nic.c +++ b/trunk/drivers/infiniband/hw/nes/nes_nic.c @@ -144,7 +144,6 @@ static int nes_netdev_open(struct net_device *netdev) u32 nic_active_bit; u32 nic_active; struct list_head *list_pos, *list_temp; - unsigned long flags; assert(nesdev != NULL); @@ -234,36 +233,18 @@ static int nes_netdev_open(struct net_device *netdev) first_nesvnic = nesvnic; } + if (nesvnic->of_device_registered) { + nesdev->iw_status = 1; + nesdev->nesadapter->send_term_ok = 1; + nes_port_ibevent(nesvnic); + } + if (first_nesvnic->linkup) { /* Enable network packets */ nesvnic->linkup = 1; netif_start_queue(netdev); netif_carrier_on(netdev); } - - spin_lock_irqsave(&nesdev->nesadapter->phy_lock, flags); - if (nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_SFP_D) { - if (nesdev->link_recheck) - cancel_delayed_work(&nesdev->work); - nesdev->link_recheck = 1; - schedule_delayed_work(&nesdev->work, NES_LINK_RECHECK_DELAY); - } - spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags); - - spin_lock_irqsave(&nesvnic->port_ibevent_lock, flags); - if (nesvnic->of_device_registered) { - nesdev->nesadapter->send_term_ok = 1; - if (nesvnic->linkup == 1) { - if (nesdev->iw_status == 0) { - nesdev->iw_status = 1; - nes_port_ibevent(nesvnic); - } - } else { - nesdev->iw_status = 0; - } - } - spin_unlock_irqrestore(&nesvnic->port_ibevent_lock, flags); - napi_enable(&nesvnic->napi); nesvnic->netdev_open = 1; @@ -282,7 +263,6 @@ static int nes_netdev_stop(struct net_device *netdev) u32 nic_active; struct nes_vnic *first_nesvnic = NULL; struct list_head *list_pos, *list_temp; - unsigned long flags; nes_debug(NES_DBG_SHUTDOWN, "nesvnic=%p, nesdev=%p, netdev=%p %s\n", nesvnic, nesdev, netdev, netdev->name); @@ -335,17 +315,12 @@ static int nes_netdev_stop(struct net_device *netdev) nic_active &= nic_active_mask; nes_write_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON, nic_active); - spin_lock_irqsave(&nesvnic->port_ibevent_lock, flags); + if (nesvnic->of_device_registered) { nesdev->nesadapter->send_term_ok = 0; nesdev->iw_status = 0; - if (nesvnic->linkup == 1) - nes_port_ibevent(nesvnic); + nes_port_ibevent(nesvnic); } - del_timer_sync(&nesvnic->event_timer); - nesvnic->event_timer.function = NULL; - spin_unlock_irqrestore(&nesvnic->port_ibevent_lock, flags); - nes_destroy_nic_qp(nesvnic); nesvnic->netdev_open = 0; @@ -1775,10 +1750,7 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev, nesvnic->rdma_enabled = 0; } nesvnic->nic_cq.cq_number = nesvnic->nic.qp_id; - init_timer(&nesvnic->event_timer); - nesvnic->event_timer.function = NULL; spin_lock_init(&nesvnic->tx_lock); - spin_lock_init(&nesvnic->port_ibevent_lock); nesdev->netdev[nesdev->netdev_count] = netdev; nes_debug(NES_DBG_INIT, "Adding nesvnic (%p) to the adapters nesvnic_list for MAC%d.\n", @@ -1791,11 +1763,8 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev, (((PCI_FUNC(nesdev->pcidev->devfn) == 1) && (nesdev->mac_index == 2)) || ((PCI_FUNC(nesdev->pcidev->devfn) == 2) && (nesdev->mac_index == 1)))))) { u32 u32temp; - u32 link_mask = 0; - u32 link_val = 0; - u16 temp_phy_data; - u16 phy_data = 0; - unsigned long flags; + u32 link_mask; + u32 link_val; u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + (0x200 * (nesdev->mac_index & 1))); @@ -1817,23 +1786,6 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev, link_val = 0x02020000; } break; - case NES_PHY_TYPE_SFP_D: - spin_lock_irqsave(&nesdev->nesadapter->phy_lock, flags); - nes_read_10G_phy_reg(nesdev, - nesdev->nesadapter->phy_index[nesdev->mac_index], - 1, 0x9003); - temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); - nes_read_10G_phy_reg(nesdev, - nesdev->nesadapter->phy_index[nesdev->mac_index], - 3, 0x0021); - nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); - nes_read_10G_phy_reg(nesdev, - nesdev->nesadapter->phy_index[nesdev->mac_index], - 3, 0x0021); - phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); - spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags); - phy_data = (!temp_phy_data && (phy_data == 0x8000)) ? 0x4 : 0x0; - break; default: link_mask = 0x0f1f0000; link_val = 0x0f0f0000; @@ -1843,14 +1795,8 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev, u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + (0x200 * (nesdev->mac_index & 1))); - - if (phy_type == NES_PHY_TYPE_SFP_D) { - if (phy_data & 0x0004) - nesvnic->linkup = 1; - } else { - if ((u32temp & link_mask) == link_val) - nesvnic->linkup = 1; - } + if ((u32temp & link_mask) == link_val) + nesvnic->linkup = 1; /* clear the MAC interrupt status, assumes direct logical to physical mapping */ u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (0x200 * nesdev->mac_index)); diff --git a/trunk/drivers/infiniband/hw/nes/nes_verbs.c b/trunk/drivers/infiniband/hw/nes/nes_verbs.c index 26d8018c0a7c..99933e4e48ff 100644 --- a/trunk/drivers/infiniband/hw/nes/nes_verbs.c +++ b/trunk/drivers/infiniband/hw/nes/nes_verbs.c @@ -3936,30 +3936,6 @@ struct nes_ib_device *nes_init_ofa_device(struct net_device *netdev) return nesibdev; } - -/** - * nes_handle_delayed_event - */ -static void nes_handle_delayed_event(unsigned long data) -{ - struct nes_vnic *nesvnic = (void *) data; - - if (nesvnic->delayed_event != nesvnic->last_dispatched_event) { - struct ib_event event; - - event.device = &nesvnic->nesibdev->ibdev; - if (!event.device) - goto stop_timer; - event.event = nesvnic->delayed_event; - event.element.port_num = nesvnic->logical_port + 1; - ib_dispatch_event(&event); - } - -stop_timer: - nesvnic->event_timer.function = NULL; -} - - void nes_port_ibevent(struct nes_vnic *nesvnic) { struct nes_ib_device *nesibdev = nesvnic->nesibdev; @@ -3968,18 +3944,7 @@ void nes_port_ibevent(struct nes_vnic *nesvnic) event.device = &nesibdev->ibdev; event.element.port_num = nesvnic->logical_port + 1; event.event = nesdev->iw_status ? IB_EVENT_PORT_ACTIVE : IB_EVENT_PORT_ERR; - - if (!nesvnic->event_timer.function) { - ib_dispatch_event(&event); - nesvnic->last_dispatched_event = event.event; - nesvnic->event_timer.function = nes_handle_delayed_event; - nesvnic->event_timer.data = (unsigned long) nesvnic; - nesvnic->event_timer.expires = jiffies + NES_EVENT_DELAY; - add_timer(&nesvnic->event_timer); - } else { - mod_timer(&nesvnic->event_timer, jiffies + NES_EVENT_DELAY); - } - nesvnic->delayed_event = event.event; + ib_dispatch_event(&event); } diff --git a/trunk/drivers/infiniband/hw/qib/qib_iba7220.c b/trunk/drivers/infiniband/hw/qib/qib_iba7220.c index de799f17cb9e..127a0d5069f0 100644 --- a/trunk/drivers/infiniband/hw/qib/qib_iba7220.c +++ b/trunk/drivers/infiniband/hw/qib/qib_iba7220.c @@ -1692,7 +1692,8 @@ static void qib_7220_quiet_serdes(struct qib_pportdata *ppd) ppd->lflags &= ~QIBL_IB_AUTONEG_INPROG; spin_unlock_irqrestore(&ppd->lflags_lock, flags); wake_up(&ppd->cpspec->autoneg_wait); - cancel_delayed_work_sync(&ppd->cpspec->autoneg_work); + cancel_delayed_work(&ppd->cpspec->autoneg_work); + flush_scheduled_work(); shutdown_7220_relock_poll(ppd->dd); val = qib_read_kreg64(ppd->dd, kr_xgxs_cfg); @@ -3514,8 +3515,8 @@ static void try_7220_autoneg(struct qib_pportdata *ppd) toggle_7220_rclkrls(ppd->dd); /* 2 msec is minimum length of a poll cycle */ - queue_delayed_work(ib_wq, &ppd->cpspec->autoneg_work, - msecs_to_jiffies(2)); + schedule_delayed_work(&ppd->cpspec->autoneg_work, + msecs_to_jiffies(2)); } /* diff --git a/trunk/drivers/infiniband/hw/qib/qib_iba7322.c b/trunk/drivers/infiniband/hw/qib/qib_iba7322.c index 50cceb3ab885..abd409d592ef 100644 --- a/trunk/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/trunk/drivers/infiniband/hw/qib/qib_iba7322.c @@ -2406,9 +2406,10 @@ static void qib_7322_mini_quiet_serdes(struct qib_pportdata *ppd) ppd->lflags &= ~QIBL_IB_AUTONEG_INPROG; spin_unlock_irqrestore(&ppd->lflags_lock, flags); wake_up(&ppd->cpspec->autoneg_wait); - cancel_delayed_work_sync(&ppd->cpspec->autoneg_work); + cancel_delayed_work(&ppd->cpspec->autoneg_work); if (ppd->dd->cspec->r1) - cancel_delayed_work_sync(&ppd->cpspec->ipg_work); + cancel_delayed_work(&ppd->cpspec->ipg_work); + flush_scheduled_work(); ppd->cpspec->chase_end = 0; if (ppd->cpspec->chase_timer.data) /* if initted */ @@ -2705,7 +2706,7 @@ static noinline void unknown_7322_gpio_intr(struct qib_devdata *dd) if (!(pins & mask)) { ++handled; qd->t_insert = get_jiffies_64(); - queue_work(ib_wq, &qd->work); + schedule_work(&qd->work); } } } @@ -4989,8 +4990,8 @@ static void try_7322_autoneg(struct qib_pportdata *ppd) set_7322_ibspeed_fast(ppd, QIB_IB_DDR); qib_7322_mini_pcs_reset(ppd); /* 2 msec is minimum length of a poll cycle */ - queue_delayed_work(ib_wq, &ppd->cpspec->autoneg_work, - msecs_to_jiffies(2)); + schedule_delayed_work(&ppd->cpspec->autoneg_work, + msecs_to_jiffies(2)); } /* @@ -5120,8 +5121,7 @@ static void try_7322_ipg(struct qib_pportdata *ppd) ib_free_send_mad(send_buf); retry: delay = 2 << ppd->cpspec->ipg_tries; - queue_delayed_work(ib_wq, &ppd->cpspec->ipg_work, - msecs_to_jiffies(delay)); + schedule_delayed_work(&ppd->cpspec->ipg_work, msecs_to_jiffies(delay)); } /* diff --git a/trunk/drivers/infiniband/hw/qib/qib_init.c b/trunk/drivers/infiniband/hw/qib/qib_init.c index ffefb78b8949..7896afbb9ce8 100644 --- a/trunk/drivers/infiniband/hw/qib/qib_init.c +++ b/trunk/drivers/infiniband/hw/qib/qib_init.c @@ -80,6 +80,7 @@ unsigned qib_wc_pat = 1; /* default (1) is to use PAT, not MTRR */ module_param_named(wc_pat, qib_wc_pat, uint, S_IRUGO); MODULE_PARM_DESC(wc_pat, "enable write-combining via PAT mechanism"); +struct workqueue_struct *qib_wq; struct workqueue_struct *qib_cq_wq; static void verify_interrupt(unsigned long); @@ -269,20 +270,23 @@ static void init_shadow_tids(struct qib_devdata *dd) struct page **pages; dma_addr_t *addrs; - pages = vzalloc(dd->cfgctxts * dd->rcvtidcnt * sizeof(struct page *)); + pages = vmalloc(dd->cfgctxts * dd->rcvtidcnt * sizeof(struct page *)); if (!pages) { qib_dev_err(dd, "failed to allocate shadow page * " "array, no expected sends!\n"); goto bail; } - addrs = vzalloc(dd->cfgctxts * dd->rcvtidcnt * sizeof(dma_addr_t)); + addrs = vmalloc(dd->cfgctxts * dd->rcvtidcnt * sizeof(dma_addr_t)); if (!addrs) { qib_dev_err(dd, "failed to allocate shadow dma handle " "array, no expected sends!\n"); goto bail_free; } + memset(pages, 0, dd->cfgctxts * dd->rcvtidcnt * sizeof(struct page *)); + memset(addrs, 0, dd->cfgctxts * dd->rcvtidcnt * sizeof(dma_addr_t)); + dd->pageshadow = pages; dd->physshadow = addrs; return; @@ -1043,10 +1047,24 @@ static int __init qlogic_ib_init(void) if (ret) goto bail; + /* + * We create our own workqueue mainly because we want to be + * able to flush it when devices are being removed. We can't + * use schedule_work()/flush_scheduled_work() because both + * unregister_netdev() and linkwatch_event take the rtnl lock, + * so flush_scheduled_work() can deadlock during device + * removal. + */ + qib_wq = create_workqueue("qib"); + if (!qib_wq) { + ret = -ENOMEM; + goto bail_dev; + } + qib_cq_wq = create_singlethread_workqueue("qib_cq"); if (!qib_cq_wq) { ret = -ENOMEM; - goto bail_dev; + goto bail_wq; } /* @@ -1076,6 +1094,8 @@ static int __init qlogic_ib_init(void) idr_destroy(&qib_unit_table); bail_cq_wq: destroy_workqueue(qib_cq_wq); +bail_wq: + destroy_workqueue(qib_wq); bail_dev: qib_dev_cleanup(); bail: @@ -1099,6 +1119,7 @@ static void __exit qlogic_ib_cleanup(void) pci_unregister_driver(&qib_driver); + destroy_workqueue(qib_wq); destroy_workqueue(qib_cq_wq); qib_cpulist_count = 0; @@ -1271,7 +1292,7 @@ static int __devinit qib_init_one(struct pci_dev *pdev, if (qib_mini_init || initfail || ret) { qib_stop_timers(dd); - flush_workqueue(ib_wq); + flush_scheduled_work(); for (pidx = 0; pidx < dd->num_pports; ++pidx) dd->f_quiet_serdes(dd->pport + pidx); if (qib_mini_init) @@ -1320,8 +1341,8 @@ static void __devexit qib_remove_one(struct pci_dev *pdev) qib_stop_timers(dd); - /* wait until all of our (qsfp) queue_work() calls complete */ - flush_workqueue(ib_wq); + /* wait until all of our (qsfp) schedule_work() calls complete */ + flush_scheduled_work(); ret = qibfs_remove(dd); if (ret) diff --git a/trunk/drivers/infiniband/hw/qib/qib_qsfp.c b/trunk/drivers/infiniband/hw/qib/qib_qsfp.c index 3374a52232c1..35b3604b691d 100644 --- a/trunk/drivers/infiniband/hw/qib/qib_qsfp.c +++ b/trunk/drivers/infiniband/hw/qib/qib_qsfp.c @@ -485,7 +485,7 @@ void qib_qsfp_init(struct qib_qsfp_data *qd, goto bail; /* We see a module, but it may be unwise to look yet. Just schedule */ qd->t_insert = get_jiffies_64(); - queue_work(ib_wq, &qd->work); + schedule_work(&qd->work); bail: return; } @@ -493,9 +493,10 @@ void qib_qsfp_init(struct qib_qsfp_data *qd, void qib_qsfp_deinit(struct qib_qsfp_data *qd) { /* - * There is nothing to do here for now. our work is scheduled - * with queue_work(), and flush_workqueue() from remove_one - * will block until all work setup with queue_work() + * There is nothing to do here for now. our + * work is scheduled with schedule_work(), and + * flush_scheduled_work() from remove_one will + * block until all work ssetup with schedule_work() * completes. */ } diff --git a/trunk/drivers/infiniband/hw/qib/qib_verbs.h b/trunk/drivers/infiniband/hw/qib/qib_verbs.h index 95e5b47223b3..63b22a9a7feb 100644 --- a/trunk/drivers/infiniband/hw/qib/qib_verbs.h +++ b/trunk/drivers/infiniband/hw/qib/qib_verbs.h @@ -805,6 +805,7 @@ static inline int qib_send_ok(struct qib_qp *qp) !(qp->s_flags & QIB_S_ANY_WAIT_SEND)); } +extern struct workqueue_struct *qib_wq; extern struct workqueue_struct *qib_cq_wq; /* @@ -813,7 +814,7 @@ extern struct workqueue_struct *qib_cq_wq; static inline void qib_schedule_send(struct qib_qp *qp) { if (qib_send_ok(qp)) - queue_work(ib_wq, &qp->s_work); + queue_work(qib_wq, &qp->s_work); } static inline int qib_pkey_ok(u16 pkey1, u16 pkey2) diff --git a/trunk/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/trunk/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 93d55806b967..c1c49f2d35b5 100644 --- a/trunk/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/trunk/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -352,13 +352,15 @@ static int ipoib_cm_nonsrq_init_rx(struct net_device *dev, struct ib_cm_id *cm_i int ret; int i; - rx->rx_ring = vzalloc(ipoib_recvq_size * sizeof *rx->rx_ring); + rx->rx_ring = vmalloc(ipoib_recvq_size * sizeof *rx->rx_ring); if (!rx->rx_ring) { printk(KERN_WARNING "%s: failed to allocate CM non-SRQ ring (%d entries)\n", priv->ca->name, ipoib_recvq_size); return -ENOMEM; } + memset(rx->rx_ring, 0, ipoib_recvq_size * sizeof *rx->rx_ring); + t = kmalloc(sizeof *t, GFP_KERNEL); if (!t) { ret = -ENOMEM; @@ -1095,12 +1097,13 @@ static int ipoib_cm_tx_init(struct ipoib_cm_tx *p, u32 qpn, struct ipoib_dev_priv *priv = netdev_priv(p->dev); int ret; - p->tx_ring = vzalloc(ipoib_sendq_size * sizeof *p->tx_ring); + p->tx_ring = vmalloc(ipoib_sendq_size * sizeof *p->tx_ring); if (!p->tx_ring) { ipoib_warn(priv, "failed to allocate tx ring\n"); ret = -ENOMEM; goto err_tx; } + memset(p->tx_ring, 0, ipoib_sendq_size * sizeof *p->tx_ring); p->qp = ipoib_cm_create_tx_qp(p->dev, p); if (IS_ERR(p->qp)) { @@ -1518,7 +1521,7 @@ static void ipoib_cm_create_srq(struct net_device *dev, int max_sge) return; } - priv->cm.srq_ring = vzalloc(ipoib_recvq_size * sizeof *priv->cm.srq_ring); + priv->cm.srq_ring = vmalloc(ipoib_recvq_size * sizeof *priv->cm.srq_ring); if (!priv->cm.srq_ring) { printk(KERN_WARNING "%s: failed to allocate CM SRQ ring (%d entries)\n", priv->ca->name, ipoib_recvq_size); @@ -1527,6 +1530,7 @@ static void ipoib_cm_create_srq(struct net_device *dev, int max_sge) return; } + memset(priv->cm.srq_ring, 0, ipoib_recvq_size * sizeof *priv->cm.srq_ring); } int ipoib_cm_dev_init(struct net_device *dev) diff --git a/trunk/drivers/infiniband/ulp/ipoib/ipoib_main.c b/trunk/drivers/infiniband/ulp/ipoib/ipoib_main.c index aca3b44f7aed..7a07a728fe0d 100644 --- a/trunk/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/trunk/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -916,12 +916,13 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port) goto out; } - priv->tx_ring = vzalloc(ipoib_sendq_size * sizeof *priv->tx_ring); + priv->tx_ring = vmalloc(ipoib_sendq_size * sizeof *priv->tx_ring); if (!priv->tx_ring) { printk(KERN_WARNING "%s: failed to allocate TX ring (%d entries)\n", ca->name, ipoib_sendq_size); goto out_rx_ring_cleanup; } + memset(priv->tx_ring, 0, ipoib_sendq_size * sizeof *priv->tx_ring); /* priv->tx_head, tx_tail & tx_outstanding are already 0 */ diff --git a/trunk/drivers/infiniband/ulp/srp/ib_srp.c b/trunk/drivers/infiniband/ulp/srp/ib_srp.c index 83664ed2804f..4b62105ed1e8 100644 --- a/trunk/drivers/infiniband/ulp/srp/ib_srp.c +++ b/trunk/drivers/infiniband/ulp/srp/ib_srp.c @@ -638,7 +638,7 @@ static int srp_reconnect_target(struct srp_target_port *target) if (target->state == SRP_TARGET_CONNECTING) { target->state = SRP_TARGET_DEAD; INIT_WORK(&target->work, srp_remove_work); - queue_work(ib_wq, &target->work); + schedule_work(&target->work); } spin_unlock_irq(&target->lock); @@ -1132,13 +1132,16 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd) spin_lock_irqsave(&target->lock, flags); iu = __srp_get_tx_iu(target, SRP_IU_CMD); - if (!iu) - goto err_unlock; - - req = list_first_entry(&target->free_reqs, struct srp_request, list); - list_del(&req->list); + if (iu) { + req = list_first_entry(&target->free_reqs, struct srp_request, + list); + list_del(&req->list); + } spin_unlock_irqrestore(&target->lock, flags); + if (!iu) + goto err; + dev = target->srp_host->srp_dev->dev; ib_dma_sync_single_for_cpu(dev, iu->dma, srp_max_iu_len, DMA_TO_DEVICE); @@ -1182,8 +1185,6 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd) spin_lock_irqsave(&target->lock, flags); list_add(&req->list, &target->free_reqs); - -err_unlock: spin_unlock_irqrestore(&target->lock, flags); err: @@ -2198,7 +2199,7 @@ static void srp_remove_one(struct ib_device *device) * started before we marked our target ports as * removed, and any target port removal tasks. */ - flush_workqueue(ib_wq); + flush_scheduled_work(); list_for_each_entry_safe(target, tmp_target, &host->target_list, list) { 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/net/mlx4/catas.c b/trunk/drivers/net/mlx4/catas.c index 32f947154c33..68aaa42d0ced 100644 --- a/trunk/drivers/net/mlx4/catas.c +++ b/trunk/drivers/net/mlx4/catas.c @@ -113,7 +113,7 @@ static void catas_reset(struct work_struct *work) void mlx4_start_catas_poll(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); - phys_addr_t addr; + unsigned long addr; INIT_LIST_HEAD(&priv->catas_err.list); init_timer(&priv->catas_err.timer); @@ -124,8 +124,8 @@ void mlx4_start_catas_poll(struct mlx4_dev *dev) priv->catas_err.map = ioremap(addr, priv->fw.catas_size * 4); if (!priv->catas_err.map) { - mlx4_warn(dev, "Failed to map internal error buffer at 0x%llx\n", - (unsigned long long) addr); + mlx4_warn(dev, "Failed to map internal error buffer at 0x%lx\n", + addr); return; } diff --git a/trunk/drivers/net/mlx4/en_main.c b/trunk/drivers/net/mlx4/en_main.c index 1ff6ca6466ed..f6e0d40cd876 100644 --- a/trunk/drivers/net/mlx4/en_main.c +++ b/trunk/drivers/net/mlx4/en_main.c @@ -202,8 +202,7 @@ static void *mlx4_en_add(struct mlx4_dev *dev) if (mlx4_uar_alloc(dev, &mdev->priv_uar)) goto err_pd; - mdev->uar_map = ioremap((phys_addr_t) mdev->priv_uar.pfn << PAGE_SHIFT, - PAGE_SIZE); + mdev->uar_map = ioremap(mdev->priv_uar.pfn << PAGE_SHIFT, PAGE_SIZE); if (!mdev->uar_map) goto err_uar; spin_lock_init(&mdev->uar_lock); diff --git a/trunk/drivers/net/mlx4/main.c b/trunk/drivers/net/mlx4/main.c index 4ffdc18fcb8a..782f11d8fa71 100644 --- a/trunk/drivers/net/mlx4/main.c +++ b/trunk/drivers/net/mlx4/main.c @@ -829,7 +829,7 @@ static int mlx4_setup_hca(struct mlx4_dev *dev) goto err_uar_table_free; } - priv->kar = ioremap((phys_addr_t) priv->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE); + priv->kar = ioremap(priv->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE); if (!priv->kar) { mlx4_err(dev, "Couldn't map kernel access region, " "aborting.\n"); diff --git a/trunk/drivers/net/mlx4/mcg.c b/trunk/drivers/net/mlx4/mcg.c index 79cf42db2ea9..c4f88b7ef7b6 100644 --- a/trunk/drivers/net/mlx4/mcg.c +++ b/trunk/drivers/net/mlx4/mcg.c @@ -95,8 +95,7 @@ static int mlx4_MGID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox * entry in hash chain and *mgm holds end of hash chain. */ static int find_mgm(struct mlx4_dev *dev, - u8 *gid, enum mlx4_protocol protocol, - struct mlx4_cmd_mailbox *mgm_mailbox, + u8 *gid, struct mlx4_cmd_mailbox *mgm_mailbox, u16 *hash, int *prev, int *index) { struct mlx4_cmd_mailbox *mailbox; @@ -135,8 +134,7 @@ static int find_mgm(struct mlx4_dev *dev, return err; } - if (!memcmp(mgm->gid, gid, 16) && - be32_to_cpu(mgm->members_count) >> 30 == protocol) + if (!memcmp(mgm->gid, gid, 16)) return err; *prev = *index; @@ -148,7 +146,7 @@ static int find_mgm(struct mlx4_dev *dev, } int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - int block_mcast_loopback, enum mlx4_protocol protocol) + int block_mcast_loopback) { struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_cmd_mailbox *mailbox; @@ -167,7 +165,7 @@ int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], mutex_lock(&priv->mcg_table.mutex); - err = find_mgm(dev, gid, protocol, mailbox, &hash, &prev, &index); + err = find_mgm(dev, gid, mailbox, &hash, &prev, &index); if (err) goto out; @@ -189,7 +187,7 @@ int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], memcpy(mgm->gid, gid, 16); } - members_count = be32_to_cpu(mgm->members_count) & 0xffffff; + members_count = be32_to_cpu(mgm->members_count); if (members_count == MLX4_QP_PER_MGM) { mlx4_err(dev, "MGM at index %x is full.\n", index); err = -ENOMEM; @@ -209,7 +207,7 @@ int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], else mgm->qp[members_count++] = cpu_to_be32(qp->qpn & MGM_QPN_MASK); - mgm->members_count = cpu_to_be32(members_count | (u32) protocol << 30); + mgm->members_count = cpu_to_be32(members_count); err = mlx4_WRITE_MCG(dev, index, mailbox); if (err) @@ -244,8 +242,7 @@ int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], } EXPORT_SYMBOL_GPL(mlx4_multicast_attach); -int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - enum mlx4_protocol protocol) +int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16]) { struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_cmd_mailbox *mailbox; @@ -263,7 +260,7 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], mutex_lock(&priv->mcg_table.mutex); - err = find_mgm(dev, gid, protocol, mailbox, &hash, &prev, &index); + err = find_mgm(dev, gid, mailbox, &hash, &prev, &index); if (err) goto out; @@ -273,7 +270,7 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], goto out; } - members_count = be32_to_cpu(mgm->members_count) & 0xffffff; + members_count = be32_to_cpu(mgm->members_count); for (loc = -1, i = 0; i < members_count; ++i) if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) loc = i; @@ -285,7 +282,7 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], } - mgm->members_count = cpu_to_be32(--members_count | (u32) protocol << 30); + mgm->members_count = cpu_to_be32(--members_count); mgm->qp[loc] = mgm->qp[i - 1]; mgm->qp[i - 1] = 0; 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 af824e7e0367..c787c3d95c60 100644 --- a/trunk/drivers/of/fdt.c +++ b/trunk/drivers/of/fdt.c @@ -692,6 +692,12 @@ 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 * @@ -703,7 +709,7 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, void __init unflatten_device_tree(void) { __unflatten_device_tree(initial_boot_params, &allnodes, - early_init_dt_alloc_memory_arch); + early_device_tree_alloc); /* Get pointer to OF "/chosen" node for use everywhere */ of_chosen = of_find_node_by_path("/chosen"); diff --git a/trunk/drivers/spi/spi_sh_msiof.c b/trunk/drivers/spi/spi_sh_msiof.c index 56f60c8ea0ab..d93b66743ba7 100644 --- a/trunk/drivers/spi/spi_sh_msiof.c +++ b/trunk/drivers/spi/spi_sh_msiof.c @@ -635,7 +635,7 @@ static int sh_msiof_spi_remove(struct platform_device *pdev) ret = spi_bitbang_stop(&p->bitbang); if (!ret) { pm_runtime_disable(&pdev->dev); - free_irq(platform_get_irq(pdev, 0), p); + free_irq(platform_get_irq(pdev, 0), sh_msiof_spi_irq); iounmap(p->mapbase); clk_put(p->clk); spi_master_put(p->bitbang.master); 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/bcm/Qos.c b/trunk/drivers/staging/bcm/Qos.c index feade9451b2e..8ce4536e6e28 100644 --- a/trunk/drivers/staging/bcm/Qos.c +++ b/trunk/drivers/staging/bcm/Qos.c @@ -359,11 +359,12 @@ static VOID PruneQueue(PMINI_ADAPTER Adapter, INT iIndex) if(PacketToDrop) { + struct netdev_queue *txq = netdev_get_tx_queue(Adapter->dev, iIndex); if (netif_msg_tx_err(Adapter)) pr_info(PFX "%s: tx queue %d overlimit\n", Adapter->dev->name, iIndex); - netstats->tx_dropped++; + txq->tx_dropped++; DEQUEUEPACKET(Adapter->PackInfo[iIndex].FirstTxQueue, Adapter->PackInfo[iIndex].LastTxQueue); @@ -403,7 +404,7 @@ VOID flush_all_queues(PMINI_ADAPTER Adapter) // down(&Adapter->data_packet_queue_lock); for(iQIndex=LowPriority; iQIndexdev->stats; + struct netdev_queue *txq = netdev_get_tx_queue(Adapter->dev, iQIndex); spin_lock_bh(&Adapter->PackInfo[iQIndex].SFQueueLock); while(Adapter->PackInfo[iQIndex].FirstTxQueue) @@ -412,7 +413,7 @@ VOID flush_all_queues(PMINI_ADAPTER Adapter) if(PacketToDrop) { uiTotalPacketLength = PacketToDrop->len; - netstats->tx_dropped++; + txq->tx_dropped++; } else uiTotalPacketLength = 0; diff --git a/trunk/drivers/staging/bcm/Transmit.c b/trunk/drivers/staging/bcm/Transmit.c index d5e4a7404f71..0f7000960d50 100644 --- a/trunk/drivers/staging/bcm/Transmit.c +++ b/trunk/drivers/staging/bcm/Transmit.c @@ -157,11 +157,11 @@ INT SetupNextSend(PMINI_ADAPTER Adapter, struct sk_buff *Packet, USHORT Vcid) } else { - struct net_device_stats *netstats = &Adapter->dev->stats; + struct netdev_queue *txq = netdev_get_tx_queue(Adapter->dev, QueueIndex); Adapter->PackInfo[QueueIndex].uiTotalTxBytes += Leader.PLength; - netstats->tx_bytes += Leader.PLength; - ++netstats->tx_packets; + txq->tx_bytes += Leader.PLength; + ++txq->tx_packets; Adapter->PackInfo[QueueIndex].uiCurrentTokenCount -= Leader.PLength << 3; Adapter->PackInfo[QueueIndex].uiSentBytes += (Packet->len); 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 54f923792728..0fffe1c24cec 100644 --- a/trunk/fs/autofs4/autofs_i.h +++ b/trunk/fs/autofs4/autofs_i.h @@ -88,9 +88,18 @@ struct autofs_info { uid_t uid; gid_t gid; + + mode_t mode; + size_t size; + + void (*free)(struct autofs_info *); + union { + const char *symlink; + } u; }; #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 { @@ -167,7 +176,14 @@ static inline int autofs4_ispending(struct dentry *dentry) return 0; } -struct inode *autofs4_get_inode(struct super_block *, mode_t); +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 *); /* Expiration */ @@ -196,89 +212,16 @@ 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 */ int autofs4_fill_super(struct super_block *, void *, int); -struct autofs_info *autofs4_new_ino(struct autofs_sb_info *); -void autofs4_clean_ino(struct autofs_info *); +struct autofs_info *autofs4_init_ino(struct autofs_info *, struct autofs_sb_info *sbi, mode_t mode); /* Queue management functions */ @@ -286,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); @@ -338,4 +294,5 @@ static inline void autofs4_del_expiring(struct dentry *dentry) return; } +void autofs4_dentry_release(struct dentry *); extern void autofs4_kill_sb(struct super_block *); 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 f43100b9662b..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)) { @@ -96,7 +100,7 @@ static struct dentry *get_next_positive_dentry(struct dentry *prev, struct dentry *p, *ret; if (prev == NULL) - return dget(root); + return dget(prev); spin_lock(&autofs4_lock); relock: @@ -133,7 +137,7 @@ static struct dentry *get_next_positive_dentry(struct dentry *prev, spin_lock_nested(&ret->d_lock, DENTRY_D_LOCK_NESTED); /* Negative dentry - try next */ if (!simple_positive(ret)) { - spin_unlock(&p->d_lock); + spin_unlock(&ret->d_lock); p = ret; goto again; } @@ -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 180fa2425e49..a7bdb9dcac84 100644 --- a/trunk/fs/autofs4/inode.c +++ b/trunk/fs/autofs4/inode.c @@ -22,27 +22,77 @@ #include "autofs_i.h" #include -struct autofs_info *autofs4_new_ino(struct autofs_sb_info *sbi) +static void ino_lnkfree(struct autofs_info *ino) { - struct autofs_info *ino = kzalloc(sizeof(*ino), GFP_KERNEL); - if (ino) { - INIT_LIST_HEAD(&ino->active); - INIT_LIST_HEAD(&ino->expiring); - ino->last_used = jiffies; - ino->sbi = sbi; + if (ino->u.symlink) { + kfree(ino->u.symlink); + ino->u.symlink = NULL; } - return ino; } -void autofs4_clean_ino(struct autofs_info *ino) +struct autofs_info *autofs4_init_ino(struct autofs_info *ino, + struct autofs_sb_info *sbi, mode_t mode) { + int reinit = 1; + + if (ino == NULL) { + reinit = 0; + ino = kmalloc(sizeof(*ino), GFP_KERNEL); + } + + if (ino == NULL) + return NULL; + + if (!reinit) { + ino->flags = 0; + ino->inode = NULL; + ino->dentry = NULL; + ino->size = 0; + INIT_LIST_HEAD(&ino->active); + ino->active_count = 0; + INIT_LIST_HEAD(&ino->expiring); + atomic_set(&ino->count, 0); + } + ino->uid = 0; ino->gid = 0; + ino->mode = mode; ino->last_used = jiffies; + + ino->sbi = sbi; + + if (reinit && ino->free) + (ino->free)(ino); + + memset(&ino->u, 0, sizeof(ino->u)); + + ino->free = NULL; + + if (S_ISLNK(mode)) + ino->free = ino_lnkfree; + + return 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) + (ino->free)(ino); kfree(ino); } @@ -98,16 +148,9 @@ static int autofs4_show_options(struct seq_file *m, struct vfsmount *mnt) return 0; } -static void autofs4_evict_inode(struct inode *inode) -{ - end_writeback(inode); - kfree(inode->i_private); -} - static const struct super_operations autofs4_sops = { .statfs = simple_statfs, .show_options = autofs4_show_options, - .evict_inode = autofs4_evict_inode, }; enum {Opt_err, Opt_fd, Opt_uid, Opt_gid, Opt_pgrp, Opt_minproto, Opt_maxproto, @@ -197,6 +240,21 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, return (*pipefd < 0); } +static struct autofs_info *autofs4_mkroot(struct autofs_sb_info *sbi) +{ + struct autofs_info *ino; + + ino = autofs4_init_ino(NULL, sbi, S_IFDIR | 0755); + if (!ino) + return NULL; + + 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; @@ -234,16 +292,15 @@ 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; /* * Get the root inode and dentry, but defer checking for errors. */ - ino = autofs4_new_ino(sbi); + ino = autofs4_mkroot(sbi); if (!ino) goto fail_free; - root_inode = autofs4_get_inode(s, S_IFDIR | 0755); + root_inode = autofs4_get_inode(s, ino); if (!root_inode) goto fail_ino; @@ -252,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? */ @@ -262,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 || @@ -326,14 +383,16 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) return -EINVAL; } -struct inode *autofs4_get_inode(struct super_block *sb, mode_t mode) +struct inode *autofs4_get_inode(struct super_block *sb, + struct autofs_info *inf) { struct inode *inode = new_inode(sb); if (inode == NULL) return NULL; - inode->i_mode = mode; + inf->inode = inode; + inode->i_mode = inf->mode; if (sb->s_root) { inode->i_uid = sb->s_root->d_inode->i_uid; inode->i_gid = sb->s_root->d_inode->i_gid; @@ -341,11 +400,12 @@ struct inode *autofs4_get_inode(struct super_block *sb, mode_t mode) inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; inode->i_ino = get_next_ino(); - if (S_ISDIR(mode)) { + if (S_ISDIR(inf->mode)) { inode->i_nlink = 2; inode->i_op = &autofs4_dir_inode_operations; inode->i_fop = &autofs4_dir_operations; - } else if (S_ISLNK(mode)) { + } else if (S_ISLNK(inf->mode)) { + inode->i_size = inf->size; inode->i_op = &autofs4_symlink_inode_operations; } diff --git a/trunk/fs/autofs4/root.c b/trunk/fs/autofs4/root.c index 014e7aba3b08..651e4ef563b1 100644 --- a/trunk/fs/autofs4/root.c +++ b/trunk/fs/autofs4/root.c @@ -35,9 +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_dentry_release(struct dentry *); +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, @@ -59,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, @@ -67,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) @@ -105,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; @@ -139,28 +158,279 @@ static int autofs4_dir_open(struct inode *inode, struct file *file) return dcache_dir_open(inode, file); } -static void autofs4_dentry_release(struct dentry *de) +static int try_to_fill_dentry(struct dentry *dentry, int flags) { - struct autofs_info *ino = autofs4_dentry_ino(de); - struct autofs_sb_info *sbi = autofs4_sbi(de->d_sb); + struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); + struct autofs_info *ino = autofs4_dentry_ino(dentry); + int status; - DPRINTK("releasing %p", de); + DPRINTK("dentry=%p %.*s ino=%p", + dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode); - if (!ino) - return; + /* + * 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); - if (sbi) { - spin_lock(&sbi->lookup_lock); - if (!list_empty(&ino->active)) - list_del(&ino->active); - if (!list_empty(&ino->expiring)) - list_del(&ino->expiring); - spin_unlock(&sbi->lookup_lock); + 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; + } } - autofs4_free_ino(ino); +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; + + 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)) + list_del(&inf->active); + if (!list_empty(&inf->expiring)) + 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); @@ -271,246 +541,51 @@ 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, - autofs4_oz_mode(sbi)); + 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); - ino = autofs4_new_ino(sbi); + /* + * 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); @@ -521,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; } @@ -532,7 +683,6 @@ static int autofs4_dir_symlink(struct inode *dir, struct autofs_info *ino = autofs4_dentry_ino(dentry); struct autofs_info *p_ino; struct inode *inode; - size_t size = strlen(symname); char *cp; DPRINTK("%s <- %.*s", symname, @@ -541,35 +691,45 @@ static int autofs4_dir_symlink(struct inode *dir, if (!autofs4_oz_mode(sbi)) return -EACCES; - BUG_ON(!ino); - - autofs4_clean_ino(ino); + ino = autofs4_init_ino(ino, sbi, S_IFLNK | 0555); + if (!ino) + return -ENOMEM; autofs4_del_active(dentry); - cp = kmalloc(size + 1, GFP_KERNEL); - if (!cp) + ino->size = strlen(symname); + cp = kmalloc(ino->size + 1, GFP_KERNEL); + if (!cp) { + if (!dentry->d_fsdata) + kfree(ino); return -ENOMEM; + } strcpy(cp, symname); - inode = autofs4_get_inode(dir->i_sb, S_IFLNK | 0555); + inode = autofs4_get_inode(dir->i_sb, ino); if (!inode) { kfree(cp); if (!dentry->d_fsdata) kfree(ino); return -ENOMEM; } - inode->i_private = cp; - inode->i_size = size; d_add(dentry, inode); - dget(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); 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; return 0; @@ -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) @@ -732,25 +837,32 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode) DPRINTK("dentry %p, creating %.*s", dentry, dentry->d_name.len, dentry->d_name.name); - BUG_ON(!ino); - - autofs4_clean_ino(ino); + ino = autofs4_init_ino(ino, sbi, S_IFDIR | 0555); + if (!ino) + return -ENOMEM; autofs4_del_active(dentry); - inode = autofs4_get_inode(dir->i_sb, S_IFDIR | 0555); - if (!inode) + inode = autofs4_get_inode(dir->i_sb, ino); + if (!inode) { + if (!dentry->d_fsdata) + kfree(ino); return -ENOMEM; + } 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); - dget(dentry); + 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; inc_nlink(dir); dir->i_mtime = CURRENT_TIME; @@ -832,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/symlink.c b/trunk/fs/autofs4/symlink.c index f27c094a1919..b4ea82934d2e 100644 --- a/trunk/fs/autofs4/symlink.c +++ b/trunk/fs/autofs4/symlink.c @@ -14,7 +14,8 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) { - nd_set_link(nd, dentry->d_inode->i_private); + struct autofs_info *ino = autofs4_dentry_ino(dentry); + nd_set_link(nd, (char *)ino->u.symlink); return 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/Kconfig b/trunk/fs/btrfs/Kconfig index ecb9fd3be143..7bb3c020e570 100644 --- a/trunk/fs/btrfs/Kconfig +++ b/trunk/fs/btrfs/Kconfig @@ -4,8 +4,6 @@ config BTRFS_FS select LIBCRC32C select ZLIB_INFLATE select ZLIB_DEFLATE - select LZO_COMPRESS - select LZO_DECOMPRESS help Btrfs is a new filesystem with extents, writable snapshotting, support for multiple devices and many more features. diff --git a/trunk/fs/btrfs/Makefile b/trunk/fs/btrfs/Makefile index 31610ea73aec..a35eb36b32fd 100644 --- a/trunk/fs/btrfs/Makefile +++ b/trunk/fs/btrfs/Makefile @@ -6,5 +6,5 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \ transaction.o inode.o file.o tree-defrag.o \ extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \ extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \ - export.o tree-log.o acl.o free-space-cache.o zlib.o lzo.o \ + export.o tree-log.o acl.o free-space-cache.o zlib.o \ compression.o delayed-ref.o relocation.o diff --git a/trunk/fs/btrfs/acl.c b/trunk/fs/btrfs/acl.c index 15b5ca2a2606..6ae2c8cac9d5 100644 --- a/trunk/fs/btrfs/acl.c +++ b/trunk/fs/btrfs/acl.c @@ -60,10 +60,8 @@ static struct posix_acl *btrfs_get_acl(struct inode *inode, int type) size = __btrfs_getxattr(inode, name, value, size); if (size > 0) { acl = posix_acl_from_xattr(value, size); - if (IS_ERR(acl)) { - kfree(value); + if (IS_ERR(acl)) return acl; - } set_cached_acl(inode, type, acl); } kfree(value); diff --git a/trunk/fs/btrfs/btrfs_inode.h b/trunk/fs/btrfs/btrfs_inode.h index ccc991c542df..6ad63f17eca0 100644 --- a/trunk/fs/btrfs/btrfs_inode.h +++ b/trunk/fs/btrfs/btrfs_inode.h @@ -157,7 +157,7 @@ struct btrfs_inode { /* * always compress this one file */ - unsigned force_compress:4; + unsigned force_compress:1; struct inode vfs_inode; }; diff --git a/trunk/fs/btrfs/compression.c b/trunk/fs/btrfs/compression.c index f745287fbf2e..b50bc4bd5c56 100644 --- a/trunk/fs/btrfs/compression.c +++ b/trunk/fs/btrfs/compression.c @@ -62,9 +62,6 @@ struct compressed_bio { /* number of bytes on disk */ unsigned long compressed_len; - /* the compression algorithm for this bio */ - int compress_type; - /* number of compressed pages in the array */ unsigned long nr_pages; @@ -176,12 +173,11 @@ static void end_compressed_bio_read(struct bio *bio, int err) /* ok, we're the last bio for this extent, lets start * the decompression. */ - ret = btrfs_decompress_biovec(cb->compress_type, - cb->compressed_pages, - cb->start, - cb->orig_bio->bi_io_vec, - cb->orig_bio->bi_vcnt, - cb->compressed_len); + ret = btrfs_zlib_decompress_biovec(cb->compressed_pages, + cb->start, + cb->orig_bio->bi_io_vec, + cb->orig_bio->bi_vcnt, + cb->compressed_len); csum_failed: if (ret) cb->errors = 1; @@ -592,7 +588,6 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, cb->len = uncompressed_len; cb->compressed_len = compressed_len; - cb->compress_type = extent_compress_type(bio_flags); cb->orig_bio = bio; nr_pages = (compressed_len + PAGE_CACHE_SIZE - 1) / @@ -682,317 +677,3 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, bio_put(comp_bio); return 0; } - -static struct list_head comp_idle_workspace[BTRFS_COMPRESS_TYPES]; -static spinlock_t comp_workspace_lock[BTRFS_COMPRESS_TYPES]; -static int comp_num_workspace[BTRFS_COMPRESS_TYPES]; -static atomic_t comp_alloc_workspace[BTRFS_COMPRESS_TYPES]; -static wait_queue_head_t comp_workspace_wait[BTRFS_COMPRESS_TYPES]; - -struct btrfs_compress_op *btrfs_compress_op[] = { - &btrfs_zlib_compress, - &btrfs_lzo_compress, -}; - -int __init btrfs_init_compress(void) -{ - int i; - - for (i = 0; i < BTRFS_COMPRESS_TYPES; i++) { - INIT_LIST_HEAD(&comp_idle_workspace[i]); - spin_lock_init(&comp_workspace_lock[i]); - atomic_set(&comp_alloc_workspace[i], 0); - init_waitqueue_head(&comp_workspace_wait[i]); - } - return 0; -} - -/* - * this finds an available workspace or allocates a new one - * ERR_PTR is returned if things go bad. - */ -static struct list_head *find_workspace(int type) -{ - struct list_head *workspace; - int cpus = num_online_cpus(); - int idx = type - 1; - - struct list_head *idle_workspace = &comp_idle_workspace[idx]; - spinlock_t *workspace_lock = &comp_workspace_lock[idx]; - atomic_t *alloc_workspace = &comp_alloc_workspace[idx]; - wait_queue_head_t *workspace_wait = &comp_workspace_wait[idx]; - int *num_workspace = &comp_num_workspace[idx]; -again: - spin_lock(workspace_lock); - if (!list_empty(idle_workspace)) { - workspace = idle_workspace->next; - list_del(workspace); - (*num_workspace)--; - spin_unlock(workspace_lock); - return workspace; - - } - if (atomic_read(alloc_workspace) > cpus) { - DEFINE_WAIT(wait); - - spin_unlock(workspace_lock); - prepare_to_wait(workspace_wait, &wait, TASK_UNINTERRUPTIBLE); - if (atomic_read(alloc_workspace) > cpus && !*num_workspace) - schedule(); - finish_wait(workspace_wait, &wait); - goto again; - } - atomic_inc(alloc_workspace); - spin_unlock(workspace_lock); - - workspace = btrfs_compress_op[idx]->alloc_workspace(); - if (IS_ERR(workspace)) { - atomic_dec(alloc_workspace); - wake_up(workspace_wait); - } - return workspace; -} - -/* - * put a workspace struct back on the list or free it if we have enough - * idle ones sitting around - */ -static void free_workspace(int type, struct list_head *workspace) -{ - int idx = type - 1; - struct list_head *idle_workspace = &comp_idle_workspace[idx]; - spinlock_t *workspace_lock = &comp_workspace_lock[idx]; - atomic_t *alloc_workspace = &comp_alloc_workspace[idx]; - wait_queue_head_t *workspace_wait = &comp_workspace_wait[idx]; - int *num_workspace = &comp_num_workspace[idx]; - - spin_lock(workspace_lock); - if (*num_workspace < num_online_cpus()) { - list_add_tail(workspace, idle_workspace); - (*num_workspace)++; - spin_unlock(workspace_lock); - goto wake; - } - spin_unlock(workspace_lock); - - btrfs_compress_op[idx]->free_workspace(workspace); - atomic_dec(alloc_workspace); -wake: - if (waitqueue_active(workspace_wait)) - wake_up(workspace_wait); -} - -/* - * cleanup function for module exit - */ -static void free_workspaces(void) -{ - struct list_head *workspace; - int i; - - for (i = 0; i < BTRFS_COMPRESS_TYPES; i++) { - while (!list_empty(&comp_idle_workspace[i])) { - workspace = comp_idle_workspace[i].next; - list_del(workspace); - btrfs_compress_op[i]->free_workspace(workspace); - atomic_dec(&comp_alloc_workspace[i]); - } - } -} - -/* - * given an address space and start/len, compress the bytes. - * - * pages are allocated to hold the compressed result and stored - * in 'pages' - * - * out_pages is used to return the number of pages allocated. There - * may be pages allocated even if we return an error - * - * total_in is used to return the number of bytes actually read. It - * may be smaller then len if we had to exit early because we - * ran out of room in the pages array or because we cross the - * max_out threshold. - * - * total_out is used to return the total number of compressed bytes - * - * max_out tells us the max number of bytes that we're allowed to - * stuff into pages - */ -int btrfs_compress_pages(int type, struct address_space *mapping, - u64 start, unsigned long len, - struct page **pages, - unsigned long nr_dest_pages, - unsigned long *out_pages, - unsigned long *total_in, - unsigned long *total_out, - unsigned long max_out) -{ - struct list_head *workspace; - int ret; - - workspace = find_workspace(type); - if (IS_ERR(workspace)) - return -1; - - ret = btrfs_compress_op[type-1]->compress_pages(workspace, mapping, - start, len, pages, - nr_dest_pages, out_pages, - total_in, total_out, - max_out); - free_workspace(type, workspace); - return ret; -} - -/* - * pages_in is an array of pages with compressed data. - * - * disk_start is the starting logical offset of this array in the file - * - * bvec is a bio_vec of pages from the file that we want to decompress into - * - * vcnt is the count of pages in the biovec - * - * srclen is the number of bytes in pages_in - * - * The basic idea is that we have a bio that was created by readpages. - * The pages in the bio are for the uncompressed data, and they may not - * be contiguous. They all correspond to the range of bytes covered by - * the compressed extent. - */ -int btrfs_decompress_biovec(int type, struct page **pages_in, u64 disk_start, - struct bio_vec *bvec, int vcnt, size_t srclen) -{ - struct list_head *workspace; - int ret; - - workspace = find_workspace(type); - if (IS_ERR(workspace)) - return -ENOMEM; - - ret = btrfs_compress_op[type-1]->decompress_biovec(workspace, pages_in, - disk_start, - bvec, vcnt, srclen); - free_workspace(type, workspace); - return ret; -} - -/* - * a less complex decompression routine. Our compressed data fits in a - * single page, and we want to read a single page out of it. - * start_byte tells us the offset into the compressed data we're interested in - */ -int btrfs_decompress(int type, unsigned char *data_in, struct page *dest_page, - unsigned long start_byte, size_t srclen, size_t destlen) -{ - struct list_head *workspace; - int ret; - - workspace = find_workspace(type); - if (IS_ERR(workspace)) - return -ENOMEM; - - ret = btrfs_compress_op[type-1]->decompress(workspace, data_in, - dest_page, start_byte, - srclen, destlen); - - free_workspace(type, workspace); - return ret; -} - -void __exit btrfs_exit_compress(void) -{ - free_workspaces(); -} - -/* - * Copy uncompressed data from working buffer to pages. - * - * buf_start is the byte offset we're of the start of our workspace buffer. - * - * total_out is the last byte of the buffer - */ -int btrfs_decompress_buf2page(char *buf, unsigned long buf_start, - unsigned long total_out, u64 disk_start, - struct bio_vec *bvec, int vcnt, - unsigned long *page_index, - unsigned long *pg_offset) -{ - unsigned long buf_offset; - unsigned long current_buf_start; - unsigned long start_byte; - unsigned long working_bytes = total_out - buf_start; - unsigned long bytes; - char *kaddr; - struct page *page_out = bvec[*page_index].bv_page; - - /* - * start byte is the first byte of the page we're currently - * copying into relative to the start of the compressed data. - */ - start_byte = page_offset(page_out) - disk_start; - - /* we haven't yet hit data corresponding to this page */ - if (total_out <= start_byte) - return 1; - - /* - * the start of the data we care about is offset into - * the middle of our working buffer - */ - if (total_out > start_byte && buf_start < start_byte) { - buf_offset = start_byte - buf_start; - working_bytes -= buf_offset; - } else { - buf_offset = 0; - } - current_buf_start = buf_start; - - /* copy bytes from the working buffer into the pages */ - while (working_bytes > 0) { - bytes = min(PAGE_CACHE_SIZE - *pg_offset, - PAGE_CACHE_SIZE - buf_offset); - bytes = min(bytes, working_bytes); - kaddr = kmap_atomic(page_out, KM_USER0); - memcpy(kaddr + *pg_offset, buf + buf_offset, bytes); - kunmap_atomic(kaddr, KM_USER0); - flush_dcache_page(page_out); - - *pg_offset += bytes; - buf_offset += bytes; - working_bytes -= bytes; - current_buf_start += bytes; - - /* check if we need to pick another page */ - if (*pg_offset == PAGE_CACHE_SIZE) { - (*page_index)++; - if (*page_index >= vcnt) - return 0; - - page_out = bvec[*page_index].bv_page; - *pg_offset = 0; - start_byte = page_offset(page_out) - disk_start; - - /* - * make sure our new page is covered by this - * working buffer - */ - if (total_out <= start_byte) - return 1; - - /* - * the next page in the biovec might not be adjacent - * to the last page, but it might still be found - * inside this working buffer. bump our offset pointer - */ - if (total_out > start_byte && - current_buf_start < start_byte) { - buf_offset = start_byte - buf_start; - working_bytes = total_out - start_byte; - current_buf_start = buf_start + buf_offset; - } - } - } - - return 1; -} diff --git a/trunk/fs/btrfs/compression.h b/trunk/fs/btrfs/compression.h index 51000174b9d7..421f5b4aa715 100644 --- a/trunk/fs/btrfs/compression.h +++ b/trunk/fs/btrfs/compression.h @@ -19,42 +19,11 @@ #ifndef __BTRFS_COMPRESSION_ #define __BTRFS_COMPRESSION_ -int btrfs_init_compress(void); -void btrfs_exit_compress(void); - -int btrfs_compress_pages(int type, struct address_space *mapping, - u64 start, unsigned long len, - struct page **pages, - unsigned long nr_dest_pages, - unsigned long *out_pages, - unsigned long *total_in, - unsigned long *total_out, - unsigned long max_out); -int btrfs_decompress_biovec(int type, struct page **pages_in, u64 disk_start, - struct bio_vec *bvec, int vcnt, size_t srclen); -int btrfs_decompress(int type, unsigned char *data_in, struct page *dest_page, - unsigned long start_byte, size_t srclen, size_t destlen); -int btrfs_decompress_buf2page(char *buf, unsigned long buf_start, - unsigned long total_out, u64 disk_start, - struct bio_vec *bvec, int vcnt, - unsigned long *page_index, - unsigned long *pg_offset); - -int btrfs_submit_compressed_write(struct inode *inode, u64 start, - unsigned long len, u64 disk_start, - unsigned long compressed_len, - struct page **compressed_pages, - unsigned long nr_pages); -int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, - int mirror_num, unsigned long bio_flags); - -struct btrfs_compress_op { - struct list_head *(*alloc_workspace)(void); - - void (*free_workspace)(struct list_head *workspace); - - int (*compress_pages)(struct list_head *workspace, - struct address_space *mapping, +int btrfs_zlib_decompress(unsigned char *data_in, + struct page *dest_page, + unsigned long start_byte, + size_t srclen, size_t destlen); +int btrfs_zlib_compress_pages(struct address_space *mapping, u64 start, unsigned long len, struct page **pages, unsigned long nr_dest_pages, @@ -62,22 +31,17 @@ struct btrfs_compress_op { unsigned long *total_in, unsigned long *total_out, unsigned long max_out); - - int (*decompress_biovec)(struct list_head *workspace, - struct page **pages_in, - u64 disk_start, - struct bio_vec *bvec, - int vcnt, - size_t srclen); - - int (*decompress)(struct list_head *workspace, - unsigned char *data_in, - struct page *dest_page, - unsigned long start_byte, - size_t srclen, size_t destlen); -}; - -extern struct btrfs_compress_op btrfs_zlib_compress; -extern struct btrfs_compress_op btrfs_lzo_compress; - +int btrfs_zlib_decompress_biovec(struct page **pages_in, + u64 disk_start, + struct bio_vec *bvec, + int vcnt, + size_t srclen); +void btrfs_zlib_exit(void); +int btrfs_submit_compressed_write(struct inode *inode, u64 start, + unsigned long len, u64 disk_start, + unsigned long compressed_len, + struct page **compressed_pages, + unsigned long nr_pages); +int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, + int mirror_num, unsigned long bio_flags); #endif diff --git a/trunk/fs/btrfs/ctree.c b/trunk/fs/btrfs/ctree.c index b5baff0dccfe..9ac171599258 100644 --- a/trunk/fs/btrfs/ctree.c +++ b/trunk/fs/btrfs/ctree.c @@ -105,8 +105,6 @@ noinline void btrfs_clear_path_blocking(struct btrfs_path *p, /* this also releases the path */ void btrfs_free_path(struct btrfs_path *p) { - if (!p) - return; btrfs_release_path(NULL, p); kmem_cache_free(btrfs_path_cachep, p); } @@ -2516,9 +2514,6 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root btrfs_assert_tree_locked(path->nodes[1]); right = read_node_slot(root, upper, slot + 1); - if (right == NULL) - return 1; - btrfs_tree_lock(right); btrfs_set_lock_blocking(right); @@ -2769,9 +2764,6 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root btrfs_assert_tree_locked(path->nodes[1]); left = read_node_slot(root, path->nodes[1], slot - 1); - if (left == NULL) - return 1; - btrfs_tree_lock(left); btrfs_set_lock_blocking(left); diff --git a/trunk/fs/btrfs/ctree.h b/trunk/fs/btrfs/ctree.h index 2c98b3af6052..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" @@ -295,14 +294,6 @@ static inline unsigned long btrfs_chunk_item_size(int num_stripes) #define BTRFS_FSID_SIZE 16 #define BTRFS_HEADER_FLAG_WRITTEN (1ULL << 0) #define BTRFS_HEADER_FLAG_RELOC (1ULL << 1) - -/* - * File system states - */ - -/* Errors detected */ -#define BTRFS_SUPER_FLAG_ERROR (1ULL << 2) - #define BTRFS_SUPER_FLAG_SEEDING (1ULL << 32) #define BTRFS_SUPER_FLAG_METADUMP (1ULL << 33) @@ -407,15 +398,13 @@ struct btrfs_super_block { #define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF (1ULL << 0) #define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (1ULL << 1) #define BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS (1ULL << 2) -#define BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO (1ULL << 3) #define BTRFS_FEATURE_COMPAT_SUPP 0ULL #define BTRFS_FEATURE_COMPAT_RO_SUPP 0ULL #define BTRFS_FEATURE_INCOMPAT_SUPP \ (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \ BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL | \ - BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS | \ - BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO) + BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) /* * A leaf is full of items. offset and size tell us where to find @@ -562,11 +551,9 @@ struct btrfs_timespec { } __attribute__ ((__packed__)); enum btrfs_compression_type { - BTRFS_COMPRESS_NONE = 0, - BTRFS_COMPRESS_ZLIB = 1, - BTRFS_COMPRESS_LZO = 2, - BTRFS_COMPRESS_TYPES = 2, - BTRFS_COMPRESS_LAST = 3, + BTRFS_COMPRESS_NONE = 0, + BTRFS_COMPRESS_ZLIB = 1, + BTRFS_COMPRESS_LAST = 2, }; struct btrfs_inode_item { @@ -610,8 +597,6 @@ struct btrfs_dir_item { u8 type; } __attribute__ ((__packed__)); -#define BTRFS_ROOT_SUBVOL_RDONLY (1ULL << 0) - struct btrfs_root_item { struct btrfs_inode_item inode; __le64 generation; @@ -910,8 +895,7 @@ struct btrfs_fs_info { */ u64 last_trans_log_full_commit; u64 open_ioctl_trans; - unsigned long mount_opt:20; - unsigned long compress_type:4; + unsigned long mount_opt; u64 max_inline; u64 alloc_start; struct btrfs_transaction *running_transaction; @@ -1066,9 +1050,6 @@ struct btrfs_fs_info { unsigned metadata_ratio; void *bdev_holder; - - /* filesystem state */ - u64 fs_state; }; /* @@ -1912,11 +1893,6 @@ BTRFS_SETGET_STACK_FUNCS(root_limit, struct btrfs_root_item, byte_limit, 64); BTRFS_SETGET_STACK_FUNCS(root_last_snapshot, struct btrfs_root_item, last_snapshot, 64); -static inline bool btrfs_root_readonly(struct btrfs_root *root) -{ - return root->root_item.flags & BTRFS_ROOT_SUBVOL_RDONLY; -} - /* struct btrfs_super_block */ BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64); @@ -2169,7 +2145,6 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, int btrfs_remove_block_group(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 group_start); u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags); -u64 btrfs_get_alloc_profile(struct btrfs_root *root, int data); void btrfs_set_inode_space_info(struct btrfs_root *root, struct inode *ionde); void btrfs_clear_space_info_full(struct btrfs_fs_info *info); int btrfs_check_data_free_space(struct inode *inode, u64 bytes); @@ -2213,12 +2188,6 @@ int btrfs_set_block_group_ro(struct btrfs_root *root, int btrfs_set_block_group_rw(struct btrfs_root *root, struct btrfs_block_group_cache *cache); void btrfs_put_block_group_cache(struct btrfs_fs_info *info); -u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo); -int btrfs_error_unpin_extent_range(struct btrfs_root *root, - u64 start, u64 end); -int btrfs_error_discard_extent(struct btrfs_root *root, u64 bytenr, - u64 num_bytes); - /* ctree.c */ int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key, int level, int *slot); @@ -2572,14 +2541,6 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size); /* super.c */ int btrfs_parse_options(struct btrfs_root *root, char *options); int btrfs_sync_fs(struct super_block *sb, int wait); -void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function, - unsigned int line, int errno); - -#define btrfs_std_error(fs_info, errno) \ -do { \ - if ((errno)) \ - __btrfs_std_error((fs_info), __func__, __LINE__, (errno));\ -} while (0) /* acl.c */ #ifdef CONFIG_BTRFS_FS_POSIX_ACL diff --git a/trunk/fs/btrfs/disk-io.c b/trunk/fs/btrfs/disk-io.c index b531c36455d8..51d2e4de34eb 100644 --- a/trunk/fs/btrfs/disk-io.c +++ b/trunk/fs/btrfs/disk-io.c @@ -44,20 +44,6 @@ static struct extent_io_ops btree_extent_io_ops; static void end_workqueue_fn(struct btrfs_work *work); static void free_fs_root(struct btrfs_root *root); -static void btrfs_check_super_valid(struct btrfs_fs_info *fs_info, - int read_only); -static int btrfs_destroy_ordered_operations(struct btrfs_root *root); -static int btrfs_destroy_ordered_extents(struct btrfs_root *root); -static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, - struct btrfs_root *root); -static int btrfs_destroy_pending_snapshots(struct btrfs_transaction *t); -static int btrfs_destroy_delalloc_inodes(struct btrfs_root *root); -static int btrfs_destroy_marked_extents(struct btrfs_root *root, - struct extent_io_tree *dirty_pages, - int mark); -static int btrfs_destroy_pinned_extent(struct btrfs_root *root, - struct extent_io_tree *pinned_extents); -static int btrfs_cleanup_transaction(struct btrfs_root *root); /* * end_io_wq structs are used to do processing in task context when an IO is @@ -367,10 +353,6 @@ static int csum_dirty_buffer(struct btrfs_root *root, struct page *page) WARN_ON(len == 0); eb = alloc_extent_buffer(tree, start, len, page, GFP_NOFS); - if (eb == NULL) { - WARN_ON(1); - goto out; - } ret = btree_read_extent_buffer_pages(root, eb, start + PAGE_CACHE_SIZE, btrfs_header_generation(eb)); BUG_ON(ret); @@ -445,10 +427,6 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end, WARN_ON(len == 0); eb = alloc_extent_buffer(tree, start, len, page, GFP_NOFS); - if (eb == NULL) { - ret = -EIO; - goto out; - } found_start = btrfs_header_bytenr(eb); if (found_start != start) { @@ -1167,7 +1145,6 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root, } btrfs_free_path(path); if (ret) { - kfree(root); if (ret > 0) ret = -ENOENT; return ERR_PTR(ret); @@ -1736,10 +1713,8 @@ struct btrfs_root *open_ctree(struct super_block *sb, fs_info, BTRFS_ROOT_TREE_OBJECTID); bh = btrfs_read_dev_super(fs_devices->latest_bdev); - if (!bh) { - err = -EINVAL; + if (!bh) goto fail_iput; - } memcpy(&fs_info->super_copy, bh->b_data, sizeof(fs_info->super_copy)); memcpy(&fs_info->super_for_commit, &fs_info->super_copy, @@ -1752,11 +1727,6 @@ struct btrfs_root *open_ctree(struct super_block *sb, if (!btrfs_super_root(disk_super)) goto fail_iput; - /* check FS state, whether FS is broken. */ - fs_info->fs_state |= btrfs_super_flags(disk_super); - - btrfs_check_super_valid(fs_info, sb->s_flags & MS_RDONLY); - ret = btrfs_parse_options(tree_root, options); if (ret) { err = ret; @@ -1774,10 +1744,10 @@ struct btrfs_root *open_ctree(struct super_block *sb, } features = btrfs_super_incompat_flags(disk_super); - features |= BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF; - if (tree_root->fs_info->compress_type & BTRFS_COMPRESS_LZO) - features |= BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO; - btrfs_set_super_incompat_flags(disk_super, features); + if (!(features & BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF)) { + features |= BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF; + btrfs_set_super_incompat_flags(disk_super, features); + } features = btrfs_super_compat_ro_flags(disk_super) & ~BTRFS_FEATURE_COMPAT_RO_SUPP; @@ -1987,9 +1957,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, btrfs_set_opt(fs_info->mount_opt, SSD); } - /* do not make disk changes in broken FS */ - if (btrfs_super_log_root(disk_super) != 0 && - !(fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR)) { + if (btrfs_super_log_root(disk_super) != 0) { u64 bytenr = btrfs_super_log_root(disk_super); if (fs_devices->rw_devices == 0) { @@ -2474,28 +2442,8 @@ int close_ctree(struct btrfs_root *root) smp_mb(); btrfs_put_block_group_cache(fs_info); - - /* - * Here come 2 situations when btrfs is broken to flip readonly: - * - * 1. when btrfs flips readonly somewhere else before - * btrfs_commit_super, sb->s_flags has MS_RDONLY flag, - * and btrfs will skip to write sb directly to keep - * ERROR state on disk. - * - * 2. when btrfs flips readonly just in btrfs_commit_super, - * and in such case, btrfs cannnot write sb via btrfs_commit_super, - * and since fs_state has been set BTRFS_SUPER_FLAG_ERROR flag, - * btrfs will cleanup all FS resources first and write sb then. - */ if (!(fs_info->sb->s_flags & MS_RDONLY)) { - ret = btrfs_commit_super(root); - if (ret) - printk(KERN_ERR "btrfs: commit super ret %d\n", ret); - } - - if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) { - ret = btrfs_error_commit_super(root); + ret = btrfs_commit_super(root); if (ret) printk(KERN_ERR "btrfs: commit super ret %d\n", ret); } @@ -2671,352 +2619,6 @@ int btree_lock_page_hook(struct page *page) return 0; } -static void btrfs_check_super_valid(struct btrfs_fs_info *fs_info, - int read_only) -{ - if (read_only) - return; - - if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) - printk(KERN_WARNING "warning: mount fs with errors, " - "running btrfsck is recommended\n"); -} - -int btrfs_error_commit_super(struct btrfs_root *root) -{ - int ret; - - mutex_lock(&root->fs_info->cleaner_mutex); - btrfs_run_delayed_iputs(root); - mutex_unlock(&root->fs_info->cleaner_mutex); - - down_write(&root->fs_info->cleanup_work_sem); - up_write(&root->fs_info->cleanup_work_sem); - - /* cleanup FS via transaction */ - btrfs_cleanup_transaction(root); - - ret = write_ctree_super(NULL, root, 0); - - return ret; -} - -static int btrfs_destroy_ordered_operations(struct btrfs_root *root) -{ - struct btrfs_inode *btrfs_inode; - struct list_head splice; - - INIT_LIST_HEAD(&splice); - - mutex_lock(&root->fs_info->ordered_operations_mutex); - spin_lock(&root->fs_info->ordered_extent_lock); - - list_splice_init(&root->fs_info->ordered_operations, &splice); - while (!list_empty(&splice)) { - btrfs_inode = list_entry(splice.next, struct btrfs_inode, - ordered_operations); - - list_del_init(&btrfs_inode->ordered_operations); - - btrfs_invalidate_inodes(btrfs_inode->root); - } - - spin_unlock(&root->fs_info->ordered_extent_lock); - mutex_unlock(&root->fs_info->ordered_operations_mutex); - - return 0; -} - -static int btrfs_destroy_ordered_extents(struct btrfs_root *root) -{ - struct list_head splice; - struct btrfs_ordered_extent *ordered; - struct inode *inode; - - INIT_LIST_HEAD(&splice); - - spin_lock(&root->fs_info->ordered_extent_lock); - - list_splice_init(&root->fs_info->ordered_extents, &splice); - while (!list_empty(&splice)) { - ordered = list_entry(splice.next, struct btrfs_ordered_extent, - root_extent_list); - - list_del_init(&ordered->root_extent_list); - atomic_inc(&ordered->refs); - - /* the inode may be getting freed (in sys_unlink path). */ - inode = igrab(ordered->inode); - - spin_unlock(&root->fs_info->ordered_extent_lock); - if (inode) - iput(inode); - - atomic_set(&ordered->refs, 1); - btrfs_put_ordered_extent(ordered); - - spin_lock(&root->fs_info->ordered_extent_lock); - } - - spin_unlock(&root->fs_info->ordered_extent_lock); - - return 0; -} - -static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, - struct btrfs_root *root) -{ - struct rb_node *node; - struct btrfs_delayed_ref_root *delayed_refs; - struct btrfs_delayed_ref_node *ref; - int ret = 0; - - delayed_refs = &trans->delayed_refs; - - spin_lock(&delayed_refs->lock); - if (delayed_refs->num_entries == 0) { - printk(KERN_INFO "delayed_refs has NO entry\n"); - return ret; - } - - node = rb_first(&delayed_refs->root); - while (node) { - ref = rb_entry(node, struct btrfs_delayed_ref_node, rb_node); - node = rb_next(node); - - ref->in_tree = 0; - rb_erase(&ref->rb_node, &delayed_refs->root); - delayed_refs->num_entries--; - - atomic_set(&ref->refs, 1); - if (btrfs_delayed_ref_is_head(ref)) { - struct btrfs_delayed_ref_head *head; - - head = btrfs_delayed_node_to_head(ref); - mutex_lock(&head->mutex); - kfree(head->extent_op); - delayed_refs->num_heads--; - if (list_empty(&head->cluster)) - delayed_refs->num_heads_ready--; - list_del_init(&head->cluster); - mutex_unlock(&head->mutex); - } - - spin_unlock(&delayed_refs->lock); - btrfs_put_delayed_ref(ref); - - cond_resched(); - spin_lock(&delayed_refs->lock); - } - - spin_unlock(&delayed_refs->lock); - - return ret; -} - -static int btrfs_destroy_pending_snapshots(struct btrfs_transaction *t) -{ - struct btrfs_pending_snapshot *snapshot; - struct list_head splice; - - INIT_LIST_HEAD(&splice); - - list_splice_init(&t->pending_snapshots, &splice); - - while (!list_empty(&splice)) { - snapshot = list_entry(splice.next, - struct btrfs_pending_snapshot, - list); - - list_del_init(&snapshot->list); - - kfree(snapshot); - } - - return 0; -} - -static int btrfs_destroy_delalloc_inodes(struct btrfs_root *root) -{ - struct btrfs_inode *btrfs_inode; - struct list_head splice; - - INIT_LIST_HEAD(&splice); - - list_splice_init(&root->fs_info->delalloc_inodes, &splice); - - spin_lock(&root->fs_info->delalloc_lock); - - while (!list_empty(&splice)) { - btrfs_inode = list_entry(splice.next, struct btrfs_inode, - delalloc_inodes); - - list_del_init(&btrfs_inode->delalloc_inodes); - - btrfs_invalidate_inodes(btrfs_inode->root); - } - - spin_unlock(&root->fs_info->delalloc_lock); - - return 0; -} - -static int btrfs_destroy_marked_extents(struct btrfs_root *root, - struct extent_io_tree *dirty_pages, - int mark) -{ - int ret; - struct page *page; - struct inode *btree_inode = root->fs_info->btree_inode; - struct extent_buffer *eb; - u64 start = 0; - u64 end; - u64 offset; - unsigned long index; - - while (1) { - ret = find_first_extent_bit(dirty_pages, start, &start, &end, - mark); - if (ret) - break; - - clear_extent_bits(dirty_pages, start, end, mark, GFP_NOFS); - while (start <= end) { - index = start >> PAGE_CACHE_SHIFT; - start = (u64)(index + 1) << PAGE_CACHE_SHIFT; - page = find_get_page(btree_inode->i_mapping, index); - if (!page) - continue; - offset = page_offset(page); - - spin_lock(&dirty_pages->buffer_lock); - eb = radix_tree_lookup( - &(&BTRFS_I(page->mapping->host)->io_tree)->buffer, - offset >> PAGE_CACHE_SHIFT); - spin_unlock(&dirty_pages->buffer_lock); - if (eb) { - ret = test_and_clear_bit(EXTENT_BUFFER_DIRTY, - &eb->bflags); - atomic_set(&eb->refs, 1); - } - if (PageWriteback(page)) - end_page_writeback(page); - - lock_page(page); - if (PageDirty(page)) { - clear_page_dirty_for_io(page); - spin_lock_irq(&page->mapping->tree_lock); - radix_tree_tag_clear(&page->mapping->page_tree, - page_index(page), - PAGECACHE_TAG_DIRTY); - spin_unlock_irq(&page->mapping->tree_lock); - } - - page->mapping->a_ops->invalidatepage(page, 0); - unlock_page(page); - } - } - - return ret; -} - -static int btrfs_destroy_pinned_extent(struct btrfs_root *root, - struct extent_io_tree *pinned_extents) -{ - struct extent_io_tree *unpin; - u64 start; - u64 end; - int ret; - - unpin = pinned_extents; - while (1) { - ret = find_first_extent_bit(unpin, 0, &start, &end, - EXTENT_DIRTY); - if (ret) - break; - - /* opt_discard */ - ret = btrfs_error_discard_extent(root, start, end + 1 - start); - - clear_extent_dirty(unpin, start, end, GFP_NOFS); - btrfs_error_unpin_extent_range(root, start, end); - cond_resched(); - } - - return 0; -} - -static int btrfs_cleanup_transaction(struct btrfs_root *root) -{ - struct btrfs_transaction *t; - LIST_HEAD(list); - - WARN_ON(1); - - mutex_lock(&root->fs_info->trans_mutex); - mutex_lock(&root->fs_info->transaction_kthread_mutex); - - list_splice_init(&root->fs_info->trans_list, &list); - while (!list_empty(&list)) { - t = list_entry(list.next, struct btrfs_transaction, list); - if (!t) - break; - - btrfs_destroy_ordered_operations(root); - - btrfs_destroy_ordered_extents(root); - - btrfs_destroy_delayed_refs(t, root); - - btrfs_block_rsv_release(root, - &root->fs_info->trans_block_rsv, - t->dirty_pages.dirty_bytes); - - /* FIXME: cleanup wait for commit */ - t->in_commit = 1; - t->blocked = 1; - if (waitqueue_active(&root->fs_info->transaction_blocked_wait)) - wake_up(&root->fs_info->transaction_blocked_wait); - - t->blocked = 0; - if (waitqueue_active(&root->fs_info->transaction_wait)) - wake_up(&root->fs_info->transaction_wait); - mutex_unlock(&root->fs_info->trans_mutex); - - mutex_lock(&root->fs_info->trans_mutex); - t->commit_done = 1; - if (waitqueue_active(&t->commit_wait)) - wake_up(&t->commit_wait); - mutex_unlock(&root->fs_info->trans_mutex); - - mutex_lock(&root->fs_info->trans_mutex); - - btrfs_destroy_pending_snapshots(t); - - btrfs_destroy_delalloc_inodes(root); - - spin_lock(&root->fs_info->new_trans_lock); - root->fs_info->running_transaction = NULL; - spin_unlock(&root->fs_info->new_trans_lock); - - btrfs_destroy_marked_extents(root, &t->dirty_pages, - EXTENT_DIRTY); - - btrfs_destroy_pinned_extent(root, - root->fs_info->pinned_extents); - - t->use_count = 0; - list_del_init(&t->list); - memset(t, 0, sizeof(*t)); - kmem_cache_free(btrfs_transaction_cachep, t); - } - - mutex_unlock(&root->fs_info->transaction_kthread_mutex); - mutex_unlock(&root->fs_info->trans_mutex); - - return 0; -} - static struct extent_io_ops btree_extent_io_ops = { .write_cache_pages_lock_hook = btree_lock_page_hook, .readpage_end_io_hook = btree_readpage_end_io_hook, diff --git a/trunk/fs/btrfs/disk-io.h b/trunk/fs/btrfs/disk-io.h index 07b20dc2fd95..88e825a0bf21 100644 --- a/trunk/fs/btrfs/disk-io.h +++ b/trunk/fs/btrfs/disk-io.h @@ -52,7 +52,6 @@ int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root *root, int max_mirrors); struct buffer_head *btrfs_read_dev_super(struct block_device *bdev); int btrfs_commit_super(struct btrfs_root *root); -int btrfs_error_commit_super(struct btrfs_root *root); struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize); struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info, diff --git a/trunk/fs/btrfs/extent-tree.c b/trunk/fs/btrfs/extent-tree.c index b55269340cec..227e5815d838 100644 --- a/trunk/fs/btrfs/extent-tree.c +++ b/trunk/fs/btrfs/extent-tree.c @@ -3089,7 +3089,7 @@ static u64 get_alloc_profile(struct btrfs_root *root, u64 flags) return btrfs_reduce_alloc_profile(root, flags); } -u64 btrfs_get_alloc_profile(struct btrfs_root *root, int data) +static u64 btrfs_get_alloc_profile(struct btrfs_root *root, int data) { u64 flags; @@ -3161,12 +3161,8 @@ int btrfs_check_data_free_space(struct inode *inode, u64 bytes) bytes + 2 * 1024 * 1024, alloc_target, 0); btrfs_end_transaction(trans, root); - if (ret < 0) { - if (ret != -ENOSPC) - return ret; - else - goto commit_trans; - } + if (ret < 0) + return ret; if (!data_sinfo) { btrfs_set_inode_space_info(root, inode); @@ -3177,7 +3173,6 @@ int btrfs_check_data_free_space(struct inode *inode, u64 bytes) spin_unlock(&data_sinfo->lock); /* commit the current transaction and try again */ -commit_trans: if (!committed && !root->fs_info->open_ioctl_trans) { committed = 1; trans = btrfs_join_transaction(root, 1); @@ -3726,6 +3721,11 @@ int btrfs_block_rsv_check(struct btrfs_trans_handle *trans, return 0; } + WARN_ON(1); + printk(KERN_INFO"block_rsv size %llu reserved %llu freed %llu %llu\n", + block_rsv->size, block_rsv->reserved, + block_rsv->freed[0], block_rsv->freed[1]); + return -ENOSPC; } @@ -7970,14 +7970,13 @@ static int set_block_group_ro(struct btrfs_block_group_cache *cache) if (sinfo->bytes_used + sinfo->bytes_reserved + sinfo->bytes_pinned + sinfo->bytes_may_use + sinfo->bytes_readonly + - cache->reserved_pinned + num_bytes <= sinfo->total_bytes) { + cache->reserved_pinned + num_bytes < sinfo->total_bytes) { sinfo->bytes_readonly += num_bytes; sinfo->bytes_reserved += cache->reserved_pinned; cache->reserved_pinned = 0; cache->ro = 1; ret = 0; } - spin_unlock(&cache->lock); spin_unlock(&sinfo->lock); return ret; @@ -8013,62 +8012,6 @@ int btrfs_set_block_group_ro(struct btrfs_root *root, return ret; } -/* - * helper to account the unused space of all the readonly block group in the - * list. takes mirrors into account. - */ -static u64 __btrfs_get_ro_block_group_free_space(struct list_head *groups_list) -{ - struct btrfs_block_group_cache *block_group; - u64 free_bytes = 0; - int factor; - - list_for_each_entry(block_group, groups_list, list) { - spin_lock(&block_group->lock); - - if (!block_group->ro) { - spin_unlock(&block_group->lock); - continue; - } - - if (block_group->flags & (BTRFS_BLOCK_GROUP_RAID1 | - BTRFS_BLOCK_GROUP_RAID10 | - BTRFS_BLOCK_GROUP_DUP)) - factor = 2; - else - factor = 1; - - free_bytes += (block_group->key.offset - - btrfs_block_group_used(&block_group->item)) * - factor; - - spin_unlock(&block_group->lock); - } - - return free_bytes; -} - -/* - * helper to account the unused space of all the readonly block group in the - * space_info. takes mirrors into account. - */ -u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo) -{ - int i; - u64 free_bytes = 0; - - spin_lock(&sinfo->lock); - - for(i = 0; i < BTRFS_NR_RAID_TYPES; i++) - if (!list_empty(&sinfo->block_groups[i])) - free_bytes += __btrfs_get_ro_block_group_free_space( - &sinfo->block_groups[i]); - - spin_unlock(&sinfo->lock); - - return free_bytes; -} - int btrfs_set_block_group_rw(struct btrfs_root *root, struct btrfs_block_group_cache *cache) { @@ -8149,7 +8092,7 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr) mutex_lock(&root->fs_info->chunk_mutex); list_for_each_entry(device, &fs_devices->alloc_list, dev_alloc_list) { u64 min_free = btrfs_block_group_used(&block_group->item); - u64 dev_offset; + u64 dev_offset, max_avail; /* * check to make sure we can actually find a chunk with enough @@ -8157,7 +8100,7 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr) */ if (device->total_bytes > device->bytes_used + min_free) { ret = find_free_dev_extent(NULL, device, min_free, - &dev_offset, NULL); + &dev_offset, &max_avail); if (!ret) break; ret = -1; @@ -8641,14 +8584,3 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, btrfs_free_path(path); return ret; } - -int btrfs_error_unpin_extent_range(struct btrfs_root *root, u64 start, u64 end) -{ - return unpin_extent_range(root, start, end); -} - -int btrfs_error_discard_extent(struct btrfs_root *root, u64 bytenr, - u64 num_bytes) -{ - return btrfs_discard_extent(root, bytenr, num_bytes); -} diff --git a/trunk/fs/btrfs/extent_io.c b/trunk/fs/btrfs/extent_io.c index 2e993cf1766e..3e86b9f36507 100644 --- a/trunk/fs/btrfs/extent_io.c +++ b/trunk/fs/btrfs/extent_io.c @@ -2028,11 +2028,8 @@ static int __extent_read_full_page(struct extent_io_tree *tree, BUG_ON(extent_map_end(em) <= cur); BUG_ON(end < cur); - if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) { + if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) this_bio_flag = EXTENT_BIO_COMPRESSED; - extent_set_compress_type(&this_bio_flag, - em->compress_type); - } iosize = min(extent_map_end(em) - cur, end - cur + 1); cur_end = min(extent_map_end(em) - 1, end); @@ -3075,8 +3072,6 @@ static struct extent_buffer *__alloc_extent_buffer(struct extent_io_tree *tree, #endif eb = kmem_cache_zalloc(extent_buffer_cache, mask); - if (eb == NULL) - return NULL; eb->start = start; eb->len = len; spin_lock_init(&eb->lock); diff --git a/trunk/fs/btrfs/extent_io.h b/trunk/fs/btrfs/extent_io.h index 7083cfafd061..4183c8178f01 100644 --- a/trunk/fs/btrfs/extent_io.h +++ b/trunk/fs/btrfs/extent_io.h @@ -20,12 +20,8 @@ #define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK) #define EXTENT_CTLBITS (EXTENT_DO_ACCOUNTING | EXTENT_FIRST_DELALLOC) -/* - * flags for bio submission. The high bits indicate the compression - * type for this bio - */ +/* flags for bio submission */ #define EXTENT_BIO_COMPRESSED 1 -#define EXTENT_BIO_FLAG_SHIFT 16 /* these are bit numbers for test/set bit */ #define EXTENT_BUFFER_UPTODATE 0 @@ -139,17 +135,6 @@ struct extent_buffer { wait_queue_head_t lock_wq; }; -static inline void extent_set_compress_type(unsigned long *bio_flags, - int compress_type) -{ - *bio_flags |= compress_type << EXTENT_BIO_FLAG_SHIFT; -} - -static inline int extent_compress_type(unsigned long bio_flags) -{ - return bio_flags >> EXTENT_BIO_FLAG_SHIFT; -} - struct extent_map_tree; static inline struct extent_state *extent_state_next(struct extent_state *state) diff --git a/trunk/fs/btrfs/extent_map.c b/trunk/fs/btrfs/extent_map.c index b0e1fce12530..23cb8da3ff66 100644 --- a/trunk/fs/btrfs/extent_map.c +++ b/trunk/fs/btrfs/extent_map.c @@ -3,7 +3,6 @@ #include #include #include -#include "ctree.h" #include "extent_map.h" @@ -55,7 +54,6 @@ struct extent_map *alloc_extent_map(gfp_t mask) return em; em->in_tree = 0; em->flags = 0; - em->compress_type = BTRFS_COMPRESS_NONE; atomic_set(&em->refs, 1); return em; } diff --git a/trunk/fs/btrfs/extent_map.h b/trunk/fs/btrfs/extent_map.h index 28b44dbd1e35..ab6d74b6e647 100644 --- a/trunk/fs/btrfs/extent_map.h +++ b/trunk/fs/btrfs/extent_map.h @@ -26,8 +26,7 @@ struct extent_map { unsigned long flags; struct block_device *bdev; atomic_t refs; - unsigned int in_tree:1; - unsigned int compress_type:4; + int in_tree; }; struct extent_map_tree { diff --git a/trunk/fs/btrfs/file.c b/trunk/fs/btrfs/file.c index c800d58f3013..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 @@ -225,7 +224,6 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, split->bdev = em->bdev; split->flags = flags; - split->compress_type = em->compress_type; ret = add_extent_mapping(em_tree, split); BUG_ON(ret); free_extent_map(split); @@ -240,7 +238,6 @@ int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, split->len = em->start + em->len - (start + len); split->bdev = em->bdev; split->flags = flags; - split->compress_type = em->compress_type; if (compressed) { split->block_len = em->block_len; @@ -893,17 +890,6 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb, if (err) goto out; - /* - * If BTRFS flips readonly due to some impossible error - * (fs_info->fs_state now has BTRFS_SUPER_FLAG_ERROR), - * although we have opened a file as writable, we have - * to stop this write operation to ensure FS consistency. - */ - if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) { - err = -EROFS; - goto out; - } - file_update_time(file); BTRFS_I(inode)->sequence++; @@ -1251,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, @@ -1373,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 160b55b3e132..a3798a3aa0d2 100644 --- a/trunk/fs/btrfs/inode.c +++ b/trunk/fs/btrfs/inode.c @@ -122,10 +122,10 @@ static noinline int insert_inline_extent(struct btrfs_trans_handle *trans, size_t cur_size = size; size_t datasize; unsigned long offset; - int compress_type = BTRFS_COMPRESS_NONE; + int use_compress = 0; if (compressed_size && compressed_pages) { - compress_type = root->fs_info->compress_type; + use_compress = 1; cur_size = compressed_size; } @@ -159,7 +159,7 @@ static noinline int insert_inline_extent(struct btrfs_trans_handle *trans, btrfs_set_file_extent_ram_bytes(leaf, ei, size); ptr = btrfs_file_extent_inline_start(ei); - if (compress_type != BTRFS_COMPRESS_NONE) { + if (use_compress) { struct page *cpage; int i = 0; while (compressed_size > 0) { @@ -176,7 +176,7 @@ static noinline int insert_inline_extent(struct btrfs_trans_handle *trans, compressed_size -= cur_size; } btrfs_set_file_extent_compression(leaf, ei, - compress_type); + BTRFS_COMPRESS_ZLIB); } else { page = find_get_page(inode->i_mapping, start >> PAGE_CACHE_SHIFT); @@ -263,7 +263,6 @@ struct async_extent { u64 compressed_size; struct page **pages; unsigned long nr_pages; - int compress_type; struct list_head list; }; @@ -281,8 +280,7 @@ static noinline int add_async_extent(struct async_cow *cow, u64 start, u64 ram_size, u64 compressed_size, struct page **pages, - unsigned long nr_pages, - int compress_type) + unsigned long nr_pages) { struct async_extent *async_extent; @@ -292,7 +290,6 @@ static noinline int add_async_extent(struct async_cow *cow, async_extent->compressed_size = compressed_size; async_extent->pages = pages; async_extent->nr_pages = nr_pages; - async_extent->compress_type = compress_type; list_add_tail(&async_extent->list, &cow->extents); return 0; } @@ -335,7 +332,6 @@ static noinline int compress_file_range(struct inode *inode, unsigned long max_uncompressed = 128 * 1024; int i; int will_compress; - int compress_type = root->fs_info->compress_type; actual_end = min_t(u64, isize, end + 1); again: @@ -385,16 +381,12 @@ static noinline int compress_file_range(struct inode *inode, WARN_ON(pages); pages = kzalloc(sizeof(struct page *) * nr_pages, GFP_NOFS); - if (BTRFS_I(inode)->force_compress) - compress_type = BTRFS_I(inode)->force_compress; - - ret = btrfs_compress_pages(compress_type, - inode->i_mapping, start, - total_compressed, pages, - nr_pages, &nr_pages_ret, - &total_in, - &total_compressed, - max_compressed); + ret = btrfs_zlib_compress_pages(inode->i_mapping, start, + total_compressed, pages, + nr_pages, &nr_pages_ret, + &total_in, + &total_compressed, + max_compressed); if (!ret) { unsigned long offset = total_compressed & @@ -501,8 +493,7 @@ static noinline int compress_file_range(struct inode *inode, * and will submit them to the elevator. */ add_async_extent(async_cow, start, num_bytes, - total_compressed, pages, nr_pages_ret, - compress_type); + total_compressed, pages, nr_pages_ret); if (start + num_bytes < end) { start += num_bytes; @@ -524,8 +515,7 @@ static noinline int compress_file_range(struct inode *inode, __set_page_dirty_nobuffers(locked_page); /* unlocked later on in the async handlers */ } - add_async_extent(async_cow, start, end - start + 1, - 0, NULL, 0, BTRFS_COMPRESS_NONE); + add_async_extent(async_cow, start, end - start + 1, 0, NULL, 0); *num_added += 1; } @@ -650,7 +640,6 @@ static noinline int submit_compressed_extents(struct inode *inode, em->block_start = ins.objectid; em->block_len = ins.offset; em->bdev = root->fs_info->fs_devices->latest_bdev; - em->compress_type = async_extent->compress_type; set_bit(EXTENT_FLAG_PINNED, &em->flags); set_bit(EXTENT_FLAG_COMPRESSED, &em->flags); @@ -667,13 +656,11 @@ static noinline int submit_compressed_extents(struct inode *inode, async_extent->ram_size - 1, 0); } - ret = btrfs_add_ordered_extent_compress(inode, - async_extent->start, - ins.objectid, - async_extent->ram_size, - ins.offset, - BTRFS_ORDERED_COMPRESSED, - async_extent->compress_type); + ret = btrfs_add_ordered_extent(inode, async_extent->start, + ins.objectid, + async_extent->ram_size, + ins.offset, + BTRFS_ORDERED_COMPRESSED); BUG_ON(ret); /* @@ -1683,7 +1670,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) struct btrfs_ordered_extent *ordered_extent = NULL; struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; struct extent_state *cached_state = NULL; - int compress_type = 0; + int compressed = 0; int ret; bool nolock = false; @@ -1724,9 +1711,9 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) trans->block_rsv = &root->fs_info->delalloc_block_rsv; if (test_bit(BTRFS_ORDERED_COMPRESSED, &ordered_extent->flags)) - compress_type = ordered_extent->compress_type; + compressed = 1; if (test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags)) { - BUG_ON(compress_type); + BUG_ON(compressed); ret = btrfs_mark_extent_written(trans, inode, ordered_extent->file_offset, ordered_extent->file_offset + @@ -1740,7 +1727,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) ordered_extent->disk_len, ordered_extent->len, ordered_extent->len, - compress_type, 0, 0, + compressed, 0, 0, BTRFS_FILE_EXTENT_REG); unpin_extent_cache(&BTRFS_I(inode)->extent_tree, ordered_extent->file_offset, @@ -1842,8 +1829,6 @@ static int btrfs_io_failed_hook(struct bio *failed_bio, if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) { logical = em->block_start; failrec->bio_flags = EXTENT_BIO_COMPRESSED; - extent_set_compress_type(&failrec->bio_flags, - em->compress_type); } failrec->logical = logical; free_extent_map(em); @@ -3686,12 +3671,8 @@ static int btrfs_setattr_size(struct inode *inode, struct iattr *attr) static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) { struct inode *inode = dentry->d_inode; - struct btrfs_root *root = BTRFS_I(inode)->root; int err; - if (btrfs_root_readonly(root)) - return -EROFS; - err = inode_change_ok(inode, attr); if (err) return err; @@ -4947,10 +4928,8 @@ static noinline int uncompress_inline(struct btrfs_path *path, size_t max_size; unsigned long inline_size; unsigned long ptr; - int compress_type; WARN_ON(pg_offset != 0); - compress_type = btrfs_file_extent_compression(leaf, item); max_size = btrfs_file_extent_ram_bytes(leaf, item); inline_size = btrfs_file_extent_inline_item_len(leaf, btrfs_item_nr(leaf, path->slots[0])); @@ -4960,8 +4939,8 @@ static noinline int uncompress_inline(struct btrfs_path *path, read_extent_buffer(leaf, tmp, ptr, inline_size); max_size = min_t(unsigned long, PAGE_CACHE_SIZE, max_size); - ret = btrfs_decompress(compress_type, tmp, page, - extent_offset, inline_size, max_size); + ret = btrfs_zlib_decompress(tmp, page, extent_offset, + inline_size, max_size); if (ret) { char *kaddr = kmap_atomic(page, KM_USER0); unsigned long copy_size = min_t(u64, @@ -5003,7 +4982,7 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page, struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; struct btrfs_trans_handle *trans = NULL; - int compress_type; + int compressed; again: read_lock(&em_tree->lock); @@ -5062,7 +5041,7 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page, found_type = btrfs_file_extent_type(leaf, item); extent_start = found_key.offset; - compress_type = btrfs_file_extent_compression(leaf, item); + compressed = btrfs_file_extent_compression(leaf, item); if (found_type == BTRFS_FILE_EXTENT_REG || found_type == BTRFS_FILE_EXTENT_PREALLOC) { extent_end = extent_start + @@ -5108,9 +5087,8 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page, em->block_start = EXTENT_MAP_HOLE; goto insert; } - if (compress_type != BTRFS_COMPRESS_NONE) { + if (compressed) { set_bit(EXTENT_FLAG_COMPRESSED, &em->flags); - em->compress_type = compress_type; em->block_start = bytenr; em->block_len = btrfs_file_extent_disk_num_bytes(leaf, item); @@ -5144,14 +5122,12 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page, em->len = (copy_size + root->sectorsize - 1) & ~((u64)root->sectorsize - 1); em->orig_start = EXTENT_MAP_INLINE; - if (compress_type) { + if (compressed) set_bit(EXTENT_FLAG_COMPRESSED, &em->flags); - em->compress_type = compress_type; - } ptr = btrfs_file_extent_inline_start(item) + extent_offset; if (create == 0 && !PageUptodate(page)) { - if (btrfs_file_extent_compression(leaf, item) != - BTRFS_COMPRESS_NONE) { + if (btrfs_file_extent_compression(leaf, item) == + BTRFS_COMPRESS_ZLIB) { ret = uncompress_inline(path, inode, page, pg_offset, extent_offset, item); @@ -6501,7 +6477,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb) ei->ordered_data_close = 0; ei->orphan_meta_reserved = 0; ei->dummy_inode = 0; - ei->force_compress = BTRFS_COMPRESS_NONE; + ei->force_compress = 0; inode = &ei->vfs_inode; extent_map_tree_init(&ei->extent_tree, GFP_NOFS); @@ -7122,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); @@ -7129,10 +7215,6 @@ static int btrfs_set_page_dirty(struct page *page) static int btrfs_permission(struct inode *inode, int mask, unsigned int flags) { - struct btrfs_root *root = BTRFS_I(inode)->root; - - if (btrfs_root_readonly(root) && (mask & MAY_WRITE)) - return -EROFS; if ((BTRFS_I(inode)->flags & BTRFS_INODE_READONLY) && (mask & MAY_WRITE)) return -EACCES; return generic_permission(inode, mask, flags, btrfs_check_acl); @@ -7228,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/btrfs/ioctl.c b/trunk/fs/btrfs/ioctl.c index a506a22b522a..f87552a1d7ea 100644 --- a/trunk/fs/btrfs/ioctl.c +++ b/trunk/fs/btrfs/ioctl.c @@ -147,9 +147,6 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) unsigned int flags, oldflags; int ret; - if (btrfs_root_readonly(root)) - return -EROFS; - if (copy_from_user(&flags, arg, sizeof(flags))) return -EFAULT; @@ -363,8 +360,7 @@ static noinline int create_subvol(struct btrfs_root *root, } static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, - char *name, int namelen, u64 *async_transid, - bool readonly) + char *name, int namelen, u64 *async_transid) { struct inode *inode; struct dentry *parent; @@ -382,7 +378,6 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, btrfs_init_block_rsv(&pending_snapshot->block_rsv); pending_snapshot->dentry = dentry; pending_snapshot->root = root; - pending_snapshot->readonly = readonly; trans = btrfs_start_transaction(root->fs_info->extent_root, 5); if (IS_ERR(trans)) { @@ -514,7 +509,7 @@ static inline int btrfs_may_create(struct inode *dir, struct dentry *child) static noinline int btrfs_mksubvol(struct path *parent, char *name, int namelen, struct btrfs_root *snap_src, - u64 *async_transid, bool readonly) + u64 *async_transid) { struct inode *dir = parent->dentry->d_inode; struct dentry *dentry; @@ -546,7 +541,7 @@ static noinline int btrfs_mksubvol(struct path *parent, if (snap_src) { error = create_snapshot(snap_src, dentry, - name, namelen, async_transid, readonly); + name, namelen, async_transid); } else { error = create_subvol(BTRFS_I(dir)->root, dentry, name, namelen, async_transid); @@ -643,11 +638,9 @@ static int btrfs_defrag_file(struct file *file, struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; struct btrfs_ordered_extent *ordered; struct page *page; - struct btrfs_super_block *disk_super; unsigned long last_index; unsigned long ra_pages = root->fs_info->bdi.ra_pages; unsigned long total_read = 0; - u64 features; u64 page_start; u64 page_end; u64 last_len = 0; @@ -655,14 +648,6 @@ static int btrfs_defrag_file(struct file *file, u64 defrag_end = 0; unsigned long i; int ret; - int compress_type = BTRFS_COMPRESS_ZLIB; - - if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS) { - if (range->compress_type > BTRFS_COMPRESS_TYPES) - return -EINVAL; - if (range->compress_type) - compress_type = range->compress_type; - } if (inode->i_size == 0) return 0; @@ -698,7 +683,7 @@ static int btrfs_defrag_file(struct file *file, total_read++; mutex_lock(&inode->i_mutex); if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS) - BTRFS_I(inode)->force_compress = compress_type; + BTRFS_I(inode)->force_compress = 1; ret = btrfs_delalloc_reserve_space(inode, PAGE_CACHE_SIZE); if (ret) @@ -796,17 +781,10 @@ static int btrfs_defrag_file(struct file *file, atomic_dec(&root->fs_info->async_submit_draining); mutex_lock(&inode->i_mutex); - BTRFS_I(inode)->force_compress = BTRFS_COMPRESS_NONE; + BTRFS_I(inode)->force_compress = 0; mutex_unlock(&inode->i_mutex); } - disk_super = &root->fs_info->super_copy; - features = btrfs_super_incompat_flags(disk_super); - if (range->compress_type == BTRFS_COMPRESS_LZO) { - features |= BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO; - btrfs_set_super_incompat_flags(disk_super, features); - } - return 0; err_reservations: @@ -923,8 +901,7 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file, char *name, unsigned long fd, int subvol, - u64 *transid, - bool readonly) + u64 *transid) { struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; struct file *src_file; @@ -942,7 +919,7 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file, if (subvol) { ret = btrfs_mksubvol(&file->f_path, name, namelen, - NULL, transid, readonly); + NULL, transid); } else { struct inode *src_inode; src_file = fget(fd); @@ -961,7 +938,7 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file, } ret = btrfs_mksubvol(&file->f_path, name, namelen, BTRFS_I(src_inode)->root, - transid, readonly); + transid); fput(src_file); } out: @@ -969,139 +946,58 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file, } static noinline int btrfs_ioctl_snap_create(struct file *file, - void __user *arg, int subvol) + void __user *arg, int subvol, + int v2) { - struct btrfs_ioctl_vol_args *vol_args; + struct btrfs_ioctl_vol_args *vol_args = NULL; + struct btrfs_ioctl_vol_args_v2 *vol_args_v2 = NULL; + char *name; + u64 fd; int ret; - vol_args = memdup_user(arg, sizeof(*vol_args)); - if (IS_ERR(vol_args)) - return PTR_ERR(vol_args); - vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; - - ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, - vol_args->fd, subvol, - NULL, false); + if (v2) { + u64 transid = 0; + u64 *ptr = NULL; - kfree(vol_args); - return ret; -} - -static noinline int btrfs_ioctl_snap_create_v2(struct file *file, - void __user *arg, int subvol) -{ - struct btrfs_ioctl_vol_args_v2 *vol_args; - int ret; - u64 transid = 0; - u64 *ptr = NULL; - bool readonly = false; + vol_args_v2 = memdup_user(arg, sizeof(*vol_args_v2)); + if (IS_ERR(vol_args_v2)) + return PTR_ERR(vol_args_v2); - vol_args = memdup_user(arg, sizeof(*vol_args)); - if (IS_ERR(vol_args)) - return PTR_ERR(vol_args); - vol_args->name[BTRFS_SUBVOL_NAME_MAX] = '\0'; + if (vol_args_v2->flags & ~BTRFS_SUBVOL_CREATE_ASYNC) { + ret = -EINVAL; + goto out; + } - if (vol_args->flags & - ~(BTRFS_SUBVOL_CREATE_ASYNC | BTRFS_SUBVOL_RDONLY)) { - ret = -EOPNOTSUPP; - goto out; - } + name = vol_args_v2->name; + fd = vol_args_v2->fd; + vol_args_v2->name[BTRFS_SUBVOL_NAME_MAX] = '\0'; - if (vol_args->flags & BTRFS_SUBVOL_CREATE_ASYNC) - ptr = &transid; - if (vol_args->flags & BTRFS_SUBVOL_RDONLY) - readonly = true; + if (vol_args_v2->flags & BTRFS_SUBVOL_CREATE_ASYNC) + ptr = &transid; - ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, - vol_args->fd, subvol, - ptr, readonly); + ret = btrfs_ioctl_snap_create_transid(file, name, fd, + subvol, ptr); - if (ret == 0 && ptr && - copy_to_user(arg + - offsetof(struct btrfs_ioctl_vol_args_v2, - transid), ptr, sizeof(*ptr))) - ret = -EFAULT; + if (ret == 0 && ptr && + copy_to_user(arg + + offsetof(struct btrfs_ioctl_vol_args_v2, + transid), ptr, sizeof(*ptr))) + ret = -EFAULT; + } else { + vol_args = memdup_user(arg, sizeof(*vol_args)); + if (IS_ERR(vol_args)) + return PTR_ERR(vol_args); + name = vol_args->name; + fd = vol_args->fd; + vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; + + ret = btrfs_ioctl_snap_create_transid(file, name, fd, + subvol, NULL); + } out: kfree(vol_args); - return ret; -} + kfree(vol_args_v2); -static noinline int btrfs_ioctl_subvol_getflags(struct file *file, - void __user *arg) -{ - struct inode *inode = fdentry(file)->d_inode; - struct btrfs_root *root = BTRFS_I(inode)->root; - int ret = 0; - u64 flags = 0; - - if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID) - return -EINVAL; - - down_read(&root->fs_info->subvol_sem); - if (btrfs_root_readonly(root)) - flags |= BTRFS_SUBVOL_RDONLY; - up_read(&root->fs_info->subvol_sem); - - if (copy_to_user(arg, &flags, sizeof(flags))) - ret = -EFAULT; - - return ret; -} - -static noinline int btrfs_ioctl_subvol_setflags(struct file *file, - void __user *arg) -{ - struct inode *inode = fdentry(file)->d_inode; - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_trans_handle *trans; - u64 root_flags; - u64 flags; - int ret = 0; - - if (root->fs_info->sb->s_flags & MS_RDONLY) - return -EROFS; - - if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID) - return -EINVAL; - - if (copy_from_user(&flags, arg, sizeof(flags))) - return -EFAULT; - - if (flags & ~BTRFS_SUBVOL_CREATE_ASYNC) - return -EINVAL; - - if (flags & ~BTRFS_SUBVOL_RDONLY) - return -EOPNOTSUPP; - - down_write(&root->fs_info->subvol_sem); - - /* nothing to do */ - if (!!(flags & BTRFS_SUBVOL_RDONLY) == btrfs_root_readonly(root)) - goto out; - - root_flags = btrfs_root_flags(&root->root_item); - if (flags & BTRFS_SUBVOL_RDONLY) - btrfs_set_root_flags(&root->root_item, - root_flags | BTRFS_ROOT_SUBVOL_RDONLY); - else - btrfs_set_root_flags(&root->root_item, - root_flags & ~BTRFS_ROOT_SUBVOL_RDONLY); - - trans = btrfs_start_transaction(root, 1); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto out_reset; - } - - ret = btrfs_update_root(trans, root, - &root->root_key, &root->root_item); - - btrfs_commit_transaction(trans, root); -out_reset: - if (ret) - btrfs_set_root_flags(&root->root_item, root_flags); -out: - up_write(&root->fs_info->subvol_sem); return ret; } @@ -1613,9 +1509,6 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp) struct btrfs_ioctl_defrag_range_args *range; int ret; - if (btrfs_root_readonly(root)) - return -EROFS; - ret = mnt_want_write(file->f_path.mnt); if (ret) return ret; @@ -1744,9 +1637,6 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, if (!(file->f_mode & FMODE_WRITE) || (file->f_flags & O_APPEND)) return -EINVAL; - if (btrfs_root_readonly(root)) - return -EROFS; - ret = mnt_want_write(file->f_path.mnt); if (ret) return ret; @@ -2068,10 +1958,6 @@ static long btrfs_ioctl_trans_start(struct file *file) if (file->private_data) goto out; - ret = -EROFS; - if (btrfs_root_readonly(root)) - goto out; - ret = mnt_want_write(file->f_path.mnt); if (ret) goto out; @@ -2371,17 +2257,13 @@ long btrfs_ioctl(struct file *file, unsigned int case FS_IOC_GETVERSION: return btrfs_ioctl_getversion(file, argp); case BTRFS_IOC_SNAP_CREATE: - return btrfs_ioctl_snap_create(file, argp, 0); + return btrfs_ioctl_snap_create(file, argp, 0, 0); case BTRFS_IOC_SNAP_CREATE_V2: - return btrfs_ioctl_snap_create_v2(file, argp, 0); + return btrfs_ioctl_snap_create(file, argp, 0, 1); case BTRFS_IOC_SUBVOL_CREATE: - return btrfs_ioctl_snap_create(file, argp, 1); + return btrfs_ioctl_snap_create(file, argp, 1, 0); case BTRFS_IOC_SNAP_DESTROY: return btrfs_ioctl_snap_destroy(file, argp); - case BTRFS_IOC_SUBVOL_GETFLAGS: - return btrfs_ioctl_subvol_getflags(file, argp); - case BTRFS_IOC_SUBVOL_SETFLAGS: - return btrfs_ioctl_subvol_setflags(file, argp); case BTRFS_IOC_DEFAULT_SUBVOL: return btrfs_ioctl_default_subvol(file, argp); case BTRFS_IOC_DEFRAG: diff --git a/trunk/fs/btrfs/ioctl.h b/trunk/fs/btrfs/ioctl.h index 8fb382167b13..c344d12c646b 100644 --- a/trunk/fs/btrfs/ioctl.h +++ b/trunk/fs/btrfs/ioctl.h @@ -31,7 +31,6 @@ struct btrfs_ioctl_vol_args { }; #define BTRFS_SUBVOL_CREATE_ASYNC (1ULL << 0) -#define BTRFS_SUBVOL_RDONLY (1ULL << 1) #define BTRFS_SUBVOL_NAME_MAX 4039 struct btrfs_ioctl_vol_args_v2 { @@ -134,15 +133,8 @@ struct btrfs_ioctl_defrag_range_args { */ __u32 extent_thresh; - /* - * which compression method to use if turning on compression - * for this defrag operation. If unspecified, zlib will - * be used - */ - __u32 compress_type; - /* spare for later */ - __u32 unused[4]; + __u32 unused[5]; }; struct btrfs_ioctl_space_info { @@ -201,6 +193,4 @@ struct btrfs_ioctl_space_args { #define BTRFS_IOC_WAIT_SYNC _IOW(BTRFS_IOCTL_MAGIC, 22, __u64) #define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \ struct btrfs_ioctl_vol_args_v2) -#define BTRFS_IOC_SUBVOL_GETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 25, __u64) -#define BTRFS_IOC_SUBVOL_SETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 26, __u64) #endif diff --git a/trunk/fs/btrfs/lzo.c b/trunk/fs/btrfs/lzo.c deleted file mode 100644 index cc9b450399df..000000000000 --- a/trunk/fs/btrfs/lzo.c +++ /dev/null @@ -1,420 +0,0 @@ -/* - * Copyright (C) 2008 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "compression.h" - -#define LZO_LEN 4 - -struct workspace { - void *mem; - void *buf; /* where compressed data goes */ - void *cbuf; /* where decompressed data goes */ - struct list_head list; -}; - -static void lzo_free_workspace(struct list_head *ws) -{ - struct workspace *workspace = list_entry(ws, struct workspace, list); - - vfree(workspace->buf); - vfree(workspace->cbuf); - vfree(workspace->mem); - kfree(workspace); -} - -static struct list_head *lzo_alloc_workspace(void) -{ - struct workspace *workspace; - - workspace = kzalloc(sizeof(*workspace), GFP_NOFS); - if (!workspace) - return ERR_PTR(-ENOMEM); - - workspace->mem = vmalloc(LZO1X_MEM_COMPRESS); - workspace->buf = vmalloc(lzo1x_worst_compress(PAGE_CACHE_SIZE)); - workspace->cbuf = vmalloc(lzo1x_worst_compress(PAGE_CACHE_SIZE)); - if (!workspace->mem || !workspace->buf || !workspace->cbuf) - goto fail; - - INIT_LIST_HEAD(&workspace->list); - - return &workspace->list; -fail: - lzo_free_workspace(&workspace->list); - return ERR_PTR(-ENOMEM); -} - -static inline void write_compress_length(char *buf, size_t len) -{ - __le32 dlen; - - dlen = cpu_to_le32(len); - memcpy(buf, &dlen, LZO_LEN); -} - -static inline size_t read_compress_length(char *buf) -{ - __le32 dlen; - - memcpy(&dlen, buf, LZO_LEN); - return le32_to_cpu(dlen); -} - -static int lzo_compress_pages(struct list_head *ws, - struct address_space *mapping, - u64 start, unsigned long len, - struct page **pages, - unsigned long nr_dest_pages, - unsigned long *out_pages, - unsigned long *total_in, - unsigned long *total_out, - unsigned long max_out) -{ - struct workspace *workspace = list_entry(ws, struct workspace, list); - int ret = 0; - char *data_in; - char *cpage_out; - int nr_pages = 0; - struct page *in_page = NULL; - struct page *out_page = NULL; - unsigned long bytes_left; - - size_t in_len; - size_t out_len; - char *buf; - unsigned long tot_in = 0; - unsigned long tot_out = 0; - unsigned long pg_bytes_left; - unsigned long out_offset; - unsigned long bytes; - - *out_pages = 0; - *total_out = 0; - *total_in = 0; - - in_page = find_get_page(mapping, start >> PAGE_CACHE_SHIFT); - data_in = kmap(in_page); - - /* - * store the size of all chunks of compressed data in - * the first 4 bytes - */ - out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM); - if (out_page == NULL) { - ret = -ENOMEM; - goto out; - } - cpage_out = kmap(out_page); - out_offset = LZO_LEN; - tot_out = LZO_LEN; - pages[0] = out_page; - nr_pages = 1; - pg_bytes_left = PAGE_CACHE_SIZE - LZO_LEN; - - /* compress at most one page of data each time */ - in_len = min(len, PAGE_CACHE_SIZE); - while (tot_in < len) { - ret = lzo1x_1_compress(data_in, in_len, workspace->cbuf, - &out_len, workspace->mem); - if (ret != LZO_E_OK) { - printk(KERN_DEBUG "btrfs deflate in loop returned %d\n", - ret); - ret = -1; - goto out; - } - - /* store the size of this chunk of compressed data */ - write_compress_length(cpage_out + out_offset, out_len); - tot_out += LZO_LEN; - out_offset += LZO_LEN; - pg_bytes_left -= LZO_LEN; - - tot_in += in_len; - tot_out += out_len; - - /* copy bytes from the working buffer into the pages */ - buf = workspace->cbuf; - while (out_len) { - bytes = min_t(unsigned long, pg_bytes_left, out_len); - - memcpy(cpage_out + out_offset, buf, bytes); - - out_len -= bytes; - pg_bytes_left -= bytes; - buf += bytes; - out_offset += bytes; - - /* - * we need another page for writing out. - * - * Note if there's less than 4 bytes left, we just - * skip to a new page. - */ - if ((out_len == 0 && pg_bytes_left < LZO_LEN) || - pg_bytes_left == 0) { - if (pg_bytes_left) { - memset(cpage_out + out_offset, 0, - pg_bytes_left); - tot_out += pg_bytes_left; - } - - /* we're done, don't allocate new page */ - if (out_len == 0 && tot_in >= len) - break; - - kunmap(out_page); - if (nr_pages == nr_dest_pages) { - out_page = NULL; - ret = -1; - goto out; - } - - out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM); - if (out_page == NULL) { - ret = -ENOMEM; - goto out; - } - cpage_out = kmap(out_page); - pages[nr_pages++] = out_page; - - pg_bytes_left = PAGE_CACHE_SIZE; - out_offset = 0; - } - } - - /* we're making it bigger, give up */ - if (tot_in > 8192 && tot_in < tot_out) - goto out; - - /* we're all done */ - if (tot_in >= len) - break; - - if (tot_out > max_out) - break; - - bytes_left = len - tot_in; - kunmap(in_page); - page_cache_release(in_page); - - start += PAGE_CACHE_SIZE; - in_page = find_get_page(mapping, start >> PAGE_CACHE_SHIFT); - data_in = kmap(in_page); - in_len = min(bytes_left, PAGE_CACHE_SIZE); - } - - if (tot_out > tot_in) - goto out; - - /* store the size of all chunks of compressed data */ - cpage_out = kmap(pages[0]); - write_compress_length(cpage_out, tot_out); - - kunmap(pages[0]); - - ret = 0; - *total_out = tot_out; - *total_in = tot_in; -out: - *out_pages = nr_pages; - if (out_page) - kunmap(out_page); - - if (in_page) { - kunmap(in_page); - page_cache_release(in_page); - } - - return ret; -} - -static int lzo_decompress_biovec(struct list_head *ws, - struct page **pages_in, - u64 disk_start, - struct bio_vec *bvec, - int vcnt, - size_t srclen) -{ - struct workspace *workspace = list_entry(ws, struct workspace, list); - int ret = 0, ret2; - char *data_in; - unsigned long page_in_index = 0; - unsigned long page_out_index = 0; - unsigned long total_pages_in = (srclen + PAGE_CACHE_SIZE - 1) / - PAGE_CACHE_SIZE; - unsigned long buf_start; - unsigned long buf_offset = 0; - unsigned long bytes; - unsigned long working_bytes; - unsigned long pg_offset; - - size_t in_len; - size_t out_len; - unsigned long in_offset; - unsigned long in_page_bytes_left; - unsigned long tot_in; - unsigned long tot_out; - unsigned long tot_len; - char *buf; - - data_in = kmap(pages_in[0]); - tot_len = read_compress_length(data_in); - - tot_in = LZO_LEN; - in_offset = LZO_LEN; - tot_len = min_t(size_t, srclen, tot_len); - in_page_bytes_left = PAGE_CACHE_SIZE - LZO_LEN; - - tot_out = 0; - pg_offset = 0; - - while (tot_in < tot_len) { - in_len = read_compress_length(data_in + in_offset); - in_page_bytes_left -= LZO_LEN; - in_offset += LZO_LEN; - tot_in += LZO_LEN; - - tot_in += in_len; - working_bytes = in_len; - - /* fast path: avoid using the working buffer */ - if (in_page_bytes_left >= in_len) { - buf = data_in + in_offset; - bytes = in_len; - goto cont; - } - - /* copy bytes from the pages into the working buffer */ - buf = workspace->cbuf; - buf_offset = 0; - while (working_bytes) { - bytes = min(working_bytes, in_page_bytes_left); - - memcpy(buf + buf_offset, data_in + in_offset, bytes); - buf_offset += bytes; -cont: - working_bytes -= bytes; - in_page_bytes_left -= bytes; - in_offset += bytes; - - /* check if we need to pick another page */ - if ((working_bytes == 0 && in_page_bytes_left < LZO_LEN) - || in_page_bytes_left == 0) { - tot_in += in_page_bytes_left; - - if (working_bytes == 0 && tot_in >= tot_len) - break; - - kunmap(pages_in[page_in_index]); - page_in_index++; - if (page_in_index >= total_pages_in) { - ret = -1; - data_in = NULL; - goto done; - } - data_in = kmap(pages_in[page_in_index]); - - in_page_bytes_left = PAGE_CACHE_SIZE; - in_offset = 0; - } - } - - out_len = lzo1x_worst_compress(PAGE_CACHE_SIZE); - ret = lzo1x_decompress_safe(buf, in_len, workspace->buf, - &out_len); - if (ret != LZO_E_OK) { - printk(KERN_WARNING "btrfs decompress failed\n"); - ret = -1; - break; - } - - buf_start = tot_out; - tot_out += out_len; - - ret2 = btrfs_decompress_buf2page(workspace->buf, buf_start, - tot_out, disk_start, - bvec, vcnt, - &page_out_index, &pg_offset); - if (ret2 == 0) - break; - } -done: - if (data_in) - kunmap(pages_in[page_in_index]); - return ret; -} - -static int lzo_decompress(struct list_head *ws, unsigned char *data_in, - struct page *dest_page, - unsigned long start_byte, - size_t srclen, size_t destlen) -{ - struct workspace *workspace = list_entry(ws, struct workspace, list); - size_t in_len; - size_t out_len; - size_t tot_len; - int ret = 0; - char *kaddr; - unsigned long bytes; - - BUG_ON(srclen < LZO_LEN); - - tot_len = read_compress_length(data_in); - data_in += LZO_LEN; - - in_len = read_compress_length(data_in); - data_in += LZO_LEN; - - out_len = PAGE_CACHE_SIZE; - ret = lzo1x_decompress_safe(data_in, in_len, workspace->buf, &out_len); - if (ret != LZO_E_OK) { - printk(KERN_WARNING "btrfs decompress failed!\n"); - ret = -1; - goto out; - } - - if (out_len < start_byte) { - ret = -1; - goto out; - } - - bytes = min_t(unsigned long, destlen, out_len - start_byte); - - kaddr = kmap_atomic(dest_page, KM_USER0); - memcpy(kaddr, workspace->buf + start_byte, bytes); - kunmap_atomic(kaddr, KM_USER0); -out: - return ret; -} - -struct btrfs_compress_op btrfs_lzo_compress = { - .alloc_workspace = lzo_alloc_workspace, - .free_workspace = lzo_free_workspace, - .compress_pages = lzo_compress_pages, - .decompress_biovec = lzo_decompress_biovec, - .decompress = lzo_decompress, -}; diff --git a/trunk/fs/btrfs/ordered-data.c b/trunk/fs/btrfs/ordered-data.c index 2b61e1ddcd99..ae7737e352c9 100644 --- a/trunk/fs/btrfs/ordered-data.c +++ b/trunk/fs/btrfs/ordered-data.c @@ -172,7 +172,7 @@ static inline struct rb_node *tree_search(struct btrfs_ordered_inode_tree *tree, */ static int __btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, u64 start, u64 len, u64 disk_len, - int type, int dio, int compress_type) + int type, int dio) { struct btrfs_ordered_inode_tree *tree; struct rb_node *node; @@ -189,7 +189,6 @@ static int __btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, entry->disk_len = disk_len; entry->bytes_left = len; entry->inode = inode; - entry->compress_type = compress_type; if (type != BTRFS_ORDERED_IO_DONE && type != BTRFS_ORDERED_COMPLETE) set_bit(type, &entry->flags); @@ -221,25 +220,14 @@ int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, u64 start, u64 len, u64 disk_len, int type) { return __btrfs_add_ordered_extent(inode, file_offset, start, len, - disk_len, type, 0, - BTRFS_COMPRESS_NONE); + disk_len, type, 0); } int btrfs_add_ordered_extent_dio(struct inode *inode, u64 file_offset, u64 start, u64 len, u64 disk_len, int type) { return __btrfs_add_ordered_extent(inode, file_offset, start, len, - disk_len, type, 1, - BTRFS_COMPRESS_NONE); -} - -int btrfs_add_ordered_extent_compress(struct inode *inode, u64 file_offset, - u64 start, u64 len, u64 disk_len, - int type, int compress_type) -{ - return __btrfs_add_ordered_extent(inode, file_offset, start, len, - disk_len, type, 0, - compress_type); + disk_len, type, 1); } /* diff --git a/trunk/fs/btrfs/ordered-data.h b/trunk/fs/btrfs/ordered-data.h index ff1f69aa1883..61dca83119dd 100644 --- a/trunk/fs/btrfs/ordered-data.h +++ b/trunk/fs/btrfs/ordered-data.h @@ -68,7 +68,7 @@ struct btrfs_ordered_sum { #define BTRFS_ORDERED_NOCOW 2 /* set when we want to write in place */ -#define BTRFS_ORDERED_COMPRESSED 3 /* writing a zlib compressed extent */ +#define BTRFS_ORDERED_COMPRESSED 3 /* writing a compressed extent */ #define BTRFS_ORDERED_PREALLOC 4 /* set when writing to prealloced extent */ @@ -93,9 +93,6 @@ struct btrfs_ordered_extent { /* flags (described above) */ unsigned long flags; - /* compression algorithm */ - int compress_type; - /* reference count */ atomic_t refs; @@ -151,9 +148,6 @@ int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, u64 start, u64 len, u64 disk_len, int type); int btrfs_add_ordered_extent_dio(struct inode *inode, u64 file_offset, u64 start, u64 len, u64 disk_len, int type); -int btrfs_add_ordered_extent_compress(struct inode *inode, u64 file_offset, - u64 start, u64 len, u64 disk_len, - int type, int compress_type); int btrfs_add_ordered_sum(struct inode *inode, struct btrfs_ordered_extent *entry, struct btrfs_ordered_sum *sum); diff --git a/trunk/fs/btrfs/super.c b/trunk/fs/btrfs/super.c index b2130c46fdb5..22acdaa78ce1 100644 --- a/trunk/fs/btrfs/super.c +++ b/trunk/fs/btrfs/super.c @@ -54,90 +54,6 @@ static const struct super_operations btrfs_super_ops; -static const char *btrfs_decode_error(struct btrfs_fs_info *fs_info, int errno, - char nbuf[16]) -{ - char *errstr = NULL; - - switch (errno) { - case -EIO: - errstr = "IO failure"; - break; - case -ENOMEM: - errstr = "Out of memory"; - break; - case -EROFS: - errstr = "Readonly filesystem"; - break; - default: - if (nbuf) { - if (snprintf(nbuf, 16, "error %d", -errno) >= 0) - errstr = nbuf; - } - break; - } - - return errstr; -} - -static void __save_error_info(struct btrfs_fs_info *fs_info) -{ - /* - * today we only save the error info into ram. Long term we'll - * also send it down to the disk - */ - fs_info->fs_state = BTRFS_SUPER_FLAG_ERROR; -} - -/* NOTE: - * We move write_super stuff at umount in order to avoid deadlock - * for umount hold all lock. - */ -static void save_error_info(struct btrfs_fs_info *fs_info) -{ - __save_error_info(fs_info); -} - -/* btrfs handle error by forcing the filesystem readonly */ -static void btrfs_handle_error(struct btrfs_fs_info *fs_info) -{ - struct super_block *sb = fs_info->sb; - - if (sb->s_flags & MS_RDONLY) - return; - - if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) { - sb->s_flags |= MS_RDONLY; - printk(KERN_INFO "btrfs is forced readonly\n"); - } -} - -/* - * __btrfs_std_error decodes expected errors from the caller and - * invokes the approciate error response. - */ -void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function, - unsigned int line, int errno) -{ - struct super_block *sb = fs_info->sb; - char nbuf[16]; - const char *errstr; - - /* - * Special case: if the error is EROFS, and we're already - * under MS_RDONLY, then it is safe here. - */ - if (errno == -EROFS && (sb->s_flags & MS_RDONLY)) - return; - - errstr = btrfs_decode_error(fs_info, errno, nbuf); - printk(KERN_CRIT "BTRFS error (device %s) in %s:%d: %s\n", - sb->s_id, function, line, errstr); - save_error_info(fs_info); - - btrfs_handle_error(fs_info); -} - static void btrfs_put_super(struct super_block *sb) { struct btrfs_root *root = btrfs_sb(sb); @@ -153,9 +69,9 @@ enum { Opt_degraded, Opt_subvol, Opt_subvolid, Opt_device, Opt_nodatasum, Opt_nodatacow, Opt_max_inline, Opt_alloc_start, Opt_nobarrier, Opt_ssd, Opt_nossd, Opt_ssd_spread, Opt_thread_pool, Opt_noacl, Opt_compress, - Opt_compress_type, Opt_compress_force, Opt_compress_force_type, - Opt_notreelog, Opt_ratio, Opt_flushoncommit, Opt_discard, - Opt_space_cache, Opt_clear_cache, Opt_user_subvol_rm_allowed, Opt_err, + Opt_compress_force, Opt_notreelog, Opt_ratio, Opt_flushoncommit, + Opt_discard, Opt_space_cache, Opt_clear_cache, Opt_err, + Opt_user_subvol_rm_allowed, }; static match_table_t tokens = { @@ -170,9 +86,7 @@ static match_table_t tokens = { {Opt_alloc_start, "alloc_start=%s"}, {Opt_thread_pool, "thread_pool=%d"}, {Opt_compress, "compress"}, - {Opt_compress_type, "compress=%s"}, {Opt_compress_force, "compress-force"}, - {Opt_compress_force_type, "compress-force=%s"}, {Opt_ssd, "ssd"}, {Opt_ssd_spread, "ssd_spread"}, {Opt_nossd, "nossd"}, @@ -198,8 +112,6 @@ int btrfs_parse_options(struct btrfs_root *root, char *options) char *p, *num, *orig; int intarg; int ret = 0; - char *compress_type; - bool compress_force = false; if (!options) return 0; @@ -242,32 +154,14 @@ int btrfs_parse_options(struct btrfs_root *root, char *options) btrfs_set_opt(info->mount_opt, NODATACOW); btrfs_set_opt(info->mount_opt, NODATASUM); break; - case Opt_compress_force: - case Opt_compress_force_type: - compress_force = true; case Opt_compress: - case Opt_compress_type: - if (token == Opt_compress || - token == Opt_compress_force || - strcmp(args[0].from, "zlib") == 0) { - compress_type = "zlib"; - info->compress_type = BTRFS_COMPRESS_ZLIB; - } else if (strcmp(args[0].from, "lzo") == 0) { - compress_type = "lzo"; - info->compress_type = BTRFS_COMPRESS_LZO; - } else { - ret = -EINVAL; - goto out; - } - + printk(KERN_INFO "btrfs: use compression\n"); + btrfs_set_opt(info->mount_opt, COMPRESS); + break; + case Opt_compress_force: + printk(KERN_INFO "btrfs: forcing compression\n"); + btrfs_set_opt(info->mount_opt, FORCE_COMPRESS); btrfs_set_opt(info->mount_opt, COMPRESS); - if (compress_force) { - btrfs_set_opt(info->mount_opt, FORCE_COMPRESS); - pr_info("btrfs: force %s compression\n", - compress_type); - } else - pr_info("btrfs: use %s compression\n", - compress_type); break; case Opt_ssd: printk(KERN_INFO "btrfs: use ssd allocation scheme\n"); @@ -859,127 +753,6 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data) return 0; } -/* - * The helper to calc the free space on the devices that can be used to store - * file data. - */ -static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes) -{ - struct btrfs_fs_info *fs_info = root->fs_info; - struct btrfs_device_info *devices_info; - struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; - struct btrfs_device *device; - u64 skip_space; - u64 type; - u64 avail_space; - u64 used_space; - u64 min_stripe_size; - int min_stripes = 1; - int i = 0, nr_devices; - int ret; - - nr_devices = fs_info->fs_devices->rw_devices; - BUG_ON(!nr_devices); - - devices_info = kmalloc(sizeof(*devices_info) * nr_devices, - GFP_NOFS); - if (!devices_info) - return -ENOMEM; - - /* calc min stripe number for data space alloction */ - type = btrfs_get_alloc_profile(root, 1); - if (type & BTRFS_BLOCK_GROUP_RAID0) - min_stripes = 2; - else if (type & BTRFS_BLOCK_GROUP_RAID1) - min_stripes = 2; - else if (type & BTRFS_BLOCK_GROUP_RAID10) - min_stripes = 4; - - if (type & BTRFS_BLOCK_GROUP_DUP) - min_stripe_size = 2 * BTRFS_STRIPE_LEN; - else - min_stripe_size = BTRFS_STRIPE_LEN; - - list_for_each_entry(device, &fs_devices->alloc_list, dev_alloc_list) { - if (!device->in_fs_metadata) - continue; - - avail_space = device->total_bytes - device->bytes_used; - - /* align with stripe_len */ - do_div(avail_space, BTRFS_STRIPE_LEN); - avail_space *= BTRFS_STRIPE_LEN; - - /* - * In order to avoid overwritting the superblock on the drive, - * btrfs starts at an offset of at least 1MB when doing chunk - * allocation. - */ - skip_space = 1024 * 1024; - - /* user can set the offset in fs_info->alloc_start. */ - if (fs_info->alloc_start + BTRFS_STRIPE_LEN <= - device->total_bytes) - skip_space = max(fs_info->alloc_start, skip_space); - - /* - * btrfs can not use the free space in [0, skip_space - 1], - * we must subtract it from the total. In order to implement - * it, we account the used space in this range first. - */ - ret = btrfs_account_dev_extents_size(device, 0, skip_space - 1, - &used_space); - if (ret) { - kfree(devices_info); - return ret; - } - - /* calc the free space in [0, skip_space - 1] */ - skip_space -= used_space; - - /* - * we can use the free space in [0, skip_space - 1], subtract - * it from the total. - */ - if (avail_space && avail_space >= skip_space) - avail_space -= skip_space; - else - avail_space = 0; - - if (avail_space < min_stripe_size) - continue; - - devices_info[i].dev = device; - devices_info[i].max_avail = avail_space; - - i++; - } - - nr_devices = i; - - btrfs_descending_sort_devices(devices_info, nr_devices); - - i = nr_devices - 1; - avail_space = 0; - while (nr_devices >= min_stripes) { - if (devices_info[i].max_avail >= min_stripe_size) { - int j; - u64 alloc_size; - - avail_space += devices_info[i].max_avail * min_stripes; - alloc_size = devices_info[i].max_avail; - for (j = i + 1 - min_stripes; j <= i; j++) - devices_info[j].max_avail -= alloc_size; - } - i--; - nr_devices--; - } - - kfree(devices_info); - *free_bytes = avail_space; - return 0; -} - static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) { struct btrfs_root *root = btrfs_sb(dentry->d_sb); @@ -987,21 +760,17 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) struct list_head *head = &root->fs_info->space_info; struct btrfs_space_info *found; u64 total_used = 0; - u64 total_free_data = 0; + u64 total_used_data = 0; int bits = dentry->d_sb->s_blocksize_bits; __be32 *fsid = (__be32 *)root->fs_info->fsid; - int ret; - /* holding chunk_muext to avoid allocating new chunks */ - mutex_lock(&root->fs_info->chunk_mutex); rcu_read_lock(); list_for_each_entry_rcu(found, head, list) { - if (found->flags & BTRFS_BLOCK_GROUP_DATA) { - total_free_data += found->disk_total - found->disk_used; - total_free_data -= - btrfs_account_ro_block_groups_free_space(found); - } - + if (found->flags & (BTRFS_BLOCK_GROUP_METADATA | + BTRFS_BLOCK_GROUP_SYSTEM)) + total_used_data += found->disk_total; + else + total_used_data += found->disk_used; total_used += found->disk_used; } rcu_read_unlock(); @@ -1009,17 +778,9 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) buf->f_namelen = BTRFS_NAME_LEN; buf->f_blocks = btrfs_super_total_bytes(disk_super) >> bits; buf->f_bfree = buf->f_blocks - (total_used >> bits); + buf->f_bavail = buf->f_blocks - (total_used_data >> bits); buf->f_bsize = dentry->d_sb->s_blocksize; buf->f_type = BTRFS_SUPER_MAGIC; - buf->f_bavail = total_free_data; - ret = btrfs_calc_avail_data_space(root, &total_free_data); - if (ret) { - mutex_unlock(&root->fs_info->chunk_mutex); - return ret; - } - buf->f_bavail += total_free_data; - buf->f_bavail = buf->f_bavail >> bits; - mutex_unlock(&root->fs_info->chunk_mutex); /* We treat it as constant endianness (it doesn't matter _which_) because we want the fsid to come out the same whether mounted @@ -1136,13 +897,9 @@ static int __init init_btrfs_fs(void) if (err) return err; - err = btrfs_init_compress(); - if (err) - goto free_sysfs; - err = btrfs_init_cachep(); if (err) - goto free_compress; + goto free_sysfs; err = extent_io_init(); if (err) @@ -1171,8 +928,6 @@ static int __init init_btrfs_fs(void) extent_io_exit(); free_cachep: btrfs_destroy_cachep(); -free_compress: - btrfs_exit_compress(); free_sysfs: btrfs_exit_sysfs(); return err; @@ -1187,7 +942,7 @@ static void __exit exit_btrfs_fs(void) unregister_filesystem(&btrfs_fs_type); btrfs_exit_sysfs(); btrfs_cleanup_fs_uuids(); - btrfs_exit_compress(); + btrfs_zlib_exit(); } module_init(init_btrfs_fs) diff --git a/trunk/fs/btrfs/transaction.c b/trunk/fs/btrfs/transaction.c index bae5c7b8bbe2..f50e931fc217 100644 --- a/trunk/fs/btrfs/transaction.c +++ b/trunk/fs/btrfs/transaction.c @@ -181,9 +181,6 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root, struct btrfs_trans_handle *h; struct btrfs_transaction *cur_trans; int ret; - - if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) - return ERR_PTR(-EROFS); again: h = kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS); if (!h) @@ -913,7 +910,6 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, u64 to_reserve = 0; u64 index = 0; u64 objectid; - u64 root_flags; new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS); if (!new_root_item) { @@ -971,13 +967,6 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, btrfs_set_root_last_snapshot(&root->root_item, trans->transid); memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); - root_flags = btrfs_root_flags(new_root_item); - if (pending->readonly) - root_flags |= BTRFS_ROOT_SUBVOL_RDONLY; - else - root_flags &= ~BTRFS_ROOT_SUBVOL_RDONLY; - btrfs_set_root_flags(new_root_item, root_flags); - old = btrfs_lock_root_node(root); btrfs_cow_block(trans, root, old, NULL, 0, &old); btrfs_set_lock_blocking(old); diff --git a/trunk/fs/btrfs/transaction.h b/trunk/fs/btrfs/transaction.h index 229a594cacd5..f104b57ad4ef 100644 --- a/trunk/fs/btrfs/transaction.h +++ b/trunk/fs/btrfs/transaction.h @@ -62,7 +62,6 @@ struct btrfs_pending_snapshot { struct btrfs_block_rsv block_rsv; /* extra metadata reseration for relocation */ int error; - bool readonly; struct list_head list; }; diff --git a/trunk/fs/btrfs/volumes.c b/trunk/fs/btrfs/volumes.c index d158530233b7..1718e1a5c320 100644 --- a/trunk/fs/btrfs/volumes.c +++ b/trunk/fs/btrfs/volumes.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include "compat.h" #include "ctree.h" @@ -601,10 +600,8 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices, set_blocksize(bdev, 4096); bh = btrfs_read_dev_super(bdev); - if (!bh) { - ret = -EINVAL; + if (!bh) goto error_close; - } disk_super = (struct btrfs_super_block *)bh->b_data; devid = btrfs_stack_device_id(&disk_super->dev_item); @@ -706,7 +703,7 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, goto error_close; bh = btrfs_read_dev_super(bdev); if (!bh) { - ret = -EINVAL; + ret = -EIO; goto error_close; } disk_super = (struct btrfs_super_block *)bh->b_data; @@ -732,167 +729,59 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, return ret; } -/* helper to account the used device space in the range */ -int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start, - u64 end, u64 *length) -{ - struct btrfs_key key; - struct btrfs_root *root = device->dev_root; - struct btrfs_dev_extent *dev_extent; - struct btrfs_path *path; - u64 extent_end; - int ret; - int slot; - struct extent_buffer *l; - - *length = 0; - - if (start >= device->total_bytes) - return 0; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - path->reada = 2; - - key.objectid = device->devid; - key.offset = start; - key.type = BTRFS_DEV_EXTENT_KEY; - - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - goto out; - if (ret > 0) { - ret = btrfs_previous_item(root, path, key.objectid, key.type); - if (ret < 0) - goto out; - } - - while (1) { - l = path->nodes[0]; - slot = path->slots[0]; - if (slot >= btrfs_header_nritems(l)) { - ret = btrfs_next_leaf(root, path); - if (ret == 0) - continue; - if (ret < 0) - goto out; - - break; - } - btrfs_item_key_to_cpu(l, &key, slot); - - if (key.objectid < device->devid) - goto next; - - if (key.objectid > device->devid) - break; - - if (btrfs_key_type(&key) != BTRFS_DEV_EXTENT_KEY) - goto next; - - dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent); - extent_end = key.offset + btrfs_dev_extent_length(l, - dev_extent); - if (key.offset <= start && extent_end > end) { - *length = end - start + 1; - break; - } else if (key.offset <= start && extent_end > start) - *length += extent_end - start; - else if (key.offset > start && extent_end <= end) - *length += extent_end - key.offset; - else if (key.offset > start && key.offset <= end) { - *length += end - key.offset + 1; - break; - } else if (key.offset > end) - break; - -next: - path->slots[0]++; - } - ret = 0; -out: - btrfs_free_path(path); - return ret; -} - /* - * find_free_dev_extent - find free space in the specified device - * @trans: transaction handler - * @device: the device which we search the free space in - * @num_bytes: the size of the free space that we need - * @start: store the start of the free space. - * @len: the size of the free space. that we find, or the size of the max - * free space if we don't find suitable free space - * * this uses a pretty simple search, the expectation is that it is * called very infrequently and that a given device has a small number * of extents - * - * @start is used to store the start of the free space if we find. But if we - * don't find suitable free space, it will be used to store the start position - * of the max free space. - * - * @len is used to store the size of the free space that we find. - * But if we don't find suitable free space, it is used to store the size of - * the max free space. */ int find_free_dev_extent(struct btrfs_trans_handle *trans, struct btrfs_device *device, u64 num_bytes, - u64 *start, u64 *len) + u64 *start, u64 *max_avail) { struct btrfs_key key; struct btrfs_root *root = device->dev_root; - struct btrfs_dev_extent *dev_extent; + struct btrfs_dev_extent *dev_extent = NULL; struct btrfs_path *path; - u64 hole_size; - u64 max_hole_start; - u64 max_hole_size; - u64 extent_end; - u64 search_start; + u64 hole_size = 0; + u64 last_byte = 0; + u64 search_start = 0; u64 search_end = device->total_bytes; int ret; - int slot; + int slot = 0; + int start_found; struct extent_buffer *l; + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + path->reada = 2; + start_found = 0; + /* FIXME use last free of some kind */ /* we don't want to overwrite the superblock on the drive, * so we make sure to start at an offset of at least 1MB */ - search_start = 1024 * 1024; + search_start = max((u64)1024 * 1024, search_start); - if (root->fs_info->alloc_start + num_bytes <= search_end) + if (root->fs_info->alloc_start + num_bytes <= device->total_bytes) search_start = max(root->fs_info->alloc_start, search_start); - max_hole_start = search_start; - max_hole_size = 0; - - if (search_start >= search_end) { - ret = -ENOSPC; - goto error; - } - - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto error; - } - path->reada = 2; - key.objectid = device->devid; key.offset = search_start; key.type = BTRFS_DEV_EXTENT_KEY; - ret = btrfs_search_slot(trans, root, &key, path, 0, 0); if (ret < 0) - goto out; + goto error; if (ret > 0) { ret = btrfs_previous_item(root, path, key.objectid, key.type); if (ret < 0) - goto out; + goto error; + if (ret > 0) + start_found = 1; } - + l = path->nodes[0]; + btrfs_item_key_to_cpu(l, &key, path->slots[0]); while (1) { l = path->nodes[0]; slot = path->slots[0]; @@ -901,9 +790,24 @@ int find_free_dev_extent(struct btrfs_trans_handle *trans, if (ret == 0) continue; if (ret < 0) - goto out; - - break; + goto error; +no_more_items: + if (!start_found) { + if (search_start >= search_end) { + ret = -ENOSPC; + goto error; + } + *start = search_start; + start_found = 1; + goto check_pending; + } + *start = last_byte > search_start ? + last_byte : search_start; + if (search_end <= *start) { + ret = -ENOSPC; + goto error; + } + goto check_pending; } btrfs_item_key_to_cpu(l, &key, slot); @@ -911,62 +815,48 @@ int find_free_dev_extent(struct btrfs_trans_handle *trans, goto next; if (key.objectid > device->devid) - break; + goto no_more_items; - if (btrfs_key_type(&key) != BTRFS_DEV_EXTENT_KEY) - goto next; + if (key.offset >= search_start && key.offset > last_byte && + start_found) { + if (last_byte < search_start) + last_byte = search_start; + hole_size = key.offset - last_byte; - if (key.offset > search_start) { - hole_size = key.offset - search_start; + if (hole_size > *max_avail) + *max_avail = hole_size; - if (hole_size > max_hole_size) { - max_hole_start = search_start; - max_hole_size = hole_size; - } - - /* - * If this free space is greater than which we need, - * it must be the max free space that we have found - * until now, so max_hole_start must point to the start - * of this free space and the length of this free space - * is stored in max_hole_size. Thus, we return - * max_hole_start and max_hole_size and go back to the - * caller. - */ - if (hole_size >= num_bytes) { - ret = 0; - goto out; + if (key.offset > last_byte && + hole_size >= num_bytes) { + *start = last_byte; + goto check_pending; } } + if (btrfs_key_type(&key) != BTRFS_DEV_EXTENT_KEY) + goto next; + start_found = 1; dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent); - extent_end = key.offset + btrfs_dev_extent_length(l, - dev_extent); - if (extent_end > search_start) - search_start = extent_end; + last_byte = key.offset + btrfs_dev_extent_length(l, dev_extent); next: path->slots[0]++; cond_resched(); } +check_pending: + /* we have to make sure we didn't find an extent that has already + * been allocated by the map tree or the original allocation + */ + BUG_ON(*start < search_start); - hole_size = search_end- search_start; - if (hole_size > max_hole_size) { - max_hole_start = search_start; - max_hole_size = hole_size; - } - - /* See above. */ - if (hole_size < num_bytes) + if (*start + num_bytes > search_end) { ret = -ENOSPC; - else - ret = 0; + goto error; + } + /* check for pending inserts here */ + ret = 0; -out: - btrfs_free_path(path); error: - *start = max_hole_start; - if (len) - *len = max_hole_size; + btrfs_free_path(path); return ret; } @@ -1306,7 +1196,7 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) set_blocksize(bdev, 4096); bh = btrfs_read_dev_super(bdev); if (!bh) { - ret = -EINVAL; + ret = -EIO; goto error_close; } disk_super = (struct btrfs_super_block *)bh->b_data; @@ -2026,9 +1916,6 @@ int btrfs_balance(struct btrfs_root *dev_root) if (dev_root->fs_info->sb->s_flags & MS_RDONLY) return -EROFS; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - mutex_lock(&dev_root->fs_info->volume_mutex); dev_root = dev_root->fs_info->dev_root; @@ -2267,67 +2154,66 @@ static noinline u64 chunk_bytes_by_type(u64 type, u64 calc_size, return calc_size * num_stripes; } -/* Used to sort the devices by max_avail(descending sort) */ -int btrfs_cmp_device_free_bytes(const void *dev_info1, const void *dev_info2) +static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, + struct btrfs_root *extent_root, + struct map_lookup **map_ret, + u64 *num_bytes, u64 *stripe_size, + u64 start, u64 type) { - if (((struct btrfs_device_info *)dev_info1)->max_avail > - ((struct btrfs_device_info *)dev_info2)->max_avail) - return -1; - else if (((struct btrfs_device_info *)dev_info1)->max_avail < - ((struct btrfs_device_info *)dev_info2)->max_avail) - return 1; - else - return 0; -} + struct btrfs_fs_info *info = extent_root->fs_info; + struct btrfs_device *device = NULL; + struct btrfs_fs_devices *fs_devices = info->fs_devices; + struct list_head *cur; + struct map_lookup *map = NULL; + struct extent_map_tree *em_tree; + struct extent_map *em; + struct list_head private_devs; + int min_stripe_size = 1 * 1024 * 1024; + u64 calc_size = 1024 * 1024 * 1024; + u64 max_chunk_size = calc_size; + u64 min_free; + u64 avail; + u64 max_avail = 0; + u64 dev_offset; + int num_stripes = 1; + int min_stripes = 1; + int sub_stripes = 0; + int looped = 0; + int ret; + int index; + int stripe_len = 64 * 1024; -static int __btrfs_calc_nstripes(struct btrfs_fs_devices *fs_devices, u64 type, - int *num_stripes, int *min_stripes, - int *sub_stripes) -{ - *num_stripes = 1; - *min_stripes = 1; - *sub_stripes = 0; + if ((type & BTRFS_BLOCK_GROUP_RAID1) && + (type & BTRFS_BLOCK_GROUP_DUP)) { + WARN_ON(1); + type &= ~BTRFS_BLOCK_GROUP_DUP; + } + if (list_empty(&fs_devices->alloc_list)) + return -ENOSPC; if (type & (BTRFS_BLOCK_GROUP_RAID0)) { - *num_stripes = fs_devices->rw_devices; - *min_stripes = 2; + num_stripes = fs_devices->rw_devices; + min_stripes = 2; } if (type & (BTRFS_BLOCK_GROUP_DUP)) { - *num_stripes = 2; - *min_stripes = 2; + num_stripes = 2; + min_stripes = 2; } if (type & (BTRFS_BLOCK_GROUP_RAID1)) { if (fs_devices->rw_devices < 2) return -ENOSPC; - *num_stripes = 2; - *min_stripes = 2; + num_stripes = 2; + min_stripes = 2; } if (type & (BTRFS_BLOCK_GROUP_RAID10)) { - *num_stripes = fs_devices->rw_devices; - if (*num_stripes < 4) + num_stripes = fs_devices->rw_devices; + if (num_stripes < 4) return -ENOSPC; - *num_stripes &= ~(u32)1; - *sub_stripes = 2; - *min_stripes = 4; + num_stripes &= ~(u32)1; + sub_stripes = 2; + min_stripes = 4; } - return 0; -} - -static u64 __btrfs_calc_stripe_size(struct btrfs_fs_devices *fs_devices, - u64 proposed_size, u64 type, - int num_stripes, int small_stripe) -{ - int min_stripe_size = 1 * 1024 * 1024; - u64 calc_size = proposed_size; - u64 max_chunk_size = calc_size; - int ncopies = 1; - - if (type & (BTRFS_BLOCK_GROUP_RAID1 | - BTRFS_BLOCK_GROUP_DUP | - BTRFS_BLOCK_GROUP_RAID10)) - ncopies = 2; - if (type & BTRFS_BLOCK_GROUP_DATA) { max_chunk_size = 10 * calc_size; min_stripe_size = 64 * 1024 * 1024; @@ -2344,209 +2230,51 @@ static u64 __btrfs_calc_stripe_size(struct btrfs_fs_devices *fs_devices, max_chunk_size = min(div_factor(fs_devices->total_rw_bytes, 1), max_chunk_size); - if (calc_size * num_stripes > max_chunk_size * ncopies) { - calc_size = max_chunk_size * ncopies; +again: + max_avail = 0; + if (!map || map->num_stripes != num_stripes) { + kfree(map); + map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS); + if (!map) + return -ENOMEM; + map->num_stripes = num_stripes; + } + + if (calc_size * num_stripes > max_chunk_size) { + calc_size = max_chunk_size; do_div(calc_size, num_stripes); - do_div(calc_size, BTRFS_STRIPE_LEN); - calc_size *= BTRFS_STRIPE_LEN; + do_div(calc_size, stripe_len); + calc_size *= stripe_len; } /* we don't want tiny stripes */ - if (!small_stripe) + if (!looped) calc_size = max_t(u64, min_stripe_size, calc_size); /* - * we're about to do_div by the BTRFS_STRIPE_LEN so lets make sure + * we're about to do_div by the stripe_len so lets make sure * we end up with something bigger than a stripe */ - calc_size = max_t(u64, calc_size, BTRFS_STRIPE_LEN); - - do_div(calc_size, BTRFS_STRIPE_LEN); - calc_size *= BTRFS_STRIPE_LEN; - - return calc_size; -} - -static struct map_lookup *__shrink_map_lookup_stripes(struct map_lookup *map, - int num_stripes) -{ - struct map_lookup *new; - size_t len = map_lookup_size(num_stripes); - - BUG_ON(map->num_stripes < num_stripes); - - if (map->num_stripes == num_stripes) - return map; - - new = kmalloc(len, GFP_NOFS); - if (!new) { - /* just change map->num_stripes */ - map->num_stripes = num_stripes; - return map; - } - - memcpy(new, map, len); - new->num_stripes = num_stripes; - kfree(map); - return new; -} - -/* - * helper to allocate device space from btrfs_device_info, in which we stored - * max free space information of every device. It is used when we can not - * allocate chunks by default size. - * - * By this helper, we can allocate a new chunk as larger as possible. - */ -static int __btrfs_alloc_tiny_space(struct btrfs_trans_handle *trans, - struct btrfs_fs_devices *fs_devices, - struct btrfs_device_info *devices, - int nr_device, u64 type, - struct map_lookup **map_lookup, - int min_stripes, u64 *stripe_size) -{ - int i, index, sort_again = 0; - int min_devices = min_stripes; - u64 max_avail, min_free; - struct map_lookup *map = *map_lookup; - int ret; - - if (nr_device < min_stripes) - return -ENOSPC; - - btrfs_descending_sort_devices(devices, nr_device); - - max_avail = devices[0].max_avail; - if (!max_avail) - return -ENOSPC; - - for (i = 0; i < nr_device; i++) { - /* - * if dev_offset = 0, it means the free space of this device - * is less than what we need, and we didn't search max avail - * extent on this device, so do it now. - */ - if (!devices[i].dev_offset) { - ret = find_free_dev_extent(trans, devices[i].dev, - max_avail, - &devices[i].dev_offset, - &devices[i].max_avail); - if (ret != 0 && ret != -ENOSPC) - return ret; - sort_again = 1; - } - } - - /* we update the max avail free extent of each devices, sort again */ - if (sort_again) - btrfs_descending_sort_devices(devices, nr_device); - - if (type & BTRFS_BLOCK_GROUP_DUP) - min_devices = 1; - - if (!devices[min_devices - 1].max_avail) - return -ENOSPC; - - max_avail = devices[min_devices - 1].max_avail; - if (type & BTRFS_BLOCK_GROUP_DUP) - do_div(max_avail, 2); - - max_avail = __btrfs_calc_stripe_size(fs_devices, max_avail, type, - min_stripes, 1); - if (type & BTRFS_BLOCK_GROUP_DUP) - min_free = max_avail * 2; - else - min_free = max_avail; - - if (min_free > devices[min_devices - 1].max_avail) - return -ENOSPC; - - map = __shrink_map_lookup_stripes(map, min_stripes); - *stripe_size = max_avail; - - index = 0; - for (i = 0; i < min_stripes; i++) { - map->stripes[i].dev = devices[index].dev; - map->stripes[i].physical = devices[index].dev_offset; - if (type & BTRFS_BLOCK_GROUP_DUP) { - i++; - map->stripes[i].dev = devices[index].dev; - map->stripes[i].physical = devices[index].dev_offset + - max_avail; - } - index++; - } - *map_lookup = map; - - return 0; -} + calc_size = max_t(u64, calc_size, stripe_len * 4); -static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, - struct btrfs_root *extent_root, - struct map_lookup **map_ret, - u64 *num_bytes, u64 *stripe_size, - u64 start, u64 type) -{ - struct btrfs_fs_info *info = extent_root->fs_info; - struct btrfs_device *device = NULL; - struct btrfs_fs_devices *fs_devices = info->fs_devices; - struct list_head *cur; - struct map_lookup *map; - struct extent_map_tree *em_tree; - struct extent_map *em; - struct btrfs_device_info *devices_info; - struct list_head private_devs; - u64 calc_size = 1024 * 1024 * 1024; - u64 min_free; - u64 avail; - u64 dev_offset; - int num_stripes; - int min_stripes; - int sub_stripes; - int min_devices; /* the min number of devices we need */ - int i; - int ret; - int index; - - if ((type & BTRFS_BLOCK_GROUP_RAID1) && - (type & BTRFS_BLOCK_GROUP_DUP)) { - WARN_ON(1); - type &= ~BTRFS_BLOCK_GROUP_DUP; - } - if (list_empty(&fs_devices->alloc_list)) - return -ENOSPC; - - ret = __btrfs_calc_nstripes(fs_devices, type, &num_stripes, - &min_stripes, &sub_stripes); - if (ret) - return ret; - - devices_info = kzalloc(sizeof(*devices_info) * fs_devices->rw_devices, - GFP_NOFS); - if (!devices_info) - return -ENOMEM; - - map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS); - if (!map) { - ret = -ENOMEM; - goto error; - } - map->num_stripes = num_stripes; + do_div(calc_size, stripe_len); + calc_size *= stripe_len; cur = fs_devices->alloc_list.next; index = 0; - i = 0; - calc_size = __btrfs_calc_stripe_size(fs_devices, calc_size, type, - num_stripes, 0); - - if (type & BTRFS_BLOCK_GROUP_DUP) { + if (type & BTRFS_BLOCK_GROUP_DUP) min_free = calc_size * 2; - min_devices = 1; - } else { + else min_free = calc_size; - min_devices = min_stripes; - } + + /* + * we add 1MB because we never use the first 1MB of the device, unless + * we've looped, then we are likely allocating the maximum amount of + * space left already + */ + if (!looped) + min_free += 1024 * 1024; INIT_LIST_HEAD(&private_devs); while (index < num_stripes) { @@ -2559,39 +2287,27 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, cur = cur->next; if (device->in_fs_metadata && avail >= min_free) { - ret = find_free_dev_extent(trans, device, min_free, - &devices_info[i].dev_offset, - &devices_info[i].max_avail); + ret = find_free_dev_extent(trans, device, + min_free, &dev_offset, + &max_avail); if (ret == 0) { list_move_tail(&device->dev_alloc_list, &private_devs); map->stripes[index].dev = device; - map->stripes[index].physical = - devices_info[i].dev_offset; + map->stripes[index].physical = dev_offset; index++; if (type & BTRFS_BLOCK_GROUP_DUP) { map->stripes[index].dev = device; map->stripes[index].physical = - devices_info[i].dev_offset + - calc_size; + dev_offset + calc_size; index++; } - } else if (ret != -ENOSPC) - goto error; - - devices_info[i].dev = device; - i++; - } else if (device->in_fs_metadata && - avail >= BTRFS_STRIPE_LEN) { - devices_info[i].dev = device; - devices_info[i].max_avail = avail; - i++; - } - + } + } else if (device->in_fs_metadata && avail > max_avail) + max_avail = avail; if (cur == &fs_devices->alloc_list) break; } - list_splice(&private_devs, &fs_devices->alloc_list); if (index < num_stripes) { if (index >= min_stripes) { @@ -2600,36 +2316,34 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, num_stripes /= sub_stripes; num_stripes *= sub_stripes; } - - map = __shrink_map_lookup_stripes(map, num_stripes); - } else if (i >= min_devices) { - ret = __btrfs_alloc_tiny_space(trans, fs_devices, - devices_info, i, type, - &map, min_stripes, - &calc_size); - if (ret) - goto error; - } else { - ret = -ENOSPC; - goto error; + looped = 1; + goto again; + } + if (!looped && max_avail > 0) { + looped = 1; + calc_size = max_avail; + goto again; } + kfree(map); + return -ENOSPC; } map->sector_size = extent_root->sectorsize; - map->stripe_len = BTRFS_STRIPE_LEN; - map->io_align = BTRFS_STRIPE_LEN; - map->io_width = BTRFS_STRIPE_LEN; + map->stripe_len = stripe_len; + map->io_align = stripe_len; + map->io_width = stripe_len; map->type = type; + map->num_stripes = num_stripes; map->sub_stripes = sub_stripes; *map_ret = map; *stripe_size = calc_size; *num_bytes = chunk_bytes_by_type(type, calc_size, - map->num_stripes, sub_stripes); + num_stripes, sub_stripes); em = alloc_extent_map(GFP_NOFS); if (!em) { - ret = -ENOMEM; - goto error; + kfree(map); + return -ENOMEM; } em->bdev = (struct block_device *)map; em->start = start; @@ -2662,13 +2376,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, index++; } - kfree(devices_info); return 0; - -error: - kfree(map); - kfree(devices_info); - return ret; } static int __finish_chunk_alloc(struct btrfs_trans_handle *trans, diff --git a/trunk/fs/btrfs/volumes.h b/trunk/fs/btrfs/volumes.h index 7fb59d45fe8c..1be781079450 100644 --- a/trunk/fs/btrfs/volumes.h +++ b/trunk/fs/btrfs/volumes.h @@ -20,11 +20,8 @@ #define __BTRFS_VOLUMES_ #include -#include #include "async-thread.h" -#define BTRFS_STRIPE_LEN (64 * 1024) - struct buffer_head; struct btrfs_pending_bios { struct bio *head; @@ -139,30 +136,6 @@ struct btrfs_multi_bio { struct btrfs_bio_stripe stripes[]; }; -struct btrfs_device_info { - struct btrfs_device *dev; - u64 dev_offset; - u64 max_avail; -}; - -/* Used to sort the devices by max_avail(descending sort) */ -int btrfs_cmp_device_free_bytes(const void *dev_info1, const void *dev_info2); - -/* - * sort the devices by max_avail, in which max free extent size of each device - * is stored.(Descending Sort) - */ -static inline void btrfs_descending_sort_devices( - struct btrfs_device_info *devices, - size_t nr_devices) -{ - sort(devices, nr_devices, sizeof(struct btrfs_device_info), - btrfs_cmp_device_free_bytes, NULL); -} - -int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start, - u64 end, u64 *length); - #define btrfs_multi_bio_size(n) (sizeof(struct btrfs_multi_bio) + \ (sizeof(struct btrfs_bio_stripe) * (n))) diff --git a/trunk/fs/btrfs/xattr.c b/trunk/fs/btrfs/xattr.c index a5776531dc2b..698fdd2c739c 100644 --- a/trunk/fs/btrfs/xattr.c +++ b/trunk/fs/btrfs/xattr.c @@ -316,15 +316,6 @@ ssize_t btrfs_getxattr(struct dentry *dentry, const char *name, int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { - struct btrfs_root *root = BTRFS_I(dentry->d_inode)->root; - - /* - * The permission on security.* and system.* is not checked - * in permission(). - */ - if (btrfs_root_readonly(root)) - return -EROFS; - /* * If this is a request for a synthetic attribute in the system.* * namespace use the generic infrastructure to resolve a handler @@ -345,15 +336,6 @@ int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value, int btrfs_removexattr(struct dentry *dentry, const char *name) { - struct btrfs_root *root = BTRFS_I(dentry->d_inode)->root; - - /* - * The permission on security.* and system.* is not checked - * in permission(). - */ - if (btrfs_root_readonly(root)) - return -EROFS; - /* * If this is a request for a synthetic attribute in the system.* * namespace use the generic infrastructure to resolve a handler diff --git a/trunk/fs/btrfs/zlib.c b/trunk/fs/btrfs/zlib.c index f5ec2d44150d..b9cd5445f71c 100644 --- a/trunk/fs/btrfs/zlib.c +++ b/trunk/fs/btrfs/zlib.c @@ -32,6 +32,15 @@ #include #include "compression.h" +/* Plan: call deflate() with avail_in == *sourcelen, + avail_out = *dstlen - 12 and flush == Z_FINISH. + If it doesn't manage to finish, call it again with + avail_in == 0 and avail_out set to the remaining 12 + bytes for it to clean up. + Q: Is 12 bytes sufficient? +*/ +#define STREAM_END_SPACE 12 + struct workspace { z_stream inf_strm; z_stream def_strm; @@ -39,51 +48,152 @@ struct workspace { struct list_head list; }; -static void zlib_free_workspace(struct list_head *ws) -{ - struct workspace *workspace = list_entry(ws, struct workspace, list); +static LIST_HEAD(idle_workspace); +static DEFINE_SPINLOCK(workspace_lock); +static unsigned long num_workspace; +static atomic_t alloc_workspace = ATOMIC_INIT(0); +static DECLARE_WAIT_QUEUE_HEAD(workspace_wait); - vfree(workspace->def_strm.workspace); - vfree(workspace->inf_strm.workspace); - kfree(workspace->buf); - kfree(workspace); -} - -static struct list_head *zlib_alloc_workspace(void) +/* + * this finds an available zlib workspace or allocates a new one + * NULL or an ERR_PTR is returned if things go bad. + */ +static struct workspace *find_zlib_workspace(void) { struct workspace *workspace; + int ret; + int cpus = num_online_cpus(); + +again: + spin_lock(&workspace_lock); + if (!list_empty(&idle_workspace)) { + workspace = list_entry(idle_workspace.next, struct workspace, + list); + list_del(&workspace->list); + num_workspace--; + spin_unlock(&workspace_lock); + return workspace; + } + spin_unlock(&workspace_lock); + if (atomic_read(&alloc_workspace) > cpus) { + DEFINE_WAIT(wait); + prepare_to_wait(&workspace_wait, &wait, TASK_UNINTERRUPTIBLE); + if (atomic_read(&alloc_workspace) > cpus) + schedule(); + finish_wait(&workspace_wait, &wait); + goto again; + } + atomic_inc(&alloc_workspace); workspace = kzalloc(sizeof(*workspace), GFP_NOFS); - if (!workspace) - return ERR_PTR(-ENOMEM); + if (!workspace) { + ret = -ENOMEM; + goto fail; + } workspace->def_strm.workspace = vmalloc(zlib_deflate_workspacesize()); + if (!workspace->def_strm.workspace) { + ret = -ENOMEM; + goto fail; + } workspace->inf_strm.workspace = vmalloc(zlib_inflate_workspacesize()); + if (!workspace->inf_strm.workspace) { + ret = -ENOMEM; + goto fail_inflate; + } workspace->buf = kmalloc(PAGE_CACHE_SIZE, GFP_NOFS); - if (!workspace->def_strm.workspace || - !workspace->inf_strm.workspace || !workspace->buf) - goto fail; - - INIT_LIST_HEAD(&workspace->list); + if (!workspace->buf) { + ret = -ENOMEM; + goto fail_kmalloc; + } + return workspace; - return &workspace->list; +fail_kmalloc: + vfree(workspace->inf_strm.workspace); +fail_inflate: + vfree(workspace->def_strm.workspace); fail: - zlib_free_workspace(&workspace->list); - return ERR_PTR(-ENOMEM); + kfree(workspace); + atomic_dec(&alloc_workspace); + wake_up(&workspace_wait); + return ERR_PTR(ret); +} + +/* + * put a workspace struct back on the list or free it if we have enough + * idle ones sitting around + */ +static int free_workspace(struct workspace *workspace) +{ + spin_lock(&workspace_lock); + if (num_workspace < num_online_cpus()) { + list_add_tail(&workspace->list, &idle_workspace); + num_workspace++; + spin_unlock(&workspace_lock); + if (waitqueue_active(&workspace_wait)) + wake_up(&workspace_wait); + return 0; + } + spin_unlock(&workspace_lock); + vfree(workspace->def_strm.workspace); + vfree(workspace->inf_strm.workspace); + kfree(workspace->buf); + kfree(workspace); + + atomic_dec(&alloc_workspace); + if (waitqueue_active(&workspace_wait)) + wake_up(&workspace_wait); + return 0; +} + +/* + * cleanup function for module exit + */ +static void free_workspaces(void) +{ + struct workspace *workspace; + while (!list_empty(&idle_workspace)) { + workspace = list_entry(idle_workspace.next, struct workspace, + list); + list_del(&workspace->list); + vfree(workspace->def_strm.workspace); + vfree(workspace->inf_strm.workspace); + kfree(workspace->buf); + kfree(workspace); + atomic_dec(&alloc_workspace); + } } -static int zlib_compress_pages(struct list_head *ws, - struct address_space *mapping, - u64 start, unsigned long len, - struct page **pages, - unsigned long nr_dest_pages, - unsigned long *out_pages, - unsigned long *total_in, - unsigned long *total_out, - unsigned long max_out) +/* + * given an address space and start/len, compress the bytes. + * + * pages are allocated to hold the compressed result and stored + * in 'pages' + * + * out_pages is used to return the number of pages allocated. There + * may be pages allocated even if we return an error + * + * total_in is used to return the number of bytes actually read. It + * may be smaller then len if we had to exit early because we + * ran out of room in the pages array or because we cross the + * max_out threshold. + * + * total_out is used to return the total number of compressed bytes + * + * max_out tells us the max number of bytes that we're allowed to + * stuff into pages + */ +int btrfs_zlib_compress_pages(struct address_space *mapping, + u64 start, unsigned long len, + struct page **pages, + unsigned long nr_dest_pages, + unsigned long *out_pages, + unsigned long *total_in, + unsigned long *total_out, + unsigned long max_out) { - struct workspace *workspace = list_entry(ws, struct workspace, list); int ret; + struct workspace *workspace; char *data_in; char *cpage_out; int nr_pages = 0; @@ -95,6 +205,10 @@ static int zlib_compress_pages(struct list_head *ws, *total_out = 0; *total_in = 0; + workspace = find_zlib_workspace(); + if (IS_ERR(workspace)) + return -1; + if (Z_OK != zlib_deflateInit(&workspace->def_strm, 3)) { printk(KERN_WARNING "deflateInit failed\n"); ret = -1; @@ -108,10 +222,6 @@ static int zlib_compress_pages(struct list_head *ws, data_in = kmap(in_page); out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM); - if (out_page == NULL) { - ret = -1; - goto out; - } cpage_out = kmap(out_page); pages[0] = out_page; nr_pages = 1; @@ -150,10 +260,6 @@ static int zlib_compress_pages(struct list_head *ws, goto out; } out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM); - if (out_page == NULL) { - ret = -1; - goto out; - } cpage_out = kmap(out_page); pages[nr_pages] = out_page; nr_pages++; @@ -208,26 +314,55 @@ static int zlib_compress_pages(struct list_head *ws, kunmap(in_page); page_cache_release(in_page); } + free_workspace(workspace); return ret; } -static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in, - u64 disk_start, - struct bio_vec *bvec, - int vcnt, - size_t srclen) +/* + * pages_in is an array of pages with compressed data. + * + * disk_start is the starting logical offset of this array in the file + * + * bvec is a bio_vec of pages from the file that we want to decompress into + * + * vcnt is the count of pages in the biovec + * + * srclen is the number of bytes in pages_in + * + * The basic idea is that we have a bio that was created by readpages. + * The pages in the bio are for the uncompressed data, and they may not + * be contiguous. They all correspond to the range of bytes covered by + * the compressed extent. + */ +int btrfs_zlib_decompress_biovec(struct page **pages_in, + u64 disk_start, + struct bio_vec *bvec, + int vcnt, + size_t srclen) { - struct workspace *workspace = list_entry(ws, struct workspace, list); - int ret = 0, ret2; + int ret = 0; int wbits = MAX_WBITS; + struct workspace *workspace; char *data_in; size_t total_out = 0; + unsigned long page_bytes_left; unsigned long page_in_index = 0; unsigned long page_out_index = 0; + struct page *page_out; unsigned long total_pages_in = (srclen + PAGE_CACHE_SIZE - 1) / PAGE_CACHE_SIZE; unsigned long buf_start; + unsigned long buf_offset; + unsigned long bytes; + unsigned long working_bytes; unsigned long pg_offset; + unsigned long start_byte; + unsigned long current_buf_start; + char *kaddr; + + workspace = find_zlib_workspace(); + if (IS_ERR(workspace)) + return -ENOMEM; data_in = kmap(pages_in[page_in_index]); workspace->inf_strm.next_in = data_in; @@ -237,6 +372,8 @@ static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in, workspace->inf_strm.total_out = 0; workspace->inf_strm.next_out = workspace->buf; workspace->inf_strm.avail_out = PAGE_CACHE_SIZE; + page_out = bvec[page_out_index].bv_page; + page_bytes_left = PAGE_CACHE_SIZE; pg_offset = 0; /* If it's deflate, and it's got no preset dictionary, then @@ -252,29 +389,107 @@ static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in, if (Z_OK != zlib_inflateInit2(&workspace->inf_strm, wbits)) { printk(KERN_WARNING "inflateInit failed\n"); - return -1; + ret = -1; + goto out; } while (workspace->inf_strm.total_in < srclen) { ret = zlib_inflate(&workspace->inf_strm, Z_NO_FLUSH); if (ret != Z_OK && ret != Z_STREAM_END) break; - + /* + * buf start is the byte offset we're of the start of + * our workspace buffer + */ buf_start = total_out; + + /* total_out is the last byte of the workspace buffer */ total_out = workspace->inf_strm.total_out; - /* we didn't make progress in this inflate call, we're done */ - if (buf_start == total_out) - break; + working_bytes = total_out - buf_start; + + /* + * start byte is the first byte of the page we're currently + * copying into relative to the start of the compressed data. + */ + start_byte = page_offset(page_out) - disk_start; - ret2 = btrfs_decompress_buf2page(workspace->buf, buf_start, - total_out, disk_start, - bvec, vcnt, - &page_out_index, &pg_offset); - if (ret2 == 0) { - ret = 0; - goto done; + if (working_bytes == 0) { + /* we didn't make progress in this inflate + * call, we're done + */ + if (ret != Z_STREAM_END) + ret = -1; + break; } + /* we haven't yet hit data corresponding to this page */ + if (total_out <= start_byte) + goto next; + + /* + * the start of the data we care about is offset into + * the middle of our working buffer + */ + if (total_out > start_byte && buf_start < start_byte) { + buf_offset = start_byte - buf_start; + working_bytes -= buf_offset; + } else { + buf_offset = 0; + } + current_buf_start = buf_start; + + /* copy bytes from the working buffer into the pages */ + while (working_bytes > 0) { + bytes = min(PAGE_CACHE_SIZE - pg_offset, + PAGE_CACHE_SIZE - buf_offset); + bytes = min(bytes, working_bytes); + kaddr = kmap_atomic(page_out, KM_USER0); + memcpy(kaddr + pg_offset, workspace->buf + buf_offset, + bytes); + kunmap_atomic(kaddr, KM_USER0); + flush_dcache_page(page_out); + + pg_offset += bytes; + page_bytes_left -= bytes; + buf_offset += bytes; + working_bytes -= bytes; + current_buf_start += bytes; + + /* check if we need to pick another page */ + if (page_bytes_left == 0) { + page_out_index++; + if (page_out_index >= vcnt) { + ret = 0; + goto done; + } + + page_out = bvec[page_out_index].bv_page; + pg_offset = 0; + page_bytes_left = PAGE_CACHE_SIZE; + start_byte = page_offset(page_out) - disk_start; + + /* + * make sure our new page is covered by this + * working buffer + */ + if (total_out <= start_byte) + goto next; + + /* the next page in the biovec might not + * be adjacent to the last page, but it + * might still be found inside this working + * buffer. bump our offset pointer + */ + if (total_out > start_byte && + current_buf_start < start_byte) { + buf_offset = start_byte - buf_start; + working_bytes = total_out - start_byte; + current_buf_start = buf_start + + buf_offset; + } + } + } +next: workspace->inf_strm.next_out = workspace->buf; workspace->inf_strm.avail_out = PAGE_CACHE_SIZE; @@ -301,21 +516,35 @@ static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in, zlib_inflateEnd(&workspace->inf_strm); if (data_in) kunmap(pages_in[page_in_index]); +out: + free_workspace(workspace); return ret; } -static int zlib_decompress(struct list_head *ws, unsigned char *data_in, - struct page *dest_page, - unsigned long start_byte, - size_t srclen, size_t destlen) +/* + * a less complex decompression routine. Our compressed data fits in a + * single page, and we want to read a single page out of it. + * start_byte tells us the offset into the compressed data we're interested in + */ +int btrfs_zlib_decompress(unsigned char *data_in, + struct page *dest_page, + unsigned long start_byte, + size_t srclen, size_t destlen) { - struct workspace *workspace = list_entry(ws, struct workspace, list); int ret = 0; int wbits = MAX_WBITS; + struct workspace *workspace; unsigned long bytes_left = destlen; unsigned long total_out = 0; char *kaddr; + if (destlen > PAGE_CACHE_SIZE) + return -ENOMEM; + + workspace = find_zlib_workspace(); + if (IS_ERR(workspace)) + return -ENOMEM; + workspace->inf_strm.next_in = data_in; workspace->inf_strm.avail_in = srclen; workspace->inf_strm.total_in = 0; @@ -336,7 +565,8 @@ static int zlib_decompress(struct list_head *ws, unsigned char *data_in, if (Z_OK != zlib_inflateInit2(&workspace->inf_strm, wbits)) { printk(KERN_WARNING "inflateInit failed\n"); - return -1; + ret = -1; + goto out; } while (bytes_left > 0) { @@ -386,13 +616,12 @@ static int zlib_decompress(struct list_head *ws, unsigned char *data_in, ret = 0; zlib_inflateEnd(&workspace->inf_strm); +out: + free_workspace(workspace); return ret; } -struct btrfs_compress_op btrfs_zlib_compress = { - .alloc_workspace = zlib_alloc_workspace, - .free_workspace = zlib_free_workspace, - .compress_pages = zlib_compress_pages, - .decompress_biovec = zlib_decompress_biovec, - .decompress = zlib_decompress, -}; +void btrfs_zlib_exit(void) +{ + free_workspaces(); +} 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/ecryptfs/crypto.c b/trunk/fs/ecryptfs/crypto.c index bfd8b680e648..cbadc1bee6e7 100644 --- a/trunk/fs/ecryptfs/crypto.c +++ b/trunk/fs/ecryptfs/crypto.c @@ -348,7 +348,7 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, BUG_ON(!crypt_stat || !crypt_stat->tfm || !(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED)); if (unlikely(ecryptfs_verbosity > 0)) { - ecryptfs_printk(KERN_DEBUG, "Key size [%zd]; key:\n", + ecryptfs_printk(KERN_DEBUG, "Key size [%d]; key:\n", crypt_stat->key_size); ecryptfs_dump_hex(crypt_stat->key, crypt_stat->key_size); @@ -413,9 +413,10 @@ static int ecryptfs_encrypt_extent(struct page *enc_extent_page, rc = ecryptfs_derive_iv(extent_iv, crypt_stat, (extent_base + extent_offset)); if (rc) { - ecryptfs_printk(KERN_ERR, "Error attempting to derive IV for " - "extent [0x%.16llx]; rc = [%d]\n", - (unsigned long long)(extent_base + extent_offset), rc); + ecryptfs_printk(KERN_ERR, "Error attempting to " + "derive IV for extent [0x%.16x]; " + "rc = [%d]\n", (extent_base + extent_offset), + rc); goto out; } if (unlikely(ecryptfs_verbosity > 0)) { @@ -442,9 +443,9 @@ static int ecryptfs_encrypt_extent(struct page *enc_extent_page, } rc = 0; if (unlikely(ecryptfs_verbosity > 0)) { - ecryptfs_printk(KERN_DEBUG, "Encrypt extent [0x%.16llx]; " - "rc = [%d]\n", - (unsigned long long)(extent_base + extent_offset), rc); + ecryptfs_printk(KERN_DEBUG, "Encrypt extent [0x%.16x]; " + "rc = [%d]\n", (extent_base + extent_offset), + rc); ecryptfs_printk(KERN_DEBUG, "First 8 bytes after " "encryption:\n"); ecryptfs_dump_hex((char *)(page_address(enc_extent_page)), 8); @@ -539,9 +540,10 @@ static int ecryptfs_decrypt_extent(struct page *page, rc = ecryptfs_derive_iv(extent_iv, crypt_stat, (extent_base + extent_offset)); if (rc) { - ecryptfs_printk(KERN_ERR, "Error attempting to derive IV for " - "extent [0x%.16llx]; rc = [%d]\n", - (unsigned long long)(extent_base + extent_offset), rc); + ecryptfs_printk(KERN_ERR, "Error attempting to " + "derive IV for extent [0x%.16x]; " + "rc = [%d]\n", (extent_base + extent_offset), + rc); goto out; } if (unlikely(ecryptfs_verbosity > 0)) { @@ -569,9 +571,9 @@ static int ecryptfs_decrypt_extent(struct page *page, } rc = 0; if (unlikely(ecryptfs_verbosity > 0)) { - ecryptfs_printk(KERN_DEBUG, "Decrypt extent [0x%.16llx]; " - "rc = [%d]\n", - (unsigned long long)(extent_base + extent_offset), rc); + ecryptfs_printk(KERN_DEBUG, "Decrypt extent [0x%.16x]; " + "rc = [%d]\n", (extent_base + extent_offset), + rc); ecryptfs_printk(KERN_DEBUG, "First 8 bytes after " "decryption:\n"); ecryptfs_dump_hex((char *)(page_address(page) @@ -778,7 +780,7 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat) } ecryptfs_printk(KERN_DEBUG, "Initializing cipher [%s]; strlen = [%d]; " - "key_size_bits = [%zd]\n", + "key_size_bits = [%d]\n", crypt_stat->cipher, (int)strlen(crypt_stat->cipher), crypt_stat->key_size << 3); if (crypt_stat->tfm) { diff --git a/trunk/fs/ecryptfs/ecryptfs_kernel.h b/trunk/fs/ecryptfs/ecryptfs_kernel.h index dbc84ed96336..413a3c48f0bb 100644 --- a/trunk/fs/ecryptfs/ecryptfs_kernel.h +++ b/trunk/fs/ecryptfs/ecryptfs_kernel.h @@ -192,6 +192,7 @@ ecryptfs_get_key_payload_data(struct key *key) (((struct user_key_payload*)key->payload.data)->data); } +#define ECRYPTFS_SUPER_MAGIC 0xf15f #define ECRYPTFS_MAX_KEYSET_SIZE 1024 #define ECRYPTFS_MAX_CIPHER_NAME_SIZE 32 #define ECRYPTFS_MAX_NUM_ENC_KEYS 64 @@ -583,7 +584,6 @@ ecryptfs_set_dentry_lower_mnt(struct dentry *dentry, struct vfsmount *lower_mnt) #define ecryptfs_printk(type, fmt, arg...) \ __ecryptfs_printk(type "%s: " fmt, __func__, ## arg); -__attribute__ ((format(printf, 1, 2))) void __ecryptfs_printk(const char *fmt, ...); extern const struct file_operations ecryptfs_main_fops; diff --git a/trunk/fs/ecryptfs/file.c b/trunk/fs/ecryptfs/file.c index 81e10e6a9443..91da02987bff 100644 --- a/trunk/fs/ecryptfs/file.c +++ b/trunk/fs/ecryptfs/file.c @@ -47,7 +47,7 @@ static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos) { - ssize_t rc; + int rc; struct dentry *lower_dentry; struct vfsmount *lower_vfsmount; struct file *file = iocb->ki_filp; @@ -191,16 +191,18 @@ static int ecryptfs_open(struct inode *inode, struct file *file) | ECRYPTFS_ENCRYPTED); } mutex_unlock(&crypt_stat->cs_mutex); - rc = ecryptfs_init_persistent_file(ecryptfs_dentry); - if (rc) { - printk(KERN_ERR "%s: Error attempting to initialize " - "the persistent file for the dentry with name " - "[%s]; rc = [%d]\n", __func__, - ecryptfs_dentry->d_name.name, rc); - goto out_free; + if (!ecryptfs_inode_to_private(inode)->lower_file) { + rc = ecryptfs_init_persistent_file(ecryptfs_dentry); + if (rc) { + printk(KERN_ERR "%s: Error attempting to initialize " + "the persistent file for the dentry with name " + "[%s]; rc = [%d]\n", __func__, + ecryptfs_dentry->d_name.name, rc); + goto out_free; + } } - if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_ACCMODE) - == O_RDONLY && (file->f_flags & O_ACCMODE) != O_RDONLY) { + if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_RDONLY) + && !(file->f_flags & O_RDONLY)) { rc = -EPERM; printk(KERN_WARNING "%s: Lower persistent file is RO; eCryptfs " "file must hence be opened RO\n", __func__); @@ -241,9 +243,9 @@ static int ecryptfs_open(struct inode *inode, struct file *file) } } mutex_unlock(&crypt_stat->cs_mutex); - ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = " - "[0x%.16lx] size: [0x%.16llx]\n", inode, inode->i_ino, - (unsigned long long)i_size_read(inode)); + ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = [0x%.16x] " + "size: [0x%.16x]\n", inode, inode->i_ino, + i_size_read(inode)); goto out; out_free: kmem_cache_free(ecryptfs_file_info_cache, diff --git a/trunk/fs/ecryptfs/inode.c b/trunk/fs/ecryptfs/inode.c index bd33f87a1907..64ff02330752 100644 --- a/trunk/fs/ecryptfs/inode.c +++ b/trunk/fs/ecryptfs/inode.c @@ -185,13 +185,15 @@ static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry) "context; rc = [%d]\n", rc); goto out; } - rc = ecryptfs_init_persistent_file(ecryptfs_dentry); - if (rc) { - printk(KERN_ERR "%s: Error attempting to initialize " - "the persistent file for the dentry with name " - "[%s]; rc = [%d]\n", __func__, - ecryptfs_dentry->d_name.name, rc); - goto out; + if (!ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->lower_file) { + rc = ecryptfs_init_persistent_file(ecryptfs_dentry); + if (rc) { + printk(KERN_ERR "%s: Error attempting to initialize " + "the persistent file for the dentry with name " + "[%s]; rc = [%d]\n", __func__, + ecryptfs_dentry->d_name.name, rc); + goto out; + } } rc = ecryptfs_write_metadata(ecryptfs_dentry); if (rc) { @@ -300,13 +302,15 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, rc = -ENOMEM; goto out; } - rc = ecryptfs_init_persistent_file(ecryptfs_dentry); - if (rc) { - printk(KERN_ERR "%s: Error attempting to initialize " - "the persistent file for the dentry with name " - "[%s]; rc = [%d]\n", __func__, - ecryptfs_dentry->d_name.name, rc); - goto out_free_kmem; + if (!ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->lower_file) { + rc = ecryptfs_init_persistent_file(ecryptfs_dentry); + if (rc) { + printk(KERN_ERR "%s: Error attempting to initialize " + "the persistent file for the dentry with name " + "[%s]; rc = [%d]\n", __func__, + ecryptfs_dentry->d_name.name, rc); + goto out_free_kmem; + } } crypt_stat = &ecryptfs_inode_to_private( ecryptfs_dentry->d_inode)->crypt_stat; diff --git a/trunk/fs/ecryptfs/keystore.c b/trunk/fs/ecryptfs/keystore.c index c1436cff6f2d..b1f6858a5223 100644 --- a/trunk/fs/ecryptfs/keystore.c +++ b/trunk/fs/ecryptfs/keystore.c @@ -59,7 +59,7 @@ static int process_request_key_err(long err_code) break; default: ecryptfs_printk(KERN_WARNING, "Unknown error code: " - "[0x%.16lx]\n", err_code); + "[0x%.16x]\n", err_code); rc = -EINVAL; } return rc; @@ -130,7 +130,7 @@ int ecryptfs_write_packet_length(char *dest, size_t size, } else { rc = -EINVAL; ecryptfs_printk(KERN_WARNING, - "Unsupported packet size: [%zd]\n", size); + "Unsupported packet size: [%d]\n", size); } return rc; } @@ -1672,7 +1672,7 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok, auth_tok->session_key.decrypted_key_size); crypt_stat->flags |= ECRYPTFS_KEY_VALID; if (unlikely(ecryptfs_verbosity > 0)) { - ecryptfs_printk(KERN_DEBUG, "FEK of size [%zd]:\n", + ecryptfs_printk(KERN_DEBUG, "FEK of size [%d]:\n", crypt_stat->key_size); ecryptfs_dump_hex(crypt_stat->key, crypt_stat->key_size); @@ -1754,7 +1754,7 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat, if (ECRYPTFS_SIG_SIZE != tag_11_contents_size) { ecryptfs_printk(KERN_ERR, "Expected " "signature of size [%d]; " - "read size [%zd]\n", + "read size [%d]\n", ECRYPTFS_SIG_SIZE, tag_11_contents_size); rc = -EIO; @@ -1787,8 +1787,8 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat, goto out_wipe_list; break; default: - ecryptfs_printk(KERN_DEBUG, "No packet at offset [%zd] " - "of the file header; hex value of " + ecryptfs_printk(KERN_DEBUG, "No packet at offset " + "[%d] of the file header; hex value of " "character is [0x%.2x]\n", i, src[i]); next_packet_is_auth_tok_packet = 0; } @@ -1864,8 +1864,8 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat, "session key for authentication token with sig " "[%.*s]; rc = [%d]. Removing auth tok " "candidate from the list and searching for " - "the next match.\n", ECRYPTFS_SIG_SIZE_HEX, - candidate_auth_tok_sig, rc); + "the next match.\n", candidate_auth_tok_sig, + ECRYPTFS_SIG_SIZE_HEX, rc); list_for_each_entry_safe(auth_tok_list_item, auth_tok_list_item_tmp, &auth_tok_list, list) { @@ -2168,7 +2168,7 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes, if (encrypted_session_key_valid) { ecryptfs_printk(KERN_DEBUG, "encrypted_session_key_valid != 0; " "using auth_tok->session_key.encrypted_key, " - "where key_rec->enc_key_size = [%zd]\n", + "where key_rec->enc_key_size = [%d]\n", key_rec->enc_key_size); memcpy(key_rec->enc_key, auth_tok->session_key.encrypted_key, @@ -2198,7 +2198,7 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes, if (rc < 1 || rc > 2) { ecryptfs_printk(KERN_ERR, "Error generating scatterlist " "for crypt_stat session key; expected rc = 1; " - "got rc = [%d]. key_rec->enc_key_size = [%zd]\n", + "got rc = [%d]. key_rec->enc_key_size = [%d]\n", rc, key_rec->enc_key_size); rc = -ENOMEM; goto out; @@ -2209,7 +2209,7 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes, ecryptfs_printk(KERN_ERR, "Error generating scatterlist " "for crypt_stat encrypted session key; " "expected rc = 1; got rc = [%d]. " - "key_rec->enc_key_size = [%zd]\n", rc, + "key_rec->enc_key_size = [%d]\n", rc, key_rec->enc_key_size); rc = -ENOMEM; goto out; @@ -2224,7 +2224,7 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes, goto out; } rc = 0; - ecryptfs_printk(KERN_DEBUG, "Encrypting [%zd] bytes of the key\n", + ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes of the key\n", crypt_stat->key_size); rc = crypto_blkcipher_encrypt(&desc, dst_sg, src_sg, (*key_rec).enc_key_size); @@ -2235,7 +2235,7 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes, } ecryptfs_printk(KERN_DEBUG, "This should be the encrypted key:\n"); if (ecryptfs_verbosity > 0) { - ecryptfs_printk(KERN_DEBUG, "EFEK of size [%zd]:\n", + ecryptfs_printk(KERN_DEBUG, "EFEK of size [%d]:\n", key_rec->enc_key_size); ecryptfs_dump_hex(key_rec->enc_key, key_rec->enc_key_size); diff --git a/trunk/fs/ecryptfs/main.c b/trunk/fs/ecryptfs/main.c index 758323a0f09a..d3b28abdd6aa 100644 --- a/trunk/fs/ecryptfs/main.c +++ b/trunk/fs/ecryptfs/main.c @@ -36,7 +36,6 @@ #include #include #include -#include #include "ecryptfs_kernel.h" /** @@ -565,7 +564,6 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags ecryptfs_set_superblock_lower(s, path.dentry->d_sb); s->s_maxbytes = path.dentry->d_sb->s_maxbytes; s->s_blocksize = path.dentry->d_sb->s_blocksize; - s->s_magic = ECRYPTFS_SUPER_MAGIC; inode = ecryptfs_get_inode(path.dentry->d_inode, s); rc = PTR_ERR(inode); @@ -810,10 +808,9 @@ static int __init ecryptfs_init(void) ecryptfs_printk(KERN_ERR, "The eCryptfs extent size is " "larger than the host's page size, and so " "eCryptfs cannot run on this system. The " - "default eCryptfs extent size is [%u] bytes; " - "the page size is [%lu] bytes.\n", - ECRYPTFS_DEFAULT_EXTENT_SIZE, - (unsigned long)PAGE_CACHE_SIZE); + "default eCryptfs extent size is [%d] bytes; " + "the page size is [%d] bytes.\n", + ECRYPTFS_DEFAULT_EXTENT_SIZE, PAGE_CACHE_SIZE); goto out; } rc = ecryptfs_init_kmem_caches(); diff --git a/trunk/fs/ecryptfs/mmap.c b/trunk/fs/ecryptfs/mmap.c index cc64fca89f8d..b1d82756544b 100644 --- a/trunk/fs/ecryptfs/mmap.c +++ b/trunk/fs/ecryptfs/mmap.c @@ -65,7 +65,7 @@ static int ecryptfs_writepage(struct page *page, struct writeback_control *wbc) rc = ecryptfs_encrypt_page(page); if (rc) { ecryptfs_printk(KERN_WARNING, "Error encrypting " - "page (upper index [0x%.16lx])\n", page->index); + "page (upper index [0x%.16x])\n", page->index); ClearPageUptodate(page); goto out; } @@ -237,7 +237,7 @@ static int ecryptfs_readpage(struct file *file, struct page *page) ClearPageUptodate(page); else SetPageUptodate(page); - ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16lx]\n", + ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16x]\n", page->index); unlock_page(page); return rc; @@ -290,7 +290,6 @@ static int ecryptfs_write_begin(struct file *file, return -ENOMEM; *pagep = page; - prev_page_end_size = ((loff_t)index << PAGE_CACHE_SHIFT); if (!PageUptodate(page)) { struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(mapping->host)->crypt_stat; @@ -336,23 +335,18 @@ static int ecryptfs_write_begin(struct file *file, SetPageUptodate(page); } } else { - if (prev_page_end_size - >= i_size_read(page->mapping->host)) { - zero_user(page, 0, PAGE_CACHE_SIZE); - } else { - rc = ecryptfs_decrypt_page(page); - if (rc) { - printk(KERN_ERR "%s: Error decrypting " - "page at index [%ld]; " - "rc = [%d]\n", - __func__, page->index, rc); - ClearPageUptodate(page); - goto out; - } + rc = ecryptfs_decrypt_page(page); + if (rc) { + printk(KERN_ERR "%s: Error decrypting page " + "at index [%ld]; rc = [%d]\n", + __func__, page->index, rc); + ClearPageUptodate(page); + goto out; } SetPageUptodate(page); } } + prev_page_end_size = ((loff_t)index << PAGE_CACHE_SHIFT); /* If creating a page or more of holes, zero them out via truncate. * Note, this will increase i_size. */ if (index != 0) { @@ -494,7 +488,7 @@ static int ecryptfs_write_end(struct file *file, } else ecryptfs_printk(KERN_DEBUG, "Not a new file\n"); ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page" - "(page w/ index = [0x%.16lx], to = [%d])\n", index, to); + "(page w/ index = [0x%.16x], to = [%d])\n", index, to); if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { rc = ecryptfs_write_lower_page_segment(ecryptfs_inode, page, 0, to); @@ -509,20 +503,19 @@ static int ecryptfs_write_end(struct file *file, rc = fill_zeros_to_end_of_page(page, to); if (rc) { ecryptfs_printk(KERN_WARNING, "Error attempting to fill " - "zeros in page with index = [0x%.16lx]\n", index); + "zeros in page with index = [0x%.16x]\n", index); goto out; } rc = ecryptfs_encrypt_page(page); if (rc) { ecryptfs_printk(KERN_WARNING, "Error encrypting page (upper " - "index [0x%.16lx])\n", index); + "index [0x%.16x])\n", index); goto out; } if (pos + copied > i_size_read(ecryptfs_inode)) { i_size_write(ecryptfs_inode, pos + copied); ecryptfs_printk(KERN_DEBUG, "Expanded file size to " - "[0x%.16llx]\n", - (unsigned long long)i_size_read(ecryptfs_inode)); + "[0x%.16x]\n", i_size_read(ecryptfs_inode)); } rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode); if (rc) 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 7d77f24d32a9..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,30 +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)) { - path_put_conditional(path, nd); - 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: @@ -1315,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 @@ -1461,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); @@ -2364,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) @@ -2515,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; @@ -3574,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/fs/xfs/support/debug.c b/trunk/fs/xfs/support/debug.c index 0df88897ef84..e6cf955ec0fc 100644 --- a/trunk/fs/xfs/support/debug.c +++ b/trunk/fs/xfs/support/debug.c @@ -75,11 +75,11 @@ xfs_cmn_err( { struct va_format vaf; va_list args; - int do_panic = 0; + int panic = 0; if (xfs_panic_mask && (xfs_panic_mask & panic_tag)) { printk(KERN_ALERT "XFS: Transforming an alert into a BUG."); - do_panic = 1; + panic = 1; } va_start(args, fmt); @@ -89,7 +89,7 @@ xfs_cmn_err( printk(KERN_ALERT "Filesystem %s: %pV", mp->m_fsname, &vaf); va_end(args); - BUG_ON(do_panic); + BUG_ON(panic); } void 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/magic.h b/trunk/include/linux/magic.h index 62730ea2b56e..ff690d05f129 100644 --- a/trunk/include/linux/magic.h +++ b/trunk/include/linux/magic.h @@ -16,7 +16,6 @@ #define TMPFS_MAGIC 0x01021994 #define HUGETLBFS_MAGIC 0x958458f6 /* some random number */ #define SQUASHFS_MAGIC 0x73717368 -#define ECRYPTFS_SUPER_MAGIC 0xf15f #define EFS_SUPER_MAGIC 0x414A53 #define EXT2_SUPER_MAGIC 0xEF53 #define EXT3_SUPER_MAGIC 0xEF53 diff --git a/trunk/include/linux/mlx4/device.h b/trunk/include/linux/mlx4/device.h index 049214642036..a7b15bc7648e 100644 --- a/trunk/include/linux/mlx4/device.h +++ b/trunk/include/linux/mlx4/device.h @@ -144,11 +144,6 @@ enum { MLX4_STAT_RATE_OFFSET = 5 }; -enum mlx4_protocol { - MLX4_PROTOCOL_IB, - MLX4_PROTOCOL_EN, -}; - enum { MLX4_MTT_FLAG_PRESENT = 1 }; @@ -505,9 +500,8 @@ int mlx4_INIT_PORT(struct mlx4_dev *dev, int port); int mlx4_CLOSE_PORT(struct mlx4_dev *dev, int port); int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - int block_mcast_loopback, enum mlx4_protocol protocol); -int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - enum mlx4_protocol protocol); + int block_mcast_loopback); +int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16]); int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *index); void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, int index); diff --git a/trunk/include/linux/mlx4/driver.h b/trunk/include/linux/mlx4/driver.h index e1eebf78caba..f407cd4bfb34 100644 --- a/trunk/include/linux/mlx4/driver.h +++ b/trunk/include/linux/mlx4/driver.h @@ -34,7 +34,6 @@ #define MLX4_DRIVER_H #include -#include struct mlx4_dev; @@ -45,6 +44,11 @@ enum mlx4_dev_event { MLX4_DEV_EVENT_PORT_REINIT, }; +enum mlx4_protocol { + MLX4_PROTOCOL_IB, + MLX4_PROTOCOL_EN, +}; + struct mlx4_interface { void * (*add) (struct mlx4_dev *dev); void (*remove)(struct mlx4_dev *dev, void *context); 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 c84d900fbbb3..0ef22a1f129e 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 void * early_init_dt_alloc_memory_arch(u64 size, u64 align); +extern u64 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/include/rdma/ib_verbs.h b/trunk/include/rdma/ib_verbs.h index 55cd0a0bc977..e04c4888d1fd 100644 --- a/trunk/include/rdma/ib_verbs.h +++ b/trunk/include/rdma/ib_verbs.h @@ -47,13 +47,10 @@ #include #include #include -#include #include #include -extern struct workqueue_struct *ib_wq; - union ib_gid { u8 raw[16]; struct { diff --git a/trunk/include/sound/ac97_codec.h b/trunk/include/sound/ac97_codec.h index b602f475cdbb..49400459b477 100644 --- a/trunk/include/sound/ac97_codec.h +++ b/trunk/include/sound/ac97_codec.h @@ -477,7 +477,7 @@ struct snd_ac97_template { struct snd_ac97 { /* -- lowlevel (hardware) driver specific -- */ - const struct snd_ac97_build_ops *build_ops; + struct snd_ac97_build_ops * build_ops; void *private_data; void (*private_free) (struct snd_ac97 *ac97); /* --- */ diff --git a/trunk/mm/internal.h b/trunk/mm/internal.h index 69488205723d..4c98630f0f77 100644 --- a/trunk/mm/internal.h +++ b/trunk/mm/internal.h @@ -39,6 +39,15 @@ static inline void __put_page(struct page *page) extern unsigned long highest_memmap_pfn; +#ifdef CONFIG_SMP +extern int putback_active_lru_page(struct zone *zone, struct page *page); +#else +static inline int putback_active_lru_page(struct zone *zone, struct page *page) +{ + return 0; +} +#endif + /* * in mm/vmscan.c: */ 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 diff --git a/trunk/mm/swap.c b/trunk/mm/swap.c index c02f93611a84..bbc1ce9f9460 100644 --- a/trunk/mm/swap.c +++ b/trunk/mm/swap.c @@ -178,15 +178,13 @@ void put_pages_list(struct list_head *pages) } EXPORT_SYMBOL(put_pages_list); -/* - * pagevec_move_tail() must be called with IRQ disabled. - * Otherwise this may cause nasty races. - */ -static void pagevec_move_tail(struct pagevec *pvec) +static void pagevec_lru_move_fn(struct pagevec *pvec, + void (*move_fn)(struct page *page, void *arg), + void *arg) { int i; - int pgmoved = 0; struct zone *zone = NULL; + unsigned long flags = 0; for (i = 0; i < pagevec_count(pvec); i++) { struct page *page = pvec->pages[i]; @@ -194,29 +192,49 @@ static void pagevec_move_tail(struct pagevec *pvec) if (pagezone != zone) { if (zone) - spin_unlock(&zone->lru_lock); + spin_unlock_irqrestore(&zone->lru_lock, flags); zone = pagezone; - spin_lock(&zone->lru_lock); - } - if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) { - int lru = page_lru_base_type(page); - list_move_tail(&page->lru, &zone->lru[lru].list); - pgmoved++; + spin_lock_irqsave(&zone->lru_lock, flags); } + + (*move_fn)(page, arg); } if (zone) - spin_unlock(&zone->lru_lock); - __count_vm_events(PGROTATED, pgmoved); - release_pages(pvec->pages, pvec->nr, pvec->cold); + spin_unlock_irqrestore(&zone->lru_lock, flags); + release_pages(pvec->pages, pagevec_count(pvec), pvec->cold); pagevec_reinit(pvec); } +static void pagevec_move_tail_fn(struct page *page, void *arg) +{ + int *pgmoved = arg; + struct zone *zone = page_zone(page); + + if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) { + int lru = page_lru_base_type(page); + list_move_tail(&page->lru, &zone->lru[lru].list); + (*pgmoved)++; + } +} + +/* + * pagevec_move_tail() must be called with IRQ disabled. + * Otherwise this may cause nasty races. + */ +static void pagevec_move_tail(struct pagevec *pvec) +{ + int pgmoved = 0; + + pagevec_lru_move_fn(pvec, pagevec_move_tail_fn, &pgmoved); + __count_vm_events(PGROTATED, pgmoved); +} + /* * Writeback is about to end against a page which has been marked for immediate * reclaim. If it still appears to be reclaimable, move it to the tail of the * inactive list. */ -void rotate_reclaimable_page(struct page *page) +void rotate_reclaimable_page(struct page *page) { if (!PageLocked(page) && !PageDirty(page) && !PageActive(page) && !PageUnevictable(page) && PageLRU(page)) { @@ -253,27 +271,94 @@ static void update_page_reclaim_stat(struct zone *zone, struct page *page, } /* - * FIXME: speed this up? + * A page will go to active list either by activate_page or putback_lru_page. + * In the activate_page case, the page hasn't active bit set. The page might + * not in LRU list because it's isolated before it gets a chance to be moved to + * active list. The window is small because pagevec just stores several pages. + * For such case, we do nothing for such page. + * In the putback_lru_page case, the page isn't in lru list but has active + * bit set */ -void activate_page(struct page *page) +static void __activate_page(struct page *page, void *arg) { struct zone *zone = page_zone(page); + int file = page_is_file_cache(page); + int lru = page_lru_base_type(page); + bool putback = !PageLRU(page); - spin_lock_irq(&zone->lru_lock); - if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) { - int file = page_is_file_cache(page); - int lru = page_lru_base_type(page); + /* The page is isolated before it's moved to active list */ + if (!PageLRU(page) && !PageActive(page)) + return; + if ((PageLRU(page) && PageActive(page)) || PageUnevictable(page)) + return; + + if (!putback) del_page_from_lru_list(zone, page, lru); + else + SetPageLRU(page); - SetPageActive(page); - lru += LRU_ACTIVE; - add_page_to_lru_list(zone, page, lru); - __count_vm_event(PGACTIVATE); + SetPageActive(page); + lru += LRU_ACTIVE; + add_page_to_lru_list(zone, page, lru); + + if (putback) + return; + __count_vm_event(PGACTIVATE); + update_page_reclaim_stat(zone, page, file, 1); +} + +#ifdef CONFIG_SMP +static DEFINE_PER_CPU(struct pagevec, activate_page_pvecs); + +static void activate_page_drain(int cpu) +{ + struct pagevec *pvec = &per_cpu(activate_page_pvecs, cpu); + + if (pagevec_count(pvec)) + pagevec_lru_move_fn(pvec, __activate_page, NULL); +} - update_page_reclaim_stat(zone, page, file, 1); +void activate_page(struct page *page) +{ + if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) { + struct pagevec *pvec = &get_cpu_var(activate_page_pvecs); + + page_cache_get(page); + if (!pagevec_add(pvec, page)) + pagevec_lru_move_fn(pvec, __activate_page, NULL); + put_cpu_var(activate_page_pvecs); } +} + +/* Caller should hold zone->lru_lock */ +int putback_active_lru_page(struct zone *zone, struct page *page) +{ + struct pagevec *pvec = &get_cpu_var(activate_page_pvecs); + + if (!pagevec_add(pvec, page)) { + spin_unlock_irq(&zone->lru_lock); + pagevec_lru_move_fn(pvec, __activate_page, NULL); + spin_lock_irq(&zone->lru_lock); + } + put_cpu_var(activate_page_pvecs); + return 1; +} + +#else +static inline void activate_page_drain(int cpu) +{ +} + +void activate_page(struct page *page) +{ + struct zone *zone = page_zone(page); + + spin_lock_irq(&zone->lru_lock); + if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) + __activate_page(page, NULL); spin_unlock_irq(&zone->lru_lock); } +#endif /* * Mark a page as having seen activity. @@ -372,6 +457,7 @@ static void drain_cpu_pagevecs(int cpu) pagevec_move_tail(pvec); local_irq_restore(flags); } + activate_page_drain(cpu); } void lru_add_drain(void) @@ -516,44 +602,33 @@ void lru_add_page_tail(struct zone* zone, } } +static void ____pagevec_lru_add_fn(struct page *page, void *arg) +{ + enum lru_list lru = (enum lru_list)arg; + struct zone *zone = page_zone(page); + int file = is_file_lru(lru); + int active = is_active_lru(lru); + + VM_BUG_ON(PageActive(page)); + VM_BUG_ON(PageUnevictable(page)); + VM_BUG_ON(PageLRU(page)); + + SetPageLRU(page); + if (active) + SetPageActive(page); + update_page_reclaim_stat(zone, page, file, active); + add_page_to_lru_list(zone, page, lru); +} + /* * Add the passed pages to the LRU, then drop the caller's refcount * on them. Reinitialises the caller's pagevec. */ void ____pagevec_lru_add(struct pagevec *pvec, enum lru_list lru) { - int i; - struct zone *zone = NULL; - VM_BUG_ON(is_unevictable_lru(lru)); - for (i = 0; i < pagevec_count(pvec); i++) { - struct page *page = pvec->pages[i]; - struct zone *pagezone = page_zone(page); - int file; - int active; - - if (pagezone != zone) { - if (zone) - spin_unlock_irq(&zone->lru_lock); - zone = pagezone; - spin_lock_irq(&zone->lru_lock); - } - VM_BUG_ON(PageActive(page)); - VM_BUG_ON(PageUnevictable(page)); - VM_BUG_ON(PageLRU(page)); - SetPageLRU(page); - active = is_active_lru(lru); - file = is_file_lru(lru); - if (active) - SetPageActive(page); - update_page_reclaim_stat(zone, page, file, active); - add_page_to_lru_list(zone, page, lru); - } - if (zone) - spin_unlock_irq(&zone->lru_lock); - release_pages(pvec->pages, pvec->nr, pvec->cold); - pagevec_reinit(pvec); + pagevec_lru_move_fn(pvec, ____pagevec_lru_add_fn, (void *)lru); } EXPORT_SYMBOL(____pagevec_lru_add); diff --git a/trunk/mm/vmscan.c b/trunk/mm/vmscan.c index 47a50962ce81..99999a9b2b0b 100644 --- a/trunk/mm/vmscan.c +++ b/trunk/mm/vmscan.c @@ -1271,14 +1271,16 @@ putback_lru_pages(struct zone *zone, struct scan_control *sc, spin_lock_irq(&zone->lru_lock); continue; } - SetPageLRU(page); lru = page_lru(page); - add_page_to_lru_list(zone, page, lru); if (is_active_lru(lru)) { int file = is_file_lru(lru); int numpages = hpage_nr_pages(page); reclaim_stat->recent_rotated[file] += numpages; + if (putback_active_lru_page(zone, page)) + continue; } + SetPageLRU(page); + add_page_to_lru_list(zone, page, lru); if (!pagevec_add(&pvec, page)) { spin_unlock_irq(&zone->lru_lock); __pagevec_release(&pvec); diff --git a/trunk/sound/pci/ac97/ac97_codec.c b/trunk/sound/pci/ac97/ac97_codec.c index cb62d178b3e0..0fc614ce16c1 100644 --- a/trunk/sound/pci/ac97/ac97_codec.c +++ b/trunk/sound/pci/ac97/ac97_codec.c @@ -1961,7 +1961,7 @@ static int snd_ac97_dev_disconnect(struct snd_device *device) } /* build_ops to do nothing */ -static const struct snd_ac97_build_ops null_build_ops; +static struct snd_ac97_build_ops null_build_ops; #ifdef CONFIG_SND_AC97_POWER_SAVE static void do_update_power(struct work_struct *work) diff --git a/trunk/sound/pci/ac97/ac97_patch.c b/trunk/sound/pci/ac97/ac97_patch.c index bf47574ca1f0..e68c98ef4041 100644 --- a/trunk/sound/pci/ac97/ac97_patch.c +++ b/trunk/sound/pci/ac97/ac97_patch.c @@ -371,7 +371,7 @@ static int patch_yamaha_ymf743_build_spdif(struct snd_ac97 *ac97) return 0; } -static const struct snd_ac97_build_ops patch_yamaha_ymf743_ops = { +static struct snd_ac97_build_ops patch_yamaha_ymf743_ops = { .build_spdif = patch_yamaha_ymf743_build_spdif, .build_3d = patch_yamaha_ymf7x3_3d, }; @@ -455,7 +455,7 @@ static int patch_yamaha_ymf753_post_spdif(struct snd_ac97 * ac97) return 0; } -static const struct snd_ac97_build_ops patch_yamaha_ymf753_ops = { +static struct snd_ac97_build_ops patch_yamaha_ymf753_ops = { .build_3d = patch_yamaha_ymf7x3_3d, .build_post_spdif = patch_yamaha_ymf753_post_spdif }; @@ -502,7 +502,7 @@ static int patch_wolfson_wm9703_specific(struct snd_ac97 * ac97) return 0; } -static const struct snd_ac97_build_ops patch_wolfson_wm9703_ops = { +static struct snd_ac97_build_ops patch_wolfson_wm9703_ops = { .build_specific = patch_wolfson_wm9703_specific, }; @@ -533,7 +533,7 @@ static int patch_wolfson_wm9704_specific(struct snd_ac97 * ac97) return 0; } -static const struct snd_ac97_build_ops patch_wolfson_wm9704_ops = { +static struct snd_ac97_build_ops patch_wolfson_wm9704_ops = { .build_specific = patch_wolfson_wm9704_specific, }; @@ -677,7 +677,7 @@ static int patch_wolfson_wm9711_specific(struct snd_ac97 * ac97) return 0; } -static const struct snd_ac97_build_ops patch_wolfson_wm9711_ops = { +static struct snd_ac97_build_ops patch_wolfson_wm9711_ops = { .build_specific = patch_wolfson_wm9711_specific, }; @@ -871,7 +871,7 @@ static void patch_wolfson_wm9713_resume (struct snd_ac97 * ac97) } #endif -static const struct snd_ac97_build_ops patch_wolfson_wm9713_ops = { +static struct snd_ac97_build_ops patch_wolfson_wm9713_ops = { .build_specific = patch_wolfson_wm9713_specific, .build_3d = patch_wolfson_wm9713_3d, #ifdef CONFIG_PM @@ -976,7 +976,7 @@ static int patch_sigmatel_stac97xx_specific(struct snd_ac97 * ac97) return 0; } -static const struct snd_ac97_build_ops patch_sigmatel_stac9700_ops = { +static struct snd_ac97_build_ops patch_sigmatel_stac9700_ops = { .build_3d = patch_sigmatel_stac9700_3d, .build_specific = patch_sigmatel_stac97xx_specific }; @@ -1023,7 +1023,7 @@ static int patch_sigmatel_stac9708_specific(struct snd_ac97 *ac97) return patch_sigmatel_stac97xx_specific(ac97); } -static const struct snd_ac97_build_ops patch_sigmatel_stac9708_ops = { +static struct snd_ac97_build_ops patch_sigmatel_stac9708_ops = { .build_3d = patch_sigmatel_stac9708_3d, .build_specific = patch_sigmatel_stac9708_specific }; @@ -1252,7 +1252,7 @@ static int patch_sigmatel_stac9758_specific(struct snd_ac97 *ac97) return 0; } -static const struct snd_ac97_build_ops patch_sigmatel_stac9758_ops = { +static struct snd_ac97_build_ops patch_sigmatel_stac9758_ops = { .build_3d = patch_sigmatel_stac9700_3d, .build_specific = patch_sigmatel_stac9758_specific }; @@ -1327,7 +1327,7 @@ static int patch_cirrus_build_spdif(struct snd_ac97 * ac97) return 0; } -static const struct snd_ac97_build_ops patch_cirrus_ops = { +static struct snd_ac97_build_ops patch_cirrus_ops = { .build_spdif = patch_cirrus_build_spdif }; @@ -1384,7 +1384,7 @@ static int patch_conexant_build_spdif(struct snd_ac97 * ac97) return 0; } -static const struct snd_ac97_build_ops patch_conexant_ops = { +static struct snd_ac97_build_ops patch_conexant_ops = { .build_spdif = patch_conexant_build_spdif }; @@ -1560,7 +1560,7 @@ static void patch_ad1881_chained(struct snd_ac97 * ac97, int unchained_idx, int } } -static const struct snd_ac97_build_ops patch_ad1881_build_ops = { +static struct snd_ac97_build_ops patch_ad1881_build_ops = { #ifdef CONFIG_PM .resume = ad18xx_resume #endif @@ -1647,7 +1647,7 @@ static int patch_ad1885_specific(struct snd_ac97 * ac97) return 0; } -static const struct snd_ac97_build_ops patch_ad1885_build_ops = { +static struct snd_ac97_build_ops patch_ad1885_build_ops = { .build_specific = &patch_ad1885_specific, #ifdef CONFIG_PM .resume = ad18xx_resume @@ -1674,7 +1674,7 @@ static int patch_ad1886_specific(struct snd_ac97 * ac97) return 0; } -static const struct snd_ac97_build_ops patch_ad1886_build_ops = { +static struct snd_ac97_build_ops patch_ad1886_build_ops = { .build_specific = &patch_ad1886_specific, #ifdef CONFIG_PM .resume = ad18xx_resume @@ -1881,7 +1881,7 @@ static int patch_ad1981a_specific(struct snd_ac97 * ac97) ARRAY_SIZE(snd_ac97_ad1981x_jack_sense)); } -static const struct snd_ac97_build_ops patch_ad1981a_build_ops = { +static struct snd_ac97_build_ops patch_ad1981a_build_ops = { .build_post_spdif = patch_ad198x_post_spdif, .build_specific = patch_ad1981a_specific, #ifdef CONFIG_PM @@ -1936,7 +1936,7 @@ static int patch_ad1981b_specific(struct snd_ac97 *ac97) ARRAY_SIZE(snd_ac97_ad1981x_jack_sense)); } -static const struct snd_ac97_build_ops patch_ad1981b_build_ops = { +static struct snd_ac97_build_ops patch_ad1981b_build_ops = { .build_post_spdif = patch_ad198x_post_spdif, .build_specific = patch_ad1981b_specific, #ifdef CONFIG_PM @@ -2075,7 +2075,7 @@ static int patch_ad1888_specific(struct snd_ac97 *ac97) return patch_build_controls(ac97, snd_ac97_ad1888_controls, ARRAY_SIZE(snd_ac97_ad1888_controls)); } -static const struct snd_ac97_build_ops patch_ad1888_build_ops = { +static struct snd_ac97_build_ops patch_ad1888_build_ops = { .build_post_spdif = patch_ad198x_post_spdif, .build_specific = patch_ad1888_specific, #ifdef CONFIG_PM @@ -2124,7 +2124,7 @@ static int patch_ad1980_specific(struct snd_ac97 *ac97) return patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1); } -static const struct snd_ac97_build_ops patch_ad1980_build_ops = { +static struct snd_ac97_build_ops patch_ad1980_build_ops = { .build_post_spdif = patch_ad198x_post_spdif, .build_specific = patch_ad1980_specific, #ifdef CONFIG_PM @@ -2239,7 +2239,7 @@ static int patch_ad1985_specific(struct snd_ac97 *ac97) ARRAY_SIZE(snd_ac97_ad1985_controls)); } -static const struct snd_ac97_build_ops patch_ad1985_build_ops = { +static struct snd_ac97_build_ops patch_ad1985_build_ops = { .build_post_spdif = patch_ad198x_post_spdif, .build_specific = patch_ad1985_specific, #ifdef CONFIG_PM @@ -2531,7 +2531,7 @@ static int patch_ad1986_specific(struct snd_ac97 *ac97) ARRAY_SIZE(snd_ac97_ad1985_controls)); } -static const struct snd_ac97_build_ops patch_ad1986_build_ops = { +static struct snd_ac97_build_ops patch_ad1986_build_ops = { .build_post_spdif = patch_ad198x_post_spdif, .build_specific = patch_ad1986_specific, #ifdef CONFIG_PM @@ -2636,7 +2636,7 @@ static int patch_alc650_specific(struct snd_ac97 * ac97) return 0; } -static const struct snd_ac97_build_ops patch_alc650_ops = { +static struct snd_ac97_build_ops patch_alc650_ops = { .build_specific = patch_alc650_specific, .update_jacks = alc650_update_jacks }; @@ -2788,7 +2788,7 @@ static int patch_alc655_specific(struct snd_ac97 * ac97) return 0; } -static const struct snd_ac97_build_ops patch_alc655_ops = { +static struct snd_ac97_build_ops patch_alc655_ops = { .build_specific = patch_alc655_specific, .update_jacks = alc655_update_jacks }; @@ -2900,7 +2900,7 @@ static int patch_alc850_specific(struct snd_ac97 *ac97) return 0; } -static const struct snd_ac97_build_ops patch_alc850_ops = { +static struct snd_ac97_build_ops patch_alc850_ops = { .build_specific = patch_alc850_specific, .update_jacks = alc850_update_jacks }; @@ -2962,7 +2962,7 @@ static int patch_cm9738_specific(struct snd_ac97 * ac97) return patch_build_controls(ac97, snd_ac97_cm9738_controls, ARRAY_SIZE(snd_ac97_cm9738_controls)); } -static const struct snd_ac97_build_ops patch_cm9738_ops = { +static struct snd_ac97_build_ops patch_cm9738_ops = { .build_specific = patch_cm9738_specific, .update_jacks = cm9738_update_jacks }; @@ -3053,7 +3053,7 @@ static int patch_cm9739_post_spdif(struct snd_ac97 * ac97) return patch_build_controls(ac97, snd_ac97_cm9739_controls_spdif, ARRAY_SIZE(snd_ac97_cm9739_controls_spdif)); } -static const struct snd_ac97_build_ops patch_cm9739_ops = { +static struct snd_ac97_build_ops patch_cm9739_ops = { .build_specific = patch_cm9739_specific, .build_post_spdif = patch_cm9739_post_spdif, .update_jacks = cm9739_update_jacks @@ -3227,7 +3227,7 @@ static int patch_cm9761_specific(struct snd_ac97 * ac97) return patch_build_controls(ac97, snd_ac97_cm9761_controls, ARRAY_SIZE(snd_ac97_cm9761_controls)); } -static const struct snd_ac97_build_ops patch_cm9761_ops = { +static struct snd_ac97_build_ops patch_cm9761_ops = { .build_specific = patch_cm9761_specific, .build_post_spdif = patch_cm9761_post_spdif, .update_jacks = cm9761_update_jacks @@ -3323,7 +3323,7 @@ static int patch_cm9780_specific(struct snd_ac97 *ac97) return patch_build_controls(ac97, cm9780_controls, ARRAY_SIZE(cm9780_controls)); } -static const struct snd_ac97_build_ops patch_cm9780_ops = { +static struct snd_ac97_build_ops patch_cm9780_ops = { .build_specific = patch_cm9780_specific, .build_post_spdif = patch_cm9761_post_spdif /* identical with CM9761 */ }; @@ -3443,7 +3443,7 @@ static int patch_vt1616_specific(struct snd_ac97 * ac97) return 0; } -static const struct snd_ac97_build_ops patch_vt1616_ops = { +static struct snd_ac97_build_ops patch_vt1616_ops = { .build_specific = patch_vt1616_specific }; @@ -3797,7 +3797,7 @@ static int patch_it2646_specific(struct snd_ac97 * ac97) return 0; } -static const struct snd_ac97_build_ops patch_it2646_ops = { +static struct snd_ac97_build_ops patch_it2646_ops = { .build_specific = patch_it2646_specific, .update_jacks = it2646_update_jacks }; @@ -3831,7 +3831,7 @@ static int patch_si3036_specific(struct snd_ac97 * ac97) return 0; } -static const struct snd_ac97_build_ops patch_si3036_ops = { +static struct snd_ac97_build_ops patch_si3036_ops = { .build_specific = patch_si3036_specific, }; @@ -3898,7 +3898,7 @@ static int patch_ucb1400_specific(struct snd_ac97 * ac97) return 0; } -static const struct snd_ac97_build_ops patch_ucb1400_ops = { +static struct snd_ac97_build_ops patch_ucb1400_ops = { .build_specific = patch_ucb1400_specific, }; diff --git a/trunk/sound/pci/au88x0/au88x0_pcm.c b/trunk/sound/pci/au88x0/au88x0_pcm.c index 5439d662d104..b9d2f202cf9b 100644 --- a/trunk/sound/pci/au88x0/au88x0_pcm.c +++ b/trunk/sound/pci/au88x0/au88x0_pcm.c @@ -42,7 +42,11 @@ static struct snd_pcm_hardware snd_vortex_playback_hw_adb = { .rate_min = 5000, .rate_max = 48000, .channels_min = 1, +#ifdef CHIP_AU8830 + .channels_max = 4, +#else .channels_max = 2, +#endif .buffer_bytes_max = 0x10000, .period_bytes_min = 0x1, .period_bytes_max = 0x1000, @@ -111,17 +115,6 @@ static struct snd_pcm_hardware snd_vortex_playback_hw_wt = { .periods_max = 64, }; #endif -#ifdef CHIP_AU8830 -static unsigned int au8830_channels[3] = { - 1, 2, 4, -}; - -static struct snd_pcm_hw_constraint_list hw_constraints_au8830_channels = { - .count = ARRAY_SIZE(au8830_channels), - .list = au8830_channels, - .mask = 0, -}; -#endif /* open callback */ static int snd_vortex_pcm_open(struct snd_pcm_substream *substream) { @@ -163,15 +156,6 @@ static int snd_vortex_pcm_open(struct snd_pcm_substream *substream) if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB || VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_I2S) runtime->hw = snd_vortex_playback_hw_adb; -#ifdef CHIP_AU8830 - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && - VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) { - runtime->hw.channels_max = 4; - snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - &hw_constraints_au8830_channels); - } -#endif substream->runtime->private_data = NULL; } #ifndef CHIP_AU8810 diff --git a/trunk/sound/pci/hda/hda_codec.c b/trunk/sound/pci/hda/hda_codec.c index ae5c5d5e4b7c..05e5ec88c2d9 100644 --- a/trunk/sound/pci/hda/hda_codec.c +++ b/trunk/sound/pci/hda/hda_codec.c @@ -2134,10 +2134,10 @@ int snd_hda_codec_reset(struct hda_codec *codec) * This function returns zero if successful or a negative error code. */ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, - unsigned int *tlv, const char * const *slaves) + unsigned int *tlv, const char **slaves) { struct snd_kcontrol *kctl; - const char * const *s; + const char **s; int err; for (s = slaves; *s && !snd_hda_find_mixer_ctl(codec, *s); s++) @@ -3689,7 +3689,7 @@ EXPORT_SYMBOL_HDA(snd_hda_build_pcms); * If no entries are matching, the function returns a negative value. */ int snd_hda_check_board_config(struct hda_codec *codec, - int num_configs, const char * const *models, + int num_configs, const char **models, const struct snd_pci_quirk *tbl) { if (codec->modelname && models) { @@ -3753,7 +3753,7 @@ EXPORT_SYMBOL_HDA(snd_hda_check_board_config); * If no entries are matching, the function returns a negative value. */ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec, - int num_configs, const char * const *models, + int num_configs, const char **models, const struct snd_pci_quirk *tbl) { const struct snd_pci_quirk *q; @@ -4690,7 +4690,7 @@ const char *hda_get_input_pin_label(struct hda_codec *codec, hda_nid_t pin, int check_location) { unsigned int def_conf; - static const char * const mic_names[] = { + static const char *mic_names[] = { "Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic", }; int attr; diff --git a/trunk/sound/pci/hda/hda_generic.c b/trunk/sound/pci/hda/hda_generic.c index a63c54d9d767..fb0582f8d725 100644 --- a/trunk/sound/pci/hda/hda_generic.c +++ b/trunk/sound/pci/hda/hda_generic.c @@ -762,8 +762,7 @@ static int check_existing_control(struct hda_codec *codec, const char *type, con /* * build output mixer controls */ -static int create_output_mixers(struct hda_codec *codec, - const char * const *names) +static int create_output_mixers(struct hda_codec *codec, const char **names) { struct hda_gspec *spec = codec->spec; int i, err; @@ -781,8 +780,8 @@ static int create_output_mixers(struct hda_codec *codec, static int build_output_controls(struct hda_codec *codec) { struct hda_gspec *spec = codec->spec; - static const char * const types_speaker[] = { "Speaker", "Headphone" }; - static const char * const types_line[] = { "Front", "Headphone" }; + static const char *types_speaker[] = { "Speaker", "Headphone" }; + static const char *types_line[] = { "Front", "Headphone" }; switch (spec->pcm_vol_nodes) { case 1: diff --git a/trunk/sound/pci/hda/hda_intel.c b/trunk/sound/pci/hda/hda_intel.c index 2e91a991eb15..d3d18be483e1 100644 --- a/trunk/sound/pci/hda/hda_intel.c +++ b/trunk/sound/pci/hda/hda_intel.c @@ -2809,8 +2809,6 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { #endif /* Vortex86MX */ { PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC }, - /* VMware HDAudio */ - { PCI_DEVICE(0x15ad, 0x1977), .driver_data = AZX_DRIVER_GENERIC }, /* AMD/ATI Generic, PCI class code and Vendor ID for HD Audio */ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, diff --git a/trunk/sound/pci/hda/hda_local.h b/trunk/sound/pci/hda/hda_local.h index 3ab5e7a303db..46bbefe2e4a9 100644 --- a/trunk/sound/pci/hda/hda_local.h +++ b/trunk/sound/pci/hda/hda_local.h @@ -140,7 +140,7 @@ void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, const char *name); int snd_hda_add_vmaster(struct hda_codec *codec, char *name, - unsigned int *tlv, const char * const *slaves); + unsigned int *tlv, const char **slaves); int snd_hda_codec_reset(struct hda_codec *codec); /* amp value bits */ @@ -341,10 +341,10 @@ void snd_print_pcm_bits(int pcm, char *buf, int buflen); * Misc */ int snd_hda_check_board_config(struct hda_codec *codec, int num_configs, - const char * const *modelnames, + const char **modelnames, const struct snd_pci_quirk *pci_list); int snd_hda_check_board_codec_sid_config(struct hda_codec *codec, - int num_configs, const char * const *models, + int num_configs, const char **models, const struct snd_pci_quirk *tbl); int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew); diff --git a/trunk/sound/pci/hda/hda_proc.c b/trunk/sound/pci/hda/hda_proc.c index bfe74c2fb079..f025200f2a62 100644 --- a/trunk/sound/pci/hda/hda_proc.c +++ b/trunk/sound/pci/hda/hda_proc.c @@ -418,7 +418,7 @@ static void print_digital_conv(struct snd_info_buffer *buffer, static const char *get_pwr_state(u32 state) { - static const char * const buf[4] = { + static const char *buf[4] = { "D0", "D1", "D2", "D3" }; if (state < 4) diff --git a/trunk/sound/pci/hda/patch_analog.c b/trunk/sound/pci/hda/patch_analog.c index 8dabab798689..46780670162b 100644 --- a/trunk/sound/pci/hda/patch_analog.c +++ b/trunk/sound/pci/hda/patch_analog.c @@ -46,9 +46,6 @@ struct ad198x_spec { unsigned int cur_eapd; unsigned int need_dac_fix; - hda_nid_t *alt_dac_nid; - struct hda_pcm_stream *stream_analog_alt_playback; - /* capture */ unsigned int num_adc_nids; hda_nid_t *adc_nids; @@ -84,8 +81,8 @@ struct ad198x_spec { #endif /* for virtual master */ hda_nid_t vmaster_nid; - const char * const *slave_vols; - const char * const *slave_sws; + const char **slave_vols; + const char **slave_sws; }; /* @@ -133,7 +130,7 @@ static int ad198x_init(struct hda_codec *codec) return 0; } -static const char * const ad_slave_vols[] = { +static const char *ad_slave_vols[] = { "Front Playback Volume", "Surround Playback Volume", "Center Playback Volume", @@ -146,7 +143,7 @@ static const char * const ad_slave_vols[] = { NULL }; -static const char * const ad_slave_sws[] = { +static const char *ad_slave_sws[] = { "Front Playback Switch", "Surround Playback Switch", "Center Playback Switch", @@ -159,25 +156,6 @@ static const char * const ad_slave_sws[] = { NULL }; -static const char * const ad1988_6stack_fp_slave_vols[] = { - "Front Playback Volume", - "Surround Playback Volume", - "Center Playback Volume", - "LFE Playback Volume", - "Side Playback Volume", - "IEC958 Playback Volume", - NULL -}; - -static const char * const ad1988_6stack_fp_slave_sws[] = { - "Front Playback Switch", - "Surround Playback Switch", - "Center Playback Switch", - "LFE Playback Switch", - "Side Playback Switch", - "IEC958 Playback Switch", - NULL -}; static void ad198x_free_kctls(struct hda_codec *codec); #ifdef CONFIG_SND_HDA_INPUT_BEEP @@ -331,38 +309,6 @@ static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); } -static int ad198x_alt_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - snd_hda_codec_setup_stream(codec, spec->alt_dac_nid[0], stream_tag, - 0, format); - return 0; -} - -static int ad198x_alt_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - snd_hda_codec_cleanup_stream(codec, spec->alt_dac_nid[0]); - return 0; -} - -static struct hda_pcm_stream ad198x_pcm_analog_alt_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in ad198x_build_pcms */ - .ops = { - .prepare = ad198x_alt_playback_pcm_prepare, - .cleanup = ad198x_alt_playback_pcm_cleanup - }, -}; - /* * Digital out */ @@ -500,17 +446,6 @@ static int ad198x_build_pcms(struct hda_codec *codec) } } - if (spec->alt_dac_nid && spec->stream_analog_alt_playback) { - codec->num_pcms++; - info = spec->pcm_rec + 2; - info->name = "AD198x Headphone"; - info->pcm_type = HDA_PCM_TYPE_AUDIO; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - *spec->stream_analog_alt_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->alt_dac_nid[0]; - } - return 0; } @@ -1134,7 +1069,7 @@ enum { AD1986A_MODELS }; -static const char * const ad1986a_models[AD1986A_MODELS] = { +static const char *ad1986a_models[AD1986A_MODELS] = { [AD1986A_6STACK] = "6stack", [AD1986A_3STACK] = "3stack", [AD1986A_LAPTOP] = "laptop", @@ -1878,7 +1813,7 @@ enum { AD1981_MODELS }; -static const char * const ad1981_models[AD1981_MODELS] = { +static const char *ad1981_models[AD1981_MODELS] = { [AD1981_HP] = "hp", [AD1981_THINKPAD] = "thinkpad", [AD1981_BASIC] = "basic", @@ -2080,7 +2015,6 @@ static int patch_ad1981(struct hda_codec *codec) enum { AD1988_6STACK, AD1988_6STACK_DIG, - AD1988_6STACK_DIG_FP, AD1988_3STACK, AD1988_3STACK_DIG, AD1988_LAPTOP, @@ -2113,10 +2047,6 @@ static hda_nid_t ad1988_6stack_dac_nids_rev2[4] = { 0x04, 0x05, 0x0a, 0x06 }; -static hda_nid_t ad1988_alt_dac_nid[1] = { - 0x03 -}; - static hda_nid_t ad1988_3stack_dac_nids_rev2[3] = { 0x04, 0x0a, 0x06 }; @@ -2236,35 +2166,6 @@ static struct snd_kcontrol_new ad1988_6stack_mixers2[] = { { } /* end */ }; -static struct snd_kcontrol_new ad1988_6stack_fp_mixers[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - - HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT), - HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), - - HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT), - - HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT), - - { } /* end */ -}; - /* 3-stack mode */ static struct snd_kcontrol_new ad1988_3stack_mixers1[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), @@ -2544,68 +2445,6 @@ static struct hda_verb ad1988_6stack_init_verbs[] = { { } }; -static struct hda_verb ad1988_6stack_fp_init_verbs[] = { - /* Front, Surround, CLFE, side DAC; unmute as default */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Headphone; unmute as default */ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Port-A front headphon path */ - {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Port-D line-out path */ - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Port-F surround path */ - {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Port-G CLFE path */ - {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Port-H side path */ - {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Mono out path */ - {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */ - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */ - /* Port-B front mic-in path */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* Port-C line-in path */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x33, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Port-E mic-in path */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x34, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Analog CD Input */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Analog Mix output amp */ - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ - - { } -}; - static struct hda_verb ad1988_capture_init_verbs[] = { /* mute analog mix */ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, @@ -2953,9 +2792,7 @@ static int ad1988_auto_create_multi_out_ctls(struct ad198x_spec *spec, const struct auto_pin_cfg *cfg) { char name[32]; - static const char * const chname[4] = { - "Front", "Surround", NULL /*CLFE*/, "Side" - }; + static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; hda_nid_t nid; int i, err; @@ -3237,13 +3074,13 @@ static int ad1988_auto_init(struct hda_codec *codec) return 0; } + /* */ -static const char * const ad1988_models[AD1988_MODEL_LAST] = { +static const char *ad1988_models[AD1988_MODEL_LAST] = { [AD1988_6STACK] = "6stack", [AD1988_6STACK_DIG] = "6stack-dig", - [AD1988_6STACK_DIG_FP] = "6stack-dig-fp", [AD1988_3STACK] = "3stack", [AD1988_3STACK_DIG] = "3stack-dig", [AD1988_LAPTOP] = "laptop", @@ -3303,7 +3140,6 @@ static int patch_ad1988(struct hda_codec *codec) switch (board_config) { case AD1988_6STACK: case AD1988_6STACK_DIG: - case AD1988_6STACK_DIG_FP: spec->multiout.max_channels = 8; spec->multiout.num_dacs = 4; if (is_rev2(codec)) @@ -3316,22 +3152,10 @@ static int patch_ad1988(struct hda_codec *codec) spec->mixers[0] = ad1988_6stack_mixers1_rev2; else spec->mixers[0] = ad1988_6stack_mixers1; - if (board_config == AD1988_6STACK_DIG_FP) { - spec->mixers[1] = ad1988_6stack_fp_mixers; - spec->slave_vols = ad1988_6stack_fp_slave_vols; - spec->slave_sws = ad1988_6stack_fp_slave_sws; - spec->alt_dac_nid = ad1988_alt_dac_nid; - spec->stream_analog_alt_playback = - &ad198x_pcm_analog_alt_playback; - } else - spec->mixers[1] = ad1988_6stack_mixers2; + spec->mixers[1] = ad1988_6stack_mixers2; spec->num_init_verbs = 1; - if (board_config == AD1988_6STACK_DIG_FP) - spec->init_verbs[0] = ad1988_6stack_fp_init_verbs; - else - spec->init_verbs[0] = ad1988_6stack_init_verbs; - if ((board_config == AD1988_6STACK_DIG) || - (board_config == AD1988_6STACK_DIG_FP)) { + spec->init_verbs[0] = ad1988_6stack_init_verbs; + if (board_config == AD1988_6STACK_DIG) { spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; spec->dig_in_nid = AD1988_SPDIF_IN; } @@ -3575,7 +3399,7 @@ static struct hda_amp_list ad1884_loopbacks[] = { }; #endif -static const char * const ad1884_slave_vols[] = { +static const char *ad1884_slave_vols[] = { "PCM Playback Volume", "Mic Playback Volume", "Mono Playback Volume", @@ -3813,7 +3637,7 @@ enum { AD1984_MODELS }; -static const char * const ad1984_models[AD1984_MODELS] = { +static const char *ad1984_models[AD1984_MODELS] = { [AD1984_BASIC] = "basic", [AD1984_THINKPAD] = "thinkpad", [AD1984_DELL_DESKTOP] = "dell_desktop", @@ -4484,7 +4308,7 @@ enum { AD1884A_MODELS }; -static const char * const ad1884a_models[AD1884A_MODELS] = { +static const char *ad1884a_models[AD1884A_MODELS] = { [AD1884A_DESKTOP] = "desktop", [AD1884A_LAPTOP] = "laptop", [AD1884A_MOBILE] = "mobile", @@ -4872,7 +4696,7 @@ enum { AD1882_MODELS }; -static const char * const ad1882_models[AD1986A_MODELS] = { +static const char *ad1882_models[AD1986A_MODELS] = { [AD1882_3STACK] = "3stack", [AD1882_6STACK] = "6stack", }; diff --git a/trunk/sound/pci/hda/patch_cirrus.c b/trunk/sound/pci/hda/patch_cirrus.c index a07b031090d8..18af38ebf757 100644 --- a/trunk/sound/pci/hda/patch_cirrus.c +++ b/trunk/sound/pci/hda/patch_cirrus.c @@ -490,7 +490,7 @@ static int parse_digital_input(struct hda_codec *codec) * create mixer controls */ -static const char * const dir_sfx[2] = { "Playback", "Capture" }; +static const char *dir_sfx[2] = { "Playback", "Capture" }; static int add_mute(struct hda_codec *codec, const char *name, int index, unsigned int pval, int dir, struct snd_kcontrol **kctlp) @@ -1156,7 +1156,7 @@ static int cs_parse_auto_config(struct hda_codec *codec) return 0; } -static const char * const cs420x_models[CS420X_MODELS] = { +static const char *cs420x_models[CS420X_MODELS] = { [CS420X_MBP53] = "mbp53", [CS420X_MBP55] = "mbp55", [CS420X_IMAC27] = "imac27", diff --git a/trunk/sound/pci/hda/patch_cmedia.c b/trunk/sound/pci/hda/patch_cmedia.c index 1f8bbcd0f802..ff60908f4554 100644 --- a/trunk/sound/pci/hda/patch_cmedia.c +++ b/trunk/sound/pci/hda/patch_cmedia.c @@ -608,7 +608,7 @@ static void cmi9880_free(struct hda_codec *codec) /* */ -static const char * const cmi9880_models[CMI_MODELS] = { +static const char *cmi9880_models[CMI_MODELS] = { [CMI_MINIMAL] = "minimal", [CMI_MIN_FP] = "min_fp", [CMI_FULL] = "full", diff --git a/trunk/sound/pci/hda/patch_conexant.c b/trunk/sound/pci/hda/patch_conexant.c index 9bb030a469cd..e96581fcdbdb 100644 --- a/trunk/sound/pci/hda/patch_conexant.c +++ b/trunk/sound/pci/hda/patch_conexant.c @@ -537,13 +537,13 @@ static struct snd_kcontrol_new cxt_beep_mixer[] = { }; #endif -static const char * const slave_vols[] = { +static const char *slave_vols[] = { "Headphone Playback Volume", "Speaker Playback Volume", NULL }; -static const char * const slave_sws[] = { +static const char *slave_sws[] = { "Headphone Playback Switch", "Speaker Playback Switch", NULL @@ -1134,7 +1134,7 @@ enum { CXT5045_MODELS }; -static const char * const cxt5045_models[CXT5045_MODELS] = { +static const char *cxt5045_models[CXT5045_MODELS] = { [CXT5045_LAPTOP_HPSENSE] = "laptop-hpsense", [CXT5045_LAPTOP_MICSENSE] = "laptop-micsense", [CXT5045_LAPTOP_HPMICSENSE] = "laptop-hpmicsense", @@ -1579,7 +1579,7 @@ enum { CXT5047_MODELS }; -static const char * const cxt5047_models[CXT5047_MODELS] = { +static const char *cxt5047_models[CXT5047_MODELS] = { [CXT5047_LAPTOP] = "laptop", [CXT5047_LAPTOP_HP] = "laptop-hp", [CXT5047_LAPTOP_EAPD] = "laptop-eapd", @@ -1995,7 +1995,7 @@ enum { CXT5051_MODELS }; -static const char *const cxt5051_models[CXT5051_MODELS] = { +static const char *cxt5051_models[CXT5051_MODELS] = { [CXT5051_LAPTOP] = "laptop", [CXT5051_HP] = "hp", [CXT5051_HP_DV6736] = "hp-dv6736", @@ -3084,7 +3084,7 @@ enum { CXT5066_MODELS }; -static const char * const cxt5066_models[CXT5066_MODELS] = { +static const char *cxt5066_models[CXT5066_MODELS] = { [CXT5066_LAPTOP] = "laptop", [CXT5066_DELL_LAPTOP] = "dell-laptop", [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5", @@ -3746,7 +3746,7 @@ static int cx_auto_build_output_controls(struct hda_codec *codec) struct conexant_spec *spec = codec->spec; int i, err; int num_line = 0, num_hp = 0, num_spk = 0; - static const char * const texts[3] = { "Front", "Surround", "CLFE" }; + static const char *texts[3] = { "Front", "Surround", "CLFE" }; if (spec->dac_info_filled == 1) return cx_auto_add_pb_volume(codec, spec->dac_info[0].dac, diff --git a/trunk/sound/pci/hda/patch_hdmi.c b/trunk/sound/pci/hda/patch_hdmi.c index 2d5b83fa8d24..f29b97b5de8f 100644 --- a/trunk/sound/pci/hda/patch_hdmi.c +++ b/trunk/sound/pci/hda/patch_hdmi.c @@ -817,7 +817,6 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, struct hdmi_spec *spec = codec->spec; struct hdmi_eld *eld; struct hda_pcm_stream *codec_pars; - struct snd_pcm_runtime *runtime = substream->runtime; unsigned int idx; for (idx = 0; idx < spec->num_cvts; idx++) @@ -845,14 +844,6 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, hinfo->formats = codec_pars->formats; hinfo->maxbps = codec_pars->maxbps; } - /* store the updated parameters */ - runtime->hw.channels_min = hinfo->channels_min; - runtime->hw.channels_max = hinfo->channels_max; - runtime->hw.formats = hinfo->formats; - runtime->hw.rates = hinfo->rates; - - snd_pcm_hw_constraint_step(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, 2); return 0; } @@ -1247,9 +1238,6 @@ static int simple_playback_pcm_open(struct hda_pcm_stream *hinfo, snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, hw_constraints_channels); - } else { - snd_pcm_hw_constraint_step(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, 2); } return snd_hda_multi_out_dig_open(codec, &spec->multiout); diff --git a/trunk/sound/pci/hda/patch_realtek.c b/trunk/sound/pci/hda/patch_realtek.c index 269dbff70b92..51c08edd7563 100644 --- a/trunk/sound/pci/hda/patch_realtek.c +++ b/trunk/sound/pci/hda/patch_realtek.c @@ -303,8 +303,6 @@ struct alc_customize_define { unsigned int fixup:1; /* Means that this sku is set by driver, not read from hw */ }; -struct alc_fixup; - struct alc_spec { /* codec parameterization */ struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ @@ -406,11 +404,6 @@ struct alc_spec { /* for PLL fix */ hda_nid_t pll_nid; unsigned int pll_coef_idx, pll_coef_bit; - - /* fix-up list */ - int fixup_id; - const struct alc_fixup *fixup_list; - const char *fixup_name; }; /* @@ -1690,131 +1683,88 @@ struct alc_model_fixup { }; struct alc_fixup { - int type; - bool chained; - int chain_id; - union { - unsigned int sku; - const struct alc_pincfg *pins; - const struct hda_verb *verbs; - void (*func)(struct hda_codec *codec, - const struct alc_fixup *fix, - int action); - } v; -}; - -enum { - ALC_FIXUP_INVALID, - ALC_FIXUP_SKU, - ALC_FIXUP_PINS, - ALC_FIXUP_VERBS, - ALC_FIXUP_FUNC, + unsigned int sku; + const struct alc_pincfg *pins; + const struct hda_verb *verbs; + void (*func)(struct hda_codec *codec, const struct alc_fixup *fix, + int pre_init); }; -enum { - ALC_FIXUP_ACT_PRE_PROBE, - ALC_FIXUP_ACT_PROBE, - ALC_FIXUP_ACT_INIT, -}; - -static void alc_apply_fixup(struct hda_codec *codec, int action) +static void __alc_pick_fixup(struct hda_codec *codec, + const struct alc_fixup *fix, + const char *modelname, + int pre_init) { - struct alc_spec *spec = codec->spec; - int id = spec->fixup_id; - const char *modelname = spec->fixup_name; - int depth = 0; - - if (!spec->fixup_list) - return; + const struct alc_pincfg *cfg; + struct alc_spec *spec; - while (id >= 0) { - const struct alc_fixup *fix = spec->fixup_list + id; - const struct alc_pincfg *cfg; - - switch (fix->type) { - case ALC_FIXUP_SKU: - if (action != ALC_FIXUP_ACT_PRE_PROBE || !fix->v.sku) - break;; - snd_printdd(KERN_INFO "hda_codec: %s: " - "Apply sku override for %s\n", - codec->chip_name, modelname); - spec->cdefine.sku_cfg = fix->v.sku; - spec->cdefine.fixup = 1; - break; - case ALC_FIXUP_PINS: - cfg = fix->v.pins; - if (action != ALC_FIXUP_ACT_PRE_PROBE || !cfg) - break; - snd_printdd(KERN_INFO "hda_codec: %s: " - "Apply pincfg for %s\n", - codec->chip_name, modelname); - for (; cfg->nid; cfg++) - snd_hda_codec_set_pincfg(codec, cfg->nid, - cfg->val); - break; - case ALC_FIXUP_VERBS: - if (action != ALC_FIXUP_ACT_PROBE || !fix->v.verbs) - break; - snd_printdd(KERN_INFO "hda_codec: %s: " - "Apply fix-verbs for %s\n", - codec->chip_name, modelname); - add_verb(codec->spec, fix->v.verbs); - break; - case ALC_FIXUP_FUNC: - if (!fix->v.func) - break; - snd_printdd(KERN_INFO "hda_codec: %s: " - "Apply fix-func for %s\n", - codec->chip_name, modelname); - fix->v.func(codec, fix, action); - break; - default: - snd_printk(KERN_ERR "hda_codec: %s: " - "Invalid fixup type %d\n", - codec->chip_name, fix->type); - break; - } - if (!fix[id].chained) - break; - if (++depth > 10) - break; - id = fix[id].chain_id; + cfg = fix->pins; + if (pre_init && fix->sku) { +#ifdef CONFIG_SND_DEBUG_VERBOSE + snd_printdd(KERN_INFO "hda_codec: %s: Apply sku override for %s\n", + codec->chip_name, modelname); +#endif + spec = codec->spec; + spec->cdefine.sku_cfg = fix->sku; + spec->cdefine.fixup = 1; + } + if (pre_init && cfg) { +#ifdef CONFIG_SND_DEBUG_VERBOSE + snd_printdd(KERN_INFO "hda_codec: %s: Apply pincfg for %s\n", + codec->chip_name, modelname); +#endif + for (; cfg->nid; cfg++) + snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val); + } + if (!pre_init && fix->verbs) { +#ifdef CONFIG_SND_DEBUG_VERBOSE + snd_printdd(KERN_INFO "hda_codec: %s: Apply fix-verbs for %s\n", + codec->chip_name, modelname); +#endif + add_verb(codec->spec, fix->verbs); + } + if (fix->func) { +#ifdef CONFIG_SND_DEBUG_VERBOSE + snd_printdd(KERN_INFO "hda_codec: %s: Apply fix-func for %s\n", + codec->chip_name, modelname); +#endif + fix->func(codec, fix, pre_init); } } static void alc_pick_fixup(struct hda_codec *codec, - const struct alc_model_fixup *models, - const struct snd_pci_quirk *quirk, - const struct alc_fixup *fixlist) + const struct snd_pci_quirk *quirk, + const struct alc_fixup *fix, + int pre_init) { - struct alc_spec *spec = codec->spec; - int id = -1; - const char *name = NULL; + quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk); + if (quirk) { + fix += quirk->value; +#ifdef CONFIG_SND_DEBUG_VERBOSE + __alc_pick_fixup(codec, fix, quirk->name, pre_init); +#else + __alc_pick_fixup(codec, fix, NULL, pre_init); +#endif + } +} +static void alc_pick_fixup_model(struct hda_codec *codec, + const struct alc_model_fixup *models, + const struct snd_pci_quirk *quirk, + const struct alc_fixup *fix, + int pre_init) +{ if (codec->modelname && models) { while (models->name) { if (!strcmp(codec->modelname, models->name)) { - id = models->id; - name = models->name; + fix += models->id; break; } models++; } - } - if (id < 0) { - quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk); - if (quirk) { - id = quirk->value; -#ifdef CONFIG_SND_DEBUG_VERBOSE - name = quirk->name; -#endif - } - } - - spec->fixup_id = id; - if (id >= 0) { - spec->fixup_list = fixlist; - spec->fixup_name = name; + __alc_pick_fixup(codec, fix, codec->modelname, pre_init); + } else { + alc_pick_fixup(codec, quirk, fix, pre_init); } } @@ -2916,7 +2866,7 @@ static struct snd_kcontrol_new alc880_uniwill_p53_mixer[] = { /* * slave controls for virtual master */ -static const char * const alc_slave_vols[] = { +static const char *alc_slave_vols[] = { "Front Playback Volume", "Surround Playback Volume", "Center Playback Volume", @@ -2930,7 +2880,7 @@ static const char * const alc_slave_vols[] = { NULL, }; -static const char * const alc_slave_sws[] = { +static const char *alc_slave_sws[] = { "Front Playback Switch", "Surround Playback Switch", "Center Playback Switch", @@ -3911,8 +3861,6 @@ static int alc_init(struct hda_codec *codec) if (spec->init_hook) spec->init_hook(codec); - alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT); - hda_call_check_power_status(codec, 0x01); return 0; } @@ -4611,7 +4559,7 @@ static struct hda_verb alc880_test_init_verbs[] = { /* */ -static const char * const alc880_models[ALC880_MODEL_LAST] = { +static const char *alc880_models[ALC880_MODEL_LAST] = { [ALC880_3ST] = "3stack", [ALC880_TCL_S700] = "tcl", [ALC880_3ST_DIG] = "3stack-digout", @@ -5144,7 +5092,7 @@ static const char *alc_get_line_out_pfx(const struct auto_pin_cfg *cfg, static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) { - static const char * const chname[4] = { + static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; const char *pfx = alc_get_line_out_pfx(cfg, false); @@ -7142,8 +7090,7 @@ enum { static const struct alc_fixup alc260_fixups[] = { [PINFIX_HP_DC5750] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .pins = (const struct alc_pincfg[]) { { 0x11, 0x90130110 }, /* speaker */ { } } @@ -7158,7 +7105,7 @@ static struct snd_pci_quirk alc260_fixup_tbl[] = { /* * ALC260 configurations */ -static const char * const alc260_models[ALC260_MODEL_LAST] = { +static const char *alc260_models[ALC260_MODEL_LAST] = { [ALC260_BASIC] = "basic", [ALC260_HP] = "hp", [ALC260_HP_3013] = "hp-3013", @@ -7354,10 +7301,8 @@ static int patch_alc260(struct hda_codec *codec) board_config = ALC260_AUTO; } - if (board_config == ALC260_AUTO) { - alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); - } + if (board_config == ALC260_AUTO) + alc_pick_fixup(codec, alc260_fixup_tbl, alc260_fixups, 1); if (board_config == ALC260_AUTO) { /* automatic parse from the BIOS config */ @@ -7405,7 +7350,8 @@ static int patch_alc260(struct hda_codec *codec) set_capture_mixer(codec); set_beep_amp(spec, 0x07, 0x05, HDA_INPUT); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + if (board_config == ALC260_AUTO) + alc_pick_fixup(codec, alc260_fixup_tbl, alc260_fixups, 0); spec->vmaster_nid = 0x08; @@ -9781,7 +9727,7 @@ static hda_nid_t alc1200_slave_dig_outs[] = { /* * configuration and preset */ -static const char * const alc882_models[ALC882_MODEL_LAST] = { +static const char *alc882_models[ALC882_MODEL_LAST] = { [ALC882_3ST_DIG] = "3stack-dig", [ALC882_6ST_DIG] = "6stack-dig", [ALC882_ARIMA] = "arima", @@ -10732,8 +10678,7 @@ enum { static const struct alc_fixup alc882_fixups[] = { [PINFIX_ABIT_AW9D_MAX] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .pins = (const struct alc_pincfg[]) { { 0x15, 0x01080104 }, /* side */ { 0x16, 0x01011012 }, /* rear */ { 0x17, 0x01016011 }, /* clfe */ @@ -10741,15 +10686,13 @@ static const struct alc_fixup alc882_fixups[] = { } }, [PINFIX_PB_M5210] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { + .verbs = (const struct hda_verb[]) { { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 }, {} } }, [PINFIX_ACER_ASPIRE_7736] = { - .type = ALC_FIXUP_SKU, - .v.sku = ALC_FIXUP_SKU_IGNORE, + .sku = ALC_FIXUP_SKU_IGNORE, }, }; @@ -11041,10 +10984,8 @@ static int patch_alc882(struct hda_codec *codec) board_config = ALC882_AUTO; } - if (board_config == ALC882_AUTO) { - alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); - } + if (board_config == ALC882_AUTO) + alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 1); alc_auto_parse_customize_define(codec); @@ -11120,7 +11061,8 @@ static int patch_alc882(struct hda_codec *codec) if (has_cdefine_beep(codec)) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + if (board_config == ALC882_AUTO) + alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups, 0); spec->vmaster_nid = 0x0c; @@ -12510,14 +12452,19 @@ enum { static const struct alc_fixup alc262_fixups[] = { [PINFIX_FSC_H270] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .pins = (const struct alc_pincfg[]) { { 0x14, 0x99130110 }, /* speaker */ { 0x15, 0x0221142f }, /* front HP */ { 0x1b, 0x0121141f }, /* rear HP */ { } } }, + [PINFIX_PB_M5210] = { + .verbs = (const struct hda_verb[]) { + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 }, + {} + } + }, }; static struct snd_pci_quirk alc262_fixup_tbl[] = { @@ -12607,7 +12554,7 @@ static void alc262_auto_init(struct hda_codec *codec) /* * configuration and preset */ -static const char * const alc262_models[ALC262_MODEL_LAST] = { +static const char *alc262_models[ALC262_MODEL_LAST] = { [ALC262_BASIC] = "basic", [ALC262_HIPPO] = "hippo", [ALC262_HIPPO_1] = "hippo_1", @@ -12948,10 +12895,8 @@ static int patch_alc262(struct hda_codec *codec) board_config = ALC262_AUTO; } - if (board_config == ALC262_AUTO) { - alc_pick_fixup(codec, NULL, alc262_fixup_tbl, alc262_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); - } + if (board_config == ALC262_AUTO) + alc_pick_fixup(codec, alc262_fixup_tbl, alc262_fixups, 1); if (board_config == ALC262_AUTO) { /* automatic parse from the BIOS config */ @@ -13021,7 +12966,8 @@ static int patch_alc262(struct hda_codec *codec) if (!spec->no_analog && has_cdefine_beep(codec)) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + if (board_config == ALC262_AUTO) + alc_pick_fixup(codec, alc262_fixup_tbl, alc262_fixups, 0); spec->vmaster_nid = 0x0c; @@ -13795,7 +13741,7 @@ static void alc268_auto_init(struct hda_codec *codec) /* * configuration and preset */ -static const char * const alc268_models[ALC268_MODEL_LAST] = { +static const char *alc268_models[ALC268_MODEL_LAST] = { [ALC267_QUANTA_IL1] = "quanta-il1", [ALC268_3ST] = "3stack", [ALC268_TOSHIBA] = "toshiba", @@ -14876,19 +14822,17 @@ static int alc269_resume(struct hda_codec *codec) #endif /* SND_HDA_NEEDS_RESUME */ static void alc269_fixup_hweq(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct alc_fixup *fix, int pre_init) { int coef; - if (action != ALC_FIXUP_ACT_INIT) - return; coef = alc_read_coef_idx(codec, 0x1e); alc_write_coef_idx(codec, 0x1e, coef | 0x80); } enum { ALC269_FIXUP_SONY_VAIO, - ALC275_FIXUP_SONY_VAIO_GPIO2, + ALC275_FIX_SONY_VAIO_GPIO2, ALC269_FIXUP_DELL_M101Z, ALC269_FIXUP_SKU_IGNORE, ALC269_FIXUP_ASUS_G73JW, @@ -14898,26 +14842,22 @@ enum { static const struct alc_fixup alc269_fixups[] = { [ALC269_FIXUP_SONY_VAIO] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { + .verbs = (const struct hda_verb[]) { {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD}, {} } }, - [ALC275_FIXUP_SONY_VAIO_GPIO2] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { + [ALC275_FIX_SONY_VAIO_GPIO2] = { + .verbs = (const struct hda_verb[]) { {0x01, AC_VERB_SET_GPIO_MASK, 0x04}, {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04}, {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD}, { } - }, - .chained = true, - .chain_id = ALC269_FIXUP_SONY_VAIO + } }, [ALC269_FIXUP_DELL_M101Z] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { + .verbs = (const struct hda_verb[]) { /* Enables internal speaker */ {0x20, AC_VERB_SET_COEF_INDEX, 13}, {0x20, AC_VERB_SET_PROC_COEF, 0x4040}, @@ -14925,33 +14865,34 @@ static const struct alc_fixup alc269_fixups[] = { } }, [ALC269_FIXUP_SKU_IGNORE] = { - .type = ALC_FIXUP_SKU, - .v.sku = ALC_FIXUP_SKU_IGNORE, + .sku = ALC_FIXUP_SKU_IGNORE, }, [ALC269_FIXUP_ASUS_G73JW] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .pins = (const struct alc_pincfg[]) { { 0x17, 0x99130111 }, /* subwoofer */ { } } }, [ALC269_FIXUP_LENOVO_EAPD] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { + .verbs = (const struct hda_verb[]) { {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0}, {} } }, [ALC275_FIXUP_SONY_HWEQ] = { - .type = ALC_FIXUP_FUNC, - .v.func = alc269_fixup_hweq, - .chained = true, - .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2 + .func = alc269_fixup_hweq, + .verbs = (const struct hda_verb[]) { + {0x01, AC_VERB_SET_GPIO_MASK, 0x04}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD}, + { } + } } }; static struct snd_pci_quirk alc269_fixup_tbl[] = { - SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2), + SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIX_SONY_VAIO_GPIO2), SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), @@ -14967,7 +14908,7 @@ static struct snd_pci_quirk alc269_fixup_tbl[] = { /* * configuration and preset */ -static const char * const alc269_models[ALC269_MODEL_LAST] = { +static const char *alc269_models[ALC269_MODEL_LAST] = { [ALC269_BASIC] = "basic", [ALC269_QUANTA_FL1] = "quanta", [ALC269_AMIC] = "laptop-amic", @@ -15243,10 +15184,8 @@ static int patch_alc269(struct hda_codec *codec) board_config = ALC269_AUTO; } - if (board_config == ALC269_AUTO) { - alc_pick_fixup(codec, NULL, alc269_fixup_tbl, alc269_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); - } + if (board_config == ALC269_AUTO) + alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 1); if (board_config == ALC269_AUTO) { /* automatic parse from the BIOS config */ @@ -15307,7 +15246,8 @@ static int patch_alc269(struct hda_codec *codec) if (has_cdefine_beep(codec)) set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + if (board_config == ALC269_AUTO) + alc_pick_fixup(codec, alc269_fixup_tbl, alc269_fixups, 0); spec->vmaster_nid = 0x02; @@ -16010,7 +15950,7 @@ static int alc861_auto_create_multi_out_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { struct alc_spec *spec = codec->spec; - static const char * const chname[4] = { + static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; const char *pfx = alc_get_line_out_pfx(cfg, true); @@ -16216,7 +16156,7 @@ static struct hda_amp_list alc861_loopbacks[] = { /* * configuration and preset */ -static const char * const alc861_models[ALC861_MODEL_LAST] = { +static const char *alc861_models[ALC861_MODEL_LAST] = { [ALC861_3ST] = "3stack", [ALC660_3ST] = "3stack-660", [ALC861_3ST_DIG] = "3stack-dig", @@ -16366,8 +16306,7 @@ enum { static const struct alc_fixup alc861_fixups[] = { [PINFIX_FSC_AMILO_PI1505] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .pins = (const struct alc_pincfg[]) { { 0x0b, 0x0221101f }, /* HP */ { 0x0f, 0x90170310 }, /* speaker */ { } @@ -16402,10 +16341,8 @@ static int patch_alc861(struct hda_codec *codec) board_config = ALC861_AUTO; } - if (board_config == ALC861_AUTO) { - alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); - } + if (board_config == ALC861_AUTO) + alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups, 1); if (board_config == ALC861_AUTO) { /* automatic parse from the BIOS config */ @@ -16442,7 +16379,8 @@ static int patch_alc861(struct hda_codec *codec) spec->vmaster_nid = 0x03; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + if (board_config == ALC861_AUTO) + alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups, 0); codec->patch_ops = alc_patch_ops; if (board_config == ALC861_AUTO) { @@ -16919,7 +16857,7 @@ static void alc861vd_dallas_setup(struct hda_codec *codec) /* * configuration and preset */ -static const char * const alc861vd_models[ALC861VD_MODEL_LAST] = { +static const char *alc861vd_models[ALC861VD_MODEL_LAST] = { [ALC660VD_3ST] = "3stack-660", [ALC660VD_3ST_DIG] = "3stack-660-digout", [ALC660VD_ASUS_V1S] = "asus-v1s", @@ -17139,9 +17077,7 @@ static void alc861vd_auto_init_analog_input(struct hda_codec *codec) static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) { - static const char * const chname[4] = { - "Front", "Surround", "CLFE", "Side" - }; + static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"}; const char *pfx = alc_get_line_out_pfx(cfg, true); hda_nid_t nid_v, nid_s; int i, err; @@ -17326,8 +17262,7 @@ enum { /* reset GPIO1 */ static const struct alc_fixup alc861vd_fixups[] = { [ALC660VD_FIX_ASUS_GPIO1] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { + .verbs = (const struct hda_verb[]) { {0x01, AC_VERB_SET_GPIO_MASK, 0x03}, {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01}, {0x01, AC_VERB_SET_GPIO_DATA, 0x01}, @@ -17362,10 +17297,8 @@ static int patch_alc861vd(struct hda_codec *codec) board_config = ALC861VD_AUTO; } - if (board_config == ALC861VD_AUTO) { - alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); - } + if (board_config == ALC861VD_AUTO) + alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups, 1); if (board_config == ALC861VD_AUTO) { /* automatic parse from the BIOS config */ @@ -17413,7 +17346,8 @@ static int patch_alc861vd(struct hda_codec *codec) spec->vmaster_nid = 0x02; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + if (board_config == ALC861VD_AUTO) + alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups, 0); codec->patch_ops = alc_patch_ops; @@ -18696,7 +18630,7 @@ static struct snd_kcontrol_new alc272_nc10_mixer[] = { /* * configuration and preset */ -static const char * const alc662_models[ALC662_MODEL_LAST] = { +static const char *alc662_models[ALC662_MODEL_LAST] = { [ALC662_3ST_2ch_DIG] = "3stack-dig", [ALC662_3ST_6ch_DIG] = "3stack-6ch-dig", [ALC662_3ST_6ch] = "3stack-6ch", @@ -19211,7 +19145,7 @@ static int alc662_auto_create_multi_out_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { struct alc_spec *spec = codec->spec; - static const char * const chname[4] = { + static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; const char *pfx = alc_get_line_out_pfx(cfg, true); @@ -19444,10 +19378,7 @@ static void alc662_auto_init(struct hda_codec *codec) } static void alc272_fixup_mario(struct hda_codec *codec, - const struct alc_fixup *fix, int action) -{ - if (action != ALC_FIXUP_ACT_PROBE) - return; + const struct alc_fixup *fix, int pre_init) { if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT, (0x3b << AC_AMPCAP_OFFSET_SHIFT) | (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) | @@ -19465,22 +19396,19 @@ enum { static const struct alc_fixup alc662_fixups[] = { [ALC662_FIXUP_ASPIRE] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .pins = (const struct alc_pincfg[]) { { 0x15, 0x99130112 }, /* subwoofer */ { } } }, [ALC662_FIXUP_IDEAPAD] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .pins = (const struct alc_pincfg[]) { { 0x17, 0x99130112 }, /* subwoofer */ { } } }, [ALC272_FIXUP_MARIO] = { - .type = ALC_FIXUP_FUNC, - .v.func = alc272_fixup_mario, + .func = alc272_fixup_mario, } }; @@ -19534,9 +19462,7 @@ static int patch_alc662(struct hda_codec *codec) } if (board_config == ALC662_AUTO) { - alc_pick_fixup(codec, alc662_fixup_models, - alc662_fixup_tbl, alc662_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + alc_pick_fixup(codec, alc662_fixup_tbl, alc662_fixups, 1); /* automatic parse from the BIOS config */ err = alc662_parse_auto_config(codec); if (err < 0) { @@ -19594,11 +19520,12 @@ static int patch_alc662(struct hda_codec *codec) } spec->vmaster_nid = 0x02; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); - codec->patch_ops = alc_patch_ops; - if (board_config == ALC662_AUTO) + if (board_config == ALC662_AUTO) { spec->init_hook = alc662_auto_init; + alc_pick_fixup_model(codec, alc662_fixup_models, + alc662_fixup_tbl, alc662_fixups, 0); + } alc_init_jacks(codec); @@ -19986,7 +19913,7 @@ static void alc680_auto_init(struct hda_codec *codec) /* * configuration and preset */ -static const char * const alc680_models[ALC680_MODEL_LAST] = { +static const char *alc680_models[ALC680_MODEL_LAST] = { [ALC680_BASE] = "base", [ALC680_AUTO] = "auto", }; diff --git a/trunk/sound/pci/hda/patch_sigmatel.c b/trunk/sound/pci/hda/patch_sigmatel.c index 9ea48b425d0b..4ab019d0924e 100644 --- a/trunk/sound/pci/hda/patch_sigmatel.c +++ b/trunk/sound/pci/hda/patch_sigmatel.c @@ -266,7 +266,7 @@ struct sigmatel_spec { struct sigmatel_mic_route int_mic; struct sigmatel_mic_route dock_mic; - const char * const *spdif_labels; + const char **spdif_labels; hda_nid_t dig_in_nid; hda_nid_t mono_nid; @@ -524,7 +524,7 @@ static unsigned long stac927x_capsws[] = { HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT), }; -static const char * const stac927x_spdif_labels[5] = { +static const char *stac927x_spdif_labels[5] = { "Digital Playback", "ADAT", "Analog Mux 1", "Analog Mux 2", "Analog Mux 3" }; @@ -1062,7 +1062,7 @@ static struct snd_kcontrol_new stac_smux_mixer = { .put = stac92xx_smux_enum_put, }; -static const char * const slave_vols[] = { +static const char *slave_vols[] = { "Front Playback Volume", "Surround Playback Volume", "Center Playback Volume", @@ -1073,7 +1073,7 @@ static const char * const slave_vols[] = { NULL }; -static const char * const slave_sws[] = { +static const char *slave_sws[] = { "Front Playback Switch", "Surround Playback Switch", "Center Playback Switch", @@ -1354,7 +1354,7 @@ static unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = { [STAC_9200_PANASONIC] = ref9200_pin_configs, }; -static const char * const stac9200_models[STAC_9200_MODELS] = { +static const char *stac9200_models[STAC_9200_MODELS] = { [STAC_AUTO] = "auto", [STAC_REF] = "ref", [STAC_9200_OQO] = "oqo", @@ -1500,7 +1500,7 @@ static unsigned int *stac925x_brd_tbl[STAC_925x_MODELS] = { [STAC_M6] = stac925xM6_pin_configs, }; -static const char * const stac925x_models[STAC_925x_MODELS] = { +static const char *stac925x_models[STAC_925x_MODELS] = { [STAC_925x_AUTO] = "auto", [STAC_REF] = "ref", [STAC_M1] = "m1", @@ -1574,7 +1574,7 @@ static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = { [STAC_92HD73XX_INTEL] = intel_dg45id_pin_configs, }; -static const char * const stac92hd73xx_models[STAC_92HD73XX_MODELS] = { +static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = { [STAC_92HD73XX_AUTO] = "auto", [STAC_92HD73XX_NO_JD] = "no-jd", [STAC_92HD73XX_REF] = "ref", @@ -1660,7 +1660,7 @@ static unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = { [STAC_HP_DV7_4000] = hp_dv7_4000_pin_configs, }; -static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { +static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { [STAC_92HD83XXX_AUTO] = "auto", [STAC_92HD83XXX_REF] = "ref", [STAC_92HD83XXX_PWR_REF] = "mic-ref", @@ -1722,7 +1722,7 @@ static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = { [STAC_HP_DV4_1222NR] = NULL, }; -static const char * const stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = { +static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = { [STAC_92HD71BXX_AUTO] = "auto", [STAC_92HD71BXX_REF] = "ref", [STAC_DELL_M4_1] = "dell-m4-1", @@ -1915,7 +1915,7 @@ static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = { [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs, }; -static const char * const stac922x_models[STAC_922X_MODELS] = { +static const char *stac922x_models[STAC_922X_MODELS] = { [STAC_922X_AUTO] = "auto", [STAC_D945_REF] = "ref", [STAC_D945GTP5] = "5stack", @@ -2077,7 +2077,7 @@ static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { [STAC_927X_VOLKNOB] = NULL, }; -static const char * const stac927x_models[STAC_927X_MODELS] = { +static const char *stac927x_models[STAC_927X_MODELS] = { [STAC_927X_AUTO] = "auto", [STAC_D965_REF_NO_JD] = "ref-no-jd", [STAC_D965_REF] = "ref", @@ -2180,7 +2180,7 @@ static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = { [STAC_9205_EAPD] = NULL, }; -static const char * const stac9205_models[STAC_9205_MODELS] = { +static const char *stac9205_models[STAC_9205_MODELS] = { [STAC_9205_AUTO] = "auto", [STAC_9205_REF] = "ref", [STAC_9205_DELL_M42] = "dell-m42", @@ -3123,7 +3123,7 @@ static int create_multi_out_ctls(struct hda_codec *codec, int num_outs, int type) { struct sigmatel_spec *spec = codec->spec; - static const char * const chname[4] = { + static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; hda_nid_t nid; @@ -3256,7 +3256,7 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, } /* labels for mono mux outputs */ -static const char * const stac92xx_mono_labels[4] = { +static const char *stac92xx_mono_labels[4] = { "DAC0", "DAC1", "Mixer", "DAC2" }; @@ -3380,7 +3380,7 @@ static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec) return 0; }; -static const char * const stac92xx_spdif_labels[3] = { +static const char *stac92xx_spdif_labels[3] = { "Digital Playback", "Analog Mux 1", "Analog Mux 2", }; @@ -3388,7 +3388,7 @@ static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; struct hda_input_mux *spdif_mux = &spec->private_smux; - const char * const *labels = spec->spdif_labels; + const char **labels = spec->spdif_labels; int i, num_cons; hda_nid_t con_lst[HDA_MAX_NUM_INPUTS]; @@ -3409,7 +3409,7 @@ static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec) } /* labels for dmic mux inputs */ -static const char * const stac92xx_dmic_labels[5] = { +static const char *stac92xx_dmic_labels[5] = { "Analog Inputs", "Digital Mic 1", "Digital Mic 2", "Digital Mic 3", "Digital Mic 4" }; @@ -5333,7 +5333,7 @@ static int patch_stac92hd73xx(struct hda_codec *codec) return 0; } -static int hp_bnb2011_with_dock(struct hda_codec *codec) +static int stac92hd83xxx_set_system_btl_amp(struct hda_codec *codec) { if (codec->vendor_id != 0x111d7605 && codec->vendor_id != 0x111d76d1) @@ -5348,6 +5348,10 @@ static int hp_bnb2011_with_dock(struct hda_codec *codec) case 0x103c161d: case 0x103c161e: case 0x103c161f: + case 0x103c1620: + case 0x103c1621: + case 0x103c1622: + case 0x103c1623: case 0x103c162a: case 0x103c162b: @@ -5356,9 +5360,41 @@ static int hp_bnb2011_with_dock(struct hda_codec *codec) case 0x103c1631: case 0x103c1633: - case 0x103c1634: + case 0x103c1635: + case 0x103c164f: + + case 0x103c1676: + case 0x103c1677: + case 0x103c1678: + case 0x103c1679: + case 0x103c167a: + case 0x103c167b: + case 0x103c167c: + case 0x103c167d: + case 0x103c167e: + case 0x103c167f: + case 0x103c1680: + case 0x103c1681: + case 0x103c1682: + case 0x103c1683: + case 0x103c1684: + case 0x103c1685: + case 0x103c1686: + case 0x103c1687: + case 0x103c1688: + case 0x103c1689: + case 0x103c168a: + case 0x103c168b: + case 0x103c168c: + case 0x103c168d: + case 0x103c168e: + case 0x103c168f: + case 0x103c1690: + case 0x103c1691: + case 0x103c1692: + case 0x103c3587: case 0x103c3588: case 0x103c3589: @@ -5366,9 +5402,9 @@ static int hp_bnb2011_with_dock(struct hda_codec *codec) case 0x103c3667: case 0x103c3668: - case 0x103c3669: - - return 1; + /* set BTL amp level to 13.43dB for louder speaker output */ + return snd_hda_codec_write_cache(codec, codec->afg, 0, + 0x7F4, 0x14); } return 0; } @@ -5384,11 +5420,6 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - if (hp_bnb2011_with_dock(codec)) { - snd_hda_codec_set_pincfg(codec, 0xa, 0x2101201f); - snd_hda_codec_set_pincfg(codec, 0xf, 0x2181205e); - } - /* reset pin power-down; Windows may leave these bits after reboot */ snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7EC, 0); snd_hda_codec_write_cache(codec, codec->afg, 0, 0x7ED, 0); @@ -5515,6 +5546,8 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) AC_VERB_SET_CONNECT_SEL, num_dacs); } + stac92hd83xxx_set_system_btl_amp(codec); + codec->proc_widget_hook = stac92hd_proc_hook; return 0; @@ -6237,7 +6270,7 @@ static unsigned int stac9872_vaio_pin_configs[9] = { 0x90a7013e }; -static const char * const stac9872_models[STAC_9872_MODELS] = { +static const char *stac9872_models[STAC_9872_MODELS] = { [STAC_9872_AUTO] = "auto", [STAC_9872_VAIO] = "vaio", }; diff --git a/trunk/sound/pci/hda/patch_via.c b/trunk/sound/pci/hda/patch_via.c index a76c3260d941..7f4852a478a1 100644 --- a/trunk/sound/pci/hda/patch_via.c +++ b/trunk/sound/pci/hda/patch_via.c @@ -2281,9 +2281,7 @@ static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec, const struct auto_pin_cfg *cfg) { char name[32]; - static const char * const chname[4] = { - "Front", "Surround", "C/LFE", "Side" - }; + static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; hda_nid_t nid, nid_vol, nid_vols[] = {0x17, 0x19, 0x1a, 0x1b}; int i, err; @@ -2372,7 +2370,7 @@ static void create_hp_imux(struct via_spec *spec) { int i; struct hda_input_mux *imux = &spec->private_imux[1]; - static const char * const texts[] = { "OFF", "ON", NULL}; + static const char *texts[] = { "OFF", "ON", NULL}; /* for hp mode select */ for (i = 0; texts[i]; i++) @@ -2892,9 +2890,7 @@ static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec, const struct auto_pin_cfg *cfg) { char name[32]; - static const char * const chname[4] = { - "Front", "Surround", "C/LFE", "Side" - }; + static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; hda_nid_t nid, nid_vol, nid_vols[] = {0x18, 0x1a, 0x1b, 0x29}; int i, err; @@ -3437,9 +3433,7 @@ static int vt1708B_auto_create_multi_out_ctls(struct via_spec *spec, const struct auto_pin_cfg *cfg) { char name[32]; - static const char * const chname[4] = { - "Front", "Surround", "C/LFE", "Side" - }; + static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; hda_nid_t nid_vols[] = {0x16, 0x18, 0x26, 0x27}; hda_nid_t nid, nid_vol = 0; int i, err; @@ -3867,9 +3861,7 @@ static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec, const struct auto_pin_cfg *cfg) { char name[32]; - static const char * const chname[4] = { - "Front", "Surround", "C/LFE", "Side" - }; + static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; hda_nid_t nid_vols[] = {0x10, 0x11, 0x24, 0x25}; hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x26, 0x27}; hda_nid_t nid, nid_vol, nid_mute; @@ -4312,7 +4304,7 @@ static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) { int err, i; struct hda_input_mux *imux; - static const char * const texts[] = { "ON", "OFF", NULL}; + static const char *texts[] = { "ON", "OFF", NULL}; if (!pin) return 0; spec->multiout.hp_nid = 0x1D; @@ -4623,9 +4615,7 @@ static int vt1718S_auto_create_multi_out_ctls(struct via_spec *spec, const struct auto_pin_cfg *cfg) { char name[32]; - static const char * const chname[4] = { - "Front", "Surround", "C/LFE", "Side" - }; + static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; hda_nid_t nid_vols[] = {0x8, 0x9, 0xa, 0xb}; hda_nid_t nid_mutes[] = {0x24, 0x25, 0x26, 0x27}; hda_nid_t nid, nid_vol, nid_mute = 0; @@ -5074,9 +5064,7 @@ static int vt1716S_auto_create_multi_out_ctls(struct via_spec *spec, const struct auto_pin_cfg *cfg) { char name[32]; - static const char * const chname[3] = { - "Front", "Surround", "C/LFE" - }; + static const char *chname[3] = { "Front", "Surround", "C/LFE" }; hda_nid_t nid_vols[] = {0x10, 0x11, 0x25}; hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x27}; hda_nid_t nid, nid_vol, nid_mute; diff --git a/trunk/sound/pci/oxygen/xonar_dg.c b/trunk/sound/pci/oxygen/xonar_dg.c index e1fa602eba79..e4de0b8d087a 100644 --- a/trunk/sound/pci/oxygen/xonar_dg.c +++ b/trunk/sound/pci/oxygen/xonar_dg.c @@ -75,7 +75,7 @@ static void cs4245_write(struct oxygen *chip, unsigned int reg, u8 value) OXYGEN_SPI_CEN_LATCH_CLOCK_HI, CS4245_SPI_ADDRESS | CS4245_SPI_WRITE | - (reg << 8) | value); + (value << 8) | reg); data->cs4245_regs[reg] = value; } diff --git a/trunk/sound/soc/codecs/Kconfig b/trunk/sound/soc/codecs/Kconfig index c48b23c1d4fc..883a312bb293 100644 --- a/trunk/sound/soc/codecs/Kconfig +++ b/trunk/sound/soc/codecs/Kconfig @@ -44,7 +44,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_TWL6040 if TWL4030_CORE select SND_SOC_UDA134X select SND_SOC_UDA1380 if I2C - select SND_SOC_WL1273 if RADIO_WL1273 + select SND_SOC_WL1273 if WL1273_CORE select SND_SOC_WM2000 if I2C select SND_SOC_WM8350 if MFD_WM8350 select SND_SOC_WM8400 if MFD_WM8400 diff --git a/trunk/sound/soc/codecs/wl1273.c b/trunk/sound/soc/codecs/wl1273.c index 861b28f543d2..d3ffa2f0122a 100644 --- a/trunk/sound/soc/codecs/wl1273.c +++ b/trunk/sound/soc/codecs/wl1273.c @@ -42,7 +42,7 @@ struct wl1273_priv { static int snd_wl1273_fm_set_i2s_mode(struct wl1273_core *core, int rate, int width) { - struct device *dev = &core->client->dev; + struct device *dev = &core->i2c_dev->dev; int r = 0; u16 mode; @@ -123,13 +123,13 @@ static int snd_wl1273_fm_set_i2s_mode(struct wl1273_core *core, dev_dbg(dev, "mode: 0x%04x\n", mode); if (core->i2s_mode != mode) { - r = core->write(core, WL1273_I2S_MODE_CONFIG_SET, mode); + r = wl1273_fm_write_cmd(core, WL1273_I2S_MODE_CONFIG_SET, mode); if (r) goto out; core->i2s_mode = mode; - r = core->write(core, WL1273_AUDIO_ENABLE, - WL1273_AUDIO_ENABLE_I2S); + r = wl1273_fm_write_cmd(core, WL1273_AUDIO_ENABLE, + WL1273_AUDIO_ENABLE_I2S); if (r) goto out; } @@ -142,7 +142,8 @@ static int snd_wl1273_fm_set_i2s_mode(struct wl1273_core *core, static int snd_wl1273_fm_set_channel_number(struct wl1273_core *core, int channel_number) { - struct device *dev = &core->client->dev; + struct i2c_client *client = core->i2c_dev; + struct device *dev = &client->dev; int r = 0; dev_dbg(dev, "%s\n", __func__); @@ -153,13 +154,17 @@ static int snd_wl1273_fm_set_channel_number(struct wl1273_core *core, goto out; if (channel_number == 1 && core->mode == WL1273_MODE_RX) - r = core->write(core, WL1273_MOST_MODE_SET, WL1273_RX_MONO); + r = wl1273_fm_write_cmd(core, WL1273_MOST_MODE_SET, + WL1273_RX_MONO); else if (channel_number == 1 && core->mode == WL1273_MODE_TX) - r = core->write(core, WL1273_MONO_SET, WL1273_TX_MONO); + r = wl1273_fm_write_cmd(core, WL1273_MONO_SET, + WL1273_TX_MONO); else if (channel_number == 2 && core->mode == WL1273_MODE_RX) - r = core->write(core, WL1273_MOST_MODE_SET, WL1273_RX_STEREO); + r = wl1273_fm_write_cmd(core, WL1273_MOST_MODE_SET, + WL1273_RX_STEREO); else if (channel_number == 2 && core->mode == WL1273_MODE_TX) - r = core->write(core, WL1273_MONO_SET, WL1273_TX_STEREO); + r = wl1273_fm_write_cmd(core, WL1273_MONO_SET, + WL1273_TX_STEREO); else r = -EINVAL; out: @@ -232,7 +237,7 @@ static int snd_wl1273_fm_audio_put(struct snd_kcontrol *kcontrol, if (wl1273->core->audio_mode == val) return 0; - r = wl1273->core->set_audio(wl1273->core, val); + r = wl1273_fm_set_audio(wl1273->core, val); if (r < 0) return r; @@ -267,8 +272,8 @@ static int snd_wl1273_fm_volume_put(struct snd_kcontrol *kcontrol, dev_dbg(codec->dev, "%s: enter.\n", __func__); - r = wl1273->core->set_volume(wl1273->core, - ucontrol->value.integer.value[0]); + r = wl1273_fm_set_volume(wl1273->core, + ucontrol->value.integer.value[0]); if (r) return r; diff --git a/trunk/sound/soc/codecs/wl1273.h b/trunk/sound/soc/codecs/wl1273.h index 43ec7e668c51..14ed027fdcfc 100644 --- a/trunk/sound/soc/codecs/wl1273.h +++ b/trunk/sound/soc/codecs/wl1273.h @@ -25,6 +25,77 @@ #ifndef __WL1273_CODEC_H__ #define __WL1273_CODEC_H__ +/* I2S protocol, left channel first, data width 16 bits */ +#define WL1273_PCM_DEF_MODE 0x00 + +/* Rx */ +#define WL1273_AUDIO_ENABLE_I2S (1 << 0) +#define WL1273_AUDIO_ENABLE_ANALOG (1 << 1) + +/* Tx */ +#define WL1273_AUDIO_IO_SET_ANALOG 0 +#define WL1273_AUDIO_IO_SET_I2S 1 + +#define WL1273_POWER_SET_OFF 0 +#define WL1273_POWER_SET_FM (1 << 0) +#define WL1273_POWER_SET_RDS (1 << 1) +#define WL1273_POWER_SET_RETENTION (1 << 4) + +#define WL1273_PUPD_SET_OFF 0x00 +#define WL1273_PUPD_SET_ON 0x01 +#define WL1273_PUPD_SET_RETENTION 0x10 + +/* I2S mode */ +#define WL1273_IS2_WIDTH_32 0x0 +#define WL1273_IS2_WIDTH_40 0x1 +#define WL1273_IS2_WIDTH_22_23 0x2 +#define WL1273_IS2_WIDTH_23_22 0x3 +#define WL1273_IS2_WIDTH_48 0x4 +#define WL1273_IS2_WIDTH_50 0x5 +#define WL1273_IS2_WIDTH_60 0x6 +#define WL1273_IS2_WIDTH_64 0x7 +#define WL1273_IS2_WIDTH_80 0x8 +#define WL1273_IS2_WIDTH_96 0x9 +#define WL1273_IS2_WIDTH_128 0xa +#define WL1273_IS2_WIDTH 0xf + +#define WL1273_IS2_FORMAT_STD (0x0 << 4) +#define WL1273_IS2_FORMAT_LEFT (0x1 << 4) +#define WL1273_IS2_FORMAT_RIGHT (0x2 << 4) +#define WL1273_IS2_FORMAT_USER (0x3 << 4) + +#define WL1273_IS2_MASTER (0x0 << 6) +#define WL1273_IS2_SLAVEW (0x1 << 6) + +#define WL1273_IS2_TRI_AFTER_SENDING (0x0 << 7) +#define WL1273_IS2_TRI_ALWAYS_ACTIVE (0x1 << 7) + +#define WL1273_IS2_SDOWS_RR (0x0 << 8) +#define WL1273_IS2_SDOWS_RF (0x1 << 8) +#define WL1273_IS2_SDOWS_FR (0x2 << 8) +#define WL1273_IS2_SDOWS_FF (0x3 << 8) + +#define WL1273_IS2_TRI_OPT (0x0 << 10) +#define WL1273_IS2_TRI_ALWAYS (0x1 << 10) + +#define WL1273_IS2_RATE_48K (0x0 << 12) +#define WL1273_IS2_RATE_44_1K (0x1 << 12) +#define WL1273_IS2_RATE_32K (0x2 << 12) +#define WL1273_IS2_RATE_22_05K (0x4 << 12) +#define WL1273_IS2_RATE_16K (0x5 << 12) +#define WL1273_IS2_RATE_12K (0x8 << 12) +#define WL1273_IS2_RATE_11_025 (0x9 << 12) +#define WL1273_IS2_RATE_8K (0xa << 12) +#define WL1273_IS2_RATE (0xf << 12) + +#define WL1273_I2S_DEF_MODE (WL1273_IS2_WIDTH_32 | \ + WL1273_IS2_FORMAT_STD | \ + WL1273_IS2_MASTER | \ + WL1273_IS2_TRI_AFTER_SENDING | \ + WL1273_IS2_SDOWS_RR | \ + WL1273_IS2_TRI_OPT | \ + WL1273_IS2_RATE_48K) + int wl1273_get_format(struct snd_soc_codec *codec, unsigned int *fmt); #endif /* End of __WL1273_CODEC_H__ */ diff --git a/trunk/sound/soc/codecs/wm8990.c b/trunk/sound/soc/codecs/wm8990.c index 100aeee5ba96..5c87a634fc04 100644 --- a/trunk/sound/soc/codecs/wm8990.c +++ b/trunk/sound/soc/codecs/wm8990.c @@ -1183,7 +1183,7 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec, WM8990_VMIDTOG); /* Delay to allow output caps to discharge */ - msleep(300); + msleep(msecs_to_jiffies(300)); /* Disable VMIDTOG */ snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | @@ -1195,17 +1195,17 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec, /* Enable outputs */ snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1b00); - msleep(50); + msleep(msecs_to_jiffies(50)); /* Enable VMID at 2x50k */ snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f02); - msleep(100); + msleep(msecs_to_jiffies(100)); /* Enable VREF */ snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03); - msleep(600); + msleep(msecs_to_jiffies(600)); /* Enable BUFIOEN */ snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | @@ -1250,7 +1250,7 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec, /* Disable VMID */ snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f01); - msleep(300); + msleep(msecs_to_jiffies(300)); /* Enable all output discharge bits */ snd_soc_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE | diff --git a/trunk/sound/soc/ep93xx/ep93xx-i2s.c b/trunk/sound/soc/ep93xx/ep93xx-i2s.c index fff579a1c134..9ac93f6b4f85 100644 --- a/trunk/sound/soc/ep93xx/ep93xx-i2s.c +++ b/trunk/sound/soc/ep93xx/ep93xx-i2s.c @@ -267,16 +267,14 @@ static int ep93xx_i2s_hw_params(struct snd_pcm_substream *substream, ep93xx_i2s_write_reg(info, EP93XX_I2S_RXWRDLEN, word_len); /* - * EP93xx I2S module can be setup so SCLK / LRCLK value can be - * 32, 64, 128. MCLK / SCLK value can be 2 and 4. - * We set LRCLK equal to `rate' and minimum SCLK / LRCLK - * value is 64, because our sample size is 32 bit * 2 channels. - * I2S standard permits us to transmit more bits than - * the codec uses. + * Calculate the sdiv (bit clock) and lrdiv (left/right clock) values. + * If the lrclk is pulse length is larger than the word size, then the + * bit clock will be gated for the unused bits. */ - div = clk_get_rate(info->mclk) / params_rate(params); + div = (clk_get_rate(info->mclk) / params_rate(params)) * + params_channels(params); for (sdiv = 2; sdiv <= 4; sdiv += 2) - for (lrdiv = 64; lrdiv <= 128; lrdiv <<= 1) + for (lrdiv = 32; lrdiv <= 128; lrdiv <<= 1) if (sdiv * lrdiv == div) { found = 1; goto out; @@ -343,7 +341,9 @@ static struct snd_soc_dai_ops ep93xx_i2s_dai_ops = { .set_fmt = ep93xx_i2s_set_dai_fmt, }; -#define EP93XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S32_LE) +#define EP93XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) static struct snd_soc_dai_driver ep93xx_i2s_dai = { .symmetric_rates= 1, diff --git a/trunk/tools/perf/builtin-record.c b/trunk/tools/perf/builtin-record.c index fcd29e8af29f..df6064ad9bf2 100644 --- a/trunk/tools/perf/builtin-record.c +++ b/trunk/tools/perf/builtin-record.c @@ -936,8 +936,6 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) list_for_each_entry(pos, &evsel_list, node) { if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) goto out_free_fd; - if (perf_header__push_event(pos->attr.config, event_name(pos))) - goto out_free_fd; } event_array = malloc((sizeof(struct pollfd) * MAX_NR_CPUS * MAX_COUNTERS * threads->nr)); diff --git a/trunk/tools/perf/util/parse-events.c b/trunk/tools/perf/util/parse-events.c index bc2732ee23eb..5cb6f4bde905 100644 --- a/trunk/tools/perf/util/parse-events.c +++ b/trunk/tools/perf/util/parse-events.c @@ -490,6 +490,32 @@ parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp, return EVT_HANDLED_ALL; } +static int store_event_type(const char *orgname) +{ + char filename[PATH_MAX], *c; + FILE *file; + int id, n; + + sprintf(filename, "%s/", debugfs_path); + strncat(filename, orgname, strlen(orgname)); + strcat(filename, "/id"); + + c = strchr(filename, ':'); + if (c) + *c = '/'; + + file = fopen(filename, "r"); + if (!file) + return 0; + n = fscanf(file, "%i", &id); + fclose(file); + if (n < 1) { + pr_err("cannot store event ID\n"); + return -EINVAL; + } + return perf_header__push_event(id, orgname); +} + static enum event_result parse_tracepoint_event(const char **strp, struct perf_event_attr *attr) { @@ -529,10 +555,13 @@ static enum event_result parse_tracepoint_event(const char **strp, if (evt_length >= MAX_EVENT_LENGTH) return EVT_FAILED; if (strpbrk(evt_name, "*?")) { - *strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */ + *strp += strlen(sys_name) + evt_length; return parse_multiple_tracepoint_event(sys_name, evt_name, flags); } else { + if (store_event_type(evt_name) < 0) + return EVT_FAILED; + return parse_single_tracepoint_event(sys_name, evt_name, evt_length, attr, strp); }